1 /*****************************************************************************
2 * audioqueue.c : AudioQueue audio output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2010-2013 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 /*****************************************************************************
39 * aout_sys_t: AudioQueue audio output method descriptor
40 *****************************************************************************
41 * This structure is part of the audio output thread descriptor.
42 * It describes the specific properties of an audio device.
43 *****************************************************************************/
46 AudioQueueRef audioQueue;
51 /*****************************************************************************
53 *****************************************************************************/
54 static int Open (vlc_object_t *);
55 static void Close (vlc_object_t *);
56 static void Play (audio_output_t *, block_t *);
57 static void Pause (audio_output_t *p_aout, bool pause, mtime_t date);
58 static void Flush (audio_output_t *p_aout, bool wait);
59 static int TimeGet (audio_output_t *aout, mtime_t *);
60 static void AudioQueueCallback (void *, AudioQueueRef, AudioQueueBufferRef);
62 /*****************************************************************************
64 *****************************************************************************/
66 set_shortname("AudioQueue")
67 set_description(N_("AudioQueue (iOS / Mac OS) audio output"))
68 set_capability("audio output", 40)
69 set_category(CAT_AUDIO)
70 set_subcategory(SUBCAT_AUDIO_AOUT)
71 add_shortcut("audioqueue")
72 set_callbacks(Open, Close)
75 /*****************************************************************************
76 * Start: open the audio device
77 *****************************************************************************/
79 static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
81 aout_sys_t *p_sys = p_aout->sys;
84 // Setup the audio device.
85 AudioStreamBasicDescription deviceFormat;
86 deviceFormat.mSampleRate = fmt->i_rate;
87 deviceFormat.mFormatID = kAudioFormatLinearPCM;
88 deviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; // FL32
89 deviceFormat.mFramesPerPacket = 1;
90 deviceFormat.mChannelsPerFrame = 2;
91 deviceFormat.mBitsPerChannel = 32;
92 deviceFormat.mBytesPerFrame = deviceFormat.mBitsPerChannel * deviceFormat.mChannelsPerFrame / 8;
93 deviceFormat.mBytesPerPacket = deviceFormat.mBytesPerFrame * deviceFormat.mFramesPerPacket;
95 // Create a new output AudioQueue for the device.
96 status = AudioQueueNewOutput(&deviceFormat, // Format
97 AudioQueueCallback, // Callback
98 NULL, // User data, passed to the callback
100 kCFRunLoopCommonModes, // RunLoop mode
101 0, // Flags ; must be zero (per documentation)...
102 &(p_sys->audioQueue)); // Output
104 msg_Dbg(p_aout, "New AudioQueue output created (status = %li)", status);
108 fmt->i_format = VLC_CODEC_FL32;
109 fmt->i_physical_channels = AOUT_CHANS_STEREO;
110 aout_FormatPrepare(fmt);
112 p_aout->sys->b_stopped = false;
114 status = AudioQueueStart(p_sys->audioQueue, NULL);
115 msg_Dbg(p_aout, "Starting AudioQueue (status = %li)", status);
117 p_aout->time_get = TimeGet;
119 p_aout->pause = Pause;
120 p_aout->flush = Flush;
128 /*****************************************************************************
129 * Stop: close the audio device
130 *****************************************************************************/
132 static void Stop (audio_output_t *p_aout)
134 p_aout->sys->b_stopped = true;
136 msg_Dbg(p_aout, "Stopping AudioQueue");
137 AudioQueueStop(p_aout->sys->audioQueue, true);
138 msg_Dbg(p_aout, "Disposing AudioQueue");
139 AudioQueueDispose(p_aout->sys->audioQueue, true);
142 /*****************************************************************************
144 *****************************************************************************/
146 static void Play (audio_output_t *p_aout, block_t *p_block)
148 if (p_block != NULL) {
149 AudioQueueBufferRef inBuffer = NULL;
152 status = AudioQueueAllocateBuffer(p_aout->sys->audioQueue, p_block->i_buffer, &inBuffer);
153 if (status != noErr) {
154 msg_Err(p_aout, "buffer alloction failed (%li)", status);
158 memcpy(inBuffer->mAudioData, p_block->p_buffer, p_block->i_buffer);
159 inBuffer->mAudioDataByteSize = p_block->i_buffer;
160 block_Release(p_block);
162 status = AudioQueueEnqueueBuffer(p_aout->sys->audioQueue, inBuffer, 0, NULL);
164 msg_Err(p_aout, "enqueuing buffer failed (%li)", status);
168 void AudioQueueCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
169 /* this function does nothing, but needs to be here to make the AudioQueue API happy.
170 * without a callback, it will refuse to create an AudioQueue instance. */
171 VLC_UNUSED(inUserData);
173 VLC_UNUSED(inBuffer);
176 static void Pause (audio_output_t *p_aout, bool pause, mtime_t date)
181 AudioQueuePause(p_aout->sys->audioQueue);
183 AudioQueueStart(p_aout->sys->audioQueue, NULL);
186 static void Flush (audio_output_t *p_aout, bool wait)
188 if (p_aout->sys->b_stopped || !p_aout->sys->audioQueue)
192 AudioQueueFlush(p_aout->sys->audioQueue);
194 AudioQueueReset(p_aout->sys->audioQueue);
197 static int TimeGet (audio_output_t *p_aout, mtime_t *restrict delay)
207 /*****************************************************************************
209 *****************************************************************************/
211 static int VolumeSet(audio_output_t * p_aout, float volume)
213 struct aout_sys_t *p_sys = p_aout->sys;
216 aout_VolumeReport(p_aout, volume);
217 p_sys->f_volume = volume;
219 /* Set volume for output unit */
220 ostatus = AudioQueueSetParameter(p_sys->audioQueue, kAudioQueueParam_Volume, volume * volume * volume);
225 /*****************************************************************************
227 *****************************************************************************/
229 static int Open(vlc_object_t *obj)
231 audio_output_t *aout = (audio_output_t *)obj;
232 aout_sys_t *sys = malloc(sizeof (*sys));
234 if (unlikely(sys == NULL))
240 aout->volume_set = VolumeSet;
243 aout_VolumeReport(aout, 1.0);
248 static void Close(vlc_object_t *obj)
250 audio_output_t *aout = (audio_output_t *)obj;
251 msg_Dbg( aout, "audioqueue: Close");
252 aout_sys_t *sys = aout->sys;