The icky noise problem has been fixed.
[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 #endif
111
112   // default to 44100, all android devices support it.
113   // then check if we can support the requested rate.
114   unsigned int sampleRate = 44100;
115   for (size_t i = 0; i < m_info.m_sampleRates.size(); i++)
116   {
117     if (m_format.m_sampleRate == m_info.m_sampleRates[i])
118     {
119       sampleRate = m_format.m_sampleRate;
120       break;
121     }
122   }
123   m_format.m_sampleRate = sampleRate;
124
125   // default to AE_FMT_S16LE,
126   // then check if we can support the requested format.
127   AEDataFormat dataFormat = AE_FMT_S16LE;
128   for (size_t i = 0; i < m_info.m_dataFormats.size(); i++)
129   {
130     if (m_format.m_dataFormat == m_info.m_dataFormats[i])
131     {
132       dataFormat = m_format.m_dataFormat;
133       break;
134     }
135   }
136   m_format.m_dataFormat = dataFormat;
137
138   m_format.m_channelLayout = m_info.m_channels;
139   m_format.m_frameSize = m_format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3);
140
141   m_draining = false;
142   m_volume_changed = false;
143   // launch the process thread and wait for the
144   // AutoTrack jni object to get created and setup.
145   m_wake.Reset();
146   m_inited.Reset();
147   Create();
148   if(!m_inited.WaitMSec(100))
149   {
150     while(!m_inited.WaitMSec(1))
151       Sleep(10);
152   }
153
154   // m_min_frames is volatile and has been setup by Process()
155   m_format.m_frames = m_min_frames;
156   m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count();
157   format = m_format;
158
159   return true;
160 }
161
162 void CAESinkAUDIOTRACK::Deinitialize()
163 {
164   // force m_bStop and set m_wake, if might be sleeping.
165   m_bStop = true;
166   m_wake.Set();
167   StopThread();
168   delete m_sinkbuffer, m_sinkbuffer = NULL;
169   if (m_alignedS16)
170     _aligned_free(m_alignedS16), m_alignedS16 = NULL;
171 }
172
173 bool CAESinkAUDIOTRACK::IsCompatible(const AEAudioFormat &format, const std::string &device)
174 {
175   return ((m_format.m_sampleRate    == format.m_sampleRate) &&
176           (m_format.m_dataFormat    == format.m_dataFormat) &&
177           (m_format.m_channelLayout == format.m_channelLayout));
178 }
179
180 double CAESinkAUDIOTRACK::GetDelay()
181 {
182   // this includes any latency due to AudioTrack buffer,
183   // AudioMixer (if any) and audio hardware driver.
184
185   double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer->GetReadSize();
186   sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec;
187   if (sinkbuffer_seconds_to_empty > 0.0)
188     sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec_tweaks;
189   return sinkbuffer_seconds_to_empty;
190 }
191
192 double CAESinkAUDIOTRACK::GetCacheTime()
193 {
194   // returns the time in seconds that it will take
195   // to underrun the buffer if no sample is added.
196
197   double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer->GetReadSize();
198   sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec;
199   if (sinkbuffer_seconds_to_empty > 0.0)
200     sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec_tweaks;
201   return sinkbuffer_seconds_to_empty;
202 }
203
204 double CAESinkAUDIOTRACK::GetCacheTotal()
205 {
206   // total amount that the audio sink can buffer in units of seconds
207
208   return m_sinkbuffer_sec + m_audiotrackbuffer_sec;
209 }
210
211 unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
212 {
213   // write as many frames of audio as we can fit into our internal buffer.
214
215   // our internal sink buffer is always AE_FMT_S16
216   unsigned int write_frames = m_sinkbuffer->GetWriteSize() / m_sink_frameSize;
217   if (write_frames > frames)
218     write_frames = frames;
219
220   if (hasAudio && write_frames)
221   {
222     switch(m_format.m_dataFormat)
223     {
224       case AE_FMT_S16LE:
225         m_sinkbuffer->Write(data, write_frames * m_sink_frameSize);
226         m_wake.Set();
227         break;
228 #if defined(__ARM_NEON__)
229       case AE_FMT_FLOAT:
230         if (!m_alignedS16)
231           m_alignedS16 = (int16_t*)_aligned_malloc(m_format.m_frames * m_sink_frameSize, 16);
232         // neon convert AE_FMT_S16LE to AE_FMT_FLOAT
233         pa_sconv_s16le_from_f32ne_neon(write_frames * m_format.m_channelLayout.Count(), (const float32_t *)data, m_alignedS16);
234         m_sinkbuffer->Write((unsigned char*)m_alignedS16, write_frames * m_sink_frameSize);
235         m_wake.Set();
236         break;
237 #endif
238       default:
239         break;
240     }
241   }
242   // AddPackets runs under a non-idled AE thread we must block or sleep.
243   // Trying to calc the optimal sleep is tricky so just a minimal sleep.
244   if(blocking)
245     Sleep(10);
246
247   return hasAudio ? write_frames:frames;
248 }
249
250 void CAESinkAUDIOTRACK::Drain()
251 {
252   CLog::Log(LOGDEBUG, "CAESinkAUDIOTRACK::Drain");
253   CSingleLock lock(m_drain_lock);
254   m_draining = true;
255   m_wake.Set();
256 }
257
258 bool CAESinkAUDIOTRACK::HasVolume()
259 {
260   return true;
261 }
262
263 void  CAESinkAUDIOTRACK::SetVolume(float scale)
264 {
265   // Android uses fixed steps, reverse scale back to percent
266   float gain = CAEUtil::ScaleToGain(scale);
267   m_volume = CAEUtil::GainToPercent(gain);
268   if (!m_passthrough)
269   {
270     CSingleLock lock(m_volume_lock);
271     m_volume_changed = true;
272   }
273 }
274
275 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
276 {
277   m_info.m_channels.Reset();
278   m_info.m_dataFormats.clear();
279   m_info.m_sampleRates.clear();
280
281   m_info.m_deviceType = AE_DEVTYPE_PCM;
282   m_info.m_deviceName = "AudioTrack";
283   m_info.m_displayName = "android";
284   m_info.m_displayNameExtra = "audiotrack";
285   m_info.m_channels += AE_CH_FL;
286   m_info.m_channels += AE_CH_FR;
287   m_info.m_sampleRates.push_back(44100);
288   m_info.m_sampleRates.push_back(48000);
289   m_info.m_dataFormats.push_back(AE_FMT_S16LE);
290 #if defined(__ARM_NEON__)
291   if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
292     m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
293 #endif
294
295   list.push_back(m_info);
296 }
297
298 void CAESinkAUDIOTRACK::Process()
299 {
300   CLog::Log(LOGDEBUG, "CAESinkAUDIOTRACK::Process");
301
302   JNIEnv *jenv = xbmc_jnienv();
303
304   jclass jcAudioTrack = jenv->FindClass("android/media/AudioTrack");
305
306   jmethodID jmInit              = jenv->GetMethodID(jcAudioTrack, "<init>", "(IIIIII)V");
307   jmethodID jmPlay              = jenv->GetMethodID(jcAudioTrack, "play", "()V");
308   jmethodID jmStop              = jenv->GetMethodID(jcAudioTrack, "stop", "()V");
309   jmethodID jmFlush             = jenv->GetMethodID(jcAudioTrack, "flush", "()V");
310   jmethodID jmRelease           = jenv->GetMethodID(jcAudioTrack, "release", "()V");
311   jmethodID jmWrite             = jenv->GetMethodID(jcAudioTrack, "write", "([BII)I");
312   jmethodID jmPlayState         = jenv->GetMethodID(jcAudioTrack, "getPlayState", "()I");
313   jmethodID jmPlayHeadPosition  = jenv->GetMethodID(jcAudioTrack, "getPlaybackHeadPosition", "()I");
314   jmethodID jmGetMinBufferSize  = jenv->GetStaticMethodID(jcAudioTrack, "getMinBufferSize", "(III)I");
315
316   jint audioFormat    = GetStaticIntField(jenv, "AudioFormat", "ENCODING_PCM_16BIT");
317   jint channelConfig  = GetStaticIntField(jenv, "AudioFormat", "CHANNEL_OUT_STEREO");
318
319   jint min_buffer_size = jenv->CallStaticIntMethod(jcAudioTrack, jmGetMinBufferSize,
320     m_format.m_sampleRate, channelConfig, audioFormat);
321
322   m_sink_frameSize = m_format.m_channelLayout.Count() * CAEUtil::DataFormatToBits(AE_FMT_S16LE) >> 3;
323   m_min_frames = min_buffer_size / m_sink_frameSize;
324
325   m_audiotrackbuffer_sec = (double)m_min_frames / (double)m_format.m_sampleRate;
326   m_audiotrack_empty_sec = 0.0;
327
328   // setup a 1/4 second internal sink lockless ring buffer
329   m_sinkbuffer = new AERingBuffer(m_sink_frameSize * m_format.m_sampleRate / 4);
330   m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_sink_frameSize * m_format.m_sampleRate);
331   m_sinkbuffer_sec = (double)m_sinkbuffer_sec_per_byte * m_sinkbuffer->GetMaxSize();
332
333   jobject joAudioTrack = jenv->NewObject(jcAudioTrack, jmInit,
334     GetStaticIntField(jenv, "AudioManager", "STREAM_MUSIC"),
335     m_format.m_sampleRate,
336     channelConfig,
337     audioFormat,
338     min_buffer_size,
339     GetStaticIntField(jenv, "AudioTrack", "MODE_STREAM"));
340
341   // Set the initial volume
342   float volume = 1.0;
343   if (!m_passthrough)
344     volume = m_volume;
345   CXBMCApp::SetSystemVolume(jenv, volume);
346
347   // The AudioTrack object has been created and waiting to play,
348   m_inited.Set();
349   // yield to give other threads a chance to do some work.
350   sched_yield();
351
352   // cache the playing int value.
353   jint playing = GetStaticIntField(jenv, "AudioTrack", "PLAYSTATE_PLAYING");
354
355   // create a java byte buffer for writing pcm data to AudioTrack.
356   jarray jbuffer = jenv->NewByteArray(min_buffer_size);
357
358   int64_t frames_written = 0;
359   int64_t frame_position = 0;
360
361   while (!m_bStop)
362   {
363     if (m_volume_changed && !m_passthrough)
364     {
365       // check of volume changes and make them,
366       // do it here to keep jni calls local to this thread.
367       CXBMCApp::SetSystemVolume(jenv, m_volume);
368       CSingleLock lock(m_volume_lock);
369       m_volume_changed = false;
370     }
371     if (m_draining)
372     {
373       unsigned char byte_drain[1024];
374       unsigned int  byte_drain_size = m_sinkbuffer->GetReadSize();
375       if (byte_drain_size > 1024)
376         byte_drain_size = 1024;
377       while (byte_drain_size)
378       {
379         m_sinkbuffer->Read(byte_drain, byte_drain_size);
380         byte_drain_size = m_sinkbuffer->GetReadSize();
381         if (byte_drain_size > 1024)
382           byte_drain_size = 1024;
383       }
384       jenv->CallVoidMethod(joAudioTrack, jmStop);
385       jenv->CallVoidMethod(joAudioTrack, jmFlush);
386       CSingleLock lock(m_drain_lock);
387       m_draining = false;
388     }
389
390     unsigned int read_bytes = m_sinkbuffer->GetReadSize();
391     if (read_bytes > (unsigned int)min_buffer_size)
392       read_bytes = min_buffer_size;
393
394     if (read_bytes > 0)
395     {
396       // android will auto pause the playstate when it senses idle,
397       // check it and set playing if it does this. Do this before
398       // writing into its buffer.
399       if (jenv->CallIntMethod(joAudioTrack, jmPlayState) != playing)
400         jenv->CallVoidMethod( joAudioTrack, jmPlay);
401
402       // Write a buffer of audio data to Java AudioTrack.
403       // Warning, no other JNI function can be called after
404       // GetPrimitiveArrayCritical until ReleasePrimitiveArrayCritical.
405       void *pBuffer = jenv->GetPrimitiveArrayCritical(jbuffer, NULL);
406       if (pBuffer)
407       {
408         m_sinkbuffer->Read((unsigned char*)pBuffer, read_bytes);
409         jenv->ReleasePrimitiveArrayCritical(jbuffer, pBuffer, 0);
410         // jmWrite is blocking and returns when the data has been transferred
411         // from the Java layer and queued for playback.
412         jenv->CallIntMethod(joAudioTrack, jmWrite, jbuffer, 0, read_bytes);
413       }
414     }
415     // calc the number of seconds until audiotrack buffer is empty.
416     frame_position = jenv->CallIntMethod(joAudioTrack, jmPlayHeadPosition);
417     if (frame_position == 0)
418       frames_written = 0;
419     frames_written += read_bytes / m_sink_frameSize;
420     m_audiotrack_empty_sec = (double)(frames_written - frame_position) / m_format.m_sampleRate;
421     // some times, we can get frame_position
422     // ahead of frames_written, not a clue why. clamp it.
423     if (m_audiotrack_empty_sec < 0.0f)
424       m_audiotrack_empty_sec = 0.0f;
425
426     if (m_sinkbuffer->GetReadSize() == 0)
427     {
428       // the sink buffer is empty, stop playback.
429       // Audiotrack will playout any written contents.
430       jenv->CallVoidMethod(joAudioTrack, jmStop);
431       // sleep this audio thread, we will get woken when we have audio data.
432       m_wake.WaitMSec(250);
433     }
434   }
435
436   jenv->CallVoidMethod(joAudioTrack, jmStop);
437   jenv->CallVoidMethod(joAudioTrack, jmFlush);
438   jenv->CallVoidMethod(joAudioTrack, jmRelease);
439
440   // might toss an exception on jmRelease so catch it.
441   jthrowable exception = jenv->ExceptionOccurred();
442   if (exception)
443   {
444     jenv->ExceptionDescribe();
445     jenv->ExceptionClear();
446   }
447
448   jenv->DeleteLocalRef(jbuffer);
449   jenv->DeleteLocalRef(joAudioTrack);
450   jenv->DeleteLocalRef(jcAudioTrack);
451 }