]> git.sesse.net Git - vlc/blobdiff - plugins/macosx/aout_macosx.c
* ./src/misc/modules_plugin.h: kludge to allow the ALSA module to be
[vlc] / plugins / macosx / aout_macosx.c
index 1498edd1f115c29f3a3067d6421146db94ec768b..056d589ba8c6b661c66c768dbdfaa4d13ed5d06e 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
- * aout_darwin.c : Darwin audio output plugin
+ * aout_macosx.c : CoreAudio output plugin
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: aout_macosx.c,v 1.7 2001/11/29 10:20:56 massiot Exp $
+ * $Id: aout_macosx.c,v 1.15 2002/03/19 03:33:52 jlj Exp $
  *
  * Authors: Colin Delacroix <colin@zoy.org>
+ *          Jon Lech Johansen <jon-vl@nanocrew.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-/*
- * 2001/03/21
- * Status of audio under Darwin
- * It currently works with 16 bits signed big endian mpeg 1 audio
- * (and probably mpeg 2). This is the most common case.
- * Note: ac3 decoder is currently broken under Darwin 
- *
- * TODO:
- * Find little endian files and adapt output
- * Find unsigned files and adapt output
- * Find 8 bits files and adapt output
- */
-#define MODULE_NAME macosx
-#include "modules_inner.h"
-
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include "defs.h"
-
 #include <string.h>
 
-#include "config.h"
-#include "common.h"                                     /* boolean_t, byte_t */
-#include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
-#include "threads.h"
-#include "mtime.h"
-#include "tests.h"
+#include <videolan/vlc.h>
 
 #include "audio_output.h"                                   /* aout_thread_t */
 
-#include "main.h"
-
-#include "modules.h"
-
 #include <Carbon/Carbon.h>
 #include <CoreAudio/AudioHardware.h>
-
-#include <sys/fcntl.h>
-
-/*
- * Debug: to dump the output of the decoder directly to a file
- * May disappear when AC3 decoder will work on Darwin
- */
-#define WRITE_AUDIO_OUTPUT_TO_FILE 0
+#include <AudioToolbox/AudioConverter.h>
 
 /*****************************************************************************
  * aout_sys_t: private audio output method descriptor
  *****************************************************************************
  * This structure is part of the audio output thread descriptor.
- * It describes the Darwin specific properties of an output thread.
+ * It describes the CoreAudio specific properties of an output thread.
  *****************************************************************************/
 typedef struct aout_sys_s
 {
-#if WRITE_AUDIO_OUTPUT_TO_FILE
-    int           fd;                         // debug: fd to dump audio
-#endif
-    AudioStreamBasicDescription        deviceFormat; // info about the default device
-    AudioDeviceID device;                                      // the default device
-    Ptr                        p_Data;                     // ptr to the 32 bit float data
-    UInt32           ui_deviceBufferSize;        // audio device buffer size
-    vlc_mutex_t   mutex_lock;                 // pthread locks for sync of
-    vlc_cond_t    cond_sync;                  // aout_Play and callback
+    AudioDeviceID       device;         // the audio device
+    AudioConverterRef   s_converter;    // the AudioConverter
+    int                 b_format;       // format begun 
+
+    AudioStreamBasicDescription s_src_stream_format;
+    AudioStreamBasicDescription s_dst_stream_format;
+
+    Ptr                            p_buffer;       // ptr to the 32 bit float data
+    UInt32                 ui_buffer_size; // audio device buffer size
+    vlc_mutex_t         mutex_lock;     // pthread locks for sync of
+    vlc_cond_t          cond_sync;      // aout_Play and callback
 } aout_sys_t;
 
 /*****************************************************************************
  * Local prototypes.
  *****************************************************************************/
-static int     aout_Probe       ( probedata_t *p_data );
-static int     aout_Open        ( aout_thread_t *p_aout );
-static int     aout_SetFormat   ( aout_thread_t *p_aout );
-static long    aout_GetBufInfo  ( aout_thread_t *p_aout, long l_buffer_info );
-static void    aout_Play        ( aout_thread_t *p_aout,
+static int      aout_Open       ( aout_thread_t *p_aout );
+static int      aout_SetFormat  ( aout_thread_t *p_aout );
+static int      aout_GetBufInfo ( aout_thread_t *p_aout, int i_buffer_info );
+static void     aout_Play       ( aout_thread_t *p_aout,
                                   byte_t *buffer, int i_size );
-static void    aout_Close       ( aout_thread_t *p_aout );
-
-static OSStatus appIOProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow, 
-                    const void* inInputData, const AudioTimeStamp* inInputTime,
-                    AudioBufferList* outOutputData, 
-                    const AudioTimeStamp* inOutputTime, 
-                    void* threadGlobals );
-static void Convert16BitIntegerTo32Float( Ptr p_in16BitDataPtr, Ptr p_out32BitDataPtr, 
-                                   UInt32 ui_totalBytes );
-static void Convert16BitIntegerTo32FloatWithByteSwap( Ptr p_in16BitDataPtr, 
-                                               Ptr p_out32BitDataPtr, 
-                                               UInt32 p_totalBytes );
-static void Convert8BitIntegerTo32Float( Ptr in8BitDataPtr, Ptr p_out32BitDataPtr, 
-                                  UInt32 ui_totalBytes );
+static void     aout_Close      ( aout_thread_t *p_aout );
+
+static int      CABeginFormat   ( aout_thread_t *p_aout );
+static int      CAEndFormat     ( aout_thread_t *p_aout );
+
+static OSStatus CAIOCallback    ( AudioDeviceID inDevice,
+                                  const AudioTimeStamp *inNow, 
+                                  const void *inInputData, 
+                                  const AudioTimeStamp *inInputTime,
+                                  AudioBufferList *outOutputData, 
+                                  const AudioTimeStamp *inOutputTime, 
+                                  void *threadGlobals );
 
 /*****************************************************************************
  * Functions exported as capabilities. They are declared as static so that
@@ -117,7 +83,6 @@ static void Convert8BitIntegerTo32Float( Ptr in8BitDataPtr, Ptr p_out32BitDataPt
  *****************************************************************************/
 void _M( aout_getfunctions )( function_list_t * p_function_list )
 {
-    p_function_list->pf_probe = aout_Probe;
     p_function_list->functions.aout.pf_open = aout_Open;
     p_function_list->functions.aout.pf_setformat = aout_SetFormat;
     p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
@@ -126,107 +91,82 @@ void _M( aout_getfunctions )( function_list_t * p_function_list )
 }
 
 /*****************************************************************************
- * aout_Probe: probe the audio device and return a score
- *****************************************************************************/
-static int aout_Probe( probedata_t *p_data )
-{
-    if( TestMethod( AOUT_METHOD_VAR, "macosx" ) )
-    {
-        return( 999 );
-    }
-
-    /* This plugin always works under OS X */
-    return( 100 );
-}
-
-/*****************************************************************************
- * aout_Open: opens a HAL audio device
+ * aout_Open: opens a CoreAudio HAL device
  *****************************************************************************/
 static int aout_Open( aout_thread_t *p_aout )
 {
-    OSStatus        err = noErr;
-    UInt32                         ui_paramSize, ui_bufferSize;
-    AudioDeviceID              device = kAudioDeviceUnknown;
-    AudioStreamBasicDescription        format;
+    OSStatus err;
+    UInt32 ui_param_size;
 
-    /* Allocate structure */
+    /* allocate instance */
     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
     if( p_aout->p_sys == NULL )
     {
-        intf_ErrMsg("aout error: %s", strerror(ENOMEM) );
+        intf_ErrMsg( "aout error: %s", strerror(ENOMEM) );
         return( 1 );
     }
 
-    /* Initialize some variables */
-    p_aout->i_format      = AOUT_FORMAT_DEFAULT;
-    p_aout->i_channels    = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
-                                                  AOUT_STEREO_DEFAULT );
-    p_aout->l_rate        =     main_GetIntVariable( AOUT_RATE_VAR,
-                                                  AOUT_RATE_DEFAULT );
+    /* initialize members */
+    memset( p_aout->p_sys, 0, sizeof( aout_sys_t ) );
 
-    p_aout->p_sys->device = kAudioDeviceUnknown;
-    p_aout->p_sys->p_Data = nil;
-    
-    /*
-     * get the default output device for the HAL
-     * it is required to pass the size of the data to be returned
-     */
-    ui_paramSize = sizeof( p_aout->p_sys->device );    
+    /* get the default output device */
+    ui_param_size = sizeof( p_aout->p_sys->device );   
     err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
-                                    &ui_paramSize, (void *) &device );
-    
-    
-    if( err == noErr
+                                    &ui_param_size, 
+                                    (void *)&p_aout->p_sys->device );
+
+    if( err != noErr 
     {
-        /* 
-         * The values we get here are not used. We may find another method for
-         * insuring us that the audio device is working !
-         *
-         * First get the buffersize that the default device uses for IO
-         */
-        ui_paramSize = sizeof( p_aout->p_sys->ui_deviceBufferSize );
-        err = AudioDeviceGetProperty( device, 0, false, 
-                                      kAudioDevicePropertyBufferSize, 
-                                      &ui_paramSize, &ui_bufferSize);
-        if( err == noErr )
-        {
-            /* get a description of the data format used by the default device */
-            ui_paramSize = sizeof(p_aout->p_sys->deviceFormat); 
-            err = AudioDeviceGetProperty( device, 0, false, 
-                                          kAudioDevicePropertyStreamFormat, 
-                                          &ui_paramSize, &format);
-            if( err == noErr )
-            {
-                if( format.mFormatID != kAudioFormatLinearPCM ) return paramErr;
-            
-                /* everything is ok so fill in p_sys */
-                p_aout->p_sys->device              = device;
-                p_aout->p_sys->ui_deviceBufferSize = ui_bufferSize;
-                p_aout->p_sys->deviceFormat        = format;
-            }
-        }
+        intf_ErrMsg( "aout error: failed to get the device: %d", err );
+        return( -1 );
     }
 
-    if (err != noErr) return err;
+    /* get the buffer size that the device uses for IO */
+    ui_param_size = sizeof( p_aout->p_sys->ui_buffer_size );
+    err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false, 
+                                  kAudioDevicePropertyBufferSize, 
+                                  &ui_param_size,
+                                  &p_aout->p_sys->ui_buffer_size );
 
-    /* 
-     * Size calcul taken from audio_output.c we may change that file so we would
-     * not be forced to compute the same value twice
-     */
-    p_aout->p_sys->ui_deviceBufferSize = 
-      2 * 2 * sizeof(s16) * ((s64)p_aout->l_rate * AOUT_BUFFER_DURATION) / 1000000; 
-    /* Allocate memory for audio */
-    p_aout->p_sys->p_Data = NewPtrClear( p_aout->p_sys->ui_deviceBufferSize );
-    if( p_aout->p_sys->p_Data == nil ) return paramErr;
-
-#if WRITE_AUDIO_OUTPUT_TO_FILE
-    p_aout->p_sys->fd = open( "audio-darwin.pcm", O_RDWR|O_CREAT );
-    intf_WarnMsg( 3, "open(...) -> %d", p_aout->p_sys->fd );
-#endif
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: failed to get device buffer size: %d", err );
+        return( -1 );
+    }
 
-    vlc_cond_init( &p_aout->p_sys->cond_sync );
+    /* get a description of the data format used by the device */
+    ui_param_size = sizeof( p_aout->p_sys->s_dst_stream_format ); 
+    err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false, 
+                                  kAudioDevicePropertyStreamFormat, 
+                                  &ui_param_size,
+                                  &p_aout->p_sys->s_dst_stream_format );
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: failed to get dst stream format: %d", err );
+        return( -1 );
+    }
+
+    if( p_aout->p_sys->s_dst_stream_format.mFormatID != kAudioFormatLinearPCM )
+    {
+        intf_ErrMsg( "aout error: kAudioFormatLinearPCM required" );
+        return( -1 );
+    }
+
+    /* initialize mutex and cond */
     vlc_mutex_init( &p_aout->p_sys->mutex_lock );
+    vlc_cond_init( &p_aout->p_sys->cond_sync );
+
+    /* initialize source stream format */
+    memcpy( &p_aout->p_sys->s_src_stream_format,
+            &p_aout->p_sys->s_dst_stream_format,
+            sizeof( p_aout->p_sys->s_src_stream_format ) );
+
+    if( CABeginFormat( p_aout ) )
+    {
+        intf_ErrMsg( "aout error: CABeginFormat failed" );
+        return( -1 );
+    }
 
     return( 0 );
 }
@@ -236,158 +176,116 @@ static int aout_Open( aout_thread_t *p_aout )
  *****************************************************************************/
 static int aout_SetFormat( aout_thread_t *p_aout )
 {
-    OSStatus err = noErr;
-    UInt32      ui_paramSize, 
-             ui_bufferSize = p_aout->p_sys->ui_deviceBufferSize;
-    AudioStreamBasicDescription        format;
-
-    /* set the buffersize that the default device uses for IO */
-    ui_paramSize = sizeof( ui_bufferSize );    
-    err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false, 
-                                  kAudioDevicePropertyBufferSize, 
-                                  ui_paramSize, &ui_bufferSize);
-    if( err != noErr )
+    if( CAEndFormat( p_aout ) )
     {
-        /* We have to tell the decoder to use audio device's buffer size  */
-        intf_ErrMsg( "aout : AudioDeviceSetProperty failed ( buffersize = %d ) -> %d",
-                     ui_bufferSize, err );
+        intf_ErrMsg( "aout error: CAEndFormat failed" );
         return( -1 );
     }
-    else
+
+    switch( p_aout->i_format )
     {
-        p_aout->p_sys->ui_deviceBufferSize = ui_bufferSize;
-    
-        ui_paramSize = sizeof( format ); 
-        err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false, 
-                                      kAudioDevicePropertyStreamFormat, 
-                                      &ui_paramSize, &format);
-
-        if( err == noErr )
-        {
-            intf_DbgMsg( "audio output format is %i", p_aout->i_format );
-            
-            /*
-             * setting format.mFormatFlags to anything but the default value 
-             * doesn't seem to work. Can anybody explain that ??
-             */
-
-            switch( p_aout->i_format )
-            {
-                case AOUT_FMT_U8:
-                    intf_ErrMsg( "Audio format (Unsigned 8) not supported now,"
-                                 "please report stream" );
-                    return( -1 );
-                    
-                case AOUT_FMT_S16_LE:           /* Little endian signed 16 */
-                    intf_DbgMsg( "This means Little endian signed 16" );
-                    // format.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-                    intf_ErrMsg( "Audio format (LE Unsigned 16) not supported now,"
-                                 "please report stream" );
-                    return( -1 );
-                    
-                case AOUT_FMT_S16_BE:              /* Big endian signed 16 */
-                    intf_DbgMsg( "This means big endian signed 16" );
-                    // format.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-                    break;
-                    
-                case AOUT_FMT_S8:
-                    intf_ErrMsg( "Audio format (Signed 8) not supported now,"
-                                 "please report stream" );
-                    return( -1 );
+        case AOUT_FMT_S8:
+            intf_ErrMsg( "Audio format (Signed 8) not supported now,"
+                         "please report stream" );
+            return( -1 );
                     
-                case AOUT_FMT_U16_LE:                 /* Little endian U16 */
-                    // format.mFormatFlags &= ~kLinearPCMFormatFlagIsSignedInteger;
-                    intf_DbgMsg( "This means Little endian U16" );
-                    intf_ErrMsg( "Audio format (LE Unsigned 8) not supported now,"
-                                 "please report stream" );
-                    return( -1 );
+        case AOUT_FMT_U8:
+            intf_ErrMsg( "Audio format (Unsigned 8) not supported now,"
+                         "please report stream" );
+            return( -1 );
+
+        case AOUT_FMT_S16_LE:
+            p_aout->p_sys->s_src_stream_format.mFormatFlags &=
+                ~kLinearPCMFormatFlagIsBigEndian;
+            p_aout->p_sys->s_src_stream_format.mFormatFlags |=
+                kLinearPCMFormatFlagIsSignedInteger;
+            break;
+
+        case AOUT_FMT_S16_BE:
+            p_aout->p_sys->s_src_stream_format.mFormatFlags |=
+                kLinearPCMFormatFlagIsBigEndian;
+            p_aout->p_sys->s_src_stream_format.mFormatFlags |=
+                kLinearPCMFormatFlagIsSignedInteger;
+            break;
+
+        case AOUT_FMT_U16_LE:
+            p_aout->p_sys->s_src_stream_format.mFormatFlags &=
+                ~kLinearPCMFormatFlagIsBigEndian;
+            p_aout->p_sys->s_src_stream_format.mFormatFlags &=
+                ~kLinearPCMFormatFlagIsSignedInteger;
+            break;
                     
-                case AOUT_FMT_U16_BE:                    /* Big endian U16 */
-                    // format.mFormatFlags &= ~kLinearPCMFormatFlagIsSignedInteger;
-                    intf_ErrMsg( "Audio format (BE Unsigned 8) not supported now,"
-                                 "please report stream" );
-                    return( -1 );
+        case AOUT_FMT_U16_BE:
+            p_aout->p_sys->s_src_stream_format.mFormatFlags |=
+                kLinearPCMFormatFlagIsBigEndian;
+            p_aout->p_sys->s_src_stream_format.mFormatFlags &=
+                ~kLinearPCMFormatFlagIsSignedInteger;
+            break;
                     
-                    break;
-                default:
-                    intf_DbgMsg( "This means Unknown aout format" );
-                    return( -1 );
-            }
-
-            /*
-             * It would have been nice to have these work (no more buffer
-             * convertion to float) but I couldn't manage to
-             */
-            // format.mFormatFlags &= ~kLinearPCMFormatFlagIsFloat;
-            // format.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
-            // format.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
-
-            format.mSampleRate       = p_aout->l_rate;
-            format.mChannelsPerFrame = p_aout->i_channels;
-
-            err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false, 
-                                          kAudioDevicePropertyStreamFormat, 
-                                          ui_paramSize, &format);
-            if( err != noErr )
-            {
-                intf_ErrMsg( "aout : AudioDeviceSetProperty( mFormatFlags = %x, " 
-                             "mSampleRate = %f, mChannelsPerFrame = %d ) -> %d", 
-                             format.mFormatFlags, format.mSampleRate, 
-                             format.mChannelsPerFrame, err );
-                return( -1 );
-            }
-        }
+        default:
+            intf_ErrMsg( "Audio format (0x%08x) not supported now,"
+                         "please report stream", p_aout->i_format );
+            return( -1 );
     }
 
-    p_aout->i_latency = 0;
+    /* source format is not float */
+    p_aout->p_sys->s_src_stream_format.mFormatFlags &=
+        ~kLinearPCMFormatFlagIsFloat;
 
-    /* add callback */
-    err = AudioDeviceAddIOProc( p_aout->p_sys->device, 
-                                (AudioDeviceIOProc)appIOProc, 
-                                (void *)p_aout->p_sys );
+    /* if destination format is float, take size diff into account */
+    if( p_aout->p_sys->s_dst_stream_format.mFormatFlags & 
+        kLinearPCMFormatFlagIsFloat )
+    {
+        p_aout->p_sys->s_src_stream_format.mBytesPerPacket =
+            p_aout->p_sys->s_dst_stream_format.mBytesPerPacket / 2;
+        p_aout->p_sys->s_src_stream_format.mBytesPerFrame =
+            p_aout->p_sys->s_src_stream_format.mBytesPerFrame / 2;
+        p_aout->p_sys->s_src_stream_format.mBitsPerChannel =
+            p_aout->p_sys->s_src_stream_format.mBitsPerChannel / 2;
+    }
 
-    /* open the output */
-    if( err == noErr )
-        err = AudioDeviceStart( p_aout->p_sys->device, (AudioDeviceIOProc)appIOProc );                 
-    
-    return( err );
+    /* set sample rate and channels per frame */
+    p_aout->p_sys->s_src_stream_format.mSampleRate = p_aout->i_rate; 
+    p_aout->p_sys->s_src_stream_format.mChannelsPerFrame = p_aout->i_channels;
+
+    if( CABeginFormat( p_aout ) )
+    {
+        intf_ErrMsg( "aout error: CABeginFormat failed" );
+        return( -1 );
+    }
+
+    return( 0 );
 }
 
 /*****************************************************************************
  * aout_GetBufInfo: returns available bytes in buffer
  *****************************************************************************/
-static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
+static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
 {
-    return( 0 ); // Send data as soon as possible
-
-    /*
-     * Tune me ?
-     *
-       return (   p_aout->p_sys->p_Data
-             + p_aout->p_sys->sizeOfDataInMemory 
-             - p_aout->p_sys->currentDataLocationPtr 
-             - p_aout->p_sys->ui_deviceBufferSize );
-     */
+    return( 0 ); /* send data as soon as possible */
 }
 
 /*****************************************************************************
- * appIOProc : callback for audio output
+ * CAIOCallback : callback for audio output
  *****************************************************************************/
-static OSStatus appIOProc( AudioDeviceID  inDevice, const AudioTimeStamp*  inNow, 
-                    const void*  inInputData, const AudioTimeStamp*  inInputTime, 
-                    AudioBufferList*  outOutputData, const AudioTimeStamp* inOutputTime, 
-                    void* threadGlobals )
+static OSStatus CAIOCallback( AudioDeviceID inDevice,
+                              const AudioTimeStamp *inNow, 
+                              const void *inInputData,
+                              const AudioTimeStamp *inInputTime, 
+                              AudioBufferList *outOutputData,
+                              const AudioTimeStamp *inOutputTime, 
+                              void *threadGlobals )
 {
-    aout_sys_t*        p_sys = threadGlobals;
+    aout_sys_t *p_sys = (aout_sys_t *)threadGlobals;
 
     /* see aout_Play below */
     vlc_mutex_lock( &p_sys->mutex_lock );
     vlc_cond_signal( &p_sys->cond_sync );
     
     /* move data into output data buffer */
-    BlockMoveData( p_sys->p_Data,
+    BlockMoveData( p_sys->p_buffer,
                    outOutputData->mBuffers[ 0 ].mData, 
-                   p_sys->ui_deviceBufferSize );
+                   p_sys->ui_buffer_size );
 
     vlc_mutex_unlock( &p_sys->mutex_lock );
 
@@ -399,107 +297,172 @@ static OSStatus appIOProc( AudioDeviceID  inDevice, const AudioTimeStamp*  inNow
  *****************************************************************************/
 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
 {
-#if WRITE_AUDIO_OUTPUT_TO_FILE
-    write( p_aout->p_sys->fd, buffer, i_size );
-    intf_DbgMsg( "write() -> %d", write( p_aout->p_sys->fd, buffer, i_size ) );
-#else
-    Convert16BitIntegerTo32Float( buffer, p_aout->p_sys->p_Data, i_size );
-    
+    OSStatus err;
+    UInt32 ui_buffer_size = p_aout->p_sys->ui_buffer_size;
+
+    err = AudioConverterConvertBuffer( p_aout->p_sys->s_converter,
+                                       i_size, buffer,
+                                       &ui_buffer_size,
+                                       p_aout->p_sys->p_buffer );
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: ConvertBuffer failed: %d", err );
+    }
+
     /* 
      * wait for a callback to occur (to flush the buffer), so aout_Play
      * can't be called twice, losing the data we just wrote. 
      */
+    vlc_mutex_lock( &p_aout->p_sys->mutex_lock );
     vlc_cond_wait( &p_aout->p_sys->cond_sync, &p_aout->p_sys->mutex_lock );
-#endif
+    vlc_mutex_unlock( &p_aout->p_sys->mutex_lock );
 }
 
 /*****************************************************************************
- * aout_Close: closes the dummy audio device
+ * aout_Close: closes the CoreAudio HAL device
  *****************************************************************************/
 static void aout_Close( aout_thread_t *p_aout )
 {
-    OSStatus   err = noErr;
-    
-    /* stop playing sound through the device */
-    err = AudioDeviceStop( p_aout->p_sys->device, 
-                           (AudioDeviceIOProc)appIOProc );                     
-    if( err == noErr )
+    if( CAEndFormat( p_aout ) )
     {
-        /* remove the callback */
-        err = AudioDeviceRemoveIOProc( p_aout->p_sys->device, 
-                                      (AudioDeviceIOProc)appIOProc );          
+        intf_ErrMsg( "aout error: CAEndFormat failed" );
     }
 
-    DisposePtr( p_aout->p_sys->p_Data );
-    return;
+    /* destroy lock and cond */
+    vlc_mutex_destroy( &p_aout->p_sys->mutex_lock );
+    vlc_cond_destroy( &p_aout->p_sys->cond_sync );
+
+    free( p_aout->p_sys );
 }
 
 /*****************************************************************************
- * Convert16BitIntegerTo32Float
+ * CABeginFormat: creates an AudioConverter 
  *****************************************************************************/
-static void Convert16BitIntegerTo32Float( Ptr p_in16BitDataPtr, Ptr p_out32BitDataPtr, 
-                                   UInt32 ui_totalBytes )
+static int CABeginFormat( aout_thread_t *p_aout )
 {
-    UInt32     i, ui_samples = ui_totalBytes / 2 /* each 16 bit sample is 2 bytes */;
-    SInt16     *p_s_inDataPtr = (SInt16 *) p_in16BitDataPtr;
-    Float32    *p_f_outDataPtr = (Float32 *) p_out32BitDataPtr;
-    
-    for( i = 0 ; i < ui_samples ; i++ )
+    OSStatus err;
+    UInt32 ui_param_size;
+
+    if( p_aout->p_sys->b_format )
     {
-        *p_f_outDataPtr = (Float32)(*p_s_inDataPtr);
-        if( *p_f_outDataPtr > 0 )
-            *p_f_outDataPtr /= 32767.0;
-        else
-            *p_f_outDataPtr /= 32768.0;
-        p_f_outDataPtr++;
-        p_s_inDataPtr++;
+        intf_ErrMsg( "aout error: CABeginFormat (b_format)" );
+        return( 1 );
     }
-}
-       
-/*****************************************************************************
- * Convert16BitIntegerTo32FloatWithByteSwap
- *****************************************************************************/
-static void Convert16BitIntegerTo32FloatWithByteSwap( Ptr p_in16BitDataPtr, 
-                                               Ptr p_out32BitDataPtr, 
-                                               UInt32 ui_totalBytes )
-{
-    UInt32     i, ui_samples = ui_totalBytes / 2 /* each 16 bit sample is 2 bytes */;
-    SInt16     *p_s_inDataPtr = (SInt16 *) p_in16BitDataPtr;
-    Float32    *p_f_outDataPtr = (Float32 *) p_out32BitDataPtr;
-    
-    for( i = 0 ; i < ui_samples ; i++ )
+
+    p_aout->p_sys->ui_buffer_size = 2 * 2 * sizeof(s16) * 
+        ((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000; 
+
+    /* set the buffer size that the device uses for IO */
+    ui_param_size = sizeof( p_aout->p_sys->ui_buffer_size );   
+    err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false, 
+                                  kAudioDevicePropertyBufferSize, 
+                                  ui_param_size,
+                                  &p_aout->p_sys->ui_buffer_size );
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: AudioDeviceSetProperty failed: %d", err );
+        return( 1 );
+    }
+
+    /* allocate audio buffer */ 
+    p_aout->p_sys->p_buffer = NewPtrClear( p_aout->p_sys->ui_buffer_size );
+
+    if( p_aout->p_sys->p_buffer == nil )
+    {
+        intf_ErrMsg( "aout error: failed to allocate audio buffer" );
+        return( 1 );
+    }
+
+    /* create a new AudioConverter */
+    err = AudioConverterNew( &p_aout->p_sys->s_src_stream_format,
+                             &p_aout->p_sys->s_dst_stream_format,
+                             &p_aout->p_sys->s_converter );
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: AudioConverterNew failed: %d", err );
+        DisposePtr( p_aout->p_sys->p_buffer );
+        return( 1 );
+    }
+
+    /* add callback */
+    err = AudioDeviceAddIOProc( p_aout->p_sys->device, 
+                                (AudioDeviceIOProc)CAIOCallback, 
+                                (void *)p_aout->p_sys );
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: AudioDeviceAddIOProc failed: %d", err );
+        AudioConverterDispose( p_aout->p_sys->s_converter );
+        DisposePtr( p_aout->p_sys->p_buffer );
+        return( 1 );
+    } 
+
+    /* open the output */
+    err = AudioDeviceStart( p_aout->p_sys->device,
+                            (AudioDeviceIOProc)CAIOCallback );
+
+    if( err != noErr )
     {
-        *p_f_outDataPtr = (Float32)CFSwapInt16LittleToHost(*p_s_inDataPtr);
-        if( *p_f_outDataPtr > 0 )
-            *p_f_outDataPtr /= 32767.0;
-        else
-            *p_f_outDataPtr /= 32768.0;
-
-        p_f_outDataPtr++;
-        p_s_inDataPtr++;
+        intf_ErrMsg( "aout error: AudioDeviceStart failed: %d", err );
+        AudioConverterDispose( p_aout->p_sys->s_converter );
+        DisposePtr( p_aout->p_sys->p_buffer );
+        return( 1 );
     }
+
+    p_aout->p_sys->b_format = 1;
+
+    return( 0 );
 }
-       
+
 /*****************************************************************************
- * Convert8BitIntegerTo32Float
+ * CAEndFormat: destroys the AudioConverter 
  *****************************************************************************/
-static void Convert8BitIntegerTo32Float( Ptr p_in8BitDataPtr, Ptr p_out32BitDataPtr, 
-                                  UInt32 ui_totalBytes )
+static int CAEndFormat( aout_thread_t *p_aout )
 {
-    UInt32     i, ui_samples = ui_totalBytes;
-    SInt8      *p_c_inDataPtr = (SInt8 *)p_in8BitDataPtr;
-    Float32    *p_f_outDataPtr = (Float32 *)p_out32BitDataPtr;
-    
-    for( i = 0 ; i < ui_samples ; i++ )
+    OSStatus err; 
+
+    if( !p_aout->p_sys->b_format )
+    {
+        intf_ErrMsg( "aout error: CAEndFormat (!b_format)" );
+        return( 1 );
+    }
+
+    /* stop playing sound through the device */
+    err = AudioDeviceStop( p_aout->p_sys->device,
+                           (AudioDeviceIOProc)CAIOCallback ); 
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: AudioDeviceStop failed: %d", err );
+        return( 1 );
+    }
+
+    /* remove the callback */
+    err = AudioDeviceRemoveIOProc( p_aout->p_sys->device,
+                                   (AudioDeviceIOProc)CAIOCallback ); 
+
+    if( err != noErr )
     {
-        *p_f_outDataPtr = (Float32)(*p_c_inDataPtr);
-        if( *p_f_outDataPtr > 0 )
-            *p_f_outDataPtr /= 32767.0;
-        else
-            *p_f_outDataPtr /= 32768.0;
-        
-        p_f_outDataPtr++;
-        p_c_inDataPtr++;
+        intf_ErrMsg( "aout error: AudioDeviceRemoveIOProc failed: %d", err );
+        return( 1 );
     }
+
+    /* destroy the AudioConverter */
+    err = AudioConverterDispose( p_aout->p_sys->s_converter );
+
+    if( err != noErr )
+    {
+        intf_ErrMsg( "aout error: AudioConverterDispose failed: %d", err );
+        return( 1 );
+    }
+
+    /* release audio buffer */
+    DisposePtr( p_aout->p_sys->p_buffer );
+
+    p_aout->p_sys->b_format = 0;
+
+    return( 0 );
 }