1 /*****************************************************************************
2 * audioqueue.c : AudioQueue audio output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2010-2012 VLC authors and VideoLAN
7 * Authors: Romain Goyet <romain.goyet@likid.org>
8 * Felix Paul Kühne <fkuehne@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
36 #include <AudioToolBox/AudioToolBox.h>
38 #define FRAME_SIZE 2048
40 /*****************************************************************************
41 * aout_sys_t: AudioQueue audio output method descriptor
42 *****************************************************************************
43 * This structure is part of the audio output thread descriptor.
44 * It describes the specific properties of an audio device.
45 *****************************************************************************/
48 AudioQueueRef audioQueue;
53 /*****************************************************************************
55 *****************************************************************************/
56 static int Open (vlc_object_t *);
57 static void Close (vlc_object_t *);
58 static void Play (audio_output_t *, block_t *);
59 static void Pause (audio_output_t *p_aout, bool pause, mtime_t date);
60 static void Flush (audio_output_t *p_aout, bool wait);
61 static int TimeGet (audio_output_t *aout, mtime_t *);
62 static void AudioQueueCallback (void *, AudioQueueRef, AudioQueueBufferRef);
64 /*****************************************************************************
66 *****************************************************************************/
68 set_shortname("AudioQueue")
69 set_description(N_("AudioQueue (iOS / Mac OS) audio output"))
70 set_capability("audio output", 40)
71 set_category(CAT_AUDIO)
72 set_subcategory(SUBCAT_AUDIO_AOUT)
73 add_shortcut("audioqueue")
74 set_callbacks(Open, Close)
77 /*****************************************************************************
78 * Start: open the audio device
79 *****************************************************************************/
81 static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
83 aout_sys_t *p_sys = p_aout->sys;
86 // Setup the audio device.
87 AudioStreamBasicDescription deviceFormat;
88 deviceFormat.mSampleRate = 44100;
89 deviceFormat.mFormatID = kAudioFormatLinearPCM;
90 deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; // Signed integer, little endian
91 deviceFormat.mBytesPerPacket = 4;
92 deviceFormat.mFramesPerPacket = 1;
93 deviceFormat.mBytesPerFrame = 4;
94 deviceFormat.mChannelsPerFrame = 2;
95 deviceFormat.mBitsPerChannel = 16;
96 deviceFormat.mReserved = 0;
98 // Create a new output AudioQueue for the device.
99 status = AudioQueueNewOutput(&deviceFormat, // Format
100 AudioQueueCallback, // Callback
101 NULL, // User data, passed to the callback
102 CFRunLoopGetMain(), // RunLoop
103 kCFRunLoopCommonModes, // RunLoop mode
104 0, // Flags ; must be zero (per documentation)...
105 &(p_sys->audioQueue)); // Output
107 msg_Dbg(p_aout, "New AudioQueue output created (status = %i)", status);
111 fmt->i_format = VLC_CODEC_S16L;
112 fmt->i_physical_channels = AOUT_CHANS_STEREO;
114 aout_FormatPrepare(fmt);
116 p_aout->sys->b_stopped = false;
118 status = AudioQueueStart(p_sys->audioQueue, NULL);
119 msg_Dbg(p_aout, "Starting AudioQueue (status = %i)", status);
121 p_aout->time_get = TimeGet;
123 p_aout->pause = Pause;
124 p_aout->flush = Flush;
132 /*****************************************************************************
133 * Stop: close the audio device
134 *****************************************************************************/
136 static void Stop (audio_output_t *p_aout)
138 p_aout->sys->b_stopped = true;
140 msg_Dbg(p_aout, "Stopping AudioQueue");
141 AudioQueueStop(p_aout->sys->audioQueue, true);
142 msg_Dbg(p_aout, "Disposing AudioQueue");
143 AudioQueueDispose(p_aout->sys->audioQueue, true);
146 /*****************************************************************************
148 *****************************************************************************/
150 static void Play (audio_output_t *p_aout, block_t *p_block)
152 if (p_block != NULL) {
153 AudioQueueBufferRef inBuffer = NULL;
156 status = AudioQueueAllocateBuffer(p_aout->sys->audioQueue, FRAME_SIZE * 2, &inBuffer);
157 if (status != noErr) {
158 msg_Err(p_aout, "buffer alloction failed (%i)", status);
162 memcpy(inBuffer->mAudioData, p_block->p_buffer, p_block->i_buffer);
163 inBuffer->mAudioDataByteSize = p_block->i_buffer;
164 block_Release(p_block);
166 status = AudioQueueEnqueueBuffer(p_aout->sys->audioQueue, inBuffer, 0, NULL);
168 msg_Err(p_aout, "enqueuing buffer failed (%i)", status);
172 void AudioQueueCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
173 /* this function does nothing, but needs to be here to make the AudioQueue API happy.
174 * without a callback, it will refuse to create an AudioQueue instance. */
175 VLC_UNUSED(inUserData);
177 VLC_UNUSED(inBuffer);
180 static void Pause (audio_output_t *p_aout, bool pause, mtime_t date)
185 AudioQueuePause(p_aout->sys->audioQueue);
187 AudioQueueStart(p_aout->sys->audioQueue, NULL);
190 static void Flush (audio_output_t *p_aout, bool wait)
192 if (p_aout->sys->b_stopped || !p_aout->sys->audioQueue)
196 AudioQueueFlush(p_aout->sys->audioQueue);
198 AudioQueueReset(p_aout->sys->audioQueue);
201 static int TimeGet (audio_output_t *p_aout, mtime_t *restrict delay)
211 /*****************************************************************************
213 *****************************************************************************/
215 static int VolumeSet(audio_output_t * p_aout, float volume)
217 struct aout_sys_t *p_sys = p_aout->sys;
220 aout_VolumeReport(p_aout, volume);
221 p_sys->f_volume = volume;
223 /* Set volume for output unit */
224 ostatus = AudioQueueSetParameter(p_sys->audioQueue, kAudioQueueParam_Volume, volume * volume * volume);
229 /*****************************************************************************
231 *****************************************************************************/
233 static int Open(vlc_object_t *obj)
235 audio_output_t *aout = (audio_output_t *)obj;
236 aout_sys_t *sys = malloc(sizeof (*sys));
238 if (unlikely(sys == NULL))
244 aout->volume_set = VolumeSet;
247 aout_VolumeReport(aout, 1.0);
252 static void Close(vlc_object_t *obj)
254 audio_output_t *aout = (audio_output_t *)obj;
255 msg_Dbg( aout, "audioqueue: Close");
256 aout_sys_t *sys = aout->sys;