1 /*****************************************************************************
2 * aout_darwin.c : Darwin audio output plugin
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
21 *****************************************************************************/
23 #define MODULE_NAME darwin
24 #include "modules_inner.h"
26 /*****************************************************************************
28 *****************************************************************************/
32 #include "common.h" /* boolean_t, byte_t */
37 #include "audio_output.h" /* aout_thread_t */
39 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
44 #include <Carbon/Carbon.h>
45 #include <CoreAudio/AudioHardware.h>
47 #include <sys/fcntl.h>
49 #define WRITE_AUDIO_OUTPUT_TO_FILE 0
51 /*****************************************************************************
52 * aout_sys_t: private audio output method descriptor
53 *****************************************************************************
54 * This structure is part of the audio output thread descriptor.
55 * It describes the Darwin specific properties of an output thread.
56 *****************************************************************************/
57 typedef struct aout_sys_s
59 #if WRITE_AUDIO_OUTPUT_TO_FILE
62 // unsigned long sizeOfDataInMemory; // size in bytes of the 32 bit float data stored in memory
63 Ptr p_Data; // Ptr to the 32 bit float data stored in memory
64 // Ptr currentDataLocationPtr; // location of the next chunk of data to send to the HAL
65 AudioDeviceID device; // the default device
66 UInt32 ui_deviceBufferSize; // bufferSize returned by kAudioDevicePropertyBufferSize
67 AudioStreamBasicDescription deviceFormat; // info about the default device
68 vlc_mutex_t mutex_lock;
72 /*****************************************************************************
74 *****************************************************************************/
75 static int aout_Probe ( probedata_t *p_data );
76 static int aout_Open ( aout_thread_t *p_aout );
77 static int aout_SetFormat ( aout_thread_t *p_aout );
78 static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info );
79 static void aout_Play ( aout_thread_t *p_aout,
80 byte_t *buffer, int i_size );
81 static void aout_Close ( aout_thread_t *p_aout );
83 OSStatus appIOProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow,
84 const void* inInputData, const AudioTimeStamp* inInputTime,
85 AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
87 void Convert16BitIntegerTo32Float( Ptr in16BitDataPtr, Ptr out32BitDataPtr, UInt32 totalBytes );
88 void Convert16BitIntegerTo32FloatWithByteSwap( Ptr in16BitDataPtr, Ptr out32BitDataPtr, UInt32 totalBytes );
89 void Convert8BitIntegerTo32Float( Ptr in8BitDataPtr, Ptr out32BitDataPtr, UInt32 totalBytes );
91 /*****************************************************************************
92 * Functions exported as capabilities. They are declared as static so that
93 * we don't pollute the namespace too much.
94 *****************************************************************************/
95 void _M( aout_getfunctions )( function_list_t * p_function_list )
97 p_function_list->pf_probe = aout_Probe;
98 p_function_list->functions.aout.pf_open = aout_Open;
99 p_function_list->functions.aout.pf_setformat = aout_SetFormat;
100 p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
101 p_function_list->functions.aout.pf_play = aout_Play;
102 p_function_list->functions.aout.pf_close = aout_Close;
105 /*****************************************************************************
106 * aout_Probe: probe the audio device and return a score
107 *****************************************************************************/
108 static int aout_Probe( probedata_t *p_data )
110 if( TestMethod( AOUT_METHOD_VAR, "darwin" ) )
115 /* The Darwin plugin always works under Darwin or MacOS X */
119 /*****************************************************************************
120 * aout_Open: opens a HAL audio device
121 *****************************************************************************/
122 static int aout_Open( aout_thread_t *p_aout )
124 OSStatus err = noErr;
125 UInt32 count, bufferSize;
126 AudioDeviceID device = kAudioDeviceUnknown;
127 AudioStreamBasicDescription format;
129 /* Allocate structure */
130 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
131 if( p_aout->p_sys == NULL )
133 intf_ErrMsg("aout error: %s", strerror(ENOMEM) );
137 /* Initialize some variables */
138 p_aout->i_format = AOUT_FORMAT_DEFAULT;
139 p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
140 AOUT_STEREO_DEFAULT );
141 p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR,
143 p_aout->p_sys->device = kAudioDeviceUnknown;
144 p_aout->p_sys->p_Data = nil;
145 // p_aout->p_sys->currentDataLocationPtr = nil;
147 // get the default output device for the HAL
148 // it is required to pass the size of the data to be returned
149 count = sizeof( p_aout->p_sys->device );
150 err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
151 &count, (void *) &device);
155 // get the buffersize that the default device uses for IO
156 // it is required to pass the size of the data to be returned
157 count = sizeof(p_aout->p_sys->ui_deviceBufferSize);
158 err = AudioDeviceGetProperty( device, 0, false,
159 kAudioDevicePropertyBufferSize,
160 &count, &bufferSize);
163 // get a description of the data format used by the default device
164 // it is required to pass the size of the data to be returned
165 count = sizeof(p_aout->p_sys->deviceFormat);
166 err = AudioDeviceGetProperty( device, 0, false,
167 kAudioDevicePropertyStreamFormat,
171 if( format.mFormatID != kAudioFormatLinearPCM ) return paramErr;
173 // everything is ok so fill in p_sys
174 p_aout->p_sys->device = device;
175 p_aout->p_sys->ui_deviceBufferSize = bufferSize;
176 p_aout->p_sys->deviceFormat = format;
181 if (err != noErr) return err;
183 p_aout->p_sys->ui_deviceBufferSize = 2 * 2 * sizeof(s16)
184 * ((s64)p_aout->l_rate * AOUT_BUFFER_DURATION) / 1000000;
185 // p_aout->p_sys->sizeOfDataInMemory = p_aout->p_sys->ui_deviceBufferSize;
187 p_aout->p_sys->p_Data = NewPtrClear( p_aout->p_sys->ui_deviceBufferSize );
188 if( p_aout->p_sys->p_Data == nil ) return paramErr;
190 #if WRITE_AUDIO_OUTPUT_TO_FILE
191 p_aout->p_sys->fd = open( "/Users/bofh/audio-darwin.pcm", O_RDWR|O_CREAT );
192 intf_ErrMsg( "open(...) -> %d", p_aout->p_sys->fd );
195 vlc_cond_init( &p_aout->p_sys->cond_sync );
196 vlc_mutex_init( &p_aout->p_sys->mutex_lock );
201 /*****************************************************************************
202 * aout_SetFormat: pretends to set the dsp output format
203 *****************************************************************************/
204 static int aout_SetFormat( aout_thread_t *p_aout )
206 OSStatus err = noErr;
208 bufferSize = p_aout->p_sys->ui_deviceBufferSize;
209 AudioStreamBasicDescription format;
211 // get the buffersize that the default device uses for IO
212 // it is required to pass the size of the data to be returned
213 count = sizeof( bufferSize );
214 err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false,
215 kAudioDevicePropertyBufferSize,
217 intf_ErrMsg( "AudioDeviceSetProperty( buffersize = %d ) -> %d", bufferSize, err );
221 p_aout->p_sys->ui_deviceBufferSize = bufferSize;
223 // get a description of the data format used by the default device
224 // it is required to pass the size of the data to be returned
225 count = sizeof( format );
227 err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false,
228 kAudioDevicePropertyStreamFormat,
233 // intf_ErrMsg( "audio output format is %i", p_aout->i_format );
234 if( format.mFormatID != kAudioFormatLinearPCM ) return paramErr;
236 switch( p_aout->i_format )
240 case AOUT_FMT_S16_LE: /* Little endian signed 16 */
241 // intf_ErrMsg( "This means Little endian signed 16" );
243 case AOUT_FMT_S16_BE: /* Big endian signed 16 */
244 // intf_ErrMsg( "This means Big endian signed 16" );
245 // format.mFormatFlags &= ~kLinearPCMFormatFlagIsFloat;
246 // format.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
247 // format.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
248 // format.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
249 // format.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
253 case AOUT_FMT_U16_LE: /* Little endian U16 */
254 // intf_ErrMsg( "This means Little endian U16" );
256 case AOUT_FMT_U16_BE: /* Big endian U16 */
257 // intf_ErrMsg( "This means Big endian U16" );
260 ; // intf_ErrMsg( "This means Unknown aout format" );
263 format.mSampleRate = p_aout->l_rate;
264 format.mChannelsPerFrame = p_aout->i_channels;
265 err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false,
266 kAudioDevicePropertyStreamFormat,
269 intf_ErrMsg( "AudioDeviceSetProperty( mFormatFlags = %x, "
271 "mChannelsPerFrame = %d ) "
275 format.mChannelsPerFrame,
281 err = AudioDeviceAddIOProc( p_aout->p_sys->device,
282 (AudioDeviceIOProc)appIOProc,
283 (void *)p_aout->p_sys );
286 err = AudioDeviceStart( p_aout->p_sys->device, (AudioDeviceIOProc)appIOProc );
291 /*****************************************************************************
292 * aout_GetBufInfo: returns available bytes in buffer
293 *****************************************************************************/
294 static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
296 return( 0 ); // Send data as soon as possible
301 return ( p_aout->p_sys->p_Data
302 + p_aout->p_sys->sizeOfDataInMemory
303 - p_aout->p_sys->currentDataLocationPtr
304 - p_aout->p_sys->ui_deviceBufferSize );
308 /*****************************************************************************
309 * appIOProc : callback for audio output
310 *****************************************************************************/
311 OSStatus appIOProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow,
312 const void* inInputData, const AudioTimeStamp* inInputTime,
313 AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
316 aout_sys_t* p_sys = appGlobals;
318 vlc_mutex_lock( &p_sys->mutex_lock );
319 vlc_cond_signal( &p_sys->cond_sync );
321 // move data into output data buffer
322 BlockMoveData( p_sys->p_Data,
323 outOutputData->mBuffers[ 0 ].mData,
324 p_sys->ui_deviceBufferSize );
326 vlc_mutex_unlock( &p_sys->mutex_lock );
331 /*****************************************************************************
332 * aout_Play: plays a sound
333 *****************************************************************************/
334 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
336 #if WRITE_AUDIO_OUTPUT_TO_FILE
337 write( p_aout->p_sys->fd, buffer, i_size );
338 // intf_ErrMsg( "write() -> %d", write( p_aout->p_sys->fd, buffer, i_size ) );
340 Convert16BitIntegerTo32Float( buffer, p_aout->p_sys->p_Data, i_size );
341 vlc_cond_wait( &p_aout->p_sys->cond_sync, &p_aout->p_sys->mutex_lock );
345 /*****************************************************************************
346 * aout_Close: closes the dummy audio device
347 *****************************************************************************/
348 static void aout_Close( aout_thread_t *p_aout )
350 OSStatus err = noErr;
352 // stop playing sound through the device
353 err = AudioDeviceStop( p_aout->p_sys->device, (AudioDeviceIOProc)appIOProc );
354 if (err != noErr) return;
356 // remove the IO proc from the device
357 err = AudioDeviceRemoveIOProc( p_aout->p_sys->device, (AudioDeviceIOProc)appIOProc );
358 if (err != noErr) return;
360 // vlc_cond_signal( &p_aout->p_sys->cond_sync );
361 DisposePtr( p_aout->p_sys->p_Data );
366 /*****************************************************************************
367 * Convert16BitIntegerTo32Float
368 *****************************************************************************/
369 void Convert16BitIntegerTo32Float( Ptr in16BitDataPtr, Ptr out32BitDataPtr,
372 UInt32 i, samples = totalBytes / 2 /* each 16 bit sample is 2 bytes */;
373 SInt16 *inDataPtr = (SInt16 *) in16BitDataPtr;
374 Float32 *outDataPtr = (Float32 *) out32BitDataPtr;
376 for( i = 0 ; i < samples ; i++ )
378 *outDataPtr = (Float32)(*inDataPtr);
379 if( *outDataPtr > 0 )
380 *outDataPtr /= 32767.0;
382 *outDataPtr /= 32768.0;
388 /*****************************************************************************
389 * Convert16BitIntegerTo32FloatWithByteSwap
390 *****************************************************************************/
391 void Convert16BitIntegerTo32FloatWithByteSwap( Ptr in16BitDataPtr,
395 UInt32 i, samples = totalBytes / 2 /* each 16 bit sample is 2 bytes */;
396 SInt16 *inDataPtr = (SInt16 *) in16BitDataPtr;
397 Float32 *outDataPtr = (Float32 *) out32BitDataPtr;
399 for( i = 0 ; i < samples ; i++ )
401 *outDataPtr = (Float32)CFSwapInt16LittleToHost(*inDataPtr);
402 if( *outDataPtr > 0 )
403 *outDataPtr /= 32767.0;
405 *outDataPtr /= 32768.0;
412 /*****************************************************************************
413 * Convert8BitIntegerTo32Float
414 *****************************************************************************/
415 void Convert8BitIntegerTo32Float( Ptr in8BitDataPtr, Ptr out32BitDataPtr,
418 UInt32 i, samples = totalBytes;
419 SInt8 *inDataPtr = (SInt8 *) in8BitDataPtr;
420 Float32 *outDataPtr = (Float32 *) out32BitDataPtr;
422 for( i = 0 ; i < samples ; i++ )
424 *outDataPtr = (Float32)(*inDataPtr);
425 if( *outDataPtr > 0 )
426 *outDataPtr /= 32767.0;
428 *outDataPtr /= 32768.0;