]> git.sesse.net Git - vlc/blob - modules/audio_output/auhal.c
Add pause callback for audio output (aout_output_t.pf_pause)
[vlc] / modules / audio_output / auhal.c
1 /*****************************************************************************
2  * auhal.c: AUHAL and Coreaudio output plugin
3  *****************************************************************************
4  * Copyright (C) 2005, 2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          Felix Paul Kühne <fkuehne at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <unistd.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_dialog.h>
37 #include <vlc_aout.h>
38
39 #include <CoreAudio/CoreAudio.h>
40 #include <AudioUnit/AudioUnit.h>
41 #include <AudioToolbox/AudioFormat.h>
42
43 #include <CoreServices/CoreServices.h>
44
45 #ifndef verify_noerr
46 #define verify_noerr(a) assert((a) == noErr)
47 #endif
48
49 #define STREAM_FORMAT_MSG( pre, sfm ) \
50     pre "[%u][%4.4s][%u][%u][%u][%u][%u][%u]", \
51     (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
52     sfm.mFormatFlags, sfm.mBytesPerPacket, \
53     sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
54     sfm.mChannelsPerFrame, sfm.mBitsPerChannel
55
56 #define STREAM_FORMAT_MSG_FULL( pre, sfm ) \
57     pre ":\nsamplerate: [%u]\nFormatID: [%4.4s]\nFormatFlags: [%u]\nBypesPerPacket: [%u]\nFramesPerPacket: [%u]\nBytesPerFrame: [%u]\nChannelsPerFrame: [%u]\nBitsPerChannel[%u]", \
58     (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
59     sfm.mFormatFlags, sfm.mBytesPerPacket, \
60     sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
61     sfm.mChannelsPerFrame, sfm.mBitsPerChannel
62
63 #define FRAMESIZE 2048
64 #define BUFSIZE (FRAMESIZE * 8) * 8
65 #define AOUT_VAR_SPDIF_FLAG 0xf00000
66
67 /*
68  * TODO:
69  * - clean up the debug info
70  * - be better at changing stream setup or devices setup changes while playing.
71  * - fix 6.1 and 7.1
72  */
73
74 /*****************************************************************************
75  * aout_sys_t: private audio output method descriptor
76  *****************************************************************************
77  * This structure is part of the audio output thread descriptor.
78  * It describes the CoreAudio specific properties of an output thread.
79  *****************************************************************************/
80 struct aout_sys_t
81 {
82     AudioDeviceID               i_default_dev;  /* Keeps DeviceID of defaultOutputDevice */
83     AudioDeviceID               i_selected_dev; /* Keeps DeviceID of the selected device */
84     AudioDeviceIOProcID         i_procID;       /* DeviceID of current device */
85     UInt32                      i_devices;      /* Number of CoreAudio Devices */
86     bool                        b_supports_digital;/* Does the currently selected device support digital mode? */
87     bool                        b_digital;      /* Are we running in digital mode? */
88     mtime_t                     clock_diff;     /* Difference between VLC clock and Device clock */
89
90     /* AUHAL specific */
91     Component                   au_component;   /* The Audiocomponent we use */
92     AudioUnit                   au_unit;        /* The AudioUnit we use */
93     uint8_t                     p_remainder_buffer[BUFSIZE];
94     uint32_t                    i_read_bytes;
95     uint32_t                    i_total_bytes;
96
97     /* CoreAudio SPDIF mode specific */
98     pid_t                       i_hog_pid;      /* The keep the pid of our hog status */
99     AudioStreamID               i_stream_id;    /* The StreamID that has a cac3 streamformat */
100     int                         i_stream_index; /* The index of i_stream_id in an AudioBufferList */
101     AudioStreamBasicDescription stream_format;  /* The format we changed the stream to */
102     AudioStreamBasicDescription sfmt_revert;    /* The original format of the stream */
103     bool                        b_revert;       /* Wether we need to revert the stream format */
104     bool                        b_changed_mixing;/* Wether we need to set the mixing mode back */
105 };
106
107 /*****************************************************************************
108  * Local prototypes.
109  *****************************************************************************/
110 static int      Open                    ( vlc_object_t * );
111 static int      OpenAnalog              ( aout_instance_t * );
112 static int      OpenSPDIF               ( aout_instance_t * );
113 static void     Close                   ( vlc_object_t * );
114
115 static void     Play                    ( aout_instance_t * );
116 static void     Probe                   ( aout_instance_t * );
117
118 static int      AudioDeviceHasOutput    ( AudioDeviceID );
119 static int      AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );
120 static int      AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );
121 static int      AudioStreamChangeFormat ( aout_instance_t *, AudioStreamID, AudioStreamBasicDescription );
122
123 static OSStatus RenderCallbackAnalog    ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
124                                           unsigned int, unsigned int, AudioBufferList *);
125 static OSStatus RenderCallbackSPDIF     ( AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
126                                           AudioBufferList *, const AudioTimeStamp *, void * );
127 static OSStatus HardwareListener        ( AudioObjectID, UInt32, const AudioObjectPropertyAddress *, void * );
128 static OSStatus StreamListener          ( AudioObjectID, UInt32, const AudioObjectPropertyAddress *, void * );
129 static int      AudioDeviceCallback     ( vlc_object_t *, const char *,
130                                           vlc_value_t, vlc_value_t, void * );
131
132
133
134 /*****************************************************************************
135  * Module descriptor
136  *****************************************************************************/
137 #define ADEV_TEXT N_("Audio Device")
138 #define ADEV_LONGTEXT N_("Choose a number corresponding to the number of an " \
139     "audio device, as listed in your 'Audio Device' menu. This device will " \
140     "then be used by default for audio playback.")
141
142 vlc_module_begin ()
143     set_shortname( "auhal" )
144     set_description( N_("HAL AudioUnit output") )
145     set_capability( "audio output", 101 )
146     set_category( CAT_AUDIO )
147     set_subcategory( SUBCAT_AUDIO_AOUT )
148     set_callbacks( Open, Close )
149     add_integer( "macosx-audio-device", 0, ADEV_TEXT, ADEV_LONGTEXT, false )
150 vlc_module_end ()
151
152 /*****************************************************************************
153  * Open: open macosx audio output
154  *****************************************************************************/
155 static int Open( vlc_object_t * p_this )
156 {
157     OSStatus                err = noErr;
158     UInt32                  i_param_size = 0;
159     struct aout_sys_t       *p_sys = NULL;
160     vlc_value_t             val;
161     aout_instance_t         *p_aout = (aout_instance_t *)p_this;
162
163     /* Use int here, to match kAudioDevicePropertyDeviceIsAlive
164      * property size */
165     int                     b_alive = false;
166
167     /* Allocate structure */
168     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
169     if( p_aout->output.p_sys == NULL )
170         return VLC_ENOMEM;
171
172     p_sys = p_aout->output.p_sys;
173     p_sys->i_default_dev = 0;
174     p_sys->i_selected_dev = 0;
175     p_sys->i_devices = 0;
176     p_sys->b_supports_digital = false;
177     p_sys->b_digital = false;
178     p_sys->au_component = NULL;
179     p_sys->au_unit = NULL;
180     p_sys->clock_diff = (mtime_t) 0;
181     p_sys->i_read_bytes = 0;
182     p_sys->i_total_bytes = 0;
183     p_sys->i_hog_pid = -1;
184     p_sys->i_stream_id = 0;
185     p_sys->i_stream_index = -1;
186     p_sys->b_revert = false;
187     p_sys->b_changed_mixing = false;
188     memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
189
190     p_aout->output.pf_play = Play;
191     p_aout->output.pf_pause = NULL;
192
193     aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output );
194
195     /* Persistent device variable */
196     if( var_Type( p_aout->p_libvlc, "macosx-audio-device" ) == 0 )
197     {
198         var_Create( p_aout->p_libvlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
199     }
200
201     /* Build a list of devices */
202     if( var_Type( p_aout, "audio-device" ) == 0 )
203     {
204         Probe( p_aout );
205     }
206
207     /* What device do we want? */
208     if( var_Get( p_aout, "audio-device", &val ) < 0 )
209     {
210         msg_Err( p_aout, "audio-device var does not exist. device probe failed." );
211         goto error;
212     }
213
214     p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG; /* remove SPDIF flag to get the true DeviceID */
215     p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? true : false;
216     if( p_sys->b_supports_digital )
217         msg_Dbg( p_aout, "audio-device supports digital output" );
218     else
219         msg_Dbg( p_aout, "audio-device does not support digital output" );
220
221     /* Check if the desired device is alive and usable */
222     /* TODO: add a callback to the device to alert us if the device dies */
223     i_param_size = sizeof( b_alive );
224     AudioObjectPropertyAddress audioDeviceAliveAddress = { kAudioDevicePropertyDeviceIsAlive,
225                                               kAudioDevicePropertyScopeOutput,
226                                               kAudioObjectPropertyElementMaster };
227     err = AudioObjectGetPropertyData( p_sys->i_selected_dev, &audioDeviceAliveAddress, 0, NULL, &i_param_size, &b_alive );
228
229     if( err != noErr )
230     {
231         /* Be tolerant, only give a warning here */
232         msg_Warn( p_aout, "could not check whether device [0x%x] is alive: %4.4s", (unsigned int)p_sys->i_selected_dev, (char *)&err );
233         b_alive = false;
234     }
235
236     if( !b_alive )
237     {
238         msg_Warn( p_aout, "selected audio device is not alive, switching to default device" );
239         p_sys->i_selected_dev = p_sys->i_default_dev;
240     }
241     else
242         msg_Dbg( p_aout, "selected audio device is alive" );
243
244     AudioObjectPropertyAddress audioDeviceHogModeAddress = { kAudioDevicePropertyHogMode,
245                                   kAudioDevicePropertyScopeOutput,
246                                   kAudioObjectPropertyElementMaster };
247     i_param_size = sizeof( p_sys->i_hog_pid );
248     err = AudioObjectGetPropertyData( p_sys->i_selected_dev, &audioDeviceHogModeAddress, 0, NULL, &i_param_size, &p_sys->i_hog_pid );
249     if( err != noErr )
250     {
251         /* This is not a fatal error. Some drivers simply don't support this property */
252         msg_Warn( p_aout, "could not check whether device is hogged: %4.4s",
253                  (char *)&err );
254         p_sys->i_hog_pid = -1;
255     }
256
257     if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() )
258     {
259         msg_Err( p_aout, "Selected audio device is exclusively in use by another program." );
260         dialog_Fatal( p_aout, _("Audio output failed"), "%s",
261                         _("The selected audio output device is exclusively in "
262                           "use by another program.") );
263         goto error;
264     }
265     else
266         msg_Dbg( p_aout, "device is free for us to use" );
267
268     /* Check for Digital mode or Analog output mode */
269     if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && p_sys->b_supports_digital )
270     {
271         if( OpenSPDIF( p_aout ) )
272         {
273             msg_Dbg( p_aout, "digital output successfully opened" );
274             return VLC_SUCCESS;
275         }
276     }
277     else
278     {
279         if( OpenAnalog( p_aout ) )
280         {
281             msg_Dbg( p_aout, "analog output successfully opened" );
282             return VLC_SUCCESS;
283         }
284     }
285
286 error:
287     /* If we reach this, this aout has failed */
288     msg_Err( p_aout, "opening the auhal output 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     ComponentDescription        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 = FindNextComponent( 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 = OpenAComponent( 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     AudioObjectPropertyAddress audioDeviceHogModeAddress = { kAudioDevicePropertyHogMode, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
627     i_param_size = sizeof( p_sys->i_hog_pid );
628     p_sys->i_hog_pid = getpid() ;
629
630     err = AudioObjectSetPropertyData( p_sys->i_selected_dev, &audioDeviceHogModeAddress, 0, NULL, 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     AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = { kAudioDevicePropertySupportsMixing , kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
640     b_writeable = AudioObjectHasProperty( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress );
641     err = AudioObjectGetPropertyDataSize( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, &i_param_size );
642     err = AudioObjectGetPropertyData( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, &i_param_size, &b_mix );
643
644     if( !err && b_writeable )
645     {
646         b_mix = 0;
647         err = AudioObjectSetPropertyData( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, i_param_size, &b_mix );
648         p_sys->b_changed_mixing = true;
649     }
650
651     if( err != noErr )
652     {
653         msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
654         return false;
655     }
656
657     /* Get a list of all the streams on this device */
658     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
659     err = AudioObjectGetPropertyDataSize( p_sys->i_selected_dev, &streamsAddress, 0, NULL, &i_param_size );
660     if( err != noErr )
661     {
662         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
663         return false;
664     }
665
666     i_streams = i_param_size / sizeof( AudioStreamID );
667     p_streams = (AudioStreamID *)malloc( i_param_size );
668     if( p_streams == NULL )
669         return false;
670
671     err = AudioObjectGetPropertyData( p_sys->i_selected_dev, &streamsAddress, 0, NULL, &i_param_size, p_streams );
672
673     if( err != noErr )
674     {
675         msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
676         free( p_streams );
677         return false;
678     }
679
680     AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyPhysicalFormats, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
681     for( i = 0; i < i_streams && p_sys->i_stream_index < 0 ; i++ )
682     {
683         /* Find a stream with a cac3 stream */
684         AudioStreamBasicDescription *p_format_list = NULL;
685         int                         i_formats = 0, j = 0;
686         bool                  b_digital = false;
687
688         /* Retrieve all the stream formats supported by each output stream */
689         err = AudioObjectGetPropertyDataSize( p_streams[i], &physicalFormatsAddress, 0, NULL, &i_param_size );
690         if( err != noErr )
691         {
692             msg_Err( p_aout, "OpenSPDIF: could not get number of streamformats: [%s] (%i)", (char *)&err, err );
693             continue;
694         }
695
696         i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
697         p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
698         if( p_format_list == NULL )
699             continue;
700
701         err = AudioObjectGetPropertyData( p_streams[i], &physicalFormatsAddress, 0, NULL, &i_param_size, p_format_list );
702         if( err != noErr )
703         {
704             msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
705             free( p_format_list );
706             continue;
707         }
708
709         /* Check if one of the supported formats is a digital format */
710         for( j = 0; j < i_formats; j++ )
711         {
712             if( p_format_list[j].mFormatID == 'IAC3' ||
713                   p_format_list[j].mFormatID == kAudioFormat60958AC3 )
714             {
715                 b_digital = true;
716                 break;
717             }
718         }
719
720         if( b_digital )
721         {
722             /* if this stream supports a digital (cac3) format, then go set it. */
723             int i_requested_rate_format = -1;
724             int i_current_rate_format = -1;
725             int i_backup_rate_format = -1;
726
727             p_sys->i_stream_id = p_streams[i];
728             p_sys->i_stream_index = i;
729
730             if( !p_sys->b_revert )
731             {
732                 /* Retrieve the original format of this stream first if not done so already */
733                 i_param_size = sizeof( p_sys->sfmt_revert );
734                 err = AudioObjectGetPropertyData( p_sys->i_stream_id, &physicalFormatsAddress, 0, NULL, &i_param_size, &p_sys->sfmt_revert );
735                 if( err != noErr )
736                 {
737                     msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
738                     continue;
739                 }
740                 p_sys->b_revert = true;
741             }
742
743             for( j = 0; j < i_formats; j++ )
744             {
745                 if( p_format_list[j].mFormatID == 'IAC3' ||
746                       p_format_list[j].mFormatID == kAudioFormat60958AC3 )
747                 {
748                     if( p_format_list[j].mSampleRate == p_aout->output.output.i_rate )
749                     {
750                         i_requested_rate_format = j;
751                         break;
752                     }
753                     else if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
754                     {
755                         i_current_rate_format = j;
756                     }
757                     else
758                     {
759                         if( i_backup_rate_format < 0 || p_format_list[j].mSampleRate > p_format_list[i_backup_rate_format].mSampleRate )
760                             i_backup_rate_format = j;
761                     }
762                 }
763
764             }
765
766             if( i_requested_rate_format >= 0 ) /* We prefer to output at the samplerate of the original audio */
767                 p_sys->stream_format = p_format_list[i_requested_rate_format];
768             else if( i_current_rate_format >= 0 ) /* If not possible, we will try to use the current samplerate of the device */
769                 p_sys->stream_format = p_format_list[i_current_rate_format];
770             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) */
771         }
772         free( p_format_list );
773     }
774     free( p_streams );
775
776     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "original stream format: ", p_sys->sfmt_revert ) );
777
778     if( !AudioStreamChangeFormat( p_aout, p_sys->i_stream_id, p_sys->stream_format ) )
779         return false;
780
781     /* Set the format flags */
782     if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
783         p_aout->output.output.i_format = VLC_CODEC_SPDIFB;
784     else
785         p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
786     p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
787     p_aout->output.output.i_frame_length = A52_FRAME_NB;
788     p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
789     p_aout->output.output.i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
790     aout_FormatPrepare( &p_aout->output.output );
791     aout_VolumeNoneInit( p_aout );
792
793     /* Add IOProc callback */
794     err = AudioDeviceCreateIOProcID( p_sys->i_selected_dev,
795                                    (AudioDeviceIOProc)RenderCallbackSPDIF,
796                                    (void *)p_aout,
797                                    &p_sys->i_procID );
798     if( err != noErr )
799     {
800         msg_Err( p_aout, "AudioDeviceCreateIOProcID failed: [%4.4s]", (char *)&err );
801         return false;
802     }
803
804     /* Check for the difference between the Device clock and mdate */
805     p_sys->clock_diff = - (mtime_t)
806         AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
807     p_sys->clock_diff += mdate();
808
809     /* Start device */
810     err = AudioDeviceStart( p_sys->i_selected_dev, p_sys->i_procID );
811     if( err != noErr )
812     {
813         msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err );
814
815         err = AudioDeviceDestroyIOProcID( p_sys->i_selected_dev,
816                                           p_sys->i_procID );
817         if( err != noErr )
818         {
819             msg_Err( p_aout, "AudioDeviceDestroyIOProcID failed: [%4.4s]", (char *)&err );
820         }
821         return false;
822     }
823
824     return true;
825 }
826
827
828 /*****************************************************************************
829  * Close: Close HAL AudioUnit
830  *****************************************************************************/
831 static void Close( vlc_object_t * p_this )
832 {
833     aout_instance_t     *p_aout = (aout_instance_t *)p_this;
834     struct aout_sys_t   *p_sys = p_aout->output.p_sys;
835     OSStatus            err = noErr;
836     UInt32              i_param_size = 0;
837
838     if( p_sys->au_unit )
839     {
840         verify_noerr( AudioOutputUnitStop( p_sys->au_unit ) );
841         verify_noerr( AudioUnitUninitialize( p_sys->au_unit ) );
842         verify_noerr( CloseComponent( p_sys->au_unit ) );
843     }
844
845     if( p_sys->b_digital )
846     {
847         /* Stop device */
848         err = AudioDeviceStop( p_sys->i_selected_dev,
849                                p_sys->i_procID );
850         if( err != noErr )
851         {
852             msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
853         }
854
855         /* Remove IOProc callback */
856         err = AudioDeviceDestroyIOProcID( p_sys->i_selected_dev,
857                                           p_sys->i_procID );
858         if( err != noErr )
859         {
860             msg_Err( p_aout, "AudioDeviceDestroyIOProcID failed: [%4.4s]", (char *)&err );
861         }
862
863         if( p_sys->b_revert )
864         {
865             AudioStreamChangeFormat( p_aout, p_sys->i_stream_id, p_sys->sfmt_revert );
866         }
867
868         if( p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3 )
869         {
870             int b_mix;
871             Boolean b_writeable;
872             /* Revert mixable to true if we are allowed to */
873             AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = { kAudioDevicePropertySupportsMixing , kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
874             b_writeable = AudioObjectHasProperty( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress );
875             err = AudioObjectGetPropertyData( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, &i_param_size, &b_mix );
876
877             if( !err && b_writeable )
878             {
879                 msg_Dbg( p_aout, "mixable is: %d", b_mix );
880                 b_mix = 1;
881                 err = AudioObjectSetPropertyData( p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, i_param_size, &b_mix );
882             }
883
884             if( err != noErr )
885             {
886                 msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
887             }
888         }
889     }
890
891     AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDevices, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
892     err = AudioObjectRemovePropertyListener( kAudioObjectSystemObject, &audioDevicesAddress, HardwareListener, NULL );
893
894     if( err != noErr )
895     {
896         msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err );
897     }
898
899     if( p_sys->i_hog_pid == getpid() )
900     {
901         p_sys->i_hog_pid = -1;
902         i_param_size = sizeof( p_sys->i_hog_pid );
903         AudioObjectPropertyAddress audioDeviceHogModeAddress = { kAudioDevicePropertyHogMode,
904             kAudioDevicePropertyScopeOutput,
905             kAudioObjectPropertyElementMaster };
906         err = AudioObjectSetPropertyData( p_sys->i_selected_dev, &audioDeviceHogModeAddress, 0, NULL, i_param_size, &p_sys->i_hog_pid );
907         if( err != noErr ) msg_Err( p_aout, "Could not release hogmode: [%4.4s]", (char *)&err );
908     }
909
910     free( p_sys );
911 }
912
913 /*****************************************************************************
914  * Play: nothing to do
915  *****************************************************************************/
916 static void Play( aout_instance_t * p_aout )
917 {
918     VLC_UNUSED(p_aout);
919 }
920
921
922 /*****************************************************************************
923  * Probe: Check which devices the OS has, and add them to our audio-device menu
924  *****************************************************************************/
925 static void Probe( aout_instance_t * p_aout )
926 {
927     OSStatus            err = noErr;
928     UInt32              i = 0, i_param_size = 0;
929     AudioDeviceID       devid_def = 0;
930     AudioDeviceID       *p_devices = NULL;
931     vlc_value_t         val, text;
932
933     struct aout_sys_t   *p_sys = p_aout->output.p_sys;
934
935     /* Get number of devices */
936     AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDevices, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
937     err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &audioDevicesAddress, 0, NULL, &i_param_size);
938     if( err != noErr )
939     {
940         msg_Err( p_aout, "Could not get number of devices: [%s]", (char *)&err );
941         goto error;
942     }
943
944     p_sys->i_devices = i_param_size / sizeof( AudioDeviceID );
945
946     if( p_sys->i_devices < 1 )
947     {
948         msg_Err( p_aout, "No audio output devices were found." );
949         goto error;
950     }
951
952     msg_Dbg( p_aout, "system has [%u] device(s)", p_sys->i_devices );
953
954     /* Allocate DeviceID array */
955     p_devices = (AudioDeviceID*)malloc( sizeof(AudioDeviceID) * p_sys->i_devices );
956     if( p_devices == NULL )
957         goto error;
958
959     /* Populate DeviceID array */
960     err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &audioDevicesAddress, 0, NULL, &i_param_size, p_devices );
961     if( err != noErr )
962     {
963         msg_Err( p_aout, "could not get the device IDs: [%s]", (char *)&err );
964         goto error;
965     }
966
967     /* Find the ID of the default Device */
968     AudioObjectPropertyAddress defaultDeviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
969     i_param_size = sizeof( AudioDeviceID );
970     err= AudioObjectGetPropertyData( kAudioObjectSystemObject, &defaultDeviceAddress, 0, NULL, &i_param_size, &devid_def );
971     if( err != noErr )
972     {
973         msg_Err( p_aout, "could not get default audio device: [%s]", (char *)&err );
974         goto error;
975     }
976     p_sys->i_default_dev = devid_def;
977
978     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE );
979     text.psz_string = (char*)_("Audio Device");
980     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
981
982     AudioObjectPropertyAddress deviceNameAddress = { kAudioDevicePropertyDeviceName, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
983
984     for( i = 0; i < p_sys->i_devices; i++ )
985     {
986         char *psz_name;
987         i_param_size = 0;
988
989         /* Retrieve the length of the device name */
990         err = AudioObjectGetPropertyDataSize( p_devices[i], &deviceNameAddress, 0, NULL, &i_param_size );
991         if( err ) goto error;
992
993         /* Retrieve the name of the device */
994         psz_name = (char *)malloc( i_param_size );
995         err = AudioObjectGetPropertyData( p_devices[i], &deviceNameAddress, 0, NULL, &i_param_size, psz_name );
996         if( err ) goto error;
997
998         msg_Dbg( p_aout, "DevID: %u DevName: %s", p_devices[i], psz_name );
999
1000         if( !AudioDeviceHasOutput( p_devices[i]) )
1001         {
1002             msg_Dbg( p_aout, "this device is INPUT only. skipping..." );
1003             free( psz_name );
1004             continue;
1005         }
1006
1007         /* Add the menu entries */
1008         val.i_int = (int)p_devices[i];
1009         text.psz_string = psz_name;
1010         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
1011         text.psz_string = NULL;
1012         if( p_sys->i_default_dev == p_devices[i] )
1013         {
1014             /* The default device is the selected device normally */
1015             var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1016             var_Set( p_aout, "audio-device", val );
1017         }
1018
1019         if( AudioDeviceSupportsDigital( p_aout, p_devices[i] ) )
1020         {
1021             val.i_int = (int)p_devices[i] | AOUT_VAR_SPDIF_FLAG;
1022             if( asprintf( &text.psz_string, _("%s (Encoded Output)"), psz_name ) != -1 )
1023             {
1024                 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
1025                 free( text.psz_string );
1026                 if( p_sys->i_default_dev == p_devices[i]
1027                  && var_InheritBool( p_aout, "spdif" ) )
1028                 {
1029                     /* We selected to prefer SPDIF output if available
1030                      * then this "dummy" entry should be selected */
1031                     var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1032                     var_Set( p_aout, "audio-device", val );
1033                 }
1034             }
1035         }
1036
1037         free( psz_name);
1038     }
1039
1040     /* If a device is already "preselected", then use this device */
1041     var_Get( p_aout->p_libvlc, "macosx-audio-device", &val );
1042     if( val.i_int > 0 )
1043     {
1044         var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1045         var_Set( p_aout, "audio-device", val );
1046     }
1047
1048     /* If we change the device we want to use, we should renegotiate the audio chain */
1049     var_AddCallback( p_aout, "audio-device", AudioDeviceCallback, NULL );
1050
1051     /* Attach a Listener so that we are notified of a change in the Device setup */
1052     err = AudioObjectAddPropertyListener( kAudioObjectSystemObject, &audioDevicesAddress, HardwareListener, (void *)p_aout );
1053     if( err )
1054         goto error;
1055
1056     free( p_devices );
1057     return;
1058
1059 error:
1060     msg_Warn( p_aout, "audio device already in use" );
1061     free( p_devices );
1062     return;
1063 }
1064
1065 /*****************************************************************************
1066  * AudioDeviceHasOutput: Checks if the Device actually provides any outputs at all
1067  *****************************************************************************/
1068 static int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
1069 {
1070     UInt32            dataSize;
1071
1072     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
1073     verify_noerr( AudioObjectGetPropertyDataSize( i_dev_id, &streamsAddress, 0, NULL, &dataSize ) );
1074     if (dataSize == 0) return FALSE;
1075
1076     return TRUE;
1077 }
1078
1079 /*****************************************************************************
1080  * AudioDeviceSupportsDigital: Check i_dev_id for digital stream support.
1081  *****************************************************************************/
1082 static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
1083 {
1084     OSStatus                    err = noErr;
1085     UInt32                      i_param_size = 0;
1086     AudioStreamID               *p_streams = NULL;
1087     int                         i = 0, i_streams = 0;
1088     bool                  b_return = false;
1089
1090     /* Retrieve all the output streams */
1091     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1092     err = AudioObjectGetPropertyDataSize( i_dev_id, &streamsAddress, 0, NULL, &i_param_size );
1093
1094     if( err != noErr )
1095     {
1096         msg_Err( p_aout, "could not get number of streams: [%s] (%i)", (char *)&err, err );
1097         return false;
1098     }
1099
1100     i_streams = i_param_size / sizeof( AudioStreamID );
1101     p_streams = (AudioStreamID *)malloc( i_param_size );
1102     if( p_streams == NULL )
1103         return VLC_ENOMEM;
1104
1105     err = AudioObjectGetPropertyData( i_dev_id, &streamsAddress, 0, NULL, &i_param_size, p_streams );
1106
1107     if( err != noErr )
1108     {
1109         msg_Err( p_aout, "could not get list of streams: [%s]", (char *)&err );
1110         return false;
1111     }
1112
1113     for( i = 0; i < i_streams; i++ )
1114     {
1115         if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) )
1116             b_return = true;
1117     }
1118
1119     free( p_streams );
1120     return b_return;
1121 }
1122
1123 /*****************************************************************************
1124  * AudioStreamSupportsDigital: Check i_stream_id for digital stream support.
1125  *****************************************************************************/
1126 static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_stream_id )
1127 {
1128     OSStatus                    err = noErr;
1129     UInt32                      i_param_size = 0;
1130     AudioStreamBasicDescription *p_format_list = NULL;
1131     int                         i = 0, i_formats = 0;
1132     bool                  b_return = false;
1133
1134     /* Retrieve all the stream formats supported by each output stream */
1135     AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
1136     err = AudioObjectGetPropertyDataSize( i_stream_id, &physicalFormatsAddress, 0, NULL, &i_param_size );
1137     if( err == kAudioHardwareUnknownPropertyError )
1138     {
1139         msg_Err( p_aout, "audio stream doesn't support query kAudioStreamPropertyAvailablePhysicalFormats" );
1140         return false;
1141     }
1142     else if( err != noErr )
1143     {
1144         msg_Err( p_aout, "AudioStreamSupportsDigital: could not get number of streamformats: [%s] (%i)", (char *)&err, err );
1145         return false;
1146     }
1147
1148     i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
1149     p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
1150     if( p_format_list == NULL )
1151         return false;
1152
1153     err = AudioObjectGetPropertyData( i_stream_id, &physicalFormatsAddress, 0, NULL, &i_param_size, p_format_list );
1154     if( err != noErr )
1155     {
1156         msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
1157         free( p_format_list);
1158         p_format_list = NULL;
1159         return false;
1160     }
1161
1162     for( i = 0; i < i_formats; i++ )
1163     {
1164         msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format: ", p_format_list[i] ) );
1165
1166         if( p_format_list[i].mFormatID == 'IAC3' ||
1167                   p_format_list[i].mFormatID == kAudioFormat60958AC3 )
1168         {
1169             b_return = true;
1170         }
1171     }
1172
1173     free( p_format_list );
1174     return b_return;
1175 }
1176
1177 /*****************************************************************************
1178  * AudioStreamChangeFormat: Change i_stream_id to change_format
1179  *****************************************************************************/
1180 static int AudioStreamChangeFormat( aout_instance_t *p_aout, AudioStreamID i_stream_id, AudioStreamBasicDescription change_format )
1181 {
1182     OSStatus            err = noErr;
1183     UInt32              i_param_size = 0;
1184     int i;
1185
1186     AudioObjectPropertyAddress physicalFormatAddress = { kAudioStreamPropertyPhysicalFormat, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
1187
1188     struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
1189
1190     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", change_format ) );
1191
1192     /* Condition because SetProperty is asynchronious */
1193     vlc_cond_init( &w.cond );
1194     vlc_mutex_init( &w.lock );
1195     vlc_mutex_lock( &w.lock );
1196
1197     /* Install the callback */
1198     err = AudioObjectAddPropertyListener( i_stream_id, &physicalFormatAddress, StreamListener, (void *)&w );
1199     if( err != noErr )
1200     {
1201         msg_Err( p_aout, "AudioObjectAddPropertyListener for kAudioStreamPropertyPhysicalFormat failed: [%4.4s]", (char *)&err );
1202         return false;
1203     }
1204
1205     /* change the format */
1206     err = AudioObjectSetPropertyData( i_stream_id, &physicalFormatAddress, 0, NULL, sizeof( AudioStreamBasicDescription ),
1207                                      &change_format );
1208     if( err != noErr )
1209     {
1210         msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
1211         return false;
1212     }
1213
1214     /* The AudioStreamSetProperty is not only asynchronious (requiring the locks)
1215      * it is also not atomic in its behaviour.
1216      * Therefore we check 5 times before we really give up.
1217      * FIXME: failing isn't actually implemented yet. */
1218     for( i = 0; i < 5; i++ )
1219     {
1220         AudioStreamBasicDescription actual_format;
1221         mtime_t timeout = mdate() + 500000;
1222
1223         if( vlc_cond_timedwait( &w.cond, &w.lock, timeout ) )
1224         {
1225             msg_Dbg( p_aout, "reached timeout" );
1226         }
1227
1228         i_param_size = sizeof( AudioStreamBasicDescription );
1229         err = AudioObjectGetPropertyData( i_stream_id, &physicalFormatAddress, 0, NULL, &i_param_size, &actual_format );
1230
1231         msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", actual_format ) );
1232         if( actual_format.mSampleRate == change_format.mSampleRate &&
1233             actual_format.mFormatID == change_format.mFormatID &&
1234             actual_format.mFramesPerPacket == change_format.mFramesPerPacket )
1235         {
1236             /* The right format is now active */
1237             break;
1238         }
1239         /* We need to check again */
1240     }
1241
1242     /* Removing the property listener */
1243     err = AudioObjectRemovePropertyListener( i_stream_id, &physicalFormatAddress, StreamListener, NULL );
1244     if( err != noErr )
1245     {
1246         msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
1247         return false;
1248     }
1249
1250     /* Destroy the lock and condition */
1251     vlc_mutex_unlock( &w.lock );
1252     vlc_mutex_destroy( &w.lock );
1253     vlc_cond_destroy( &w.cond );
1254
1255     return true;
1256 }
1257
1258 /*****************************************************************************
1259  * RenderCallbackAnalog: This function is called everytime the AudioUnit wants
1260  * us to provide some more audio data.
1261  * Don't print anything during normal playback, calling blocking function from
1262  * this callback is not allowed.
1263  *****************************************************************************/
1264 static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
1265                                       AudioUnitRenderActionFlags *ioActionFlags,
1266                                       const AudioTimeStamp *inTimeStamp,
1267                                       unsigned int inBusNumber,
1268                                       unsigned int inNumberFrames,
1269                                       AudioBufferList *ioData )
1270 {
1271     AudioTimeStamp  host_time;
1272     mtime_t         current_date = 0;
1273     uint32_t        i_mData_bytes = 0;
1274
1275     aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
1276     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1277
1278     VLC_UNUSED(ioActionFlags);
1279     VLC_UNUSED(inBusNumber);
1280     VLC_UNUSED(inNumberFrames);
1281
1282     host_time.mFlags = kAudioTimeStampHostTimeValid;
1283     AudioDeviceTranslateTime( p_sys->i_selected_dev, inTimeStamp, &host_time );
1284
1285     /* Check for the difference between the Device clock and mdate */
1286     p_sys->clock_diff = - (mtime_t)
1287         AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
1288     p_sys->clock_diff += mdate();
1289
1290     current_date = p_sys->clock_diff +
1291                    AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
1292                    //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
1293
1294     if( ioData == NULL && ioData->mNumberBuffers < 1 )
1295     {
1296         msg_Err( p_aout, "no iodata or buffers");
1297         return 0;
1298     }
1299     if( ioData->mNumberBuffers > 1 )
1300         msg_Err( p_aout, "well this is weird. seems like there is more than one buffer..." );
1301
1302
1303     if( p_sys->i_total_bytes > 0 )
1304     {
1305         i_mData_bytes = __MIN( p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize );
1306         vlc_memcpy( ioData->mBuffers[0].mData,
1307                     &p_sys->p_remainder_buffer[p_sys->i_read_bytes],
1308                     i_mData_bytes );
1309         p_sys->i_read_bytes += i_mData_bytes;
1310         current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
1311                         ( i_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output )  ); // 4 is fl32 specific
1312
1313         if( p_sys->i_read_bytes >= p_sys->i_total_bytes )
1314             p_sys->i_read_bytes = p_sys->i_total_bytes = 0;
1315     }
1316
1317     while( i_mData_bytes < ioData->mBuffers[0].mDataByteSize )
1318     {
1319         /* We don't have enough data yet */
1320         aout_buffer_t * p_buffer;
1321         p_buffer = aout_OutputNextBuffer( p_aout, current_date , false );
1322
1323         if( p_buffer != NULL )
1324         {
1325             uint32_t i_second_mData_bytes = __MIN( p_buffer->i_buffer, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
1326
1327             vlc_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes,
1328                         p_buffer->p_buffer, i_second_mData_bytes );
1329             i_mData_bytes += i_second_mData_bytes;
1330
1331             if( i_mData_bytes >= ioData->mBuffers[0].mDataByteSize )
1332             {
1333                 p_sys->i_total_bytes = p_buffer->i_buffer - i_second_mData_bytes;
1334                 vlc_memcpy( p_sys->p_remainder_buffer,
1335                             &p_buffer->p_buffer[i_second_mData_bytes],
1336                             p_sys->i_total_bytes );
1337                 aout_BufferFree( p_buffer );
1338                 break;
1339             }
1340             else
1341             {
1342                 /* update current_date */
1343                 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
1344                                 ( i_second_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output )  ); // 4 is fl32 specific
1345             }
1346             aout_BufferFree( p_buffer );
1347         }
1348         else
1349         {
1350              vlc_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes,
1351                          0,ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
1352              i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes;
1353         }
1354     }
1355     return( noErr );
1356 }
1357
1358 /*****************************************************************************
1359  * RenderCallbackSPDIF: callback for SPDIF audio output
1360  *****************************************************************************/
1361 static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
1362                                     const AudioTimeStamp * inNow,
1363                                     const void * inInputData,
1364                                     const AudioTimeStamp * inInputTime,
1365                                     AudioBufferList * outOutputData,
1366                                     const AudioTimeStamp * inOutputTime,
1367                                     void * threadGlobals )
1368 {
1369     aout_buffer_t * p_buffer;
1370     mtime_t         current_date;
1371
1372     aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
1373     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1374
1375     VLC_UNUSED(inDevice);
1376     VLC_UNUSED(inInputData);
1377     VLC_UNUSED(inInputTime);
1378
1379     /* Check for the difference between the Device clock and mdate */
1380     p_sys->clock_diff = - (mtime_t)
1381         AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
1382     p_sys->clock_diff += mdate();
1383
1384     current_date = p_sys->clock_diff +
1385                    AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000;
1386                    //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
1387
1388     p_buffer = aout_OutputNextBuffer( p_aout, current_date, true );
1389
1390 #define BUFFER outOutputData->mBuffers[p_sys->i_stream_index]
1391     if( p_buffer != NULL )
1392     {
1393         if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_buffer)
1394             msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_buffer );
1395
1396         /* move data into output data buffer */
1397         vlc_memcpy( BUFFER.mData, p_buffer->p_buffer, p_buffer->i_buffer );
1398         aout_BufferFree( p_buffer );
1399     }
1400     else
1401     {
1402         vlc_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
1403     }
1404 #undef BUFFER
1405
1406     return( noErr );
1407 }
1408
1409 /*****************************************************************************
1410  * HardwareListener: Warns us of changes in the list of registered devices
1411  *****************************************************************************/
1412 static OSStatus HardwareListener( AudioObjectID inObjectID,  UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void*inClientData)
1413 {
1414     OSStatus err = noErr;
1415     aout_instance_t     *p_aout = (aout_instance_t *)inClientData;
1416     VLC_UNUSED(inObjectID);
1417
1418     for ( unsigned int i = 0; i < inNumberAddresses; i++ )
1419     {
1420         if( inAddresses[i].mSelector == kAudioHardwarePropertyDevices )
1421         {
1422             /* something changed in the list of devices */
1423             /* We trigger the audio-device's aout_ChannelsRestart callback */
1424             var_TriggerCallback( p_aout, "audio-device" );
1425             var_Destroy( p_aout, "audio-device" );
1426         }
1427     }
1428
1429     return( err );
1430 }
1431
1432 /*****************************************************************************
1433  * StreamListener
1434  *****************************************************************************/
1435 static OSStatus StreamListener( AudioObjectID inObjectID,  UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void*inClientData)
1436 {
1437     OSStatus err = noErr;
1438     struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
1439
1440     VLC_UNUSED(inObjectID);
1441
1442     for ( unsigned int i = 0; i < inNumberAddresses; i++ )
1443     {
1444         if( inAddresses[i].mSelector == kAudioStreamPropertyPhysicalFormat )
1445         {
1446             vlc_mutex_lock( &w->lock );
1447             vlc_cond_signal( &w->cond );
1448             vlc_mutex_unlock( &w->lock );
1449         }
1450     }
1451     return( err );
1452 }
1453
1454 /*****************************************************************************
1455  * AudioDeviceCallback: Callback triggered when the audio-device variable is changed
1456  *****************************************************************************/
1457 static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable,
1458                      vlc_value_t old_val, vlc_value_t new_val, void *param )
1459 {
1460     aout_instance_t *p_aout = (aout_instance_t *)p_this;
1461     var_Set( p_aout->p_libvlc, "macosx-audio-device", new_val );
1462     msg_Dbg( p_aout, "Set Device: %#"PRIx64, new_val.i_int );
1463     return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );
1464 }
1465