3cb42505229dccabfdaaae0e30a320aae3f4663a
[vuplus_xbmc] / xbmc / cores / AudioEngine / Sinks / AESinkAUDIOTRACK.cpp
1  /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "AESinkAUDIOTRACK.h"
22 #include "Utils/AEUtil.h"
23 #include "Utils/AERingBuffer.h"
24 #include "android/activity/XBMCApp.h"
25 #include "settings/Settings.h"
26 #if defined(HAS_LIBAMCODEC)
27 #include "utils/AMLUtils.h"
28 #endif
29 #include "utils/log.h"
30
31 #include <jni.h>
32
33 #if defined(__ARM_NEON__)
34 #include <arm_neon.h>
35 #include "utils/CPUInfo.h"
36 #include "android/jni/JNIThreading.h"
37
38 // LGPLv2 from PulseAudio
39 // float values from AE are pre-clamped so we do not need to clamp again here
40 static void pa_sconv_s16le_from_f32ne_neon(unsigned n, const float32_t *a, int16_t *b)
41 {
42   unsigned int i;
43
44   const float32x4_t half4     = vdupq_n_f32(0.5f);
45   const float32x4_t scale4    = vdupq_n_f32(32767.0f);
46   const uint32x4_t  mask4     = vdupq_n_u32(0x80000000);
47
48   for (i = 0; i < (n & ~3); i += 4)
49   {
50     const float32x4_t v4 = vmulq_f32(vld1q_f32(&a[i]), scale4);
51     const float32x4_t w4 = vreinterpretq_f32_u32(
52       vorrq_u32(vandq_u32(vreinterpretq_u32_f32(v4), mask4), vreinterpretq_u32_f32(half4)));
53     vst1_s16(&b[i], vmovn_s32(vcvtq_s32_f32(vaddq_f32(v4, w4))));
54   }
55   // leftovers
56   for ( ; i < n; i++)
57     b[i] = (int16_t) lrintf(a[i] * 0x7FFF);
58 }
59 #endif
60
61 static jint GetStaticIntField(JNIEnv *jenv, std::string class_name, std::string field_name)
62 {
63   class_name.insert(0, "android/media/");
64   jclass cls = jenv->FindClass(class_name.c_str());
65   jfieldID field = jenv->GetStaticFieldID(cls, field_name.c_str(), "I");
66   jint int_field = jenv->GetStaticIntField(cls, field);
67   jenv->DeleteLocalRef(cls);
68   return int_field;
69 }
70
71 CAEDeviceInfo CAESinkAUDIOTRACK::m_info;
72 ////////////////////////////////////////////////////////////////////////////////////////////
73 CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
74   : CThread("AudioTrack")
75 {
76   m_sinkbuffer = NULL;
77   m_alignedS16 = NULL;
78   m_volume_changed = false;
79   m_min_frames = 0;
80   m_sink_frameSize = 0;
81   m_sinkbuffer_sec = 0.0;
82   m_sinkbuffer_sec_per_byte = 0.0;
83   m_draining = false;
84   m_audiotrackbuffer_sec = 0.0;
85   m_audiotrack_empty_sec = 0.0;
86   m_audiotrack_empty_sec_tweaks = 0.0;
87 #if defined(HAS_LIBAMCODEC)
88   if (aml_present())
89     m_audiotrack_empty_sec_tweaks = 0.250;
90 #endif
91   m_volume = 1.0;
92 }
93
94 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
95 {
96 }
97
98 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
99 {
100   m_format = format;
101
102   if (AE_IS_RAW(m_format.m_dataFormat))
103     m_passthrough = true;
104   else
105     m_passthrough = false;
106
107 #if defined(HAS_LIBAMCODEC)
108   if (CSettings::Get().GetBool("videoplayer.useamcodec"))
109     aml_set_audio_passthrough(m_passthrough);
110   }
111 #endif
112
113   // default to 44100, all android devices support it.
114   // then check if we can support the requested rate.
115   unsigned int sampleRate = 44100;
116   for (size_t i = 0; i < m_info.m_sampleRates.size(); i++)
117   {
118     if (m_format.m_sampleRate == m_info.m_sampleRates[i])
119     {
120       sampleRate = m_format.m_sampleRate;
121       break;
122     }
123   }
124   m_format.m_sampleRate = sampleRate;
125
126   // default to AE_FMT_S16LE,
127   // then check if we can support the requested format.
128   AEDataFormat dataFormat = AE_FMT_S16LE;
129   for (size_t i = 0; i < m_info.m_dataFormats.size(); i++)
130   {
131     if (m_format.m_dataFormat == m_info.m_dataFormats[i])
132     {
133       dataFormat = m_format.m_dataFormat;
134       break;
135     }
136   }
137   m_format.m_dataFormat = dataFormat;
138
139   m_format.m_channelLayout = m_info.m_channels;
140   m_format.m_frameSize = m_format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3);
141
142   m_draining = false;
143   m_volume_changed = false;
144   // launch the process thread and wait for the
145   // AutoTrack jni object to get created and setup.
146   m_wake.Reset();
147   m_inited.Reset();
148   Create();
149   if(!m_inited.WaitMSec(100))
150   {
151     while(!m_inited.WaitMSec(1))
152       Sleep(10);
153   }
154
155   // m_min_frames is volatile and has been setup by Process()
156   m_format.m_frames = m_min_frames;
157   m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count();
158   format = m_format;
159
160   return true;
161 }
162
163 void CAESinkAUDIOTRACK::Deinitialize()
164 {
165   // force m_bStop and set m_wake, if might be sleeping.
166   m_bStop = true;
167   m_wake.Set();
168   StopThread();
169   delete m_sinkbuffer, m_sinkbuffer = NULL;
170   if (m_alignedS16)
171     _aligned_free(m_alignedS16), m_alignedS16 = NULL;
172 }
173
174 bool CAESinkAUDIOTRACK::IsCompatible(const AEAudioFormat &format, const std::string &device)
175 {
176   return ((m_format.m_sampleRate    == format.m_sampleRate) &&
177           (m_format.m_dataFormat    == format.m_dataFormat) &&
178           (m_format.m_channelLayout == format.m_channelLayout));
179 }
180
181 double CAESinkAUDIOTRACK::GetDelay()
182 {
183   // this includes any latency due to AudioTrack buffer,
184   // AudioMixer (if any) and audio hardware driver.
185
186   double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer->GetReadSize();
187   sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec;
188   if (sinkbuffer_seconds_to_empty > 0.0)
189     sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec_tweaks;
190   return sinkbuffer_seconds_to_empty;
191 }
192
193 double CAESinkAUDIOTRACK::GetCacheTime()
194 {
195   // returns the time in seconds that it will take
196   // to underrun the buffer if no sample is added.
197
198   double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer->GetReadSize();
199   sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec;
200   if (sinkbuffer_seconds_to_empty > 0.0)
201     sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec_tweaks;
202   return sinkbuffer_seconds_to_empty;
203 }
204
205 double CAESinkAUDIOTRACK::GetCacheTotal()
206 {
207   // total amount that the audio sink can buffer in units of seconds
208
209   return m_sinkbuffer_sec + m_audiotrackbuffer_sec;
210 }
211
212 unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
213 {
214   // write as many frames of audio as we can fit into our internal buffer.
215
216   // our internal sink buffer is always AE_FMT_S16
217   unsigned int write_frames = m_sinkbuffer->GetWriteSize() / m_sink_frameSize;
218   if (write_frames > frames)
219     write_frames = frames;
220
221   if (hasAudio && write_frames)
222   {
223     switch(m_format.m_dataFormat)
224     {
225       case AE_FMT_S16LE:
226         m_sinkbuffer->Write(data, write_frames * m_sink_frameSize);
227         m_wake.Set();
228         break;
229 #if defined(__ARM_NEON__)
230       case AE_FMT_FLOAT:
231         if (!m_alignedS16)
232           m_alignedS16 = (int16_t*)_aligned_malloc(m_format.m_frames * m_sink_frameSize, 16);
233         // neon convert AE_FMT_S16LE to AE_FMT_FLOAT
234         pa_sconv_s16le_from_f32ne_neon(write_frames * m_format.m_channelLayout.Count(), (const float32_t *)data, m_alignedS16);
235         m_sinkbuffer->Write((unsigned char*)m_alignedS16, write_frames * m_sink_frameSize);
236         m_wake.Set();
237         break;
238 #endif
239       default:
240         break;
241     }
242   }
243   // AddPackets runs under a non-idled AE thread we must block or sleep.
244   // Trying to calc the optimal sleep is tricky so just a minimal sleep.
245   if(blocking)
246     Sleep(10);
247
248   return hasAudio ? write_frames:frames;
249 }
250
251 void CAESinkAUDIOTRACK::Drain()
252 {
253   CLog::Log(LOGDEBUG, "CAESinkAUDIOTRACK::Drain");
254   CSingleLock lock(m_drain_lock);
255   m_draining = true;
256   m_wake.Set();
257 }
258
259 bool CAESinkAUDIOTRACK::HasVolume()
260 {
261   return true;
262 }
263
264 void  CAESinkAUDIOTRACK::SetVolume(float scale)
265 {
266   // Android uses fixed steps, reverse scale back to percent
267   float gain = CAEUtil::ScaleToGain(scale);
268   m_volume = CAEUtil::GainToPercent(gain);
269   if (!m_passthrough)
270   {
271     CSingleLock lock(m_volume_lock);
272     m_volume_changed = true;
273   }
274 }
275
276 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
277 {
278   m_info.m_channels.Reset();
279   m_info.m_dataFormats.clear();
280   m_info.m_sampleRates.clear();
281
282   m_info.m_deviceType = AE_DEVTYPE_PCM;
283   m_info.m_deviceName = "AudioTrack";
284   m_info.m_displayName = "android";
285   m_info.m_displayNameExtra = "audiotrack";
286   m_info.m_channels += AE_CH_FL;
287   m_info.m_channels += AE_CH_FR;
288   m_info.m_sampleRates.push_back(44100);
289   m_info.m_sampleRates.push_back(48000);
290   m_info.m_dataFormats.push_back(AE_FMT_S16LE);
291 #if 0 && defined(__ARM_NEON__)
292   if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
293     m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
294 #endif
295
296   list.push_back(m_info);
297 }
298
299 void CAESinkAUDIOTRACK::Process()
300 {
301   CLog::Log(LOGDEBUG, "CAESinkAUDIOTRACK::Process");
302
303   JNIEnv *jenv = xbmc_jnienv();
304
305   jclass jcAudioTrack = jenv->FindClass("android/media/AudioTrack");
306
307   jmethodID jmInit              = jenv->GetMethodID(jcAudioTrack, "<init>", "(IIIIII)V");
308   jmethodID jmPlay              = jenv->GetMethodID(jcAudioTrack, "play", "()V");
309   jmethodID jmStop              = jenv->GetMethodID(jcAudioTrack, "stop", "()V");
310   jmethodID jmFlush             = jenv->GetMethodID(jcAudioTrack, "flush", "()V");
311   jmethodID jmRelease           = jenv->GetMethodID(jcAudioTrack, "release", "()V");
312   jmethodID jmWrite             = jenv->GetMethodID(jcAudioTrack, "write", "([BII)I");
313   jmethodID jmPlayState         = jenv->GetMethodID(jcAudioTrack, "getPlayState", "()I");
314   jmethodID jmPlayHeadPosition  = jenv->GetMethodID(jcAudioTrack, "getPlaybackHeadPosition", "()I");
315   jmethodID jmGetMinBufferSize  = jenv->GetStaticMethodID(jcAudioTrack, "getMinBufferSize", "(III)I");
316
317   jint audioFormat    = GetStaticIntField(jenv, "AudioFormat", "ENCODING_PCM_16BIT");
318   jint channelConfig  = GetStaticIntField(jenv, "AudioFormat", "CHANNEL_OUT_STEREO");
319
320   jint min_buffer_size = jenv->CallStaticIntMethod(jcAudioTrack, jmGetMinBufferSize,
321     m_format.m_sampleRate, channelConfig, audioFormat);
322
323   m_sink_frameSize = m_format.m_channelLayout.Count() * CAEUtil::DataFormatToBits(AE_FMT_S16LE) >> 3;
324   m_min_frames = min_buffer_size / m_sink_frameSize;
325
326   m_audiotrackbuffer_sec = (double)m_min_frames / (double)m_format.m_sampleRate;
327   m_audiotrack_empty_sec = 0.0;
328
329   // setup a 1/4 second internal sink lockless ring buffer
330   m_sinkbuffer = new AERingBuffer(m_sink_frameSize * m_format.m_sampleRate / 4);
331   m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_sink_frameSize * m_format.m_sampleRate);
332   m_sinkbuffer_sec = (double)m_sinkbuffer_sec_per_byte * m_sinkbuffer->GetMaxSize();
333
334   jobject joAudioTrack = jenv->NewObject(jcAudioTrack, jmInit,
335     GetStaticIntField(jenv, "AudioManager", "STREAM_MUSIC"),
336     m_format.m_sampleRate,
337     channelConfig,
338     audioFormat,
339     min_buffer_size,
340     GetStaticIntField(jenv, "AudioTrack", "MODE_STREAM"));
341
342   // Set the initial volume
343   float volume = 1.0;
344   if (!m_passthrough)
345     volume = m_volume;
346   CXBMCApp::SetSystemVolume(jenv, volume);
347
348   // The AudioTrack object has been created and waiting to play,
349   m_inited.Set();
350   // yield to give other threads a chance to do some work.
351   sched_yield();
352
353   // cache the playing int value.
354   jint playing = GetStaticIntField(jenv, "AudioTrack", "PLAYSTATE_PLAYING");
355
356   // create a java byte buffer for writing pcm data to AudioTrack.
357   jarray jbuffer = jenv->NewByteArray(min_buffer_size);
358
359   int64_t frames_written = 0;
360   int64_t frame_position = 0;
361
362   while (!m_bStop)
363   {
364     if (m_volume_changed && !m_passthrough)
365     {
366       // check of volume changes and make them,
367       // do it here to keep jni calls local to this thread.
368       CXBMCApp::SetSystemVolume(jenv, m_volume);
369       CSingleLock lock(m_volume_lock);
370       m_volume_changed = false;
371     }
372     if (m_draining)
373     {
374       unsigned char byte_drain[1024];
375       unsigned int  byte_drain_size = m_sinkbuffer->GetReadSize();
376       if (byte_drain_size > 1024)
377         byte_drain_size = 1024;
378       while (byte_drain_size)
379       {
380         m_sinkbuffer->Read(byte_drain, byte_drain_size);
381         byte_drain_size = m_sinkbuffer->GetReadSize();
382         if (byte_drain_size > 1024)
383           byte_drain_size = 1024;
384       }
385       jenv->CallVoidMethod(joAudioTrack, jmStop);
386       jenv->CallVoidMethod(joAudioTrack, jmFlush);
387       CSingleLock lock(m_drain_lock);
388       m_draining = false;
389     }
390
391     unsigned int read_bytes = m_sinkbuffer->GetReadSize();
392     if (read_bytes > (unsigned int)min_buffer_size)
393       read_bytes = min_buffer_size;
394
395     if (read_bytes > 0)
396     {
397       // android will auto pause the playstate when it senses idle,
398       // check it and set playing if it does this. Do this before
399       // writing into its buffer.
400       if (jenv->CallIntMethod(joAudioTrack, jmPlayState) != playing)
401         jenv->CallVoidMethod( joAudioTrack, jmPlay);
402
403       // Write a buffer of audio data to Java AudioTrack.
404       // Warning, no other JNI function can be called after
405       // GetPrimitiveArrayCritical until ReleasePrimitiveArrayCritical.
406       void *pBuffer = jenv->GetPrimitiveArrayCritical(jbuffer, NULL);
407       if (pBuffer)
408       {
409         m_sinkbuffer->Read((unsigned char*)pBuffer, read_bytes);
410         jenv->ReleasePrimitiveArrayCritical(jbuffer, pBuffer, 0);
411         // jmWrite is blocking and returns when the data has been transferred
412         // from the Java layer and queued for playback.
413         jenv->CallIntMethod(joAudioTrack, jmWrite, jbuffer, 0, read_bytes);
414       }
415     }
416     // calc the number of seconds until audiotrack buffer is empty.
417     frame_position = jenv->CallIntMethod(joAudioTrack, jmPlayHeadPosition);
418     if (frame_position == 0)
419       frames_written = 0;
420     frames_written += read_bytes / m_sink_frameSize;
421     m_audiotrack_empty_sec = (double)(frames_written - frame_position) / m_format.m_sampleRate;
422     // some times, we can get frame_position
423     // ahead of frames_written, not a clue why. clamp it.
424     if (m_audiotrack_empty_sec < 0.0f)
425       m_audiotrack_empty_sec = 0.0f;
426
427     if (m_sinkbuffer->GetReadSize() == 0)
428     {
429       // the sink buffer is empty, stop playback.
430       // Audiotrack will playout any written contents.
431       jenv->CallVoidMethod(joAudioTrack, jmStop);
432       // sleep this audio thread, we will get woken when we have audio data.
433       m_wake.WaitMSec(250);
434     }
435   }
436
437   jenv->CallVoidMethod(joAudioTrack, jmStop);
438   jenv->CallVoidMethod(joAudioTrack, jmFlush);
439   jenv->CallVoidMethod(joAudioTrack, jmRelease);
440
441   // might toss an exception on jmRelease so catch it.
442   jthrowable exception = jenv->ExceptionOccurred();
443   if (exception)
444   {
445     jenv->ExceptionDescribe();
446     jenv->ExceptionClear();
447   }
448
449   jenv->DeleteLocalRef(jbuffer);
450   jenv->DeleteLocalRef(joAudioTrack);
451   jenv->DeleteLocalRef(jcAudioTrack);
452 }