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