]> git.sesse.net Git - vlc/blob - modules/audio_output/auhal.c
Use var_InheritString for --decklink-video-connection.
[vlc] / modules / audio_output / auhal.c
1 /*****************************************************************************
2  * auhal.c: AUHAL and Coreaudio output plugin
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <unistd.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_dialog.h>
36 #include <vlc_aout.h>
37
38 // By pass part of header which compile with some warnings,
39 // and that we don't require.
40 #define __MACHINEEXCEPTIONS__
41
42 #include <CoreAudio/CoreAudio.h>
43 #include <AudioUnit/AudioUnit.h>
44 #include <AudioUnit/AudioUnitProperties.h>
45 #include <AudioUnit/AudioUnitParameters.h>
46 #include <AudioUnit/AudioOutputUnit.h>
47 #include <AudioToolbox/AudioFormat.h>
48
49 #ifndef verify_noerr
50 #define verify_noerr(a) assert((a) == noErr)
51 #endif
52
53 #if AUDIO_UNIT_VERSION < 1060
54 #define AudioComponent Component
55 #define AudioComponentDescription ComponentDescription
56 #define AudioComponentFindNext FindNextComponent
57 #define AudioComponentInstanceNew OpenAComponent
58 #define AudioComponentInstanceDispose CloseComponent
59 #define AudioComponentInstanceNew OpenAComponent
60 #define AudioComponentInstanceNew OpenAComponent
61 #else
62 #include <AudioUnit/AudioComponent.h>
63 #endif
64
65 #define STREAM_FORMAT_MSG( pre, sfm ) \
66     pre "[%u][%4.4s][%u][%u][%u][%u][%u][%u]", \
67     (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
68     sfm.mFormatFlags, sfm.mBytesPerPacket, \
69     sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
70     sfm.mChannelsPerFrame, sfm.mBitsPerChannel
71
72 #define STREAM_FORMAT_MSG_FULL( pre, sfm ) \
73     pre ":\nsamplerate: [%u]\nFormatID: [%4.4s]\nFormatFlags: [%u]\nBypesPerPacket: [%u]\nFramesPerPacket: [%u]\nBytesPerFrame: [%u]\nChannelsPerFrame: [%u]\nBitsPerChannel[%u]", \
74     (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
75     sfm.mFormatFlags, sfm.mBytesPerPacket, \
76     sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
77     sfm.mChannelsPerFrame, sfm.mBitsPerChannel
78
79 #define FRAMESIZE 2048
80 #define BUFSIZE (FRAMESIZE * 8) * 8
81 #define AOUT_VAR_SPDIF_FLAG 0xf00000
82
83 /*
84  * TODO:
85  * - clean up the debug info
86  * - clean up C99'isms
87  * - be better at changing stream setup or devices setup changes while playing.
88  * - fix 6.1 and 7.1
89  */
90
91 /*****************************************************************************
92  * aout_sys_t: private audio output method descriptor
93  *****************************************************************************
94  * This structure is part of the audio output thread descriptor.
95  * It describes the CoreAudio specific properties of an output thread.
96  *****************************************************************************/
97 struct aout_sys_t
98 {
99     AudioDeviceID               i_default_dev;  /* Keeps DeviceID of defaultOutputDevice */
100     AudioDeviceID               i_selected_dev; /* Keeps DeviceID of the selected device */
101     UInt32                      i_devices;      /* Number of CoreAudio Devices */
102     bool                  b_supports_digital;/* Does the currently selected device support digital mode? */
103     bool                  b_digital;      /* Are we running in digital mode? */
104     mtime_t                     clock_diff;     /* Difference between VLC clock and Device clock */
105
106     /* AUHAL specific */
107     AudioComponent              au_component;   /* The Audiocomponent we use */
108     AudioUnit                   au_unit;        /* The AudioUnit we use */
109     uint8_t                     p_remainder_buffer[BUFSIZE];
110     uint32_t                    i_read_bytes;
111     uint32_t                    i_total_bytes;
112
113     /* CoreAudio SPDIF mode specific */
114     pid_t                       i_hog_pid;      /* The keep the pid of our hog status */
115     AudioStreamID               i_stream_id;    /* The StreamID that has a cac3 streamformat */
116     int                         i_stream_index; /* The index of i_stream_id in an AudioBufferList */
117     AudioStreamBasicDescription stream_format;  /* The format we changed the stream to */
118     AudioStreamBasicDescription sfmt_revert;    /* The original format of the stream */
119     bool                  b_revert;       /* Wether we need to revert the stream format */
120     bool                  b_changed_mixing;/* Wether we need to set the mixing mode back */
121 };
122
123 /*****************************************************************************
124  * Local prototypes.
125  *****************************************************************************/
126 static int      Open                    ( vlc_object_t * );
127 static int      OpenAnalog              ( aout_instance_t * );
128 static int      OpenSPDIF               ( aout_instance_t * );
129 static void     Close                   ( vlc_object_t * );
130
131 static void     Play                    ( aout_instance_t * );
132 static void     Probe                   ( aout_instance_t * );
133
134 static int      AudioDeviceHasOutput    ( AudioDeviceID );
135 static int      AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );
136 static int      AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );
137 static int      AudioStreamChangeFormat ( aout_instance_t *, AudioStreamID, AudioStreamBasicDescription );
138
139 static OSStatus RenderCallbackAnalog    ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
140                                           unsigned int, unsigned int, AudioBufferList *);
141 static OSStatus RenderCallbackSPDIF     ( AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
142                                           AudioBufferList *, const AudioTimeStamp *, void * );
143 static OSStatus HardwareListener        ( AudioHardwarePropertyID, void *);
144 static OSStatus StreamListener          ( AudioStreamID, UInt32,
145                                           AudioDevicePropertyID, void * );
146 static int      AudioDeviceCallback     ( vlc_object_t *, const char *,
147                                           vlc_value_t, vlc_value_t, void * );
148
149
150
151 /*****************************************************************************
152  * Module descriptor
153  *****************************************************************************/
154 #define ADEV_TEXT N_("Audio Device")
155 #define ADEV_LONGTEXT N_("Choose a number corresponding to the number of an " \
156     "audio device, as listed in your 'Audio Device' menu. This device will " \
157     "then be used by default for audio playback.")
158
159 vlc_module_begin ()
160     set_shortname( "auhal" )
161     set_description( N_("HAL AudioUnit output") )
162     set_capability( "audio output", 101 )
163     set_category( CAT_AUDIO )
164     set_subcategory( SUBCAT_AUDIO_AOUT )
165     set_callbacks( Open, Close )
166     add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, false )
167 vlc_module_end ()
168
169 /*****************************************************************************
170  * Open: open macosx audio output
171  *****************************************************************************/
172 static int Open( vlc_object_t * p_this )
173 {
174     OSStatus                err = noErr;
175     UInt32                  i_param_size = 0;
176     struct aout_sys_t       *p_sys = NULL;
177     vlc_value_t             val;
178     aout_instance_t         *p_aout = (aout_instance_t *)p_this;
179
180     /* Use int here, to match kAudioDevicePropertyDeviceIsAlive
181      * property size */
182     int                     b_alive = false; 
183
184     /* Allocate structure */
185     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
186     if( p_aout->output.p_sys == NULL )
187         return VLC_ENOMEM;
188
189     p_sys = p_aout->output.p_sys;
190     p_sys->i_default_dev = 0;
191     p_sys->i_selected_dev = 0;
192     p_sys->i_devices = 0;
193     p_sys->b_supports_digital = false;
194     p_sys->b_digital = false;
195     p_sys->au_component = NULL;
196     p_sys->au_unit = NULL;
197     p_sys->clock_diff = (mtime_t) 0;
198     p_sys->i_read_bytes = 0;
199     p_sys->i_total_bytes = 0;
200     p_sys->i_hog_pid = -1;
201     p_sys->i_stream_id = 0;
202     p_sys->i_stream_index = -1;
203     p_sys->b_revert = false;
204     p_sys->b_changed_mixing = false;
205     memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
206
207     p_aout->output.pf_play = Play;
208  
209     aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output );
210  
211     /* Persistent device variable */
212     if( var_Type( p_aout->p_libvlc, "macosx-audio-device" ) == 0 )
213     {
214         var_Create( p_aout->p_libvlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
215     }
216
217     /* Build a list of devices */
218     if( var_Type( p_aout, "audio-device" ) == 0 )
219     {
220         Probe( p_aout );
221     }
222
223     /* What device do we want? */
224     if( var_Get( p_aout, "audio-device", &val ) < 0 )
225     {
226         msg_Err( p_aout, "audio-device var does not exist. device probe failed." );
227         goto error;
228     }
229
230     p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG; /* remove SPDIF flag to get the true DeviceID */
231     p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? true : false;
232
233     /* Check if the desired device is alive and usable */
234     /* TODO: add a callback to the device to alert us if the device dies */
235     i_param_size = sizeof( b_alive );
236     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
237                                   kAudioDevicePropertyDeviceIsAlive,
238                                   &i_param_size, &b_alive );
239
240     if( err != noErr )
241     {
242         /* Be tolerant, only give a warning here */
243         msg_Warn( p_aout, "could not check whether device [0x%x] is alive: %4.4s", (unsigned int)p_sys->i_selected_dev, (char *)&err );
244         b_alive = false;
245     }
246
247     if( b_alive == false )
248     {
249         msg_Warn( p_aout, "selected audio device is not alive, switching to default device" );
250         p_sys->i_selected_dev = p_sys->i_default_dev;
251     }
252
253     i_param_size = sizeof( p_sys->i_hog_pid );
254     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
255                                   kAudioDevicePropertyHogMode,
256                                   &i_param_size, &p_sys->i_hog_pid );
257
258     if( err != noErr )
259     {
260         /* This is not a fatal error. Some drivers simply don't support this property */
261         msg_Warn( p_aout, "could not check whether device is hogged: %4.4s",
262                  (char *)&err );
263         p_sys->i_hog_pid = -1;
264     }
265
266     if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() )
267     {
268         msg_Err( p_aout, "Selected audio device is exclusively in use by another program." );
269         dialog_Fatal( p_aout, _("Audio output failed"), "%s",
270                         _("The selected audio output device is exclusively in "
271                           "use by another program.") );
272         goto error;
273     }
274
275     /* Check for Digital mode or Analog output mode */
276     if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && p_sys->b_supports_digital )
277     {
278         if( OpenSPDIF( p_aout ) )
279             return VLC_SUCCESS;
280     }
281     else
282     {
283         if( OpenAnalog( p_aout ) )
284             return VLC_SUCCESS;
285     }
286
287 error:
288     /* If we reach this, this aout has failed */
289     var_Destroy( p_aout, "audio-device" );
290     free( p_sys );
291     return VLC_EGENERIC;
292 }
293
294 /*****************************************************************************
295  * Open: open and setup a HAL AudioUnit to do analog (multichannel) audio output
296  *****************************************************************************/
297 static int OpenAnalog( aout_instance_t *p_aout )
298 {
299     struct aout_sys_t           *p_sys = p_aout->output.p_sys;
300     OSStatus                    err = noErr;
301     UInt32                      i_param_size = 0, i = 0;
302     int                         i_original;
303     AudioComponentDescription   desc;
304     AudioStreamBasicDescription DeviceFormat;
305     AudioChannelLayout          *layout;
306     AudioChannelLayout          new_layout;
307     AURenderCallbackStruct      input;
308
309     /* Lets go find our Component */
310     desc.componentType = kAudioUnitType_Output;
311     desc.componentSubType = kAudioUnitSubType_HALOutput;
312     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
313     desc.componentFlags = 0;
314     desc.componentFlagsMask = 0;
315
316     p_sys->au_component = AudioComponentFindNext( NULL, &desc );
317     if( p_sys->au_component == NULL )
318     {
319         msg_Warn( p_aout, "we cannot find our HAL component" );
320         return false;
321     }
322
323     err = AudioComponentInstanceNew( p_sys->au_component, &p_sys->au_unit );
324     if( err != noErr )
325     {
326         msg_Warn( p_aout, "we cannot open our HAL component" );
327         return false;
328     }
329  
330     /* Set the device we will use for this output unit */
331     err = AudioUnitSetProperty( p_sys->au_unit,
332                          kAudioOutputUnitProperty_CurrentDevice,
333                          kAudioUnitScope_Global,
334                          0,
335                          &p_sys->i_selected_dev,
336                          sizeof( AudioDeviceID ));
337  
338     if( err != noErr )
339     {
340         msg_Warn( p_aout, "we cannot select the audio device" );
341         return false;
342     }
343  
344     /* Get the current format */
345     i_param_size = sizeof(AudioStreamBasicDescription);
346
347     err = AudioUnitGetProperty( p_sys->au_unit,
348                                    kAudioUnitProperty_StreamFormat,
349                                    kAudioUnitScope_Input,
350                                    0,
351                                    &DeviceFormat,
352                                    &i_param_size );
353  
354     if( err != noErr ) return false;
355     else msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: ", DeviceFormat ) );
356
357     /* Get the channel layout of the device side of the unit (vlc -> unit -> device) */
358     err = AudioUnitGetPropertyInfo( p_sys->au_unit,
359                                    kAudioDevicePropertyPreferredChannelLayout,
360                                    kAudioUnitScope_Output,
361                                    0,
362                                    &i_param_size,
363                                    NULL );
364
365     if( err == noErr )
366     {
367         layout = (AudioChannelLayout *)malloc( i_param_size);
368
369         verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
370                                        kAudioDevicePropertyPreferredChannelLayout,
371                                        kAudioUnitScope_Output,
372                                        0,
373                                        layout,
374                                        &i_param_size ));
375  
376         /* We need to "fill out" the ChannelLayout, because there are multiple ways that it can be set */
377         if( layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
378         {
379             /* bitmap defined channellayout */
380             verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForBitmap,
381                                     sizeof( UInt32), &layout->mChannelBitmap,
382                                     &i_param_size,
383                                     layout ));
384         }
385         else if( layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
386         {
387             /* layouttags defined channellayout */
388             verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForTag,
389                                     sizeof( AudioChannelLayoutTag ), &layout->mChannelLayoutTag,
390                                     &i_param_size,
391                                     layout ));
392         }
393
394         msg_Dbg( p_aout, "layout of AUHAL has %d channels" , (int)layout->mNumberChannelDescriptions );
395  
396         /* Initialize the VLC core channel count */
397         p_aout->output.output.i_physical_channels = 0;
398         i_original = p_aout->output.output.i_original_channels & AOUT_CHAN_PHYSMASK;
399  
400         if( i_original == AOUT_CHAN_CENTER || layout->mNumberChannelDescriptions < 2 )
401         {
402             /* We only need Mono or cannot output more than 1 channel */
403             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
404         }
405         else if( i_original == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) || layout->mNumberChannelDescriptions < 3 )
406         {
407             /* We only need Stereo or cannot output more than 2 channels */
408             p_aout->output.output.i_physical_channels = AOUT_CHAN_RIGHT | AOUT_CHAN_LEFT;
409         }
410         else
411         {
412             /* We want more than stereo and we can do that */
413             for( i = 0; i < layout->mNumberChannelDescriptions; i++ )
414             {
415                 msg_Dbg( p_aout, "this is channel: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
416
417                 switch( layout->mChannelDescriptions[i].mChannelLabel )
418                 {
419                     case kAudioChannelLabel_Left:
420                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_LEFT;
421                         continue;
422                     case kAudioChannelLabel_Right:
423                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_RIGHT;
424                         continue;
425                     case kAudioChannelLabel_Center:
426                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_CENTER;
427                         continue;
428                     case kAudioChannelLabel_LFEScreen:
429                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_LFE;
430                         continue;
431                     case kAudioChannelLabel_LeftSurround:
432                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARLEFT;
433                         continue;
434                     case kAudioChannelLabel_RightSurround:
435                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARRIGHT;
436                         continue;
437                     case kAudioChannelLabel_RearSurroundLeft:
438                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLELEFT;
439                         continue;
440                     case kAudioChannelLabel_RearSurroundRight:
441                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLERIGHT;
442                         continue;
443                     case kAudioChannelLabel_CenterSurround:
444                         p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARCENTER;
445                         continue;
446                     default:
447                         msg_Warn( p_aout, "unrecognized channel form provided by driver: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
448                 }
449             }
450             if( p_aout->output.output.i_physical_channels == 0 )
451             {
452                 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
453                 msg_Err( p_aout, "You should configure your speaker layout with Audio Midi Setup Utility in /Applications/Utilities. Now using Stereo mode." );
454                 dialog_Fatal( p_aout, _("Audio device is not configured"), "%s",
455                                 _("You should configure your speaker layout with "
456                                   "the \"Audio Midi Setup\" utility in /Applications/"
457                                   "Utilities. Stereo mode is being used now.") );
458             }
459         }
460         free( layout );
461     }
462     else
463     {
464         msg_Warn( p_aout, "this driver does not support kAudioDevicePropertyPreferredChannelLayout. BAD DRIVER AUTHOR !!!" );
465         p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
466     }
467
468     msg_Dbg( p_aout, "selected %d physical channels for device output", aout_FormatNbChannels( &p_aout->output.output ) );
469     msg_Dbg( p_aout, "VLC will output: %s", aout_FormatPrintChannels( &p_aout->output.output ));
470
471     memset (&new_layout, 0, sizeof(new_layout));
472     switch( aout_FormatNbChannels( &p_aout->output.output ) )
473     {
474         case 1:
475             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
476             break;
477         case 2:
478             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
479             break;
480         case 3:
481             if( p_aout->output.output.i_physical_channels & AOUT_CHAN_CENTER )
482             {
483                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_7; // L R C
484             }
485             else if( p_aout->output.output.i_physical_channels & AOUT_CHAN_LFE )
486             {
487                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_4; // L R LFE
488             }
489             break;
490         case 4:
491             if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER | AOUT_CHAN_LFE ) )
492             {
493                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_10; // L R C LFE
494             }
495             else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT ) )
496             {
497                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3; // L R Ls Rs
498             }
499             else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER ) )
500             {
501                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3; // L R C Cs
502             }
503             break;
504         case 5:
505             if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER ) )
506             {
507                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_19; // L R Ls Rs C
508             }
509             else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_LFE ) )
510             {
511                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_18; // L R Ls Rs LFE
512             }
513             break;
514         case 6:
515             if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_LFE ) )
516             {
517                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_20; // L R Ls Rs C LFE
518             }
519             else
520             {
521                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_6_0; // L R Ls Rs C Cs
522             }
523             break;
524         case 7:
525             /* FIXME: This is incorrect. VLC uses the internal ordering: L R Lm Rm Lr Rr C LFE but this is wrong */
526             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A; // L R C LFE Ls Rs Cs
527             break;
528         case 8:
529             /* FIXME: This is incorrect. VLC uses the internal ordering: L R Lm Rm Lr Rr C LFE but this is wrong */
530             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A; // L R C LFE Ls Rs Lc Rc
531             break;
532     }
533
534     /* Set up the format to be used */
535     DeviceFormat.mSampleRate = p_aout->output.output.i_rate;
536     DeviceFormat.mFormatID = kAudioFormatLinearPCM;
537
538     /* We use float 32. It's the best supported format by both VLC and Coreaudio */
539     p_aout->output.output.i_format = VLC_CODEC_FL32;
540     DeviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
541     DeviceFormat.mBitsPerChannel = 32;
542     DeviceFormat.mChannelsPerFrame = aout_FormatNbChannels( &p_aout->output.output );
543  
544     /* Calculate framesizes and stuff */
545     DeviceFormat.mFramesPerPacket = 1;
546     DeviceFormat.mBytesPerFrame = DeviceFormat.mBitsPerChannel * DeviceFormat.mChannelsPerFrame / 8;
547     DeviceFormat.mBytesPerPacket = DeviceFormat.mBytesPerFrame * DeviceFormat.mFramesPerPacket;
548
549     /* Set the desired format */
550     i_param_size = sizeof(AudioStreamBasicDescription);
551     verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
552                                    kAudioUnitProperty_StreamFormat,
553                                    kAudioUnitScope_Input,
554                                    0,
555                                    &DeviceFormat,
556                                    i_param_size ));
557  
558     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "we set the AU format: " , DeviceFormat ) );
559  
560     /* Retrieve actual format */
561     verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
562                                    kAudioUnitProperty_StreamFormat,
563                                    kAudioUnitScope_Input,
564                                    0,
565                                    &DeviceFormat,
566                                    &i_param_size ));
567  
568     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "the actual set AU format is " , DeviceFormat ) );
569
570     /* Do the last VLC aout setups */
571     aout_FormatPrepare( &p_aout->output.output );
572     p_aout->output.i_nb_samples = FRAMESIZE;
573     aout_VolumeSoftInit( p_aout );
574
575     /* set the IOproc callback */
576     input.inputProc = (AURenderCallback) RenderCallbackAnalog;
577     input.inputProcRefCon = p_aout;
578  
579     verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
580                             kAudioUnitProperty_SetRenderCallback,
581                             kAudioUnitScope_Input,
582                             0, &input, sizeof( input ) ) );
583
584     input.inputProc = (AURenderCallback) RenderCallbackAnalog;
585     input.inputProcRefCon = p_aout;
586  
587     /* Set the new_layout as the layout VLC will use to feed the AU unit */
588     verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
589                             kAudioUnitProperty_AudioChannelLayout,
590                             kAudioUnitScope_Input,
591                             0, &new_layout, sizeof(new_layout) ) );
592  
593     if( new_layout.mNumberChannelDescriptions > 0 )
594         free( new_layout.mChannelDescriptions );
595  
596     /* AU initiliaze */
597     verify_noerr( AudioUnitInitialize(p_sys->au_unit) );
598
599     /* Find the difference between device clock and mdate clock */
600     p_sys->clock_diff = - (mtime_t)
601         AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
602     p_sys->clock_diff += mdate();
603
604     /* Start the AU */
605     verify_noerr( AudioOutputUnitStart(p_sys->au_unit) );
606  
607     return true;
608 }
609
610 /*****************************************************************************
611  * Setup a encoded digital stream (SPDIF)
612  *****************************************************************************/
613 static int OpenSPDIF( aout_instance_t * p_aout )
614 {
615     struct aout_sys_t       *p_sys = p_aout->output.p_sys;
616     OSStatus                err = noErr;
617     UInt32                  i_param_size = 0, b_mix = 0;
618     Boolean                 b_writeable = false;
619     AudioStreamID           *p_streams = NULL;
620     int                     i = 0, i_streams = 0;
621
622     /* Start doing the SPDIF setup proces */
623     p_sys->b_digital = true;
624
625     /* Hog the device */
626     i_param_size = sizeof( p_sys->i_hog_pid );
627     p_sys->i_hog_pid = getpid() ;
628  
629     err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
630                                   kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
631  
632     if( err != noErr )
633     {
634         msg_Err( p_aout, "failed to set hogmode: [%4.4s]", (char *)&err );
635         return false;
636     }
637
638     /* Set mixable to false if we are allowed to */
639     err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
640                                     &i_param_size, &b_writeable );
641
642     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
643                                     &i_param_size, &b_mix );
644  
645     if( !err && b_writeable )
646     {
647         b_mix = 0;
648         err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
649                             kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
650         p_sys->b_changed_mixing = true;
651     }
652  
653     if( err != noErr )
654     {
655         msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
656         return false;
657     }
658
659     /* Get a list of all the streams on this device */
660     err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE,
661                                       kAudioDevicePropertyStreams,
662                                       &i_param_size, NULL );
663     if( err != noErr )
664     {
665         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
666         return false;
667     }
668  
669     i_streams = i_param_size / sizeof( AudioStreamID );
670     p_streams = (AudioStreamID *)malloc( i_param_size );
671     if( p_streams == NULL )
672         return false;
673  
674     err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
675                                     kAudioDevicePropertyStreams,
676                                     &i_param_size, p_streams );
677  
678     if( err != noErr )
679     {
680         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
681         free( p_streams );
682         return false;
683     }
684
685     for( i = 0; i < i_streams && p_sys->i_stream_index < 0 ; i++ )
686     {
687         /* Find a stream with a cac3 stream */
688         AudioStreamBasicDescription *p_format_list = NULL;
689         int                         i_formats = 0, j = 0;
690         bool                  b_digital = false;
691  
692         /* Retrieve all the stream formats supported by each output stream */
693         err = AudioStreamGetPropertyInfo( p_streams[i], 0,
694                                           kAudioStreamPropertyPhysicalFormats,
695                                           &i_param_size, NULL );
696         if( err != noErr )
697         {
698             msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
699             continue;
700         }
701  
702         i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
703         p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
704         if( p_format_list == NULL )
705             continue;
706  
707         err = AudioStreamGetProperty( p_streams[i], 0,
708                                           kAudioStreamPropertyPhysicalFormats,
709                                           &i_param_size, p_format_list );
710         if( err != noErr )
711         {
712             msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
713             free( p_format_list );
714             continue;
715         }
716
717         /* Check if one of the supported formats is a digital format */
718         for( j = 0; j < i_formats; j++ )
719         {
720             if( p_format_list[j].mFormatID == 'IAC3' ||
721                   p_format_list[j].mFormatID == kAudioFormat60958AC3 )
722             {
723                 b_digital = true;
724                 break;
725             }
726         }
727  
728         if( b_digital )
729         {
730             /* if this stream supports a digital (cac3) format, then go set it. */
731             int i_requested_rate_format = -1;
732             int i_current_rate_format = -1;
733             int i_backup_rate_format = -1;
734
735             p_sys->i_stream_id = p_streams[i];
736             p_sys->i_stream_index = i;
737
738             if( p_sys->b_revert == false )
739             {
740                 /* Retrieve the original format of this stream first if not done so already */
741                 i_param_size = sizeof( p_sys->sfmt_revert );
742                 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
743                                               kAudioStreamPropertyPhysicalFormat,
744                                               &i_param_size,
745                                               &p_sys->sfmt_revert );
746                 if( err != noErr )
747                 {
748                     msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
749                     continue;
750                 }
751                 p_sys->b_revert = true;
752             }
753
754             for( j = 0; j < i_formats; j++ )
755             {
756                 if( p_format_list[j].mFormatID == 'IAC3' ||
757                       p_format_list[j].mFormatID == kAudioFormat60958AC3 )
758                 {
759                     if( p_format_list[j].mSampleRate == p_aout->output.output.i_rate )
760                     {
761                         i_requested_rate_format = j;
762                         break;
763                     }
764                     else if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
765                     {
766                         i_current_rate_format = j;
767                     }
768                     else
769                     {
770                         if( i_backup_rate_format < 0 || p_format_list[j].mSampleRate > p_format_list[i_backup_rate_format].mSampleRate )
771                             i_backup_rate_format = j;
772                     }
773                 }
774  
775             }
776  
777             if( i_requested_rate_format >= 0 ) /* We prefer to output at the samplerate of the original audio */
778                 p_sys->stream_format = p_format_list[i_requested_rate_format];
779             else if( i_current_rate_format >= 0 ) /* If not possible, we will try to use the current samplerate of the device */
780                 p_sys->stream_format = p_format_list[i_current_rate_format];
781             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) */
782         }
783         free( p_format_list );
784     }
785     free( p_streams );
786
787     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "original stream format: ", p_sys->sfmt_revert ) );
788
789     if( !AudioStreamChangeFormat( p_aout, p_sys->i_stream_id, p_sys->stream_format ) )
790         return false;
791
792     /* Set the format flags */
793     if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
794         p_aout->output.output.i_format = VLC_CODEC_SPDIFB;
795     else
796         p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
797     p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
798     p_aout->output.output.i_frame_length = A52_FRAME_NB;
799     p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
800     p_aout->output.output.i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
801     aout_FormatPrepare( &p_aout->output.output );
802     aout_VolumeNoneInit( p_aout );
803
804     /* Add IOProc callback */
805     err = AudioDeviceAddIOProc( p_sys->i_selected_dev,
806                                (AudioDeviceIOProc)RenderCallbackSPDIF,
807                                (void *)p_aout );
808
809     if( err != noErr )
810     {
811         msg_Err( p_aout, "AudioDeviceAddIOProc failed: [%4.4s]", (char *)&err );
812         return false;
813     }
814
815     /* Check for the difference between the Device clock and mdate */
816     p_sys->clock_diff = - (mtime_t)
817         AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
818     p_sys->clock_diff += mdate();
819  
820     /* Start device */
821     err = AudioDeviceStart( p_sys->i_selected_dev, (AudioDeviceIOProc)RenderCallbackSPDIF );
822     if( err != noErr )
823     {
824         msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err );
825
826         err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
827                                      (AudioDeviceIOProc)RenderCallbackSPDIF );
828         if( err != noErr )
829         {
830             msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
831         }
832         return false;
833     }
834
835     return true;
836 }
837
838
839 /*****************************************************************************
840  * Close: Close HAL AudioUnit
841  *****************************************************************************/
842 static void Close( vlc_object_t * p_this )
843 {
844     aout_instance_t     *p_aout = (aout_instance_t *)p_this;
845     struct aout_sys_t   *p_sys = p_aout->output.p_sys;
846     OSStatus            err = noErr;
847     UInt32              i_param_size = 0;
848  
849     if( p_sys->au_unit )
850     {
851         verify_noerr( AudioOutputUnitStop( p_sys->au_unit ) );
852         verify_noerr( AudioUnitUninitialize( p_sys->au_unit ) );
853         verify_noerr( AudioComponentInstanceDispose( p_sys->au_unit ) );
854     }
855  
856     if( p_sys->b_digital )
857     {
858         /* Stop device */
859         err = AudioDeviceStop( p_sys->i_selected_dev,
860                                (AudioDeviceIOProc)RenderCallbackSPDIF );
861         if( err != noErr )
862         {
863             msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
864         }
865
866         /* Remove IOProc callback */
867         err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
868                                       (AudioDeviceIOProc)RenderCallbackSPDIF );
869         if( err != noErr )
870         {
871             msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
872         }
873  
874         if( p_sys->b_revert )
875         {
876             AudioStreamChangeFormat( p_aout, p_sys->i_stream_id, p_sys->sfmt_revert );
877         }
878
879         if( p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3 )
880         {
881             int b_mix;
882             Boolean b_writeable;
883             /* Revert mixable to true if we are allowed to */
884             err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
885                                         &i_param_size, &b_writeable );
886
887             err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
888                                         &i_param_size, &b_mix );
889  
890             if( !err && b_writeable )
891             {
892                 msg_Dbg( p_aout, "mixable is: %d", b_mix );
893                 b_mix = 1;
894                 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
895                                     kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
896             }
897
898             if( err != noErr )
899             {
900                 msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
901             }
902         }
903     }
904
905     err = AudioHardwareRemovePropertyListener( kAudioHardwarePropertyDevices,
906                                                HardwareListener );
907  
908     if( err != noErr )
909     {
910         msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err );
911     }
912  
913     if( p_sys->i_hog_pid == getpid() )
914     {
915         p_sys->i_hog_pid = -1;
916         i_param_size = sizeof( p_sys->i_hog_pid );
917         err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
918                                          kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
919         if( err != noErr ) msg_Err( p_aout, "Could not release hogmode: [%4.4s]", (char *)&err );
920     }
921  
922     free( p_sys );
923 }
924
925 /*****************************************************************************
926  * Play: nothing to do
927  *****************************************************************************/
928 static void Play( aout_instance_t * p_aout )
929 {
930     VLC_UNUSED(p_aout);
931 }
932
933
934 /*****************************************************************************
935  * Probe: Check which devices the OS has, and add them to our audio-device menu
936  *****************************************************************************/
937 static void Probe( aout_instance_t * p_aout )
938 {
939     OSStatus            err = noErr;
940     UInt32              i = 0, i_param_size = 0;
941     AudioDeviceID       devid_def = 0;
942     AudioDeviceID       *p_devices = NULL;
943     vlc_value_t         val, text;
944
945     struct aout_sys_t   *p_sys = p_aout->output.p_sys;
946
947     /* Get number of devices */
948     err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
949                                         &i_param_size, NULL );
950     if( err != noErr )
951     {
952         msg_Err( p_aout, "Could not get number of devices: [%4.4s]", (char *)&err );
953         goto error;
954     }
955
956     p_sys->i_devices = i_param_size / sizeof( AudioDeviceID );
957
958     if( p_sys->i_devices < 1 )
959     {
960         msg_Err( p_aout, "No audio output devices were found." );
961         goto error;
962     }
963
964     msg_Dbg( p_aout, "system has [%u] device(s)", p_sys->i_devices );
965
966     /* Allocate DeviceID array */
967     p_devices = (AudioDeviceID*)malloc( sizeof(AudioDeviceID) * p_sys->i_devices );
968     if( p_devices == NULL )
969         goto error;
970
971     /* Populate DeviceID array */
972     err = AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
973                                     &i_param_size, p_devices );
974     if( err != noErr )
975     {
976         msg_Err( p_aout, "could not get the device IDs: [%4.4s]", (char *)&err );
977         goto error;
978     }
979
980     /* Find the ID of the default Device */
981     i_param_size = sizeof( AudioDeviceID );
982     err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
983                                     &i_param_size, &devid_def );
984     if( err != noErr )
985     {
986         msg_Err( p_aout, "could not get default audio device: [%4.4s]", (char *)&err );
987         goto error;
988     }
989     p_sys->i_default_dev = devid_def;
990  
991     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE );
992     text.psz_string = (char*)_("Audio Device");
993     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
994  
995     for( i = 0; i < p_sys->i_devices; i++ )
996     {
997         char *psz_name;
998         i_param_size = 0;
999
1000         /* Retrieve the length of the device name */
1001         err = AudioDeviceGetPropertyInfo(
1002                     p_devices[i], 0, false,
1003                     kAudioDevicePropertyDeviceName,
1004                     &i_param_size, NULL);
1005         if( err ) goto error;
1006
1007         /* Retrieve the name of the device */
1008         psz_name = (char *)malloc( i_param_size );
1009         err = AudioDeviceGetProperty(
1010                     p_devices[i], 0, false,
1011                     kAudioDevicePropertyDeviceName,
1012                     &i_param_size, psz_name);
1013         if( err ) goto error;
1014
1015         msg_Dbg( p_aout, "DevID: %u DevName: %s", p_devices[i], psz_name );
1016
1017         if( !AudioDeviceHasOutput( p_devices[i]) )
1018         {
1019             msg_Dbg( p_aout, "this device is INPUT only. skipping..." );
1020             free( psz_name );
1021             continue;
1022         }
1023
1024         /* Add the menu entries */
1025         val.i_int = (int)p_devices[i];
1026         text.psz_string = psz_name;
1027         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
1028         text.psz_string = NULL;
1029         if( p_sys->i_default_dev == p_devices[i] )
1030         {
1031             /* The default device is the selected device normally */
1032             var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1033             var_Set( p_aout, "audio-device", val );
1034         }
1035
1036         if( AudioDeviceSupportsDigital( p_aout, p_devices[i] ) )
1037         {
1038             val.i_int = (int)p_devices[i] | AOUT_VAR_SPDIF_FLAG;
1039             if( asprintf( &text.psz_string, _("%s (Encoded Output)"), psz_name ) != -1 )
1040             {
1041                 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
1042                 free( text.psz_string );
1043                 if( p_sys->i_default_dev == p_devices[i]
1044                  && var_InheritBool( p_aout, "spdif" ) )
1045                 {
1046                     /* We selected to prefer SPDIF output if available
1047                      * then this "dummy" entry should be selected */
1048                     var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1049                     var_Set( p_aout, "audio-device", val );
1050                 }
1051             }
1052         }
1053  
1054         free( psz_name);
1055     }
1056  
1057     /* If a device is already "preselected", then use this device */
1058     var_Get( p_aout->p_libvlc, "macosx-audio-device", &val );
1059     if( val.i_int > 0 )
1060     {
1061         var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1062         var_Set( p_aout, "audio-device", val );
1063     }
1064  
1065     /* If we change the device we want to use, we should renegotiate the audio chain */
1066     var_AddCallback( p_aout, "audio-device", AudioDeviceCallback, NULL );
1067
1068     /* Attach a Listener so that we are notified of a change in the Device setup */
1069     err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
1070                                             HardwareListener,
1071                                             (void *)p_aout );
1072     if( err )
1073         goto error;
1074
1075     free( p_devices );
1076     return;
1077
1078 error:
1079     msg_Warn( p_aout, "audio device already in use" );
1080     free( p_devices );
1081     return;
1082 }
1083
1084 /*****************************************************************************
1085  * AudioDeviceHasOutput: Checks if the Device actually provides any outputs at all
1086  *****************************************************************************/
1087 static int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
1088 {
1089     UInt32            dataSize;
1090     Boolean            isWritable;
1091     
1092     verify_noerr( AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE, kAudioDevicePropertyStreams, &dataSize, &isWritable) );
1093     if (dataSize == 0) return FALSE;
1094  
1095     return TRUE;
1096 }
1097
1098 /*****************************************************************************
1099  * AudioDeviceSupportsDigital: Check i_dev_id for digital stream support.
1100  *****************************************************************************/
1101 static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
1102 {
1103     OSStatus                    err = noErr;
1104     UInt32                      i_param_size = 0;
1105     AudioStreamID               *p_streams = NULL;
1106     int                         i = 0, i_streams = 0;
1107     bool                  b_return = false;
1108  
1109     /* Retrieve all the output streams */
1110     err = AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE,
1111                                       kAudioDevicePropertyStreams,
1112                                       &i_param_size, NULL );
1113     if( err != noErr )
1114     {
1115         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
1116         return false;
1117     }
1118  
1119     i_streams = i_param_size / sizeof( AudioStreamID );
1120     p_streams = (AudioStreamID *)malloc( i_param_size );
1121     if( p_streams == NULL )
1122         return VLC_ENOMEM;
1123  
1124     err = AudioDeviceGetProperty( i_dev_id, 0, FALSE,
1125                                     kAudioDevicePropertyStreams,
1126                                     &i_param_size, p_streams );
1127  
1128     if( err != noErr )
1129     {
1130         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
1131         return false;
1132     }
1133
1134     for( i = 0; i < i_streams; i++ )
1135     {
1136         if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) )
1137             b_return = true;
1138     }
1139  
1140     free( p_streams );
1141     return b_return;
1142 }
1143
1144 /*****************************************************************************
1145  * AudioStreamSupportsDigital: Check i_stream_id for digital stream support.
1146  *****************************************************************************/
1147 static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_stream_id )
1148 {
1149     OSStatus                    err = noErr;
1150     UInt32                      i_param_size = 0;
1151     AudioStreamBasicDescription *p_format_list = NULL;
1152     int                         i = 0, i_formats = 0;
1153     bool                  b_return = false;
1154  
1155     /* Retrieve all the stream formats supported by each output stream */
1156     err = AudioStreamGetPropertyInfo( i_stream_id, 0,
1157                                       kAudioStreamPropertyPhysicalFormats,
1158                                       &i_param_size, NULL );
1159     if( err != noErr )
1160     {
1161         msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
1162         return false;
1163     }
1164  
1165     i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
1166     p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
1167     if( p_format_list == NULL )
1168         return false;
1169  
1170     err = AudioStreamGetProperty( i_stream_id, 0,
1171                                       kAudioStreamPropertyPhysicalFormats,
1172                                       &i_param_size, p_format_list );
1173     if( err != noErr )
1174     {
1175         msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
1176         free( p_format_list);
1177         p_format_list = NULL;
1178         return false;
1179     }
1180
1181     for( i = 0; i < i_formats; i++ )
1182     {
1183         msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format: ", p_format_list[i] ) );
1184  
1185         if( p_format_list[i].mFormatID == 'IAC3' ||
1186                   p_format_list[i].mFormatID == kAudioFormat60958AC3 )
1187         {
1188             b_return = true;
1189         }
1190     }
1191  
1192     free( p_format_list );
1193     return b_return;
1194 }
1195
1196 /*****************************************************************************
1197  * AudioStreamChangeFormat: Change i_stream_id to change_format
1198  *****************************************************************************/
1199 static int AudioStreamChangeFormat( aout_instance_t *p_aout, AudioStreamID i_stream_id, AudioStreamBasicDescription change_format )
1200 {
1201     OSStatus            err = noErr;
1202     UInt32              i_param_size = 0;
1203     int i;
1204
1205     struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
1206  
1207     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", change_format ) );
1208
1209     /* Condition because SetProperty is asynchronious */
1210     vlc_cond_init( &w.cond );
1211     vlc_mutex_init( &w.lock );
1212     vlc_mutex_lock( &w.lock );
1213
1214     /* Install the callback */
1215     err = AudioStreamAddPropertyListener( i_stream_id, 0,
1216                                       kAudioStreamPropertyPhysicalFormat,
1217                                       StreamListener, (void *)&w );
1218     if( err != noErr )
1219     {
1220         msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
1221         return false;
1222     }
1223
1224     /* change the format */
1225     err = AudioStreamSetProperty( i_stream_id, 0, 0,
1226                                   kAudioStreamPropertyPhysicalFormat,
1227                                   sizeof( AudioStreamBasicDescription ),
1228                                   &change_format );
1229     if( err != noErr )
1230     {
1231         msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
1232         return false;
1233     }
1234
1235     /* The AudioStreamSetProperty is not only asynchronious (requiring the locks)
1236      * it is also not atomic in its behaviour.
1237      * Therefore we check 5 times before we really give up.
1238      * FIXME: failing isn't actually implemented yet. */
1239     for( i = 0; i < 5; i++ )
1240     {
1241         AudioStreamBasicDescription actual_format;
1242         mtime_t timeout = mdate() + 500000;
1243
1244         if( vlc_cond_timedwait( &w.cond, &w.lock, timeout ) )
1245         {
1246             msg_Dbg( p_aout, "reached timeout" );
1247         }
1248
1249         i_param_size = sizeof( AudioStreamBasicDescription );
1250         err = AudioStreamGetProperty( i_stream_id, 0,
1251                                       kAudioStreamPropertyPhysicalFormat,
1252                                       &i_param_size,
1253                                       &actual_format );
1254
1255         msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", actual_format ) );
1256         if( actual_format.mSampleRate == change_format.mSampleRate &&
1257             actual_format.mFormatID == change_format.mFormatID &&
1258             actual_format.mFramesPerPacket == change_format.mFramesPerPacket )
1259         {
1260             /* The right format is now active */
1261             break;
1262         }
1263         /* We need to check again */
1264     }
1265  
1266     /* Removing the property listener */
1267     err = AudioStreamRemovePropertyListener( i_stream_id, 0,
1268                                             kAudioStreamPropertyPhysicalFormat,
1269                                             StreamListener );
1270     if( err != noErr )
1271     {
1272         msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
1273         return false;
1274     }
1275  
1276     /* Destroy the lock and condition */
1277     vlc_mutex_unlock( &w.lock );
1278     vlc_mutex_destroy( &w.lock );
1279     vlc_cond_destroy( &w.cond );
1280  
1281     return true;
1282 }
1283
1284 /*****************************************************************************
1285  * RenderCallbackAnalog: This function is called everytime the AudioUnit wants
1286  * us to provide some more audio data.
1287  * Don't print anything during normal playback, calling blocking function from
1288  * this callback is not allowed.
1289  *****************************************************************************/
1290 static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
1291                                       AudioUnitRenderActionFlags *ioActionFlags,
1292                                       const AudioTimeStamp *inTimeStamp,
1293                                       unsigned int inBusNumber,
1294                                       unsigned int inNumberFrames,
1295                                       AudioBufferList *ioData )
1296 {
1297     AudioTimeStamp  host_time;
1298     mtime_t         current_date = 0;
1299     uint32_t        i_mData_bytes = 0;
1300
1301     aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
1302     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1303
1304     VLC_UNUSED(ioActionFlags);
1305     VLC_UNUSED(inBusNumber);
1306     VLC_UNUSED(inNumberFrames);
1307
1308     host_time.mFlags = kAudioTimeStampHostTimeValid;
1309     AudioDeviceTranslateTime( p_sys->i_selected_dev, inTimeStamp, &host_time );
1310
1311     /* Check for the difference between the Device clock and mdate */
1312     p_sys->clock_diff = - (mtime_t)
1313         AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
1314     p_sys->clock_diff += mdate();
1315
1316     current_date = p_sys->clock_diff +
1317                    AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
1318                    //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
1319
1320     if( ioData == NULL && ioData->mNumberBuffers < 1 )
1321     {
1322         msg_Err( p_aout, "no iodata or buffers");
1323         return 0;
1324     }
1325     if( ioData->mNumberBuffers > 1 )
1326         msg_Err( p_aout, "well this is weird. seems like there is more than one buffer..." );
1327
1328
1329     if( p_sys->i_total_bytes > 0 )
1330     {
1331         i_mData_bytes = __MIN( p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize );
1332         vlc_memcpy( ioData->mBuffers[0].mData,
1333                     &p_sys->p_remainder_buffer[p_sys->i_read_bytes],
1334                     i_mData_bytes );
1335         p_sys->i_read_bytes += i_mData_bytes;
1336         current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
1337                         ( i_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output )  ); // 4 is fl32 specific
1338  
1339         if( p_sys->i_read_bytes >= p_sys->i_total_bytes )
1340             p_sys->i_read_bytes = p_sys->i_total_bytes = 0;
1341     }
1342  
1343     while( i_mData_bytes < ioData->mBuffers[0].mDataByteSize )
1344     {
1345         /* We don't have enough data yet */
1346         aout_buffer_t * p_buffer;
1347         p_buffer = aout_OutputNextBuffer( p_aout, current_date , false );
1348
1349         if( p_buffer != NULL )
1350         {
1351             uint32_t i_second_mData_bytes = __MIN( p_buffer->i_buffer, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
1352  
1353             vlc_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes,
1354                         p_buffer->p_buffer, i_second_mData_bytes );
1355             i_mData_bytes += i_second_mData_bytes;
1356
1357             if( i_mData_bytes >= ioData->mBuffers[0].mDataByteSize )
1358             {
1359                 p_sys->i_total_bytes = p_buffer->i_buffer - i_second_mData_bytes;
1360                 vlc_memcpy( p_sys->p_remainder_buffer,
1361                             &p_buffer->p_buffer[i_second_mData_bytes],
1362                             p_sys->i_total_bytes );
1363                 aout_BufferFree( p_buffer );
1364                 break;
1365             }
1366             else
1367             {
1368                 /* update current_date */
1369                 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
1370                                 ( i_second_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output )  ); // 4 is fl32 specific
1371             }
1372             aout_BufferFree( p_buffer );
1373         }
1374         else
1375         {
1376              vlc_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes,
1377                          0,ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
1378              i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes;
1379         }
1380     }
1381     return( noErr );
1382 }
1383
1384 /*****************************************************************************
1385  * RenderCallbackSPDIF: callback for SPDIF audio output
1386  *****************************************************************************/
1387 static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
1388                                     const AudioTimeStamp * inNow,
1389                                     const void * inInputData,
1390                                     const AudioTimeStamp * inInputTime,
1391                                     AudioBufferList * outOutputData,
1392                                     const AudioTimeStamp * inOutputTime,
1393                                     void * threadGlobals )
1394 {
1395     aout_buffer_t * p_buffer;
1396     mtime_t         current_date;
1397
1398     aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
1399     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1400
1401     VLC_UNUSED(inDevice);
1402     VLC_UNUSED(inInputData);
1403     VLC_UNUSED(inInputTime);
1404
1405     /* Check for the difference between the Device clock and mdate */
1406     p_sys->clock_diff = - (mtime_t)
1407         AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
1408     p_sys->clock_diff += mdate();
1409
1410     current_date = p_sys->clock_diff +
1411                    AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000;
1412                    //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
1413
1414     p_buffer = aout_OutputNextBuffer( p_aout, current_date, true );
1415
1416 #define BUFFER outOutputData->mBuffers[p_sys->i_stream_index]
1417     if( p_buffer != NULL )
1418     {
1419         if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_buffer)
1420             msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_buffer );
1421  
1422         /* move data into output data buffer */
1423         vlc_memcpy( BUFFER.mData, p_buffer->p_buffer, p_buffer->i_buffer );
1424         aout_BufferFree( p_buffer );
1425     }
1426     else
1427     {
1428         vlc_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
1429     }
1430 #undef BUFFER
1431
1432     return( noErr );
1433 }
1434
1435 /*****************************************************************************
1436  * HardwareListener: Warns us of changes in the list of registered devices
1437  *****************************************************************************/
1438 static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
1439                                   void * inClientData )
1440 {
1441     OSStatus err = noErr;
1442     aout_instance_t     *p_aout = (aout_instance_t *)inClientData;
1443
1444     switch( inPropertyID )
1445     {
1446         case kAudioHardwarePropertyDevices:
1447         {
1448             /* something changed in the list of devices */
1449             /* We trigger the audio-device's aout_ChannelsRestart callback */
1450             var_TriggerCallback( p_aout, "audio-device" );
1451             var_Destroy( p_aout, "audio-device" );
1452         }
1453         break;
1454     }
1455
1456     return( err );
1457 }
1458
1459 /*****************************************************************************
1460  * StreamListener
1461  *****************************************************************************/
1462 static OSStatus StreamListener( AudioStreamID inStream,
1463                                 UInt32 inChannel,
1464                                 AudioDevicePropertyID inPropertyID,
1465                                 void * inClientData )
1466 {
1467     OSStatus err = noErr;
1468     struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
1469
1470     VLC_UNUSED(inStream);
1471     VLC_UNUSED(inChannel);
1472  
1473     switch( inPropertyID )
1474     {
1475         case kAudioStreamPropertyPhysicalFormat:
1476             vlc_mutex_lock( &w->lock );
1477             vlc_cond_signal( &w->cond );
1478             vlc_mutex_unlock( &w->lock );
1479             break;
1480
1481         default:
1482             break;
1483     }
1484     return( err );
1485 }
1486
1487 /*****************************************************************************
1488  * AudioDeviceCallback: Callback triggered when the audio-device variable is changed
1489  *****************************************************************************/
1490 static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable,
1491                      vlc_value_t old_val, vlc_value_t new_val, void *param )
1492 {
1493     aout_instance_t *p_aout = (aout_instance_t *)p_this;
1494     var_Set( p_aout->p_libvlc, "macosx-audio-device", new_val );
1495     msg_Dbg( p_aout, "Set Device: %#"PRIx64, new_val.i_int );
1496     return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );
1497 }
1498