]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/auhal.c
Removes trailing spaces. Removes tabs.
[vlc] / modules / audio_output / auhal.c
index 2bf861b5e3596eab9da901315a9fa428a7152d10..e3ee3a1eb804e135a6634cb60532baa59e828772 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * auhal.c: AUHAL output plugin
+ * auhal.c: AUHAL and Coreaudio output plugin
  *****************************************************************************
  * Copyright (C) 2005 the VideoLAN team
  * $Id$
@@ -10,7 +10,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include <string.h>
-#include <stdlib.h>
 #include <unistd.h>
 
 #include <vlc/vlc.h>
-#include <vlc/aout.h>
-
-#include "aout_internal.h"
+#include <vlc_interface.h>
+#include <vlc_aout.h>
 
 #include <CoreAudio/CoreAudio.h>
-#include <CoreAudio/CoreAudioTypes.h>
 #include <AudioUnit/AudioUnitProperties.h>
 #include <AudioUnit/AudioUnitParameters.h>
 #include <AudioUnit/AudioOutputUnit.h>
@@ -62,6 +58,7 @@
  * - clean up the debug info
  * - clean up C99'isms
  * - be better at changing stream setup or devices setup changes while playing.
+ * - fix 6.1 and 7.1
  */
 
 /*****************************************************************************
@@ -78,17 +75,19 @@ struct aout_sys_t
     vlc_bool_t                  b_supports_digital;/* Does the currently selected device support digital mode? */
     vlc_bool_t                  b_digital;      /* Are we running in digital mode? */
     mtime_t                     clock_diff;     /* Difference between VLC clock and Device clock */
+
     /* AUHAL specific */
     Component                   au_component;   /* The Audiocomponent we use */
     AudioUnit                   au_unit;        /* The AudioUnit we use */
     uint8_t                     p_remainder_buffer[BUFSIZE];
     uint32_t                    i_read_bytes;
     uint32_t                    i_total_bytes;
+
     /* CoreAudio SPDIF mode specific */
     pid_t                       i_hog_pid;      /* The keep the pid of our hog status */
     AudioStreamID               i_stream_id;    /* The StreamID that has a cac3 streamformat */
     int                         i_stream_index; /* The index of i_stream_id in an AudioBufferList */
-    AudioStreamBasicDescription stream_format;  /* The format we changed the to */
+    AudioStreamBasicDescription stream_format;  /* The format we changed the stream to */
     AudioStreamBasicDescription sfmt_revert;    /* The original format of the stream */
     vlc_bool_t                  b_revert;       /* Wether we need to revert the stream format */
     vlc_bool_t                  b_changed_mixing;/* Wether we need to set the mixing mode back */
@@ -108,6 +107,7 @@ static void     Probe                   ( aout_instance_t * );
 static int      AudioDeviceHasOutput    ( AudioDeviceID );
 static int      AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );
 static int      AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );
+static int      AudioStreamChangeFormat ( aout_instance_t *, AudioStreamID, AudioStreamBasicDescription );
 
 static OSStatus RenderCallbackAnalog    ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
                                           unsigned int, unsigned int, AudioBufferList *);
@@ -135,7 +135,7 @@ vlc_module_begin();
     set_category( CAT_AUDIO );
     set_subcategory( SUBCAT_AUDIO_AOUT );
     set_callbacks( Open, Close );
-    add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE ); 
+    add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE );
 vlc_module_end();
 
 /*****************************************************************************
@@ -171,20 +171,19 @@ static int Open( vlc_object_t * p_this )
     p_sys->i_total_bytes = 0;
     p_sys->i_hog_pid = -1;
     p_sys->i_stream_id = 0;
-    p_sys->i_stream_index = 0;
+    p_sys->i_stream_index = -1;
     p_sys->b_revert = VLC_FALSE;
     p_sys->b_changed_mixing = VLC_FALSE;
     memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
 
     p_aout->output.pf_play = Play;
-    
     aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output );
-    
     /* Persistent device variable */
-    if( var_Type( p_aout->p_vlc, "macosx-audio-device" ) == 0 )
+    if( var_Type( p_aout->p_libvlc, "macosx-audio-device" ) == 0 )
     {
-        msg_Dbg( p_aout, "create macosx-audio-device" );
-        var_Create( p_aout->p_vlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+        var_Create( p_aout->p_libvlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     }
 
     /* Build a list of devices */
@@ -197,14 +196,14 @@ static int Open( vlc_object_t * p_this )
     if( var_Get( p_aout, "audio-device", &val ) < 0 )
     {
         msg_Err( p_aout, "audio-device var does not exist. device probe failed." );
-        free( p_sys );
-        return( VLC_ENOVAR );
+        goto error;
     }
 
-    p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG;
+    p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG; /* remove SPDIF flag to get the true DeviceID */
     p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? VLC_TRUE : VLC_FALSE;
 
     /* Check if the desired device is alive and usable */
+    /* TODO: add a callback to the device to alert us if the device dies */
     i_param_size = sizeof( b_alive );
     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
                                   kAudioDevicePropertyDeviceIsAlive,
@@ -212,14 +211,13 @@ static int Open( vlc_object_t * p_this )
 
     if( err != noErr )
     {
-        msg_Err( p_aout, "could not check whether device is alive: %4.4s",
-                 (char *)&err );
-        return VLC_EGENERIC;
+        msg_Err( p_aout, "could not check whether device is alive: %4.4s", (char *)&err );
+        goto error;
     }
 
     if( b_alive == VLC_FALSE )
     {
-        msg_Err( p_aout, "Selected audio device is not alive switching to default device" ); 
+        msg_Warn( p_aout, "selected audio device is not alive, switching to default device" );
         p_sys->i_selected_dev = p_sys->i_default_dev;
     }
 
@@ -230,17 +228,19 @@ static int Open( vlc_object_t * p_this )
 
     if( err != noErr )
     {
-        msg_Err( p_aout, "could not check whether device is hogged: %4.4s",
+        /* This is not a fatal error. Some drivers simply don't support this property */
+        msg_Warn( p_aout, "could not check whether device is hogged: %4.4s",
                  (char *)&err );
-        return VLC_EGENERIC;
+        p_sys->i_hog_pid = -1;
     }
 
     if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() )
     {
-        msg_Err( p_aout, "Selected audio device is exclusively in use by another program" );
-        var_Destroy( p_aout, "audio-device" );
-        free( p_sys );
-        return VLC_EGENERIC;
+        msg_Err( p_aout, "Selected audio device is exclusively in use by another program." );
+        intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
+                        _("The selected audio output device is exclusively in "
+                          "use by another program.") );
+        goto error;
     }
 
     /* Check for Digital mode or Analog output mode */
@@ -254,29 +254,29 @@ static int Open( vlc_object_t * p_this )
         if( OpenAnalog( p_aout ) )
             return VLC_SUCCESS;
     }
-    
-    /* If we reach this, the Open* failed */
+
+error:
+    /* If we reach this, this aout has failed */
     var_Destroy( p_aout, "audio-device" );
-    free( p_sys );
+    if( p_sys ) free( p_sys );
     return VLC_EGENERIC;
 }
 
 /*****************************************************************************
- * Open: open and setup a HAL AudioUnit
+ * Open: open and setup a HAL AudioUnit to do analog (multichannel) audio output
  *****************************************************************************/
 static int OpenAnalog( aout_instance_t *p_aout )
 {
-    struct aout_sys_t       *p_sys = p_aout->output.p_sys;
-    OSStatus                err = noErr;
-    UInt32                  i_param_size = 0, i = 0;
-    ComponentDescription    desc;
-        
-    if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && !p_sys->b_supports_digital )
-    {
-        msg_Dbg( p_aout, "we had requested a digital stream, but it's not possible for this device" );
-    }
+    struct aout_sys_t           *p_sys = p_aout->output.p_sys;
+    OSStatus                    err = noErr;
+    UInt32                      i_param_size = 0, i = 0;
+    int                         i_original;
+    ComponentDescription        desc;
+    AudioStreamBasicDescription DeviceFormat;
+    AudioChannelLayout          *layout;
+    AudioChannelLayout          new_layout;
+    AURenderCallbackStruct      input;
 
-    /* If analog only start setting up AUHAL */
     /* Lets go find our Component */
     desc.componentType = kAudioUnitType_Output;
     desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -287,179 +287,158 @@ static int OpenAnalog( aout_instance_t *p_aout )
     p_sys->au_component = FindNextComponent( NULL, &desc );
     if( p_sys->au_component == NULL )
     {
-        msg_Err( p_aout, "we cannot find our HAL component" );
+        msg_Warn( p_aout, "we cannot find our HAL component" );
         return VLC_FALSE;
     }
 
     err = OpenAComponent( p_sys->au_component, &p_sys->au_unit );
-    if( err )
+    if( err != noErr )
     {
-        msg_Err( p_aout, "we cannot find our HAL component" );
+        msg_Warn( p_aout, "we cannot open our HAL component" );
         return VLC_FALSE;
     }
-    
-    /* Enable IO for the component */
-    msg_Dbg( p_aout, "Device: %#x", (int)p_sys->i_selected_dev );
-    
-    /* Set the device */
-    verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
+    /* Set the device we will use for this output unit */
+    err = AudioUnitSetProperty( p_sys->au_unit,
                          kAudioOutputUnitProperty_CurrentDevice,
                          kAudioUnitScope_Global,
                          0,
                          &p_sys->i_selected_dev,
-                         sizeof( AudioDeviceID )));
-                         
+                         sizeof( AudioDeviceID ));
+    if( err != noErr )
+    {
+        msg_Warn( p_aout, "we cannot select the audio device" );
+        return VLC_FALSE;
+    }
     /* Get the current format */
-    AudioStreamBasicDescription DeviceFormat;
-    
     i_param_size = sizeof(AudioStreamBasicDescription);
 
-    verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
+    err = AudioUnitGetProperty( p_sys->au_unit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Input,
                                    0,
                                    &DeviceFormat,
-                                   &i_param_size ));
-                                   
-    msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: " , DeviceFormat ) );
+                                   &i_param_size );
+    if( err != noErr ) return VLC_FALSE;
+    else msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: ", DeviceFormat ) );
 
-    /* Get the channel layout */
-    AudioChannelLayout *layout;
-    verify_noerr( AudioUnitGetPropertyInfo( p_sys->au_unit,
+    /* Get the channel layout of the device side of the unit (vlc -> unit -> device) */
+    err = AudioUnitGetPropertyInfo( p_sys->au_unit,
                                    kAudioDevicePropertyPreferredChannelLayout,
                                    kAudioUnitScope_Output,
                                    0,
                                    &i_param_size,
-                                   NULL ));
+                                   NULL );
 
-    layout = (AudioChannelLayout *)malloc( i_param_size);
-
-    verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
-                                   kAudioDevicePropertyPreferredChannelLayout,
-                                   kAudioUnitScope_Output,
-                                   0,
-                                   layout,
-                                   &i_param_size ));
-                                   
-    /* Lets fill out the ChannelLayout */
-    if( layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
-    {
-        msg_Dbg( p_aout, "bitmap defined channellayout" );
-        verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForBitmap,
-                                sizeof( UInt32), &layout->mChannelBitmap,
-                                &i_param_size,
-                                layout ));
-    }
-    else if( layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
+    if( err == noErr )
     {
-        msg_Dbg( p_aout, "layouttags defined channellayout" );
-        verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForTag,
-                                sizeof( AudioChannelLayoutTag ), &layout->mChannelLayoutTag,
-                                &i_param_size,
-                                layout ));
-    }
+        layout = (AudioChannelLayout *)malloc( i_param_size);
+
+        verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
+                                       kAudioDevicePropertyPreferredChannelLayout,
+                                       kAudioUnitScope_Output,
+                                       0,
+                                       layout,
+                                       &i_param_size ));
+        /* We need to "fill out" the ChannelLayout, because there are multiple ways that it can be set */
+        if( layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
+        {
+            /* bitmap defined channellayout */
+            verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForBitmap,
+                                    sizeof( UInt32), &layout->mChannelBitmap,
+                                    &i_param_size,
+                                    layout ));
+        }
+        else if( layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
+        {
+            /* layouttags defined channellayout */
+            verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForTag,
+                                    sizeof( AudioChannelLayoutTag ), &layout->mChannelLayoutTag,
+                                    &i_param_size,
+                                    layout ));
+        }
 
-    msg_Dbg( p_aout, "Layout of AUHAL has %d channels" , (int)layout->mNumberChannelDescriptions );
-    
-    p_aout->output.output.i_physical_channels = 0;
-    int i_original = p_aout->output.output.i_original_channels & AOUT_CHAN_PHYSMASK;
-    
-    if( i_original == AOUT_CHAN_CENTER || layout->mNumberChannelDescriptions < 2 )
-    {
-        // We only need Mono or cannot output more
-        p_aout->output.output.i_physical_channels |= AOUT_CHAN_CENTER;
-    }
-    else if( i_original == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) || layout->mNumberChannelDescriptions < 3 )
-    {
-        // We only need Stereo or cannot output more
-        p_aout->output.output.i_physical_channels |= AOUT_CHAN_RIGHT;
-        p_aout->output.output.i_physical_channels |= AOUT_CHAN_LEFT;
-    }
-    else
-    {
-        // We want more then stereo and we can do that
-        for( i = 0; i < layout->mNumberChannelDescriptions; i++ )
+        msg_Dbg( p_aout, "layout of AUHAL has %d channels" , (int)layout->mNumberChannelDescriptions );
+        /* Initialize the VLC core channel count */
+        p_aout->output.output.i_physical_channels = 0;
+        i_original = p_aout->output.output.i_original_channels & AOUT_CHAN_PHYSMASK;
+        if( i_original == AOUT_CHAN_CENTER || layout->mNumberChannelDescriptions < 2 )
+        {
+            /* We only need Mono or cannot output more than 1 channel */
+            p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
+        }
+        else if( i_original == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) || layout->mNumberChannelDescriptions < 3 )
+        {
+            /* We only need Stereo or cannot output more than 2 channels */
+            p_aout->output.output.i_physical_channels = AOUT_CHAN_RIGHT | AOUT_CHAN_LEFT;
+        }
+        else
         {
-            msg_Dbg( p_aout, "This is channel: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
+            /* We want more than stereo and we can do that */
+            for( i = 0; i < layout->mNumberChannelDescriptions; i++ )
+            {
+                msg_Dbg( p_aout, "this is channel: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
 
-            switch( layout->mChannelDescriptions[i].mChannelLabel )
+                switch( layout->mChannelDescriptions[i].mChannelLabel )
+                {
+                    case kAudioChannelLabel_Left:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_LEFT;
+                        continue;
+                    case kAudioChannelLabel_Right:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_RIGHT;
+                        continue;
+                    case kAudioChannelLabel_Center:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_CENTER;
+                        continue;
+                    case kAudioChannelLabel_LFEScreen:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_LFE;
+                        continue;
+                    case kAudioChannelLabel_LeftSurround:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARLEFT;
+                        continue;
+                    case kAudioChannelLabel_RightSurround:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARRIGHT;
+                        continue;
+                    case kAudioChannelLabel_RearSurroundLeft:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLELEFT;
+                        continue;
+                    case kAudioChannelLabel_RearSurroundRight:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLERIGHT;
+                        continue;
+                    case kAudioChannelLabel_CenterSurround:
+                        p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARCENTER;
+                        continue;
+                    default:
+                        msg_Warn( p_aout, "unrecognized channel form provided by driver: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
+                }
+            }
+            if( p_aout->output.output.i_physical_channels == 0 )
             {
-                case kAudioChannelLabel_Left:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_LEFT;
-                    continue;
-                case kAudioChannelLabel_Right:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_RIGHT;
-                    continue;
-                case kAudioChannelLabel_Center:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_CENTER;
-                    continue;
-                case kAudioChannelLabel_LFEScreen:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_LFE;
-                    continue;
-                case kAudioChannelLabel_LeftSurround:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARLEFT;
-                    continue;
-                case kAudioChannelLabel_RightSurround:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARRIGHT;
-                    continue;
-                case kAudioChannelLabel_RearSurroundLeft:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLELEFT;
-                    continue;
-                case kAudioChannelLabel_RearSurroundRight:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLERIGHT;
-                    continue;
-                case kAudioChannelLabel_CenterSurround:
-                    p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARCENTER;
-                    continue;
-                default:
-                    msg_Warn( p_aout, "Unrecognized channel form provided by driver: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
-                    if( i == 0 )
-                    {
-                        msg_Warn( p_aout, "Probably no channellayout is set. force based on channelcount" );
-                        switch( layout->mNumberChannelDescriptions )
-                        {
-                            /* We make assumptions based on number of channels here.
-                             * Unfortunatly Apple has provided no 100% method to retrieve the speaker configuration */
-                            case 1:
-                                p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
-                                break;
-                            case 4:
-                                p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
-                                                                            AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
-                                break;
-                            case 6:
-                                p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
-                                                                            AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
-                                                                            AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
-                                break;
-                            case 7:
-                                p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
-                                                                            AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
-                                                                            AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
-                                                                            AOUT_CHAN_REARCENTER;
-                                break;
-                            case 8:
-                                p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
-                                                                            AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
-                                                                            AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
-                                                                            AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT;
-                                break;
-                            case 2:
-                            default:
-                                p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
-                        }
-                    }
-                    break;
+                p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
+                msg_Err( p_aout, "You should configure your speaker layout with Audio Midi Setup Utility in /Applications/Utilities. Now using Stereo mode." );
+                intf_UserFatal( p_aout, VLC_FALSE, _("Audio device is not configured"),
+                                _("You should configure your speaker layout with "
+                                  "the \"Audio Midi Setup Utility\" in /Applications/"
+                                  "Utilities. Stereo mode is being used now.") );
             }
         }
+        if( layout ) free( layout );
+    }
+    else
+    {
+        msg_Warn( p_aout, "this driver does not support kAudioDevicePropertyPreferredChannelLayout. BAD DRIVER AUTHOR !!!" );
+        p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
     }
-    if( layout ) free( layout );
 
-    msg_Dbg( p_aout, "we want to output these channels: %#x", p_aout->output.output.i_original_channels);
     msg_Dbg( p_aout, "selected %d physical channels for device output", aout_FormatNbChannels( &p_aout->output.output ) );
-    msg_Dbg( p_aout, "%s", aout_FormatPrintChannels( &p_aout->output.output ));
+    msg_Dbg( p_aout, "VLC will output: %s", aout_FormatPrintChannels( &p_aout->output.output ));
 
-    AudioChannelLayout new_layout;
     memset (&new_layout, 0, sizeof(new_layout));
     switch( aout_FormatNbChannels( &p_aout->output.output ) )
     {
@@ -504,7 +483,14 @@ static int OpenAnalog( aout_instance_t *p_aout )
             }
             break;
         case 6:
-            new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_20; // L R Ls Rs C LFE
+            if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_LFE ) )
+            {
+                new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_20; // L R Ls Rs C LFE
+            }
+            else
+            {
+                new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_6_0; // L R Ls Rs C Cs
+            }
             break;
         case 7:
             /* FIXME: This is incorrect. VLC uses the internal ordering: L R Lm Rm Lr Rr C LFE but this is wrong */
@@ -525,47 +511,42 @@ static int OpenAnalog( aout_instance_t *p_aout )
     DeviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
     DeviceFormat.mBitsPerChannel = 32;
     DeviceFormat.mChannelsPerFrame = aout_FormatNbChannels( &p_aout->output.output );
-    
     /* Calculate framesizes and stuff */
-    aout_FormatPrepare( &p_aout->output.output );
     DeviceFormat.mFramesPerPacket = 1;
     DeviceFormat.mBytesPerFrame = DeviceFormat.mBitsPerChannel * DeviceFormat.mChannelsPerFrame / 8;
     DeviceFormat.mBytesPerPacket = DeviceFormat.mBytesPerFrame * DeviceFormat.mFramesPerPacket;
  
+    /* Set the desired format */
     i_param_size = sizeof(AudioStreamBasicDescription);
-    /* Set desired format (Use CAStreamBasicDescription )*/
     verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Input,
                                    0,
                                    &DeviceFormat,
                                    i_param_size ));
-                                   
     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "we set the AU format: " , DeviceFormat ) );
-    
-    /* Retrieve actual format??? */
+    /* Retrieve actual format */
     verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Input,
                                    0,
                                    &DeviceFormat,
                                    &i_param_size ));
-                                   
     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "the actual set AU format is " , DeviceFormat ) );
 
+    /* Do the last VLC aout setups */
+    aout_FormatPrepare( &p_aout->output.output );
     p_aout->output.i_nb_samples = 2048;
     aout_VolumeSoftInit( p_aout );
 
-    /* Find the difference between device clock and mdate clock */
-    p_sys->clock_diff = - (mtime_t)
-        AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000; 
-    p_sys->clock_diff += mdate();
-
     /* set the IOproc callback */
-    AURenderCallbackStruct input;
     input.inputProc = (AURenderCallback) RenderCallbackAnalog;
     input.inputProcRefCon = p_aout;
-    
     verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
                             kAudioUnitProperty_SetRenderCallback,
                             kAudioUnitScope_Input,
@@ -573,18 +554,27 @@ static int OpenAnalog( aout_instance_t *p_aout )
 
     input.inputProc = (AURenderCallback) RenderCallbackAnalog;
     input.inputProcRefCon = p_aout;
-    
-    /* Set the new_layout as the layout VLC feeds to the AU unit */
+    /* Set the new_layout as the layout VLC will use to feed the AU unit */
     verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
                             kAudioUnitProperty_AudioChannelLayout,
                             kAudioUnitScope_Input,
                             0, &new_layout, sizeof(new_layout) ) );
-    
+    if( new_layout.mNumberChannelDescriptions > 0 )
+        free( new_layout.mChannelDescriptions );
     /* AU initiliaze */
     verify_noerr( AudioUnitInitialize(p_sys->au_unit) );
 
+    /* Find the difference between device clock and mdate clock */
+    p_sys->clock_diff = - (mtime_t)
+        AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
+    p_sys->clock_diff += mdate();
+
+    /* Start the AU */
     verify_noerr( AudioOutputUnitStart(p_sys->au_unit) );
-    
     return VLC_TRUE;
 }
 
@@ -600,24 +590,19 @@ static int OpenSPDIF( aout_instance_t * p_aout )
     AudioStreamID           *p_streams = NULL;
     int                     i = 0, i_streams = 0;
 
-    struct timeval now;
-    struct timespec timeout;
-    struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
-
     /* Start doing the SPDIF setup proces */
     p_sys->b_digital = VLC_TRUE;
-    msg_Dbg( p_aout, "opening in SPDIF mode" );
 
     /* Hog the device */
     i_param_size = sizeof( p_sys->i_hog_pid );
     p_sys->i_hog_pid = getpid() ;
-    
     err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
                                   kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
-    
     if( err != noErr )
     {
-        msg_Err( p_aout, "failed to set hogmode: [%4.4s]", (char *)&err );
+        msg_Err( p_aout, "failed to set hogmode: [%4.4s]", (char *)&err );
         return VLC_FALSE;
     }
 
@@ -627,7 +612,7 @@ static int OpenSPDIF( aout_instance_t * p_aout )
 
     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
                                     &i_param_size, &b_mix );
-                                    
     if( !err && b_writeable )
     {
         b_mix = 0;
@@ -635,14 +620,14 @@ static int OpenSPDIF( aout_instance_t * p_aout )
                             kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
         p_sys->b_changed_mixing = VLC_TRUE;
     }
-    
     if( err != noErr )
     {
         msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
         return VLC_FALSE;
     }
 
-    // Find stream_id of selected device with a cac3 stream
+    /* Get a list of all the streams on this device */
     err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE,
                                       kAudioDevicePropertyStreams,
                                       &i_param_size, NULL );
@@ -651,19 +636,19 @@ static int OpenSPDIF( aout_instance_t * p_aout )
         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
         return VLC_FALSE;
     }
-    
     i_streams = i_param_size / sizeof( AudioStreamID );
     p_streams = (AudioStreamID *)malloc( i_param_size );
     if( p_streams == NULL )
     {
-        msg_Err( p_aout, "Out of memory" );
+        msg_Err( p_aout, "out of memory" );
         return VLC_FALSE;
     }
-    
     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
                                     kAudioDevicePropertyStreams,
                                     &i_param_size, p_streams );
-    
     if( err != noErr )
     {
         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
@@ -671,12 +656,13 @@ static int OpenSPDIF( aout_instance_t * p_aout )
         return VLC_FALSE;
     }
 
-    for( i = 0; i < i_streams; i++ )
+    for( i = 0; i < i_streams && p_sys->i_stream_index < 0 ; i++ )
     {
-        // Find a stream with a cac3 stream
+        /* Find a stream with a cac3 stream */
         AudioStreamBasicDescription *p_format_list = NULL;
         int                         i_formats = 0, j = 0;
-        
+        vlc_bool_t                  b_digital = VLC_FALSE;
         /* Retrieve all the stream formats supported by each output stream */
         err = AudioStreamGetPropertyInfo( p_streams[i], 0,
                                           kAudioStreamPropertyPhysicalFormats,
@@ -686,15 +672,15 @@ static int OpenSPDIF( aout_instance_t * p_aout )
             msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
             continue;
         }
-        
         i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
         p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
         if( p_format_list == NULL )
         {
-            msg_Err( p_aout, "Could not malloc the memory" );
+            msg_Err( p_aout, "could not malloc the memory" );
             continue;
         }
-        
         err = AudioStreamGetProperty( p_streams[i], 0,
                                           kAudioStreamPropertyPhysicalFormats,
                                           &i_param_size, p_format_list );
@@ -705,102 +691,82 @@ static int OpenSPDIF( aout_instance_t * p_aout )
             continue;
         }
 
+        /* Check if one of the supported formats is a digital format */
         for( j = 0; j < i_formats; j++ )
         {
             if( p_format_list[j].mFormatID == 'IAC3' ||
                   p_format_list[j].mFormatID == kAudioFormat60958AC3 )
             {
-                // found a cac3 format
-                p_sys->i_stream_id = p_streams[i];
-                p_sys->i_stream_index = i;
+                b_digital = VLC_TRUE;
+                break;
+            }
+        }
+        if( b_digital )
+        {
+            /* if this stream supports a digital (cac3) format, then go set it. */
+            int i_requested_rate_format = -1;
+            int i_current_rate_format = -1;
+            int i_backup_rate_format = -1;
 
-                if( p_sys->b_revert == VLC_FALSE )
+            p_sys->i_stream_id = p_streams[i];
+            p_sys->i_stream_index = i;
+
+            if( p_sys->b_revert == VLC_FALSE )
+            {
+                /* Retrieve the original format of this stream first if not done so already */
+                i_param_size = sizeof( p_sys->sfmt_revert );
+                err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
+                                              kAudioStreamPropertyPhysicalFormat,
+                                              &i_param_size,
+                                              &p_sys->sfmt_revert );
+                if( err != noErr )
                 {
-                    i_param_size = sizeof( p_sys->sfmt_revert );
-                    err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
-                                                  kAudioStreamPropertyPhysicalFormat,
-                                                  &i_param_size, 
-                                                  &p_sys->sfmt_revert );
-                    if( err != noErr )
-                    {
-                        msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
-                        continue; 
-                    }
-                    p_sys->b_revert = VLC_TRUE;
+                    msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
+                    continue;
                 }
-                if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
+                p_sys->b_revert = VLC_TRUE;
+            }
+
+            for( j = 0; j < i_formats; j++ )
+            {
+                if( p_format_list[j].mFormatID == 'IAC3' ||
+                      p_format_list[j].mFormatID == kAudioFormat60958AC3 )
                 {
-                    p_sys->stream_format = p_format_list[j];
+                    if( p_format_list[j].mSampleRate == p_aout->output.output.i_rate )
+                    {
+                        i_requested_rate_format = j;
+                        break;
+                    }
+                    else if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
+                    {
+                        i_current_rate_format = j;
+                    }
+                    else
+                    {
+                        if( i_backup_rate_format < 0 || p_format_list[j].mSampleRate > p_format_list[i_backup_rate_format].mSampleRate )
+                            i_backup_rate_format = j;
+                    }
                 }
             }
+            if( i_requested_rate_format >= 0 ) /* We prefer to output at the samplerate of the original audio */
+                p_sys->stream_format = p_format_list[i_requested_rate_format];
+            else if( i_current_rate_format >= 0 ) /* If not possible, we will try to use the current samplerate of the device */
+                p_sys->stream_format = p_format_list[i_current_rate_format];
+            else p_sys->stream_format = p_format_list[i_backup_rate_format]; /* And if we have to, any digital format will be just fine (highest rate possible) */
         }
         if( p_format_list ) free( p_format_list );
     }
-    
     if( p_streams ) free( p_streams );
 
     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "original stream format: ", p_sys->sfmt_revert ) );
-    msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->stream_format ) );
-
-    /* Install the callback */
-    err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
-                                      kAudioStreamPropertyPhysicalFormat,
-                                      StreamListener, (void *)&w );
-    if( err != noErr )
-    {
-        msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
-        return VLC_FALSE;
-    }
-
-    /* Condition because SetProperty is asynchronious */ 
-    vlc_cond_init( p_aout, &w.cond );
-    vlc_mutex_init( p_aout, &w.lock );
-    vlc_mutex_lock( &w.lock );
-    
-    /* change the format */
-    err = AudioStreamSetProperty( p_sys->i_stream_id, 0, 0,
-                                  kAudioStreamPropertyPhysicalFormat,
-                                  sizeof( AudioStreamBasicDescription ),
-                                  &p_sys->stream_format ); 
-    if( err != noErr )
-    {
-        msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
-        vlc_mutex_unlock( &w.lock );
-        vlc_mutex_destroy( &w.lock );
-        vlc_cond_destroy( &w.cond );
-        return VLC_FALSE;
-    }
-
-    gettimeofday( &now, NULL );
-    timeout.tv_sec = now.tv_sec;
-    timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
-
-    pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
-    vlc_mutex_unlock( &w.lock );
 
-    err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
-                                        kAudioStreamPropertyPhysicalFormat,
-                                        StreamListener );
-    if( err != noErr )
-    {
-        msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
-        vlc_mutex_destroy( &w.lock );
-        vlc_cond_destroy( &w.cond );
+    if( !AudioStreamChangeFormat( p_aout, p_sys->i_stream_id, p_sys->stream_format ) )
         return VLC_FALSE;
-    }
 
-    vlc_mutex_destroy( &w.lock );
-    vlc_cond_destroy( &w.cond );
-    
-    i_param_size = sizeof( AudioStreamBasicDescription );
-    err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
-                                  kAudioStreamPropertyPhysicalFormat,
-                                  &i_param_size, 
-                                  &p_sys->stream_format );
-
-    msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
-
-    /* set the format flags */
+    /* Set the format flags */
     if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','b');
     else
@@ -809,7 +775,7 @@ static int OpenSPDIF( aout_instance_t * p_aout )
     p_aout->output.output.i_frame_length = A52_FRAME_NB;
     p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
     p_aout->output.output.i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
-
+    aout_FormatPrepare( &p_aout->output.output );
     aout_VolumeNoneInit( p_aout );
 
     /* Add IOProc callback */
@@ -824,16 +790,16 @@ static int OpenSPDIF( aout_instance_t * p_aout )
 
     /* Check for the difference between the Device clock and mdate */
     p_sys->clock_diff = - (mtime_t)
-        AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000; 
+        AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
     p_sys->clock_diff += mdate();
  
     /* Start device */
-    err = AudioDeviceStart( p_sys->i_selected_dev, (AudioDeviceIOProc)RenderCallbackSPDIF ); 
+    err = AudioDeviceStart( p_sys->i_selected_dev, (AudioDeviceIOProc)RenderCallbackSPDIF );
     if( err != noErr )
     {
         msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err );
 
-        err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev, 
+        err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
                                        (AudioDeviceIOProc)RenderCallbackSPDIF );
         if( err != noErr )
         {
@@ -855,90 +821,37 @@ static void Close( vlc_object_t * p_this )
     struct aout_sys_t   *p_sys = p_aout->output.p_sys;
     OSStatus            err = noErr;
     UInt32              i_param_size = 0;
-    
     if( p_sys->au_unit )
     {
         verify_noerr( AudioOutputUnitStop( p_sys->au_unit ) );
         verify_noerr( AudioUnitUninitialize( p_sys->au_unit ) );
         verify_noerr( CloseComponent( p_sys->au_unit ) );
     }
-    
     if( p_sys->b_digital )
     {
         /* Stop device */
-        err = AudioDeviceStop( p_sys->i_selected_dev, 
-                               (AudioDeviceIOProc)RenderCallbackSPDIF ); 
+        err = AudioDeviceStop( p_sys->i_selected_dev,
+                               (AudioDeviceIOProc)RenderCallbackSPDIF );
         if( err != noErr )
         {
             msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
         }
 
-        /* Remove callback */
+        /* Remove IOProc callback */
         err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
                                        (AudioDeviceIOProc)RenderCallbackSPDIF );
         if( err != noErr )
         {
             msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
         }
-        
         if( p_sys->b_revert )
         {
-            struct timeval now;
-            struct timespec timeout;
-            struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
-
-            /* Install the callback */
-            err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
-                                              kAudioStreamPropertyPhysicalFormat,
-                                              StreamListener, (void *)&w );
-            if( err != noErr )
-            {
-                msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
-            }
-
-            /* Condition because SetProperty is asynchronious */ 
-            vlc_cond_init( p_aout, &w.cond );
-            vlc_mutex_init( p_aout, &w.lock );
-            vlc_mutex_lock( &w.lock );
-
-            msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->sfmt_revert ) );
-
-            err = AudioStreamSetProperty( p_sys->i_stream_id, NULL, 0,
-                                            kAudioStreamPropertyPhysicalFormat,
-                                            sizeof( AudioStreamBasicDescription ),
-                                            &p_sys->sfmt_revert );
-                                            
-            if( err != noErr )
-            {
-                msg_Err( p_aout, "Streamformat reverse failed: [%4.4s]", (char *)&err );
-            }
-            
-            gettimeofday( &now, NULL );
-            timeout.tv_sec = now.tv_sec;
-            timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
-
-            pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
-            vlc_mutex_unlock( &w.lock );
-
-            err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
-                                                kAudioStreamPropertyPhysicalFormat,
-                                                StreamListener );
-            if( err != noErr )
-            {
-                msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
-            }
-
-            vlc_mutex_destroy( &w.lock );
-            vlc_cond_destroy( &w.cond );
-            
-            i_param_size = sizeof( AudioStreamBasicDescription );
-            err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
-                                          kAudioStreamPropertyPhysicalFormat,
-                                          &i_param_size, 
-                                          &p_sys->stream_format );
-
-            msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
+            AudioStreamChangeFormat( p_aout, p_sys->i_stream_id, p_sys->sfmt_revert );
         }
+
         if( p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3 )
         {
             int b_mix;
@@ -949,7 +862,7 @@ static void Close( vlc_object_t * p_this )
 
             err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
                                         &i_param_size, &b_mix );
-                                        
             if( !err && b_writeable )
             {
                 msg_Dbg( p_aout, "mixable is: %d", b_mix );
@@ -967,12 +880,12 @@ static void Close( vlc_object_t * p_this )
 
     err = AudioHardwareRemovePropertyListener( kAudioHardwarePropertyDevices,
                                                HardwareListener );
-                                               
     if( err != noErr )
     {
         msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err );
     }
-    
     if( p_sys->i_hog_pid == getpid() )
     {
         p_sys->i_hog_pid = -1;
@@ -981,7 +894,7 @@ static void Close( vlc_object_t * p_this )
                                          kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
         if( err != noErr ) msg_Err( p_aout, "Could not release hogmode: [%4.4s]", (char *)&err );
     }
-    
     if( p_sys ) free( p_sys );
 }
 
@@ -994,7 +907,7 @@ static void Play( aout_instance_t * p_aout )
 
 
 /*****************************************************************************
- * Probe
+ * Probe: Check which devices the OS has, and add them to our audio-device menu
  *****************************************************************************/
 static void Probe( aout_instance_t * p_aout )
 {
@@ -1011,7 +924,7 @@ static void Probe( aout_instance_t * p_aout )
                                         &i_param_size, NULL );
     if( err != noErr )
     {
-        msg_Err( p_aout, "could not get number of devices: [%4.4s]", (char *)&err );
+        msg_Err( p_aout, "Could not get number of devices: [%4.4s]", (char *)&err );
         goto error;
     }
 
@@ -1019,7 +932,7 @@ static void Probe( aout_instance_t * p_aout )
 
     if( p_sys->i_devices < 1 )
     {
-        msg_Err( p_aout, "no devices found" );
+        msg_Err( p_aout, "No audio output devices were found." );
         goto error;
     }
 
@@ -1038,7 +951,7 @@ static void Probe( aout_instance_t * p_aout )
                                     &i_param_size, p_devices );
     if( err != noErr )
     {
-        msg_Err( p_aout, "could not get the device ID's: [%4.4s]", (char *)&err );
+        msg_Err( p_aout, "could not get the device IDs: [%4.4s]", (char *)&err );
         goto error;
     }
 
@@ -1052,11 +965,11 @@ static void Probe( aout_instance_t * p_aout )
         goto error;
     }
     p_sys->i_default_dev = devid_def;
-    
     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE );
     text.psz_string = _("Audio Device");
     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
-    
     for( i = 0; i < p_sys->i_devices; i++ )
     {
         char *psz_name;
@@ -1077,7 +990,7 @@ static void Probe( aout_instance_t * p_aout )
                     &i_param_size, psz_name);
         if( err ) goto error;
 
-        msg_Dbg( p_aout, "DevID: %#lx  DevName: %s", p_devices[i], psz_name );
+        msg_Dbg( p_aout, "DevID: %#lx DevName: %s", p_devices[i], psz_name );
 
         if( !AudioDeviceHasOutput( p_devices[i]) )
         {
@@ -1085,11 +998,13 @@ static void Probe( aout_instance_t * p_aout )
             continue;
         }
 
+        /* Add the menu entries */
         val.i_int = (int)p_devices[i];
         text.psz_string = strdup( psz_name );
         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
         if( p_sys->i_default_dev == p_devices[i] )
         {
+            /* The default device is the selected device normally */
             var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
             var_Set( p_aout, "audio-device", val );
         }
@@ -1097,37 +1012,38 @@ static void Probe( aout_instance_t * p_aout )
         if( AudioDeviceSupportsDigital( p_aout, p_devices[i] ) )
         {
             val.i_int = (int)p_devices[i] | AOUT_VAR_SPDIF_FLAG;
-            asprintf( &text.psz_string, "%s (Encoded Output)", psz_name );
+            asprintf( &text.psz_string, _("%s (Encoded Output)"), psz_name );
             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
             if( p_sys->i_default_dev == p_devices[i] && config_GetInt( p_aout, "spdif" ) )
             {
+                /* We selected to prefer SPDIF output if available
+                 * then this "dummy" entry should be selected */
                 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
                 var_Set( p_aout, "audio-device", val );
             }
         }
-        
         free( psz_name);
     }
-    
-    var_Get( p_aout->p_vlc, "macosx-audio-device", &val );
-    msg_Dbg( p_aout, "device value override1: %#x", val.i_int );
+    /* If a device is already "preselected", then use this device */
+    var_Get( p_aout->p_libvlc, "macosx-audio-device", &val );
     if( val.i_int > 0 )
     {
-        msg_Dbg( p_aout, "device value override2: %#x", val.i_int );
         var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
         var_Set( p_aout, "audio-device", val );
     }
-    
+    /* If we change the device we want to use, we should renegotiate the audio chain */
     var_AddCallback( p_aout, "audio-device", AudioDeviceCallback, NULL );
 
-    /* attach a Listener so that we are notified of a change in the Device setup */
+    /* Attach a Listener so that we are notified of a change in the Device setup */
     err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
-                                            HardwareListener, 
+                                            HardwareListener,
                                             (void *)p_aout );
     if( err )
         goto error;
 
-    msg_Dbg( p_aout, "succesful finish of deviceslist" );
     if( p_devices ) free( p_devices );
     return;
 
@@ -1142,12 +1058,12 @@ error:
  *****************************************************************************/
 static int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
 {
-    UInt32                     dataSize;
-    Boolean                    isWritable;
-       
+    UInt32            dataSize;
+    Boolean            isWritable;
+    
     verify_noerr( AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE, kAudioDevicePropertyStreams, &dataSize, &isWritable) );
     if (dataSize == 0) return FALSE;
-    
     return TRUE;
 }
 
@@ -1161,7 +1077,7 @@ static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_
     AudioStreamID               *p_streams = NULL;
     int                         i = 0, i_streams = 0;
     vlc_bool_t                  b_return = VLC_FALSE;
-    
     /* Retrieve all the output streams */
     err = AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE,
                                       kAudioDevicePropertyStreams,
@@ -1171,19 +1087,19 @@ static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_
         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
         return VLC_FALSE;
     }
-    
     i_streams = i_param_size / sizeof( AudioStreamID );
     p_streams = (AudioStreamID *)malloc( i_param_size );
     if( p_streams == NULL )
     {
-        msg_Err( p_aout, "Out of memory" );
+        msg_Err( p_aout, "out of memory" );
         return VLC_ENOMEM;
     }
-    
     err = AudioDeviceGetProperty( i_dev_id, 0, FALSE,
                                     kAudioDevicePropertyStreams,
                                     &i_param_size, p_streams );
-    
     if( err != noErr )
     {
         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
@@ -1195,7 +1111,7 @@ static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_
         if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) )
             b_return = VLC_TRUE;
     }
-    
     if( p_streams ) free( p_streams );
     return b_return;
 }
@@ -1210,7 +1126,7 @@ static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_
     AudioStreamBasicDescription *p_format_list = NULL;
     int                         i = 0, i_formats = 0;
     vlc_bool_t                  b_return = VLC_FALSE;
-    
     /* Retrieve all the stream formats supported by each output stream */
     err = AudioStreamGetPropertyInfo( i_stream_id, 0,
                                       kAudioStreamPropertyPhysicalFormats,
@@ -1220,16 +1136,15 @@ static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_
         msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
         return VLC_FALSE;
     }
-    
     i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
-    msg_Dbg( p_aout, "number of formats: %d", i_formats );
     p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
     if( p_format_list == NULL )
     {
-        msg_Err( p_aout, "Could not malloc the memory" );
+        msg_Err( p_aout, "could not malloc the memory" );
         return VLC_FALSE;
     }
-    
     err = AudioStreamGetProperty( i_stream_id, 0,
                                       kAudioStreamPropertyPhysicalFormats,
                                       &i_param_size, p_format_list );
@@ -1244,18 +1159,111 @@ static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_
     for( i = 0; i < i_formats; i++ )
     {
         msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format: ", p_format_list[i] ) );
-        
         if( p_format_list[i].mFormatID == 'IAC3' ||
                   p_format_list[i].mFormatID == kAudioFormat60958AC3 )
         {
             b_return = VLC_TRUE;
         }
     }
-    
     if( p_format_list ) free( p_format_list );
     return b_return;
 }
 
+/*****************************************************************************
+ * AudioStreamChangeFormat: Change i_stream_id to change_format
+ *****************************************************************************/
+static int AudioStreamChangeFormat( aout_instance_t *p_aout, AudioStreamID i_stream_id, AudioStreamBasicDescription change_format )
+{
+    OSStatus            err = noErr;
+    UInt32              i_param_size = 0;
+    int i;
+
+    struct timeval now;
+    struct timespec timeout;
+    struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
+    msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", change_format ) );
+
+    /* Condition because SetProperty is asynchronious */
+    vlc_cond_init( p_aout, &w.cond );
+    vlc_mutex_init( p_aout, &w.lock );
+    vlc_mutex_lock( &w.lock );
+
+    /* Install the callback */
+    err = AudioStreamAddPropertyListener( i_stream_id, 0,
+                                      kAudioStreamPropertyPhysicalFormat,
+                                      StreamListener, (void *)&w );
+    if( err != noErr )
+    {
+        msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
+        return VLC_FALSE;
+    }
+
+    /* change the format */
+    err = AudioStreamSetProperty( i_stream_id, 0, 0,
+                                  kAudioStreamPropertyPhysicalFormat,
+                                  sizeof( AudioStreamBasicDescription ),
+                                  &change_format );
+    if( err != noErr )
+    {
+        msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
+        return VLC_FALSE;
+    }
+
+    /* The AudioStreamSetProperty is not only asynchronious (requiring the locks)
+     * it is also not atomic in its behaviour.
+     * Therefore we check 5 times before we really give up.
+     * FIXME: failing isn't actually implemented yet. */
+    for( i = 0; i < 5; i++ )
+    {
+        AudioStreamBasicDescription actual_format;
+
+        gettimeofday( &now, NULL );
+        timeout.tv_sec = now.tv_sec;
+        timeout.tv_nsec = (now.tv_usec + 500000) * 1000;
+
+        if( pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout ) )
+        {
+            msg_Dbg( p_aout, "reached timeout" );
+        }
+
+        i_param_size = sizeof( AudioStreamBasicDescription );
+        err = AudioStreamGetProperty( i_stream_id, 0,
+                                      kAudioStreamPropertyPhysicalFormat,
+                                      &i_param_size,
+                                      &actual_format );
+
+        msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", actual_format ) );
+        if( actual_format.mSampleRate == change_format.mSampleRate &&
+            actual_format.mFormatID == change_format.mFormatID &&
+            actual_format.mFramesPerPacket == change_format.mFramesPerPacket )
+        {
+            /* The right format is now active */
+            break;
+        }
+        /* We need to check again */
+    }
+    /* Removing the property listener */
+    err = AudioStreamRemovePropertyListener( i_stream_id, 0,
+                                            kAudioStreamPropertyPhysicalFormat,
+                                            StreamListener );
+    if( err != noErr )
+    {
+        msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
+        return VLC_FALSE;
+    }
+    /* Destroy the lock and condition */
+    vlc_mutex_unlock( &w.lock );
+    vlc_mutex_destroy( &w.lock );
+    vlc_cond_destroy( &w.cond );
+    return VLC_TRUE;
+}
+
 /*****************************************************************************
  * RenderCallbackAnalog: This function is called everytime the AudioUnit wants
  * us to provide some more audio data.
@@ -1271,7 +1279,7 @@ static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
 {
     AudioTimeStamp  host_time;
     mtime_t         current_date = 0;
-    uint32_t        i_mData_bytes = 0;    
+    uint32_t        i_mData_bytes = 0;
 
     aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
     struct aout_sys_t * p_sys = p_aout->output.p_sys;
@@ -1281,7 +1289,7 @@ static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
 
     /* Check for the difference between the Device clock and mdate */
     p_sys->clock_diff = - (mtime_t)
-        AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000; 
+        AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
     p_sys->clock_diff += mdate();
 
     current_date = p_sys->clock_diff +
@@ -1300,36 +1308,36 @@ static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
     if( p_sys->i_total_bytes > 0 )
     {
         i_mData_bytes = __MIN( p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize );
-        p_aout->p_vlc->pf_memcpy( ioData->mBuffers[0].mData, &p_sys->p_remainder_buffer[p_sys->i_read_bytes], i_mData_bytes );
+        p_aout->p_libvlc->pf_memcpy( ioData->mBuffers[0].mData, &p_sys->p_remainder_buffer[p_sys->i_read_bytes], i_mData_bytes );
         p_sys->i_read_bytes += i_mData_bytes;
         current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
                         ( i_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output )  ); // 4 is fl32 specific
-        
         if( p_sys->i_read_bytes >= p_sys->i_total_bytes )
             p_sys->i_read_bytes = p_sys->i_total_bytes = 0;
     }
-    
     while( i_mData_bytes < ioData->mBuffers[0].mDataByteSize )
     {
         /* We don't have enough data yet */
         aout_buffer_t * p_buffer;
         p_buffer = aout_OutputNextBuffer( p_aout, current_date , VLC_FALSE );
-        
         if( p_buffer != NULL )
         {
             uint32_t i_second_mData_bytes = __MIN( p_buffer->i_nb_bytes, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
-            
-            p_aout->p_vlc->pf_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes, p_buffer->p_buffer, i_second_mData_bytes );
+            p_aout->p_libvlc->pf_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes, p_buffer->p_buffer, i_second_mData_bytes );
             i_mData_bytes += i_second_mData_bytes;
 
             if( i_mData_bytes >= ioData->mBuffers[0].mDataByteSize )
             {
                 p_sys->i_total_bytes = p_buffer->i_nb_bytes - i_second_mData_bytes;
-                p_aout->p_vlc->pf_memcpy( p_sys->p_remainder_buffer, &p_buffer->p_buffer[i_second_mData_bytes], p_sys->i_total_bytes );
+                p_aout->p_libvlc->pf_memcpy( p_sys->p_remainder_buffer, &p_buffer->p_buffer[i_second_mData_bytes], p_sys->i_total_bytes );
             }
             else
             {
-                // update current_date
+                /* update current_date */
                 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
                                 ( i_second_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output )  ); // 4 is fl32 specific
             }
@@ -1337,22 +1345,22 @@ static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
         }
         else
         {
-             p_aout->p_vlc->pf_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes, 0, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
+             p_aout->p_libvlc->pf_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes, 0, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
              i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes;
         }
     }
-    return( noErr );     
+    return( noErr );
 }
 
 /*****************************************************************************
  * RenderCallbackSPDIF: callback for SPDIF audio output
  *****************************************************************************/
 static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
-                                    const AudioTimeStamp * inNow, 
+                                    const AudioTimeStamp * inNow,
                                     const void * inInputData,
-                                    const AudioTimeStamp * inInputTime, 
+                                    const AudioTimeStamp * inInputTime,
                                     AudioBufferList * outOutputData,
-                                    const AudioTimeStamp * inOutputTime, 
+                                    const AudioTimeStamp * inOutputTime,
                                     void * threadGlobals )
 {
     aout_buffer_t * p_buffer;
@@ -1363,7 +1371,7 @@ static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
 
     /* Check for the difference between the Device clock and mdate */
     p_sys->clock_diff = - (mtime_t)
-        AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000; 
+        AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
     p_sys->clock_diff += mdate();
 
     current_date = p_sys->clock_diff +
@@ -1377,19 +1385,19 @@ static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
     {
         if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_nb_bytes)
             msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_nb_bytes );
-        
         /* move data into output data buffer */
-        p_aout->p_vlc->pf_memcpy( BUFFER.mData,
+        p_aout->p_libvlc->pf_memcpy( BUFFER.mData,
                                   p_buffer->p_buffer, p_buffer->i_nb_bytes );
         aout_BufferFree( p_buffer );
     }
     else
     {
-        p_aout->p_vlc->pf_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
+        p_aout->p_libvlc->pf_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
     }
 #undef BUFFER
 
-    return( noErr );     
+    return( noErr );
 }
 
 /*****************************************************************************
@@ -1417,7 +1425,7 @@ static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
 }
 
 /*****************************************************************************
- * StreamListener 
+ * StreamListener
  *****************************************************************************/
 static OSStatus StreamListener( AudioStreamID inStream,
                                 UInt32 inChannel,
@@ -1426,13 +1434,13 @@ static OSStatus StreamListener( AudioStreamID inStream,
 {
     OSStatus err = noErr;
     struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
-
     switch( inPropertyID )
     {
         case kAudioStreamPropertyPhysicalFormat:
             vlc_mutex_lock( &w->lock );
             vlc_cond_signal( &w->cond );
-            vlc_mutex_unlock( &w->lock ); 
+            vlc_mutex_unlock( &w->lock );
             break;
 
         default:
@@ -1448,7 +1456,7 @@ static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable,
                      vlc_value_t old_val, vlc_value_t new_val, void *param )
 {
     aout_instance_t *p_aout = (aout_instance_t *)p_this;
-    var_Set( p_aout->p_vlc, "macosx-audio-device", new_val );
+    var_Set( p_aout->p_libvlc, "macosx-audio-device", new_val );
     msg_Dbg( p_aout, "Set Device: %#x", new_val.i_int );
     return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );
 }