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