audioqueue: fix copyright years and add missing copyright holders
[vlc.git] / modules / audio_output / audioqueue.c
1 /*****************************************************************************
2  * audioqueue.c : AudioQueue audio output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2013 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Romain Goyet <romain.goyet@likid.org>
8  *          Felix Paul Kühne <fkuehne at videolan dot org>
9  *          Rémi Denis-Courmont
10  *          Rafaël Carré <funman at videolan dot org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # import "config.h"
32 #endif
33
34 #import <vlc_common.h>
35 #import <vlc_plugin.h>
36 #import <vlc_aout.h>
37 #import <AudioToolBox/AudioQueue.h>
38
39 /*****************************************************************************
40  * aout_sys_t: private audio output method descriptor
41  *****************************************************************************
42  * This structure is part of the audio output thread descriptor.
43  * It describes the AudioQueue specific properties of an output thread.
44  *****************************************************************************/
45 struct aout_sys_t
46 {
47     AudioQueueRef           audioQueue;
48     AudioQueueTimelineRef   outTimeline;
49
50     int                     i_rate;
51     mtime_t                 i_played_length;
52     bool                    b_stopped;
53     float                   f_volume;
54 };
55
56 /*****************************************************************************
57  * Local prototypes
58  *****************************************************************************/
59 static int  Open                     (vlc_object_t *);
60 static void Close                    (vlc_object_t *);
61 static void Play                     (audio_output_t *, block_t *);
62 static void Pause                    (audio_output_t *p_aout, bool pause, mtime_t date);
63 static void Flush                    (audio_output_t *p_aout, bool wait);
64 static int  TimeGet                  (audio_output_t *aout, mtime_t *);
65 static void UnusedAudioQueueCallback (void *, AudioQueueRef, AudioQueueBufferRef);
66
67 static int Start(audio_output_t *, audio_sample_format_t *);
68 static void Stop(audio_output_t *);
69 static int VolumeSet(audio_output_t *, float );
70
71 /*****************************************************************************
72  * Module descriptor
73  *****************************************************************************/
74 vlc_module_begin ()
75 set_shortname("AudioQueue")
76 set_description(N_("AudioQueue (iOS / Mac OS) audio output"))
77 set_capability("audio output", 40)
78 set_category(CAT_AUDIO)
79 set_subcategory(SUBCAT_AUDIO_AOUT)
80 add_shortcut("audioqueue")
81 set_callbacks(Open, Close)
82 vlc_module_end ()
83
84 /*****************************************************************************
85  * Module management
86  *****************************************************************************/
87
88 static int Open(vlc_object_t *obj)
89 {
90     audio_output_t *aout = (audio_output_t *)obj;
91     aout_sys_t *sys = malloc(sizeof (*sys));
92
93     if (unlikely(sys == NULL))
94         return VLC_ENOMEM;
95
96     aout->sys = sys;
97     aout->start = Start;
98     aout->stop = Stop;
99     aout->volume_set = VolumeSet;
100
101     /* reset volume */
102     aout_VolumeReport(aout, 1.0);
103
104     return VLC_SUCCESS;
105 }
106
107 static void Close(vlc_object_t *obj)
108 {
109     audio_output_t *aout = (audio_output_t *)obj;
110     msg_Dbg( aout, "audioqueue: Close");
111     aout_sys_t *sys = aout->sys;
112
113     free(sys);
114 }
115
116 static int VolumeSet(audio_output_t * p_aout, float volume)
117 {
118     struct aout_sys_t *p_sys = p_aout->sys;
119     OSStatus ostatus;
120
121     aout_VolumeReport(p_aout, volume);
122     p_sys->f_volume = volume;
123
124     /* Set volume for output unit */
125     ostatus = AudioQueueSetParameter(p_sys->audioQueue, kAudioQueueParam_Volume, volume * volume * volume);
126
127     return ostatus;
128 }
129
130 /*****************************************************************************
131  * Start: open the audio device
132  *****************************************************************************/
133
134 static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
135 {
136     aout_sys_t *p_sys = p_aout->sys;
137     OSStatus error = 0;
138
139     // prepare the format description for our output
140     AudioStreamBasicDescription streamDescription;
141     streamDescription.mSampleRate = fmt->i_rate;
142     streamDescription.mFormatID = kAudioFormatLinearPCM;
143     streamDescription.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; // FL32
144     streamDescription.mFramesPerPacket = 1;
145     streamDescription.mChannelsPerFrame = 2;
146     streamDescription.mBitsPerChannel = 32;
147     streamDescription.mBytesPerFrame = streamDescription.mBitsPerChannel * streamDescription.mChannelsPerFrame / 8;
148     streamDescription.mBytesPerPacket = streamDescription.mBytesPerFrame * streamDescription.mFramesPerPacket;
149
150     // init new output instance
151     error = AudioQueueNewOutput(&streamDescription,           // Format
152                                  UnusedAudioQueueCallback,    // Unused Callback, which needs to be provided to have a proper instance
153                                  NULL,                        // User data, passed to the callback
154                                  NULL,                        // RunLoop
155                                  kCFRunLoopCommonModes,       // RunLoop mode
156                                  0,                           // Flags ; must be zero (per documentation)...
157                                  &(p_sys->audioQueue));       // Output
158
159     msg_Dbg(p_aout, "New AudioQueue output created (status = %li)", error);
160     if (error != noErr)
161         return VLC_EGENERIC;
162
163     fmt->i_format = VLC_CODEC_FL32;
164     fmt->i_physical_channels = AOUT_CHANS_STEREO;
165     aout_FormatPrepare(fmt);
166
167     p_aout->sys->b_stopped = false;
168     p_aout->sys->i_rate = fmt->i_rate;
169
170     // start queue
171     error = AudioQueueStart(p_sys->audioQueue, NULL);
172     msg_Dbg(p_aout, "Starting AudioQueue (status = %li)", error);
173
174     // start timeline for synchro
175     error = AudioQueueCreateTimeline(p_sys->audioQueue, &p_sys->outTimeline);
176     msg_Dbg(p_aout, "AudioQueue Timeline started (status = %li)", error);
177
178     if (error != noErr)
179         return VLC_EGENERIC;
180
181     p_aout->time_get = TimeGet;
182     p_aout->play = Play;
183     p_aout->pause = Pause;
184     p_aout->flush = Flush;
185
186     return VLC_SUCCESS;
187 }
188
189 /*****************************************************************************
190  * Stop: close the audio device
191  *****************************************************************************/
192
193 static void Stop(audio_output_t *p_aout)
194 {
195     p_aout->sys->b_stopped = true;
196     p_aout->sys->i_played_length = 0;
197
198     AudioQueueDisposeTimeline(p_aout->sys->audioQueue, p_aout->sys->outTimeline);
199     AudioQueueStop(p_aout->sys->audioQueue, true);
200     AudioQueueDispose(p_aout->sys->audioQueue, true);
201
202     msg_Dbg(p_aout, "audioqueue stopped and disposed");
203 }
204
205 /*****************************************************************************
206  * actual playback
207  *****************************************************************************/
208
209 static void Play(audio_output_t *p_aout, block_t *p_block)
210 {
211     AudioQueueBufferRef inBuffer = NULL;
212     OSStatus status;
213
214     status = AudioQueueAllocateBuffer(p_aout->sys->audioQueue, p_block->i_buffer, &inBuffer);
215     if (status != noErr) {
216         msg_Err(p_aout, "buffer alloction failed (%li)", status);
217         return;
218     }
219
220     memcpy(inBuffer->mAudioData, p_block->p_buffer, p_block->i_buffer);
221     inBuffer->mAudioDataByteSize = p_block->i_buffer;
222
223     status = AudioQueueEnqueueBuffer(p_aout->sys->audioQueue, inBuffer, 0, NULL);
224     if (status == noErr)
225         p_aout->sys->i_played_length += p_block->i_length;
226     else
227         msg_Err(p_aout, "enqueuing buffer failed (%li)", status);
228
229     block_Release(p_block);
230 }
231
232 void UnusedAudioQueueCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
233     /* this function does nothing, but needs to be here to make the AudioQueue API happy.
234      * without a callback, it will refuse to create an AudioQueue instance. */
235     VLC_UNUSED(inUserData);
236     VLC_UNUSED(inAQ);
237     VLC_UNUSED(inBuffer);
238 }
239
240 static void Pause(audio_output_t *p_aout, bool pause, mtime_t date)
241 {
242     VLC_UNUSED(date);
243
244     if (pause)
245         AudioQueuePause(p_aout->sys->audioQueue);
246     else
247         AudioQueueStart(p_aout->sys->audioQueue, NULL);
248 }
249
250 static void Flush(audio_output_t *p_aout, bool wait)
251 {
252     if (p_aout->sys->b_stopped || !p_aout->sys->audioQueue)
253         return;
254
255     AudioQueueDisposeTimeline(p_aout->sys->audioQueue, p_aout->sys->outTimeline);
256
257     if (wait)
258         AudioQueueStop(p_aout->sys->audioQueue, false);
259     else
260         AudioQueueStop(p_aout->sys->audioQueue, true);
261
262     p_aout->sys->i_played_length = 0;
263     AudioQueueStart(p_aout->sys->audioQueue, NULL);
264     AudioQueueCreateTimeline(p_aout->sys->audioQueue, &p_aout->sys->outTimeline);
265 }
266
267 static int TimeGet(audio_output_t *p_aout, mtime_t *restrict delay)
268 {
269     AudioTimeStamp outTimeStamp;
270     Boolean b_discontinuity;
271     OSStatus status = AudioQueueGetCurrentTime(p_aout->sys->audioQueue, p_aout->sys->outTimeline, &outTimeStamp, &b_discontinuity);
272
273     if (status != noErr)
274         return -1;
275
276     if (b_discontinuity)
277         msg_Dbg(p_aout, "detected output discontinuity");
278
279     mtime_t i_pos = (mtime_t) outTimeStamp.mSampleTime * CLOCK_FREQ / p_aout->sys->i_rate;
280     *delay = p_aout->sys->i_played_length - i_pos;
281
282     return 0;
283 }