1 /*****************************************************************************
2 * audiotrack.c: Android native AudioTrack audio output module
3 *****************************************************************************
4 * Copyright © 2012 VLC authors and VideoLAN
6 * Authors: Ming Hu <tewilove@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
27 #include <vlc_common.h>
28 #include <vlc_plugin.h>
34 #define SIZE_OF_AUDIOTRACK 256
36 /* From AudioSystem.h */
40 PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
41 PCM_SUB_8_BIT = 0x2 // must be 2 for backward compatibility
45 PCM = 0x00000000, // must be 0 for backward compatibility
46 PCM_16_BIT = (PCM|PCM_SUB_16_BIT),
47 PCM_8_BIT = (PCM|PCM_SUB_8_BIT)
51 CHANNEL_OUT_FRONT_LEFT = 0x4,
52 CHANNEL_OUT_FRONT_RIGHT = 0x8,
53 CHANNEL_OUT_FRONT_CENTER = 0x10,
54 CHANNEL_OUT_LOW_FREQUENCY = 0x20,
55 CHANNEL_OUT_BACK_LEFT = 0x40,
56 CHANNEL_OUT_BACK_RIGHT = 0x80,
57 CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
58 CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
59 CHANNEL_OUT_BACK_CENTER = 0x400,
60 CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
61 CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT)
64 // _ZN7android11AudioSystem19getOutputFrameCountEPii
65 typedef int (*AudioSystem_getOutputFrameCount)(int *, int);
66 // _ZN7android11AudioSystem16getOutputLatencyEPji
67 typedef int (*AudioSystem_getOutputLatency)(unsigned int *, int);
68 // _ZN7android11AudioSystem21getOutputSamplingRateEPii
69 typedef int (*AudioSystem_getOutputSamplingRate)(int *, int);
71 // _ZN7android10AudioTrack16getMinFrameCountEPiij
72 typedef int (*AudioTrack_getMinFrameCount)(int *, int, unsigned int);
74 // _ZN7android11AudioSystem17getRenderPositionEPjS1_i
75 typedef int (*AudioTrack_getRenderPosition)(uint32_t *, uint32_t *, int);
76 // _ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii
77 typedef void (*AudioTrack_ctor)(void *, int, unsigned int, int, int, int, unsigned int, void (*)(int, void *, void *), void *, int, int);
78 // _ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i
79 typedef void (*AudioTrack_ctor_legacy)(void *, int, unsigned int, int, int, int, unsigned int, void (*)(int, void *, void *), void *, int);
80 // _ZN7android10AudioTrackD1Ev
81 typedef void (*AudioTrack_dtor)(void *);
82 // _ZNK7android10AudioTrack9initCheckEv
83 typedef int (*AudioTrack_initCheck)(void *);
84 // _ZN7android10AudioTrack5startEv
85 typedef int (*AudioTrack_start)(void *);
86 // _ZN7android10AudioTrack4stopEv
87 typedef int (*AudioTrack_stop)(void *);
88 // _ZN7android10AudioTrack5writeEPKvj
89 typedef int (*AudioTrack_write)(void *, void const*, unsigned int);
90 // _ZN7android10AudioTrack5flushEv
91 typedef int (*AudioTrack_flush)(void *);
92 // _ZN7android10AudioTrack5pauseEv
93 typedef int (*AudioTrack_pause)(void *);
100 uint32_t samples_written;
107 AudioSystem_getOutputFrameCount as_getOutputFrameCount;
108 AudioSystem_getOutputLatency as_getOutputLatency;
109 AudioSystem_getOutputSamplingRate as_getOutputSamplingRate;
111 AudioTrack_getMinFrameCount at_getMinFrameCount;
112 AudioTrack_ctor at_ctor;
113 AudioTrack_ctor_legacy at_ctor_legacy;
114 AudioTrack_dtor at_dtor;
115 AudioTrack_initCheck at_initCheck;
116 AudioTrack_start at_start;
117 AudioTrack_stop at_stop;
118 AudioTrack_write at_write;
119 AudioTrack_flush at_flush;
120 AudioTrack_pause at_pause;
121 AudioTrack_getRenderPosition at_getRenderPosition;
124 /* Soft volume helper */
127 static void *InitLibrary(struct aout_sys_t *p_sys);
129 static int Open(vlc_object_t *);
130 static void Close(vlc_object_t *);
131 static void Play(audio_output_t*, block_t*);
132 static void Pause (audio_output_t *, bool, mtime_t);
133 static void Flush (audio_output_t *, bool);
136 set_shortname("AudioTrack")
137 set_description(N_("Android AudioTrack audio output"))
138 set_capability("audio output", 225)
139 set_category(CAT_AUDIO)
140 set_subcategory(SUBCAT_AUDIO_AOUT)
142 add_shortcut("android")
143 set_callbacks(Open, Close)
146 static void *InitLibrary(struct aout_sys_t *p_sys)
148 /* DL Open libmedia */
150 p_library = dlopen("libmedia.so", RTLD_NOW|RTLD_LOCAL);
154 /* Register symbols */
155 p_sys->as_getOutputFrameCount = (AudioSystem_getOutputFrameCount)(dlsym(p_library, "_ZN7android11AudioSystem19getOutputFrameCountEPii"));
156 p_sys->as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
157 if(p_sys->as_getOutputLatency == NULL) {
158 /* 4.1 Jellybean prototype */
159 p_sys->as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t"));
161 p_sys->as_getOutputSamplingRate = (AudioSystem_getOutputSamplingRate)(dlsym(p_library, "_ZN7android11AudioSystem21getOutputSamplingRateEPii"));
162 p_sys->at_getMinFrameCount = (AudioTrack_getMinFrameCount)(dlsym(p_library, "_ZN7android10AudioTrack16getMinFrameCountEPiij"));
163 if(p_sys->at_getMinFrameCount == NULL) {
164 /* 4.1 Jellybean prototype */
165 p_sys->at_getMinFrameCount = (AudioTrack_getMinFrameCount)(dlsym(p_library, "_ZN7android10AudioTrack16getMinFrameCountEPi19audio_stream_type_tj"));
167 p_sys->at_ctor = (AudioTrack_ctor)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii"));
168 p_sys->at_ctor_legacy = (AudioTrack_ctor_legacy)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i"));
169 p_sys->at_dtor = (AudioTrack_dtor)(dlsym(p_library, "_ZN7android10AudioTrackD1Ev"));
170 p_sys->at_initCheck = (AudioTrack_initCheck)(dlsym(p_library, "_ZNK7android10AudioTrack9initCheckEv"));
171 p_sys->at_start = (AudioTrack_start)(dlsym(p_library, "_ZN7android10AudioTrack5startEv"));
172 p_sys->at_stop = (AudioTrack_stop)(dlsym(p_library, "_ZN7android10AudioTrack4stopEv"));
173 p_sys->at_write = (AudioTrack_write)(dlsym(p_library, "_ZN7android10AudioTrack5writeEPKvj"));
174 p_sys->at_flush = (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv"));
175 p_sys->at_pause = (AudioTrack_pause)(dlsym(p_library, "_ZN7android10AudioTrack5pauseEv"));
177 /* this symbol can have different names depending on the mangling */
178 p_sys->at_getRenderPosition = (AudioTrack_getRenderPosition)(dlsym(p_library, "_ZN7android11AudioSystem17getRenderPositionEPjS1_i"));
179 if (!p_sys->at_getRenderPosition)
180 p_sys->at_getRenderPosition = (AudioTrack_getRenderPosition)(dlsym(p_library, "_ZN7android11AudioSystem17getRenderPositionEPjS1_19audio_stream_type_t"));
182 /* We need the first 3 or the last 1 */
183 if (!((p_sys->as_getOutputFrameCount && p_sys->as_getOutputLatency && p_sys->as_getOutputSamplingRate)
184 || p_sys->at_getMinFrameCount)) {
189 // We need all the other Symbols
190 if (!((p_sys->at_ctor || p_sys->at_ctor_legacy) && p_sys->at_dtor && p_sys->at_initCheck &&
191 p_sys->at_start && p_sys->at_stop && p_sys->at_write && p_sys->at_flush)) {
198 static int TimeGet(audio_output_t *p_aout, mtime_t *restrict delay)
200 aout_sys_t *p_sys = p_aout->sys;
203 if (!p_sys->at_getRenderPosition)
206 if (p_sys->at_getRenderPosition(&hal, &dsp, MUSIC))
209 hal = (uint32_t)((uint64_t)hal * p_sys->rate / 44100);
211 if (p_sys->samples_written == 0) {
212 p_sys->initial = hal;
216 hal -= p_sys->initial;
221 *delay = ((mtime_t)p_sys->samples_written - hal) * CLOCK_FREQ / p_sys->rate;
226 static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
228 struct aout_sys_t *p_sys = aout->sys;
231 int afSampleRate, afFrameCount, afLatency, minBufCount, minFrameCount;
232 int stream_type, channel, rate, format;
234 /* 4000 <= frequency <= 48000 */
243 /* We can only accept U8 and S16N */
244 if (fmt->i_format != VLC_CODEC_U8 && fmt->i_format != VLC_CODEC_S16N)
245 fmt->i_format = VLC_CODEC_S16N;
246 format = (fmt->i_format == VLC_CODEC_S16N) ? PCM_16_BIT : PCM_8_BIT;
248 /* TODO: android supports more channels */
249 fmt->i_original_channels = fmt->i_physical_channels;
250 switch(aout_FormatNbChannels(fmt))
253 channel = CHANNEL_OUT_MONO;
254 fmt->i_physical_channels = AOUT_CHAN_CENTER;
258 channel = CHANNEL_OUT_STEREO;
259 fmt->i_physical_channels = AOUT_CHANS_STEREO;
263 /* Get the minimum buffer value */
264 if (!p_sys->at_getMinFrameCount) {
265 status = p_sys->as_getOutputSamplingRate(&afSampleRate, stream_type);
266 status ^= p_sys->as_getOutputFrameCount(&afFrameCount, stream_type);
267 status ^= p_sys->as_getOutputLatency((uint32_t*)(&afLatency), stream_type);
269 msg_Err(aout, "Could not query the AudioStream parameters");
272 minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
275 minFrameCount = (afFrameCount * rate * minBufCount) / afSampleRate;
278 status = p_sys->at_getMinFrameCount(&minFrameCount, stream_type, rate);
280 msg_Err(aout, "Could not query the AudioTrack parameters");
285 size = minFrameCount * (channel == CHANNEL_OUT_STEREO ? 2 : 1) * 4;
287 /* Sizeof(AudioTrack) == 0x58 (not sure) on 2.2.1, this should be enough */
288 p_sys->AudioTrack = malloc(SIZE_OF_AUDIOTRACK);
289 if (!p_sys->AudioTrack)
292 *((uint32_t *) ((uint32_t)p_sys->AudioTrack + SIZE_OF_AUDIOTRACK - 4)) = 0xbaadbaad;
293 // Higher than android 2.2
295 p_sys->at_ctor(p_sys->AudioTrack, stream_type, rate, format, channel, size, 0, NULL, NULL, 0, 0);
296 // Higher than android 1.6
297 else if (p_sys->at_ctor_legacy)
298 p_sys->at_ctor_legacy(p_sys->AudioTrack, stream_type, rate, format, channel, size, 0, NULL, NULL, 0);
300 assert( (*((uint32_t *) ((uint32_t)p_sys->AudioTrack + SIZE_OF_AUDIOTRACK - 4)) == 0xbaadbaad) );
303 status = p_sys->at_initCheck(p_sys->AudioTrack);
305 /* android 1.6 uses channel count instead of stream_type */
307 channel = (channel == CHANNEL_OUT_STEREO) ? 2 : 1;
308 p_sys->at_ctor_legacy(p_sys->AudioTrack, stream_type, rate, format, channel, size, 0, NULL, NULL, 0);
309 status = p_sys->at_initCheck(p_sys->AudioTrack);
312 msg_Err(aout, "Cannot create AudioTrack!");
313 free(p_sys->AudioTrack);
317 aout_SoftVolumeStart(aout);
320 aout->time_get = NULL;
324 aout->time_get = TimeGet;
327 p_sys->samples_written = 0;
328 p_sys->bytes_per_frame = aout_FormatNbChannels(fmt) * (format == PCM_16_BIT) ? 2 : 1;
330 p_sys->at_start(p_sys->AudioTrack);
331 TimeGet(aout, NULL); /* Gets the initial value of DAC samples counter */
338 static void Stop(audio_output_t* p_aout)
340 aout_sys_t *p_sys = p_aout->sys;
342 p_sys->at_stop(p_sys->AudioTrack);
343 p_sys->at_flush(p_sys->AudioTrack);
344 p_sys->at_dtor(p_sys->AudioTrack);
345 free(p_sys->AudioTrack);
348 static void Play(audio_output_t* p_aout, block_t* p_buffer)
350 aout_sys_t *p_sys = p_aout->sys;
352 while (p_buffer->i_buffer) {
353 int ret = p_sys->at_write(p_sys->AudioTrack, p_buffer->p_buffer, p_buffer->i_buffer);
355 msg_Err(p_aout, "Write failed (error %d)", ret);
359 p_sys->samples_written += ret / p_sys->bytes_per_frame;
360 p_buffer->p_buffer += ret;
361 p_buffer->i_buffer -= ret;
364 block_Release( p_buffer );
367 static void Pause(audio_output_t *p_aout, bool pause, mtime_t date)
371 aout_sys_t *p_sys = p_aout->sys;
374 p_sys->at_pause(p_sys->AudioTrack);
376 p_sys->at_start(p_sys->AudioTrack);
380 static void Flush (audio_output_t *p_aout, bool wait)
382 aout_sys_t *p_sys = p_aout->sys;
385 if (!TimeGet(p_aout, &delay))
388 p_sys->at_stop(p_sys->AudioTrack);
389 p_sys->at_flush(p_sys->AudioTrack);
390 p_sys->samples_written = 0;
391 p_sys->at_start(p_sys->AudioTrack);
395 static int Open(vlc_object_t *obj)
397 audio_output_t *aout = (audio_output_t *)obj;
398 aout_sys_t *sys = malloc(sizeof (*sys));
400 if (unlikely(sys == NULL))
403 sys->libmedia = InitLibrary(sys);
404 if (sys->libmedia == NULL) {
405 msg_Err(aout, "Could not initialize libmedia.so!");
413 aout_SoftVolumeInit(aout);
417 static void Close(vlc_object_t *obj)
419 audio_output_t *aout = (audio_output_t *)obj;
420 aout_sys_t *sys = aout->sys;
422 dlclose(sys->libmedia);