MythTV  master
audiooutputaudiotrack.cpp
Go to the documentation of this file.
1 
2 #include "config.h"
3 
4 #include <QAndroidJniObject>
5 #include <QAndroidJniEnvironment>
6 #include <android/log.h>
7 
8 #include "mythlogging.h"
10 
11 #define CHANNELS_MIN 1
12 #define CHANNELS_MAX 8
13 
14 #define ANDROID_EXCEPTION_CHECK \
15  if (env->ExceptionCheck()) { \
16  env->ExceptionDescribe(); \
17  env->ExceptionClear(); \
18  exception=true; \
19  } else \
20  exception=false;
21 // clear exception without checking
22 #define ANDROID_EXCEPTION_CLEAR \
23  if (env->ExceptionCheck()) { \
24  env->ExceptionDescribe(); \
25  env->ExceptionClear(); \
26  }
27 
28 #define LOC QString("AudioTrack: ")
29 
30 // Constants from Android Java API
31 // class android.media.AudioFormat
32 #define AF_CHANNEL_OUT_MONO 4
33 #define AF_ENCODING_AC3 5
34 #define AF_ENCODING_E_AC3 6
35 #define AF_ENCODING_DTS 7
36 #define AF_ENCODING_DOLBY_TRUEHD 14
37 #define AF_ENCODING_PCM_8BIT 3
38 #define AF_ENCODING_PCM_16BIT 2
39 #define AF_ENCODING_PCM_FLOAT 4
40 
41 // for debugging
42 #include <android/log.h>
43 
45  AudioOutputBase(settings)
46 {
47  InitSettings(settings);
48  if (settings.m_init)
49  Reconfigure(settings);
50 }
51 
53 {
54  KillAudio();
55 }
56 
58 {
59  bool exception=false;
60  QAndroidJniEnvironment env;
61  jint encoding = 0;
62  jint sampleRate = m_sampleRate;
63 
64  // m_bitsPer10Frames = output bits per 10 frames
66 
67  if ((m_passthru || m_enc) && m_sourceBitRate > 0)
69 
70  // 50 milliseconds
72 
73  if (m_fragmentSize < 1536)
74  m_fragmentSize = 1536;
75 
76 
77  if (m_passthru || m_enc)
78  {
79  switch (m_codec)
80  {
81  case AV_CODEC_ID_AC3:
82  encoding = AF_ENCODING_AC3;
83  break;
84  case AV_CODEC_ID_DTS:
85  encoding = AF_ENCODING_DTS;
86  break;
87  case AV_CODEC_ID_EAC3:
88  encoding = AF_ENCODING_E_AC3;
89  break;
90  case AV_CODEC_ID_TRUEHD:
91  encoding = AF_ENCODING_DOLBY_TRUEHD;
92  break;
93 
94  default:
95  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + QString(" No support for audio passthru encoding %1").arg(m_codec));
96  return false;
97  }
98  }
99  else
100  {
101  switch (m_outputFormat)
102  {
103  case FORMAT_U8:
104  // This could be used to get the value from java instead // of haning these constants in pour header file.
105  // encoding = QAndroidJniObject::getStaticField<jint>
106  // ("android.media.AudioFormat","ENCODING_PCM_8BIT");
107  encoding = AF_ENCODING_PCM_8BIT;
108  break;
109  case FORMAT_S16:
110  encoding = AF_ENCODING_PCM_16BIT;
111  break;
112  case FORMAT_FLT:
113  encoding = AF_ENCODING_PCM_FLOAT;
114  break;
115  default:
116  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + QString(" No support for audio format %1").arg(m_outputFormat));
117  return false;
118  }
119  }
120 
121  jint minBufferSize = m_fragmentSize * 4;
122  m_soundcardBufferSize = minBufferSize;
123  jint channels = m_channels;
124 
125  m_audioTrack = new QAndroidJniObject("org/mythtv/audio/AudioOutputAudioTrack",
126  "(IIII)V", encoding, sampleRate, minBufferSize, channels);
128 
129  if (exception)
130  {
131  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + QString(" Java Exception when creating AudioTrack"));
132  m_audioTrack = nullptr;
133  return false;
134  }
135  if (!m_passthru && !m_enc)
136  {
137  jint bitsPer10Frames = m_bitsPer10Frames;
138  m_audioTrack->callMethod<void>("setBitsPer10Frames","(I)V",bitsPer10Frames);
139  }
140  return true;
141 }
142 
144 {
145  QAndroidJniEnvironment env;
146  if (m_audioTrack)
147  {
148  m_audioTrack->callMethod<void>("release");
150  delete m_audioTrack;
151  m_audioTrack = nullptr;
152  }
153 }
154 
156 {
157  bool exception=false;
158  QAndroidJniEnvironment env;
159  jint bufsize = 0;
160 
161  AudioOutputSettings *settings = new AudioOutputSettings();
162 
163  int supportedrate = 0;
164  while (int rate = settings->GetNextRate())
165  {
166  // Checking for valid rates using getMinBufferSize.
167  // See https://stackoverflow.com/questions/8043387/android-audiorecord-supported-sampling-rates/22317382
168  bufsize = QAndroidJniObject::callStaticMethod<jint>
169  ("android/media/AudioTrack", "getMinBufferSize", "(III)I",
172  if (bufsize > 0 && !exception)
173  {
174  settings->AddSupportedRate(rate);
175  // save any supported rate for later
176  supportedrate = rate;
177  }
178  }
179 
180  // Checking for valid format using getMinBufferSize.
181  bufsize = QAndroidJniObject::callStaticMethod<jint>
182  ("android/media/AudioTrack", "getMinBufferSize", "(III)I",
183  supportedrate, AF_CHANNEL_OUT_MONO, AF_ENCODING_PCM_8BIT);
185  if (bufsize > 0 && !exception)
186  settings->AddSupportedFormat(FORMAT_U8);
187  // 16bit always supported
188  settings->AddSupportedFormat(FORMAT_S16);
189 
190  bufsize = QAndroidJniObject::callStaticMethod<jint>
191  ("android/media/AudioTrack", "getMinBufferSize", "(III)I",
194  if (bufsize > 0 && !exception)
195  settings->AddSupportedFormat(FORMAT_FLT);
196 
197  for (uint channels = CHANNELS_MIN; channels <= CHANNELS_MAX; channels++)
198  {
199  settings->AddSupportedChannels(channels);
200  }
201  settings->setPassthrough(0);
202 
203  return settings;
204 }
205 
206 void AudioOutputAudioTrack::WriteAudio(unsigned char* aubuf, int size)
207 {
208  bool exception=false;
209  QAndroidJniEnvironment env;
210  if (m_actuallyPaused)
211  {
212  if (m_audioTrack)
213  {
214  jboolean param = true;
215  m_audioTrack->callMethod<void>("pause","(Z)V",param);
217  }
218  return;
219  }
220  // create a java byte array
221  jbyteArray arr = env->NewByteArray(size);
222  env->SetByteArrayRegion(arr, 0, size, reinterpret_cast<jbyte*>(aubuf));
223  jint ret = -99;
224  if (m_audioTrack)
225  {
226  ret = m_audioTrack->callMethod<jint>("write","([BI)I", arr, size);
228  }
229  env->DeleteLocalRef(arr);
230  if (ret != size || exception)
231  LOG(VB_GENERAL, LOG_ERR, LOC + __func__
232  + QString(" Audio Write failed, size %1 return %2 exception %3")
233  .arg(size).arg(ret).arg(exception));
234 
235  LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO, LOC + __func__
236  + QString(" WriteAudio size=%1 written=%2")
237  .arg(size).arg(ret));
238 }
239 
240 
242 {
243  bool exception=false;
244  QAndroidJniEnvironment env;
245  int buffered (0);
246  if (m_audioTrack)
247  {
248  // This may return a negative value, because there
249  // is data already played that is still in the "Audio circular buffer"
250  buffered
251  = m_audioTrack->callMethod<jint>("getBufferedBytes");
253  if (exception)
254  buffered = 0;
255  int latency
256  = m_audioTrack->callMethod<jint>("getLatencyViaHeadPosition");
258  if (exception)
259  latency = 0;
260  buffered += latency * m_sampleRate / 1000 * m_bitsPer10Frames / 80 ;
261  }
262 
263  return buffered;
264 }
265 
266 bool AudioOutputAudioTrack::AddData(void *in_buffer, int in_len,
267  int64_t timecode, int in_frames)
268 {
269  bool ret = AudioOutputBase::AddData
270  (in_buffer, in_len, timecode,in_frames);
271 
272  return ret;
273 }
274 
276 {
277  AudioOutputBase::Pause(paused);
278  if (m_audioTrack)
279  {
280  jboolean param = paused;
281  m_audioTrack->callMethod<void>("pause","(Z)V",param);
282  }
283 }
284 
286 {
288  if (m_sourceBitRate > 0
289  && (m_passthru || m_enc)
290  && m_audioTrack)
291  {
293  jint bitsPer10Frames = m_bitsPer10Frames;
294  m_audioTrack->callMethod<void>("setBitsPer10Frames","(I)V",bitsPer10Frames);
295  }
296 }
297 
299 {
300  QAndroidJniEnvironment env;
301  if (m_audioTrack)
302  {
303  m_audioTrack->callMethod<void>("setOutputThread","(Z)V",true);
305  }
306 
308 }
309 
311 {
312  QAndroidJniEnvironment env;
313  if (m_audioTrack)
314  {
315  m_audioTrack->callMethod<void>("setOutputThread","(Z)V",false);
317  }
318 
320 }
FORMAT_U8
@ FORMAT_U8
Definition: audiooutputsettings.h:27
AudioOutputBase::m_enc
bool m_enc
Definition: audiooutputbase.h:187
AudioOutputSettings::GetNextRate
int GetNextRate()
Definition: audiooutputsettings.cpp:68
AF_CHANNEL_OUT_MONO
#define AF_CHANNEL_OUT_MONO
Definition: audiooutputaudiotrack.cpp:32
AudioOutputBase::Pause
void Pause(bool paused) override
Definition: audiooutputbase.cpp:901
AudioOutputAudioTrack::m_bitsPer10Frames
int m_bitsPer10Frames
Definition: audiooutputaudiotrack.h:41
AudioOutputSettings::setPassthrough
void setPassthrough(int val)
Definition: audiooutputsettings.h:77
FORMAT_S16
@ FORMAT_S16
Definition: audiooutputsettings.h:28
AudioOutputSettings::AddSupportedFormat
void AddSupportedFormat(AudioFormat format)
Definition: audiooutputsettings.cpp:129
AF_ENCODING_PCM_FLOAT
#define AF_ENCODING_PCM_FLOAT
Definition: audiooutputaudiotrack.cpp:39
AudioOutputAudioTrack::m_audioTrack
QAndroidJniObject * m_audioTrack
Definition: audiooutputaudiotrack.h:40
AudioOutputAudioTrack::AddData
bool AddData(void *buffer, int len, int64_t timecode, int frames) override
Add data to the audiobuffer for playback.
Definition: audiooutputaudiotrack.cpp:266
AudioOutputAudioTrack::StartOutputThread
bool StartOutputThread(void) override
Definition: audiooutputaudiotrack.cpp:298
AudioOutputBase::KillAudio
void KillAudio(void)
Kill the output thread and cleanup.
Definition: audiooutputbase.cpp:859
AudioOutputAudioTrack::GetBufferedOnSoundcard
int GetBufferedOnSoundcard(void) const override
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
Definition: audiooutputaudiotrack.cpp:241
arg
arg(title).arg(filename).arg(doDelete))
CHANNELS_MIN
#define CHANNELS_MIN
Definition: audiooutputaudiotrack.cpp:11
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
AF_ENCODING_PCM_8BIT
#define AF_ENCODING_PCM_8BIT
Definition: audiooutputaudiotrack.cpp:37
LOC
#define LOC
Definition: audiooutputaudiotrack.cpp:28
AudioOutputBase::m_sampleRate
int m_sampleRate
Definition: audiooutputbase.h:177
audiooutputaudiotrack.h
AudioOutputSettings::AddSupportedChannels
void AddSupportedChannels(int channels)
Definition: audiooutputsettings.cpp:239
AudioSettings
Definition: audiosettings.h:29
AudioOutputAudioTrack::SetSourceBitrate
void SetSourceBitrate(int rate) override
Definition: audiooutputaudiotrack.cpp:285
AudioOutputBase::m_soundcardBufferSize
long m_soundcardBufferSize
Definition: audiooutputbase.h:180
AudioOutputBase
Definition: audiooutputbase.h:50
AudioSettings::m_init
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
Definition: audiosettings.h:84
mythlogging.h
AF_ENCODING_E_AC3
#define AF_ENCODING_E_AC3
Definition: audiooutputaudiotrack.cpp:34
AudioOutputBase::m_sourceSampleRate
int m_sourceSampleRate
Definition: audiooutputbase.h:214
AudioOutputBase::StopOutputThread
virtual void StopOutputThread(void)
Definition: audiooutputbase.cpp:847
FORMAT_FLT
@ FORMAT_FLT
Definition: audiooutputsettings.h:32
AudioOutputBase::Reconfigure
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
Definition: audiooutputbase.cpp:467
AudioOutputAudioTrack::WriteAudio
void WriteAudio(unsigned char *aubuf, int size) override
Definition: audiooutputaudiotrack.cpp:206
AudioOutputAudioTrack::OpenDevice
bool OpenDevice(void) override
Definition: audiooutputaudiotrack.cpp:57
ANDROID_EXCEPTION_CLEAR
#define ANDROID_EXCEPTION_CLEAR
Definition: audiooutputaudiotrack.cpp:22
AudioOutputSettings::AddSupportedRate
void AddSupportedRate(int rate)
Definition: audiooutputsettings.cpp:79
AF_ENCODING_AC3
#define AF_ENCODING_AC3
Definition: audiooutputaudiotrack.cpp:33
uint
unsigned int uint
Definition: compat.h:140
AudioOutputBase::m_passthru
bool m_passthru
Definition: audiooutputbase.h:186
AF_ENCODING_DTS
#define AF_ENCODING_DTS
Definition: audiooutputaudiotrack.cpp:35
AudioOutputBase::m_outputFormat
AudioFormat m_outputFormat
Definition: audiooutputbase.h:176
AudioOutputBase::m_channels
int m_channels
Definition: audiooutputbase.h:171
AudioOutputBase::m_codec
AVCodecID m_codec
Definition: audiooutputbase.h:172
AudioOutputAudioTrack::AudioOutputAudioTrack
AudioOutputAudioTrack(const AudioSettings &settings)
Definition: audiooutputaudiotrack.cpp:44
AudioOutputBase::m_outputBytesPerFrame
int m_outputBytesPerFrame
Definition: audiooutputbase.h:174
AudioOutputBase::m_sourceBitRate
long m_sourceBitRate
Definition: audiooutputbase.h:213
AudioOutputBase::m_actuallyPaused
bool m_actuallyPaused
Definition: audiooutputbase.h:197
AudioOutputAudioTrack::StopOutputThread
void StopOutputThread(void) override
Definition: audiooutputaudiotrack.cpp:310
AudioOutputAudioTrack::~AudioOutputAudioTrack
~AudioOutputAudioTrack() override
Definition: audiooutputaudiotrack.cpp:52
AudioOutputSettings
Definition: audiooutputsettings.h:50
AF_ENCODING_DOLBY_TRUEHD
#define AF_ENCODING_DOLBY_TRUEHD
Definition: audiooutputaudiotrack.cpp:36
AudioOutputBase::InitSettings
void InitSettings(const AudioSettings &settings)
Definition: audiooutputbase.cpp:119
AudioOutputAudioTrack::Pause
void Pause(bool paused) override
Definition: audiooutputaudiotrack.cpp:275
AudioOutputBase::StartOutputThread
virtual bool StartOutputThread(void)
Definition: audiooutputbase.cpp:835
AF_ENCODING_PCM_16BIT
#define AF_ENCODING_PCM_16BIT
Definition: audiooutputaudiotrack.cpp:38
AudioOutputBase::AddData
bool AddData(void *buffer, int len, int64_t timecode, int frames) override
Add data to the audiobuffer and perform any required processing.
Definition: audiooutputbase.cpp:1313
CHANNELS_MAX
#define CHANNELS_MAX
Definition: audiooutputaudiotrack.cpp:12
AudioOutputAudioTrack::GetOutputSettings
AudioOutputSettings * GetOutputSettings(bool digital) override
Definition: audiooutputaudiotrack.cpp:155
AudioOutputBase::m_fragmentSize
int m_fragmentSize
Definition: audiooutputbase.h:179
ANDROID_EXCEPTION_CHECK
#define ANDROID_EXCEPTION_CHECK
Definition: audiooutputaudiotrack.cpp:14
AudioOutputAudioTrack::CloseDevice
void CloseDevice(void) override
Definition: audiooutputaudiotrack.cpp:143
AudioOutputBase::SetSourceBitrate
void SetSourceBitrate(int rate) override
Set the bitrate of the source material, reported in periodic OutputEvents.
Definition: audiooutputbase.cpp:270