1 /*****************************************************************************
2 * audioqueue.c : AudioQueue audio output plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2010 VideoLAN and AUTHORS
6 * Authors: Romain Goyet <romain.goyet@likid.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 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 General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
26 #include <unistd.h> /* write(), close() */
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
36 #include <AudioToolBox/AudioToolBox.h>
38 #define FRAME_SIZE 2048
39 #define NUMBER_OF_BUFFERS 3
41 /*****************************************************************************
42 * aout_sys_t: AudioQueue audio output method descriptor
43 *****************************************************************************
44 * This structure is part of the audio output thread descriptor.
45 * It describes the specific properties of an audio device.
46 *****************************************************************************/
49 AudioQueueRef audioQueue
;
52 /*****************************************************************************
54 *****************************************************************************/
55 static int Open ( vlc_object_t
* );
56 static void Close ( vlc_object_t
* );
57 static void Play ( aout_instance_t
* );
58 static void AudioQueueCallback (void *, AudioQueueRef
, AudioQueueBufferRef
);
60 /*****************************************************************************
62 *****************************************************************************/
64 set_shortname( "AudioQueue" )
65 set_description( N_("AudioQueue (iOS / Mac OS) audio output") )
66 set_capability( "audio output", 40 )
67 set_category( CAT_AUDIO
)
68 set_subcategory( SUBCAT_AUDIO_AOUT
)
69 add_shortcut( "audioqueue" )
70 set_callbacks( Open
, Close
)
73 /*****************************************************************************
74 * Open: open the audio device
75 *****************************************************************************/
77 static int Open ( vlc_object_t
*p_this
)
79 aout_instance_t
*p_aout
= (aout_instance_t
*)p_this
;
80 struct aout_sys_t
*p_sys
= malloc(sizeof(aout_sys_t
));
81 p_aout
->output
.p_sys
= p_sys
;
85 // Setup the audio device.
86 AudioStreamBasicDescription deviceFormat
;
87 deviceFormat
.mSampleRate
= 44100;
88 deviceFormat
.mFormatID
= kAudioFormatLinearPCM
;
89 deviceFormat
.mFormatFlags
= kLinearPCMFormatFlagIsSignedInteger
; // Signed integer, little endian
90 deviceFormat
.mBytesPerPacket
= 4;
91 deviceFormat
.mFramesPerPacket
= 1;
92 deviceFormat
.mBytesPerFrame
= 4;
93 deviceFormat
.mChannelsPerFrame
= 2;
94 deviceFormat
.mBitsPerChannel
= 16;
95 deviceFormat
.mReserved
= 0;
97 // Create a new output AudioQueue for the device.
98 status
= AudioQueueNewOutput(&deviceFormat
, // Format
99 AudioQueueCallback
, // Callback
100 p_aout
, // User data, passed to the callback
101 CFRunLoopGetMain(), // RunLoop
102 kCFRunLoopDefaultMode
, // RunLoop mode
103 0, // Flags ; must be zero (per documentation)...
104 &(p_sys
->audioQueue
)); // Output
106 // This will be used for boosting the audio without the need of a mixer (floating-point conversion is expensive on ARM)
107 // AudioQueueSetParameter(p_sys->audioQueue, kAudioQueueParam_Volume, 12.0); // Defaults to 1.0
109 msg_Dbg(p_aout
, "New AudioQueue output created (status = %i)", status
);
111 // Allocate buffers for the AudioQueue, and pre-fill them.
112 for (int i
= 0; i
< NUMBER_OF_BUFFERS
; ++i
) {
113 AudioQueueBufferRef buffer
= NULL
;
114 status
= AudioQueueAllocateBuffer(p_sys
->audioQueue
, FRAME_SIZE
* 4, &buffer
);
115 AudioQueueCallback(NULL
, p_sys
->audioQueue
, buffer
);
118 /* Volume is entirely done in software. */
119 aout_VolumeSoftInit( p_aout
);
121 p_aout
->output
.output
.i_format
= VLC_CODEC_S16L
;
122 p_aout
->output
.output
.i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
;
123 p_aout
->output
.output
.i_rate
= 44100;
124 p_aout
->output
.i_nb_samples
= FRAME_SIZE
;
125 p_aout
->output
.pf_play
= Play
;
127 msg_Dbg(p_aout
, "Starting AudioQueue (status = %i)", status
);
128 status
= AudioQueueStart(p_sys
->audioQueue
, NULL
);
133 /*****************************************************************************
134 * Play: play a sound samples buffer
135 *****************************************************************************/
136 static void Play( aout_instance_t
* p_aout
)
141 /*****************************************************************************
142 * Close: close the audio device
143 *****************************************************************************/
144 static void Close ( vlc_object_t
*p_this
)
146 aout_instance_t
*p_aout
= (aout_instance_t
*)p_this
;
147 struct aout_sys_t
* p_sys
= p_aout
->output
.p_sys
;
149 msg_Dbg(p_aout
, "Stopping AudioQueue");
150 AudioQueueStop(p_sys
->audioQueue
, false);
151 msg_Dbg(p_aout
, "Disposing of AudioQueue");
152 AudioQueueDispose(p_sys
->audioQueue
, false);
156 void AudioQueueCallback(void * inUserData
, AudioQueueRef inAQ
, AudioQueueBufferRef inBuffer
) {
157 aout_instance_t
* p_aout
= (aout_instance_t
*)inUserData
;
158 aout_buffer_t
* p_buffer
= NULL
;
161 vlc_mutex_lock( &p_aout
->output_fifo_lock
);
162 p_buffer
= aout_FifoPop( p_aout
, &p_aout
->output
.fifo
);
163 vlc_mutex_unlock( &p_aout
->output_fifo_lock
);
166 if ( p_buffer
!= NULL
) {
167 vlc_memcpy( inBuffer
->mAudioData
, p_buffer
->p_buffer
, p_buffer
->i_buffer
);
168 inBuffer
->mAudioDataByteSize
= p_buffer
->i_buffer
;
169 aout_BufferFree( p_buffer
);
171 vlc_memset( inBuffer
->mAudioData
, 0, inBuffer
->mAudioDataBytesCapacity
);
172 inBuffer
->mAudioDataByteSize
= inBuffer
->mAudioDataBytesCapacity
;
174 AudioQueueEnqueueBuffer(inAQ
, inBuffer
, 0, NULL
);