From aa9ba2d5df9b2885d9deecb81c7434cb9c1f2417 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Sat, 11 Sep 2010 19:17:54 +0200 Subject: [PATCH] iOS: audio output module (Based on the AudioQueue API) This audio output is still quite young, but works fine on existing iOS devices. In theory this can also be used on Mac OS X as well, but for now it's not as powerful as the existing CoreAudio driver. Signed-off-by: Jean-Baptiste Kempf --- configure.ac | 11 ++ modules/audio_output/Modules.am | 1 + modules/audio_output/audioqueue.c | 175 ++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 modules/audio_output/audioqueue.c diff --git a/configure.ac b/configure.ac index 9f405071da..3b83d7ce7c 100644 --- a/configure.ac +++ b/configure.ac @@ -3588,6 +3588,17 @@ then ], [ AC_MSG_ERROR([cannot find CoreAudio headers]) ]) fi +dnl +dnl AudioQueue plugin +dnl +AC_ARG_ENABLE(audioqueue, + [ --enable-audioqueue AudioQueue audio module (default disabled)]) +if test "${enable_audioqueue}" = "yes" +then + VLC_ADD_PLUGIN([audioqueue]) + VLC_ADD_LDFLAGS([audioqueue], [-Wl,-framework,AudioToolbox,-framework,CoreFoundation]) +fi + dnl dnl Roku HD1000 audio dnl diff --git a/modules/audio_output/Modules.am b/modules/audio_output/Modules.am index f9df5bdb1f..ce0f47835a 100644 --- a/modules/audio_output/Modules.am +++ b/modules/audio_output/Modules.am @@ -8,6 +8,7 @@ SOURCES_portaudio = portaudio.c SOURCES_auhal = auhal.c SOURCES_jack = jack.c SOURCES_pulse = pulse.c +SOURCES_audioqueue = audioqueue.c libvlc_LTLIBRARIES += libaout_file_plugin.la diff --git a/modules/audio_output/audioqueue.c b/modules/audio_output/audioqueue.c new file mode 100644 index 0000000000..e7427b8e44 --- /dev/null +++ b/modules/audio_output/audioqueue.c @@ -0,0 +1,175 @@ +/***************************************************************************** + * audioqueue.c : AudioQueue audio output plugin for vlc + ***************************************************************************** + * Copyright (C) 2010 VideoLAN and AUTHORS + * + * Authors: Romain Goyet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* write(), close() */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include + +#define FRAME_SIZE 2048 +#define NUMBER_OF_BUFFERS 3 + +/***************************************************************************** + * aout_sys_t: AudioQueue audio output method descriptor + ***************************************************************************** + * This structure is part of the audio output thread descriptor. + * It describes the specific properties of an audio device. + *****************************************************************************/ +struct aout_sys_t +{ + AudioQueueRef audioQueue; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); +static void Play ( aout_instance_t * ); +static void AudioQueueCallback (void *, AudioQueueRef, AudioQueueBufferRef); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin () + set_shortname( "AudioQueue" ) + set_description( N_("AudioQueue (iOS / Mac OS) audio output") ) + set_capability( "audio output", 40 ) + set_category( CAT_AUDIO ) + set_subcategory( SUBCAT_AUDIO_AOUT ) + add_shortcut( "audioqueue" ) + set_callbacks( Open, Close ) +vlc_module_end () + +/***************************************************************************** + * Open: open the audio device + *****************************************************************************/ + +static int Open ( vlc_object_t *p_this ) +{ + aout_instance_t *p_aout = (aout_instance_t *)p_this; + struct aout_sys_t *p_sys = malloc(sizeof(aout_sys_t)); + p_aout->output.p_sys = p_sys; + + OSStatus status = 0; + + // Setup the audio device. + AudioStreamBasicDescription deviceFormat; + deviceFormat.mSampleRate = 44100; + deviceFormat.mFormatID = kAudioFormatLinearPCM; + deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; // Signed integer, little endian + deviceFormat.mBytesPerPacket = 4; + deviceFormat.mFramesPerPacket = 1; + deviceFormat.mBytesPerFrame = 4; + deviceFormat.mChannelsPerFrame = 2; + deviceFormat.mBitsPerChannel = 16; + deviceFormat.mReserved = 0; + + // Create a new output AudioQueue for the device. + status = AudioQueueNewOutput(&deviceFormat, // Format + AudioQueueCallback, // Callback + p_aout, // User data, passed to the callback + CFRunLoopGetMain(), // RunLoop + kCFRunLoopDefaultMode, // RunLoop mode + 0, // Flags ; must be zero (per documentation)... + &(p_sys->audioQueue)); // Output + + // This will be used for boosting the audio without the need of a mixer (floating-point conversion is expensive on ARM) + // AudioQueueSetParameter(p_sys->audioQueue, kAudioQueueParam_Volume, 12.0); // Defaults to 1.0 + + msg_Dbg(p_aout, "New AudioQueue output created (status = %ld)", status); + + // Allocate buffers for the AudioQueue, and pre-fill them. + for (int i = 0; i < NUMBER_OF_BUFFERS; ++i) { + AudioQueueBufferRef buffer = NULL; + status = AudioQueueAllocateBuffer(p_sys->audioQueue, FRAME_SIZE * 4, &buffer); + AudioQueueCallback(NULL, p_sys->audioQueue, buffer); + } + + /* Volume is entirely done in software. */ + aout_VolumeSoftInit( p_aout ); + + p_aout->output.output.i_format = VLC_CODEC_S16L; + p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; + p_aout->output.output.i_rate = 44100; + p_aout->output.i_nb_samples = FRAME_SIZE; + p_aout->output.pf_play = Play; + + msg_Dbg(p_aout, "Starting AudioQueue (status = %ld)", status); + status = AudioQueueStart(p_sys->audioQueue, NULL); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Play: play a sound samples buffer + *****************************************************************************/ +static void Play( aout_instance_t * p_aout ) +{ + VLC_UNUSED(p_aout); +} + +/***************************************************************************** + * Close: close the audio device + *****************************************************************************/ +static void Close ( vlc_object_t *p_this ) +{ + aout_instance_t *p_aout = (aout_instance_t *)p_this; + struct aout_sys_t * p_sys = p_aout->output.p_sys; + + msg_Dbg(p_aout, "Stopping AudioQueue"); + AudioQueueStop(p_sys->audioQueue, false); + msg_Dbg(p_aout, "Disposing of AudioQueue"); + AudioQueueDispose(p_sys->audioQueue, false); + free (p_sys); +} + +void AudioQueueCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { + aout_instance_t * p_aout = (aout_instance_t *)inUserData; + aout_buffer_t * p_buffer = NULL; + + if (p_aout) { + vlc_mutex_lock( &p_aout->output_fifo_lock ); + p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); + vlc_mutex_unlock( &p_aout->output_fifo_lock ); + } + + if ( p_buffer != NULL ) { + vlc_memcpy( inBuffer->mAudioData, p_buffer->p_buffer, p_buffer->i_buffer ); + inBuffer->mAudioDataByteSize = p_buffer->i_buffer; + aout_BufferFree( p_buffer ); + } else { + vlc_memset( inBuffer->mAudioData, 0, inBuffer->mAudioDataBytesCapacity ); + inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity; + } + AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); +} -- 2.39.2