Merge pull request #4539 from Matricom/amcodec
[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 "cores/AudioEngine/Utils/AEUtil.h"
23 #include "cores/AudioEngine/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 "android/jni/AudioFormat.h"
32 #include "android/jni/AudioManager.h"
33 #include "android/jni/AudioTrack.h"
34
35 using namespace jni;
36
37 #if 0 //defined(__ARM_NEON__)
38 #include <arm_neon.h>
39 #include "utils/CPUInfo.h"
40
41 // LGPLv2 from PulseAudio
42 // float values from AE are pre-clamped so we do not need to clamp again here
43 static void pa_sconv_s16le_from_f32ne_neon(unsigned n, const float32_t *a, int16_t *b)
44 {
45   unsigned int i;
46
47   const float32x4_t half4     = vdupq_n_f32(0.5f);
48   const float32x4_t scale4    = vdupq_n_f32(32767.0f);
49   const uint32x4_t  mask4     = vdupq_n_u32(0x80000000);
50
51   for (i = 0; i < (n & ~3); i += 4)
52   {
53     const float32x4_t v4 = vmulq_f32(vld1q_f32(&a[i]), scale4);
54     const float32x4_t w4 = vreinterpretq_f32_u32(
55       vorrq_u32(vandq_u32(vreinterpretq_u32_f32(v4), mask4), vreinterpretq_u32_f32(half4)));
56     vst1_s16(&b[i], vmovn_s32(vcvtq_s32_f32(vaddq_f32(v4, w4))));
57   }
58   // leftovers
59   for ( ; i < n; i++)
60     b[i] = (int16_t) lrintf(a[i] * 0x7FFF);
61 }
62 #endif
63
64 CAEDeviceInfo CAESinkAUDIOTRACK::m_info;
65 ////////////////////////////////////////////////////////////////////////////////////////////
66 CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
67 {
68   m_alignedS16 = NULL;
69   m_min_frames = 0;
70   m_sink_frameSize = 0;
71   m_audiotrackbuffer_sec = 0.0;
72   m_volume = 1.0;
73   m_at_jni = NULL;
74   m_frames_written = 0;
75 }
76
77 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
78 {
79   Deinitialize();
80 }
81
82 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
83 {
84   m_lastFormat  = format;
85   m_format      = format;
86
87   if (AE_IS_RAW(m_format.m_dataFormat))
88     m_passthrough = true;
89   else
90     m_passthrough = false;
91
92 #if defined(HAS_LIBAMCODEC)
93   if (CSettings::Get().GetBool("videoplayer.useamcodec"))
94     aml_set_audio_passthrough(m_passthrough);
95 #endif
96
97   m_format.m_sampleRate     = CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC);
98   m_format.m_dataFormat     = AE_FMT_S16LE;
99   m_format.m_channelLayout  = m_info.m_channels;
100   m_format.m_frameSize      = m_format.m_channelLayout.Count() *
101                               (CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8);
102   int min_buffer_size       = CJNIAudioTrack::getMinBufferSize( m_format.m_sampleRate,
103                                                                 CJNIAudioFormat::CHANNEL_OUT_STEREO,
104                                                                 CJNIAudioFormat::ENCODING_PCM_16BIT);
105   m_sink_frameSize          = m_format.m_channelLayout.Count() *
106                               (CAEUtil::DataFormatToBits(AE_FMT_S16LE) / 8);
107   m_min_frames              = min_buffer_size / m_sink_frameSize;
108   m_audiotrackbuffer_sec    = (double)m_min_frames / (double)m_format.m_sampleRate;
109   m_at_jni                  = new CJNIAudioTrack( CJNIAudioManager::STREAM_MUSIC,
110                                                   m_format.m_sampleRate,
111                                                   CJNIAudioFormat::CHANNEL_OUT_STEREO,
112                                                   CJNIAudioFormat::ENCODING_PCM_16BIT,
113                                                   min_buffer_size,
114                                                   CJNIAudioTrack::MODE_STREAM);
115   m_format.m_frames         = m_min_frames / 2;
116
117   m_format.m_frameSamples   = m_format.m_frames * m_format.m_channelLayout.Count();
118   format                    = m_format;
119
120   JNIEnv* jenv = xbmc_jnienv();
121   // Set the initial volume
122   float volume = 1.0;
123   if (!m_passthrough)
124     volume = m_volume;
125   CXBMCApp::SetSystemVolume(jenv, volume);
126
127   return true;
128 }
129
130 void CAESinkAUDIOTRACK::Deinitialize()
131 {
132   if (!m_at_jni)
133     return;
134
135   m_at_jni->stop();
136   m_at_jni->flush();
137   m_at_jni->release();
138   
139   m_frames_written = 0;
140
141   delete m_at_jni;
142   m_at_jni = NULL;
143 }
144
145 double CAESinkAUDIOTRACK::GetDelay()
146 {
147   if (!m_at_jni)
148     return 0.0;
149
150   // In their infinite wisdom, Google decided to make getPlaybackHeadPosition
151   // return a 32bit "int" that you should "interpret as unsigned."  As such,
152   // for wrap saftey, we need to do all ops on it in 32bit integer math.
153   uint32_t head_pos = (uint32_t)m_at_jni->getPlaybackHeadPosition();
154
155   double delay = (double)(m_frames_written - head_pos) / m_format.m_sampleRate;
156
157   return delay;
158 }
159
160 double CAESinkAUDIOTRACK::GetLatency()
161 {
162 #if defined(HAS_LIBAMCODEC)
163   if (aml_present())
164     return 0.250;
165 #endif
166   return 0.0;
167 }
168
169 double CAESinkAUDIOTRACK::GetCacheTotal()
170 {
171   // total amount that the audio sink can buffer in units of seconds
172   return m_audiotrackbuffer_sec;
173 }
174
175 // this method is supposed to block until all frames are written to the device buffer
176 // when it returns ActiveAESink will take the next buffer out of a queue
177 unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
178 {
179   if (!m_at_jni)
180     return INT_MAX;
181
182   // write as many frames of audio as we can fit into our internal buffer.
183   int written = 0;
184   if (frames)
185   {
186     // android will auto pause the playstate when it senses idle,
187     // check it and set playing if it does this. Do this before
188     // writing into its buffer.
189     if (m_at_jni->getPlayState() != CJNIAudioTrack::PLAYSTATE_PLAYING)
190       m_at_jni->play();
191
192     written = m_at_jni->write((char*)data, 0, frames * m_sink_frameSize);
193     m_frames_written += written / m_sink_frameSize;
194   }
195
196   return (unsigned int)(written/m_sink_frameSize);
197 }
198
199 void CAESinkAUDIOTRACK::Drain()
200 {
201   if (!m_at_jni)
202     return;
203
204   // TODO: does this block until last samples played out?
205   // we should not return from drain as long the device is in playing state
206   m_at_jni->stop();
207   m_frames_written = 0;
208 }
209
210 bool CAESinkAUDIOTRACK::HasVolume()
211 {
212   return true;
213 }
214
215 void  CAESinkAUDIOTRACK::SetVolume(float scale)
216 {
217   if (!m_at_jni)
218     return;
219
220   m_volume = scale;
221   if (!m_passthrough)
222   {
223     CXBMCApp::SetSystemVolume(xbmc_jnienv(), m_volume);
224   }
225 }
226
227 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
228 {
229   m_info.m_channels.Reset();
230   m_info.m_dataFormats.clear();
231   m_info.m_sampleRates.clear();
232
233   m_info.m_deviceType = AE_DEVTYPE_HDMI;
234   m_info.m_deviceName = "AudioTrack";
235   m_info.m_displayName = "android";
236   m_info.m_displayNameExtra = "audiotrack";
237   m_info.m_channels += AE_CH_FL;
238   m_info.m_channels += AE_CH_FR;
239   m_info.m_sampleRates.push_back(CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC));
240   m_info.m_dataFormats.push_back(AE_FMT_S16LE);
241   m_info.m_dataFormats.push_back(AE_FMT_AC3);
242   m_info.m_dataFormats.push_back(AE_FMT_DTS);
243 #if 0 //defined(__ARM_NEON__)
244   if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
245     m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
246 #endif
247
248   list.push_back(m_info);
249 }
250