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