1 /*****************************************************************************
2 * aout_darwin.c : Darwin audio output plugin
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: aout_darwin.c,v 1.4 2001/04/05 03:50:38 sam Exp $
7 * Authors: Colin Delacroix <colin@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
26 * Status of audio under Darwin
27 * It currently works with 16 bits signed big endian mpeg 1 audio
28 * (and probably mpeg 2). This is the most common case.
29 * Note: ac3 decoder is currently broken under Darwin
32 * Find little endian files and adapt output
33 * Find unsigned files and adapt output
34 * Find 8 bits files and adapt output
37 #define MODULE_NAME darwin
38 #include "modules_inner.h"
40 /*****************************************************************************
42 *****************************************************************************/
46 #include "common.h" /* boolean_t, byte_t */
51 #include "audio_output.h" /* aout_thread_t */
53 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
58 #include <Carbon/Carbon.h>
59 #include <CoreAudio/AudioHardware.h>
61 #include <sys/fcntl.h>
64 * Debug: to dump the output of the decoder directly to a file
65 * May disappear when AC3 decoder will work on Darwin
67 #define WRITE_AUDIO_OUTPUT_TO_FILE 0
69 /*****************************************************************************
70 * aout_sys_t: private audio output method descriptor
71 *****************************************************************************
72 * This structure is part of the audio output thread descriptor.
73 * It describes the Darwin specific properties of an output thread.
74 *****************************************************************************/
75 typedef struct aout_sys_s
77 #if WRITE_AUDIO_OUTPUT_TO_FILE
78 int fd; // debug: fd to dump audio
80 AudioStreamBasicDescription deviceFormat; // info about the default device
81 AudioDeviceID device; // the default device
82 Ptr p_Data; // ptr to the 32 bit float data
83 UInt32 ui_deviceBufferSize; // audio device buffer size
84 vlc_mutex_t mutex_lock; // pthread locks for sync of
85 vlc_cond_t cond_sync; // aout_Play and callback
88 /*****************************************************************************
90 *****************************************************************************/
91 static int aout_Probe ( probedata_t *p_data );
92 static int aout_Open ( aout_thread_t *p_aout );
93 static int aout_SetFormat ( aout_thread_t *p_aout );
94 static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info );
95 static void aout_Play ( aout_thread_t *p_aout,
96 byte_t *buffer, int i_size );
97 static void aout_Close ( aout_thread_t *p_aout );
99 OSStatus appIOProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow,
100 const void* inInputData, const AudioTimeStamp* inInputTime,
101 AudioBufferList* outOutputData,
102 const AudioTimeStamp* inOutputTime,
103 void* threadGlobals );
104 void Convert16BitIntegerTo32Float( Ptr p_in16BitDataPtr, Ptr p_out32BitDataPtr,
105 UInt32 ui_totalBytes );
106 void Convert16BitIntegerTo32FloatWithByteSwap( Ptr p_in16BitDataPtr,
107 Ptr p_out32BitDataPtr,
108 UInt32 p_totalBytes );
109 void Convert8BitIntegerTo32Float( Ptr in8BitDataPtr, Ptr p_out32BitDataPtr,
110 UInt32 ui_totalBytes );
112 /*****************************************************************************
113 * Functions exported as capabilities. They are declared as static so that
114 * we don't pollute the namespace too much.
115 *****************************************************************************/
116 void _M( aout_getfunctions )( function_list_t * p_function_list )
118 p_function_list->pf_probe = aout_Probe;
119 p_function_list->functions.aout.pf_open = aout_Open;
120 p_function_list->functions.aout.pf_setformat = aout_SetFormat;
121 p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
122 p_function_list->functions.aout.pf_play = aout_Play;
123 p_function_list->functions.aout.pf_close = aout_Close;
126 /*****************************************************************************
127 * aout_Probe: probe the audio device and return a score
128 *****************************************************************************/
129 static int aout_Probe( probedata_t *p_data )
131 if( TestMethod( AOUT_METHOD_VAR, "darwin" ) )
136 /* The Darwin plugin always works under Darwin or MacOS X */
140 /*****************************************************************************
141 * aout_Open: opens a HAL audio device
142 *****************************************************************************/
143 static int aout_Open( aout_thread_t *p_aout )
145 OSStatus err = noErr;
146 UInt32 ui_paramSize, ui_bufferSize;
147 AudioDeviceID device = kAudioDeviceUnknown;
148 AudioStreamBasicDescription format;
150 /* Allocate structure */
151 p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
152 if( p_aout->p_sys == NULL )
154 intf_ErrMsg("aout error: %s", strerror(ENOMEM) );
158 /* Initialize some variables */
159 p_aout->i_format = AOUT_FORMAT_DEFAULT;
160 p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
161 AOUT_STEREO_DEFAULT );
162 p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR,
165 p_aout->p_sys->device = kAudioDeviceUnknown;
166 p_aout->p_sys->p_Data = nil;
169 * get the default output device for the HAL
170 * it is required to pass the size of the data to be returned
172 ui_paramSize = sizeof( p_aout->p_sys->device );
173 err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
174 &ui_paramSize, (void *) &device );
180 * The values we get here are not used. We may find another method for
181 * insuring us that the audio device is working !
183 * First get the buffersize that the default device uses for IO
185 ui_paramSize = sizeof( p_aout->p_sys->ui_deviceBufferSize );
186 err = AudioDeviceGetProperty( device, 0, false,
187 kAudioDevicePropertyBufferSize,
188 &ui_paramSize, &ui_bufferSize);
191 /* get a description of the data format used by the default device */
192 ui_paramSize = sizeof(p_aout->p_sys->deviceFormat);
193 err = AudioDeviceGetProperty( device, 0, false,
194 kAudioDevicePropertyStreamFormat,
195 &ui_paramSize, &format);
198 if( format.mFormatID != kAudioFormatLinearPCM ) return paramErr;
200 /* everything is ok so fill in p_sys */
201 p_aout->p_sys->device = device;
202 p_aout->p_sys->ui_deviceBufferSize = ui_bufferSize;
203 p_aout->p_sys->deviceFormat = format;
208 if (err != noErr) return err;
211 * Size calcul taken from audio_output.c we may change that file so we would
212 * not be forced to compute the same value twice
214 p_aout->p_sys->ui_deviceBufferSize =
215 2 * 2 * sizeof(s16) * ((s64)p_aout->l_rate * AOUT_BUFFER_DURATION) / 1000000;
217 /* Allocate memory for audio */
218 p_aout->p_sys->p_Data = NewPtrClear( p_aout->p_sys->ui_deviceBufferSize );
219 if( p_aout->p_sys->p_Data == nil ) return paramErr;
221 #if WRITE_AUDIO_OUTPUT_TO_FILE
222 p_aout->p_sys->fd = open( "/Users/bofh/audio-darwin.pcm", O_RDWR|O_CREAT );
223 intf_WarnMsg( 1, "open(...) -> %d", p_aout->p_sys->fd );
226 vlc_cond_init( &p_aout->p_sys->cond_sync );
227 vlc_mutex_init( &p_aout->p_sys->mutex_lock );
232 /*****************************************************************************
233 * aout_SetFormat: pretends to set the dsp output format
234 *****************************************************************************/
235 static int aout_SetFormat( aout_thread_t *p_aout )
237 OSStatus err = noErr;
239 ui_bufferSize = p_aout->p_sys->ui_deviceBufferSize;
240 AudioStreamBasicDescription format;
242 /* set the buffersize that the default device uses for IO */
243 ui_paramSize = sizeof( ui_bufferSize );
244 err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false,
245 kAudioDevicePropertyBufferSize,
246 ui_paramSize, &ui_bufferSize);
249 /* We have to tell the decoder to use audio device's buffer size */
250 intf_ErrMsg( "AudioDeviceSetProperty failed ( buffersize = %d ) -> %d",
251 ui_bufferSize, err );
256 p_aout->p_sys->ui_deviceBufferSize = ui_bufferSize;
258 ui_paramSize = sizeof( format );
259 err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false,
260 kAudioDevicePropertyStreamFormat,
261 &ui_paramSize, &format);
265 intf_DbgMsg( "audio output format is %i", p_aout->i_format );
268 * setting format.mFormatFlags to anything but the default value
269 * doesn't seem to work. Can anybody explain that ??
272 switch( p_aout->i_format )
275 intf_ErrMsg( "Audio format (Unsigned 8) not supported now,"
276 "please report stream" );
279 case AOUT_FMT_S16_LE: /* Little endian signed 16 */
280 intf_DbgMsg( "This means Little endian signed 16" );
281 // format.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
282 intf_ErrMsg( "Audio format (LE Unsigned 16) not supported now,"
283 "please report stream" );
286 case AOUT_FMT_S16_BE: /* Big endian signed 16 */
287 intf_DbgMsg( "This means big endian signed 16" );
288 // format.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
292 intf_ErrMsg( "Audio format (Signed 8) not supported now,"
293 "please report stream" );
296 case AOUT_FMT_U16_LE: /* Little endian U16 */
297 // format.mFormatFlags &= ~kLinearPCMFormatFlagIsSignedInteger;
298 intf_DbgMsg( "This means Little endian U16" );
299 intf_ErrMsg( "Audio format (LE Unsigned 8) not supported now,"
300 "please report stream" );
303 case AOUT_FMT_U16_BE: /* Big endian U16 */
304 // format.mFormatFlags &= ~kLinearPCMFormatFlagIsSignedInteger;
305 intf_ErrMsg( "Audio format (BE Unsigned 8) not supported now,"
306 "please report stream" );
311 intf_DbgMsg( "This means Unknown aout format" );
316 * It would have been nice to have these work (no more buffer
317 * convertion to float) but I couldn't manage to
319 // format.mFormatFlags &= ~kLinearPCMFormatFlagIsFloat;
320 // format.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
321 // format.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
323 format.mSampleRate = p_aout->l_rate;
324 format.mChannelsPerFrame = p_aout->i_channels;
326 err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false,
327 kAudioDevicePropertyStreamFormat,
328 ui_paramSize, &format);
331 intf_ErrMsg( "AudioDeviceSetProperty( mFormatFlags = %x, "
332 "mSampleRate = %f, mChannelsPerFrame = %d ) -> %d",
333 format.mFormatFlags, format.mSampleRate,
334 format.mChannelsPerFrame, err );
341 err = AudioDeviceAddIOProc( p_aout->p_sys->device,
342 (AudioDeviceIOProc)appIOProc,
343 (void *)p_aout->p_sys );
345 /* open the output */
347 err = AudioDeviceStart( p_aout->p_sys->device, (AudioDeviceIOProc)appIOProc );
352 /*****************************************************************************
353 * aout_GetBufInfo: returns available bytes in buffer
354 *****************************************************************************/
355 static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
357 return( 0 ); // Send data as soon as possible
362 return ( p_aout->p_sys->p_Data
363 + p_aout->p_sys->sizeOfDataInMemory
364 - p_aout->p_sys->currentDataLocationPtr
365 - p_aout->p_sys->ui_deviceBufferSize );
369 /*****************************************************************************
370 * appIOProc : callback for audio output
371 *****************************************************************************/
372 OSStatus appIOProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow,
373 const void* inInputData, const AudioTimeStamp* inInputTime,
374 AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
375 void* threadGlobals )
377 aout_sys_t* p_sys = threadGlobals;
379 /* see aout_Play below */
380 vlc_mutex_lock( &p_sys->mutex_lock );
381 vlc_cond_signal( &p_sys->cond_sync );
383 /* move data into output data buffer */
384 BlockMoveData( p_sys->p_Data,
385 outOutputData->mBuffers[ 0 ].mData,
386 p_sys->ui_deviceBufferSize );
388 vlc_mutex_unlock( &p_sys->mutex_lock );
393 /*****************************************************************************
394 * aout_Play: plays a sound
395 *****************************************************************************/
396 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
398 #if WRITE_AUDIO_OUTPUT_TO_FILE
399 write( p_aout->p_sys->fd, buffer, i_size );
400 intf_DbgMsg( "write() -> %d", write( p_aout->p_sys->fd, buffer, i_size ) );
402 Convert16BitIntegerTo32Float( buffer, p_aout->p_sys->p_Data, i_size );
405 * wait for a callback to occur (to flush the buffer), so aout_Play
406 * can't be called twice, losing the data we just wrote.
408 vlc_cond_wait( &p_aout->p_sys->cond_sync, &p_aout->p_sys->mutex_lock );
412 /*****************************************************************************
413 * aout_Close: closes the dummy audio device
414 *****************************************************************************/
415 static void aout_Close( aout_thread_t *p_aout )
417 OSStatus err = noErr;
419 /* stop playing sound through the device */
420 err = AudioDeviceStop( p_aout->p_sys->device,
421 (AudioDeviceIOProc)appIOProc );
424 /* remove the callback */
425 err = AudioDeviceRemoveIOProc( p_aout->p_sys->device,
426 (AudioDeviceIOProc)appIOProc );
429 DisposePtr( p_aout->p_sys->p_Data );
434 /*****************************************************************************
435 * Convert16BitIntegerTo32Float
436 *****************************************************************************/
437 void Convert16BitIntegerTo32Float( Ptr p_in16BitDataPtr, Ptr p_out32BitDataPtr,
438 UInt32 ui_totalBytes )
440 UInt32 i, ui_samples = ui_totalBytes / 2 /* each 16 bit sample is 2 bytes */;
441 SInt16 *p_s_inDataPtr = (SInt16 *) p_in16BitDataPtr;
442 Float32 *p_f_outDataPtr = (Float32 *) p_out32BitDataPtr;
444 for( i = 0 ; i < ui_samples ; i++ )
446 *p_f_outDataPtr = (Float32)(*p_s_inDataPtr);
447 if( *p_f_outDataPtr > 0 )
448 *p_f_outDataPtr /= 32767.0;
450 *p_f_outDataPtr /= 32768.0;
456 /*****************************************************************************
457 * Convert16BitIntegerTo32FloatWithByteSwap
458 *****************************************************************************/
459 void Convert16BitIntegerTo32FloatWithByteSwap( Ptr p_in16BitDataPtr,
460 Ptr p_out32BitDataPtr,
461 UInt32 ui_totalBytes )
463 UInt32 i, ui_samples = ui_totalBytes / 2 /* each 16 bit sample is 2 bytes */;
464 SInt16 *p_s_inDataPtr = (SInt16 *) p_in16BitDataPtr;
465 Float32 *p_f_outDataPtr = (Float32 *) p_out32BitDataPtr;
467 for( i = 0 ; i < ui_samples ; i++ )
469 *p_f_outDataPtr = (Float32)CFSwapInt16LittleToHost(*p_s_inDataPtr);
470 if( *p_f_outDataPtr > 0 )
471 *p_f_outDataPtr /= 32767.0;
473 *p_f_outDataPtr /= 32768.0;
480 /*****************************************************************************
481 * Convert8BitIntegerTo32Float
482 *****************************************************************************/
483 void Convert8BitIntegerTo32Float( Ptr p_in8BitDataPtr, Ptr p_out32BitDataPtr,
484 UInt32 ui_totalBytes )
486 UInt32 i, ui_samples = ui_totalBytes;
487 SInt8 *p_c_inDataPtr = (SInt8 *)p_in8BitDataPtr;
488 Float32 *p_f_outDataPtr = (Float32 *)p_out32BitDataPtr;
490 for( i = 0 ; i < ui_samples ; i++ )
492 *p_f_outDataPtr = (Float32)(*p_c_inDataPtr);
493 if( *p_f_outDataPtr > 0 )
494 *p_f_outDataPtr /= 32767.0;
496 *p_f_outDataPtr /= 32768.0;