2 * Copyright (C) 2010-2013 Team XBMC
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)
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.
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/>.
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"
29 #include "utils/log.h"
31 #include "android/jni/AudioFormat.h"
32 #include "android/jni/AudioManager.h"
33 #include "android/jni/AudioTrack.h"
37 #if 0 //defined(__ARM_NEON__)
39 #include "utils/CPUInfo.h"
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)
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);
51 for (i = 0; i < (n & ~3); i += 4)
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))));
60 b[i] = (int16_t) lrintf(a[i] * 0x7FFF);
64 CAEDeviceInfo CAESinkAUDIOTRACK::m_info;
65 ////////////////////////////////////////////////////////////////////////////////////////////
66 CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
71 m_audiotrackbuffer_sec = 0.0;
77 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
82 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
84 m_lastFormat = format;
87 if (AE_IS_RAW(m_format.m_dataFormat))
90 m_passthrough = false;
92 #if defined(HAS_LIBAMCODEC)
93 if (CSettings::Get().GetBool("videoplayer.useamcodec"))
94 aml_set_audio_passthrough(m_passthrough);
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,
114 CJNIAudioTrack::MODE_STREAM);
115 m_format.m_frames = m_min_frames / 2;
117 m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count();
120 JNIEnv* jenv = xbmc_jnienv();
121 // Set the initial volume
125 CXBMCApp::SetSystemVolume(jenv, volume);
130 void CAESinkAUDIOTRACK::Deinitialize()
139 m_frames_written = 0;
145 double CAESinkAUDIOTRACK::GetDelay()
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();
155 double delay = (double)(m_frames_written - head_pos) / m_format.m_sampleRate;
160 double CAESinkAUDIOTRACK::GetLatency()
162 #if defined(HAS_LIBAMCODEC)
169 double CAESinkAUDIOTRACK::GetCacheTotal()
171 // total amount that the audio sink can buffer in units of seconds
172 return m_audiotrackbuffer_sec;
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)
182 // write as many frames of audio as we can fit into our internal buffer.
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)
192 written = m_at_jni->write((char*)data, 0, frames * m_sink_frameSize);
193 m_frames_written += written / m_sink_frameSize;
196 return (unsigned int)(written/m_sink_frameSize);
199 void CAESinkAUDIOTRACK::Drain()
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
207 m_frames_written = 0;
210 bool CAESinkAUDIOTRACK::HasVolume()
215 void CAESinkAUDIOTRACK::SetVolume(float scale)
223 CXBMCApp::SetSystemVolume(xbmc_jnienv(), m_volume);
227 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
229 m_info.m_channels.Reset();
230 m_info.m_dataFormats.clear();
231 m_info.m_sampleRates.clear();
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);
248 list.push_back(m_info);