]> git.sesse.net Git - vlc/blob - modules/audio_output/auhal.c
auhal: fix memory corruption crash when device list changes (refs #8286)
[vlc] / modules / audio_output / auhal.c
1 /*****************************************************************************
2  * auhal.c: AUHAL and Coreaudio output plugin
3  *****************************************************************************
4  * Copyright (C) 2005 - 2013 VLC authors and VideoLAN
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 it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser 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 #pragma mark includes
26
27 #ifdef HAVE_CONFIG_H
28 # import "config.h"
29 #endif
30
31 #import <vlc_common.h>
32 #import <vlc_plugin.h>
33 #import <vlc_dialog.h>                      // dialog_Fatal
34 #import <vlc_aout.h>                        // aout_*
35
36 #import <AudioUnit/AudioUnit.h>             // AudioUnit
37 #import <CoreAudio/CoreAudio.h>             // AudioDeviceID
38 #import <AudioToolbox/AudioFormat.h>        // AudioFormatGetProperty
39 #import <CoreServices/CoreServices.h>
40
41 #import "TPCircularBuffer.h"
42
43 #pragma mark -
44 #pragma mark private declarations
45
46 #ifndef verify_noerr
47 # define verify_noerr(a) assert((a) == noErr)
48 #endif
49
50 #define STREAM_FORMAT_MSG(pre, sfm) \
51     pre "[%f][%4.4s][%u][%u][%u][%u][%u][%u]", \
52     sfm.mSampleRate, (char *)&sfm.mFormatID, \
53     (unsigned int)sfm.mFormatFlags, (unsigned int)sfm.mBytesPerPacket, \
54     (unsigned int)sfm.mFramesPerPacket, (unsigned int)sfm.mBytesPerFrame, \
55     (unsigned int)sfm.mChannelsPerFrame, (unsigned int)sfm.mBitsPerChannel
56
57 #define AOUT_VAR_SPDIF_FLAG 0xf00000
58
59 #define kBufferLength 2048 * 8 * 8 * 4
60
61 #define AOUT_VOLUME_DEFAULT             256
62 #define AOUT_VOLUME_MAX                 512
63
64 #define VOLUME_TEXT N_("Audio volume")
65 #define VOLUME_LONGTEXT VOLUME_TEXT
66
67 #define DEVICE_TEXT N_("Last audio device")
68 #define DEVICE_LONGTEXT DEVICE_TEXT
69
70 /*****************************************************************************
71  * aout_sys_t: private audio output method descriptor
72  *****************************************************************************
73  * This structure is part of the audio output thread descriptor.
74  * It describes the CoreAudio specific properties of an output thread.
75  *****************************************************************************/
76 struct aout_sys_t
77 {
78     AudioObjectID               i_default_dev;      /* DeviceID of defaultOutputDevice */
79     AudioObjectID               i_selected_dev;     /* DeviceID of the selected device */
80     bool                        b_selected_dev_is_digital;
81     AudioDeviceIOProcID         i_procID;           /* DeviceID of current device */
82     bool                        b_digital;          /* Are we running in digital mode? */
83     mtime_t                     clock_diff;         /* Difference between VLC clock and Device clock */
84
85     uint8_t                     chans_to_reorder;   /* do we need channel reordering */
86     uint8_t                     chan_table[AOUT_CHAN_MAX];
87
88     UInt32                      i_numberOfChannels;
89     TPCircularBuffer            circular_buffer;    /* circular buffer to swap the audio data */
90
91     /* AUHAL specific */
92     AudioComponent              au_component;       /* The AudioComponent we use */
93     AudioUnit                   au_unit;            /* The AudioUnit we use */
94
95     /* CoreAudio SPDIF mode specific */
96     pid_t                       i_hog_pid;          /* The keep the pid of our hog status */
97     AudioStreamID               i_stream_id;        /* The StreamID that has a cac3 streamformat */
98     int                         i_stream_index;     /* The index of i_stream_id in an AudioBufferList */
99     AudioStreamBasicDescription stream_format;      /* The format we changed the stream to */
100     AudioStreamBasicDescription sfmt_revert;        /* The original format of the stream */
101     bool                        b_revert;           /* Whether we need to revert the stream format */
102     bool                        b_changed_mixing;   /* Whether we need to set the mixing mode back */
103     bool                        b_got_first_sample; /* did the aout core provide something to render? */
104
105     int                         i_rate;             /* media sample rate */
106     mtime_t                     i_played_length;    /* how much did we play already */
107     mtime_t                     i_last_sample_time; /* last sample time played by the AudioUnit */
108
109     struct audio_device_t       *devices;
110
111     vlc_mutex_t                 lock;
112 };
113
114 struct audio_device_t
115 {
116     struct audio_device_t *next;
117     UInt32 deviceid;
118     char *name;
119 };
120
121
122 #pragma mark -
123 #pragma mark local prototypes & module descriptor
124
125 static int      Open                    (vlc_object_t *);
126 static void     Close                   (vlc_object_t *);
127 static int      Start                   (audio_output_t *, audio_sample_format_t *);
128 static int      StartAnalog             (audio_output_t *, audio_sample_format_t *);
129 static int      StartSPDIF              (audio_output_t *, audio_sample_format_t *);
130 static void     Stop                    (audio_output_t *);
131
132 static int      DeviceList              (audio_output_t *p_aout, char ***namesp, char ***descsp);
133 static void     RebuildDeviceList       (audio_output_t *);
134 static int      SwitchAudioDevice       (audio_output_t *p_aout, const char *name);
135 static int      VolumeSet               (audio_output_t *, float);
136 static int      MuteSet                 (audio_output_t *, bool);
137
138 static void     Play                    (audio_output_t *, block_t *);
139 static void     Pause                   (audio_output_t *, bool, mtime_t);
140 static void     Flush                   (audio_output_t *, bool);
141 static int      TimeGet                 (audio_output_t *, mtime_t *);
142 static OSStatus RenderCallbackAnalog    (vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
143                                          UInt32 , UInt32, AudioBufferList *);
144
145 static OSStatus RenderCallbackSPDIF     (AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
146                                          AudioBufferList *, const AudioTimeStamp *, void *);
147
148 static OSStatus HardwareListener        (AudioObjectID, UInt32, const AudioObjectPropertyAddress *, void *);
149 static OSStatus StreamListener          (AudioObjectID, UInt32, const AudioObjectPropertyAddress *, void *);
150
151 static int      AudioDeviceHasOutput    (AudioDeviceID);
152 static int      AudioDeviceSupportsDigital(audio_output_t *, AudioDeviceID);
153 static int      AudioStreamSupportsDigital(audio_output_t *, AudioStreamID);
154 static int      AudioStreamChangeFormat (audio_output_t *, AudioStreamID, AudioStreamBasicDescription);
155
156
157 vlc_module_begin ()
158     set_shortname("auhal")
159     set_description(N_("HAL AudioUnit output"))
160     set_capability("audio output", 101)
161     set_category(CAT_AUDIO)
162     set_subcategory(SUBCAT_AUDIO_AOUT)
163     set_callbacks(Open, Close)
164     add_integer("auhal-volume", AOUT_VOLUME_DEFAULT,
165                 VOLUME_TEXT, VOLUME_LONGTEXT, true)
166     change_integer_range(0, AOUT_VOLUME_MAX)
167     add_string("auhal-audio-device", "", DEVICE_TEXT, DEVICE_LONGTEXT, true)
168     add_obsolete_integer("macosx-audio-device") /* since 2.1.0 */
169 vlc_module_end ()
170
171 #pragma mark -
172 #pragma mark initialization
173
174 static int Open(vlc_object_t *obj)
175 {
176     audio_output_t *aout = (audio_output_t *)obj;
177     aout_sys_t *sys = malloc(sizeof (*sys));
178
179     if (unlikely(sys == NULL))
180         return VLC_ENOMEM;
181
182     vlc_mutex_init(&sys->lock);
183
184     aout->sys = sys;
185     aout->start = Start;
186     aout->stop = Stop;
187     aout->volume_set = VolumeSet;
188     aout->mute_set = MuteSet;
189     aout->device_enum = DeviceList;
190     aout->sys->devices = NULL;
191     aout->device_select = SwitchAudioDevice;
192
193     RebuildDeviceList(aout);
194
195     /* remember the volume */
196     aout_VolumeReport(aout, var_InheritInteger(aout, "auhal-volume") / (float)AOUT_VOLUME_DEFAULT);
197     MuteSet(aout, var_InheritBool(aout, "mute"));
198
199     SwitchAudioDevice(aout, config_GetPsz(aout, "auhal-audio-device"));
200
201     return VLC_SUCCESS;
202 }
203
204 static void Close(vlc_object_t *obj)
205 {
206     audio_output_t *aout = (audio_output_t *)obj;
207     aout_sys_t *sys = aout->sys;
208
209     config_PutPsz(aout, "auhal-audio-device", aout_DeviceGet(aout));
210
211     for (struct audio_device_t * device = sys->devices, *next; device != NULL; device = next) {
212         next = device->next;
213         free(device->name);
214         free(device);
215     }
216
217     vlc_mutex_destroy(&sys->lock);
218
219     free(sys);
220 }
221
222 static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
223 {
224     OSStatus                err = noErr;
225     UInt32                  i_param_size = 0;
226     struct aout_sys_t       *p_sys = NULL;
227
228     /* Use int here, to match kAudioDevicePropertyDeviceIsAlive
229      * property size */
230     int                     b_alive = false;
231
232     p_sys = p_aout->sys;
233     p_sys->b_digital = false;
234     p_sys->au_component = NULL;
235     p_sys->au_unit = NULL;
236     p_sys->clock_diff = (mtime_t) 0;
237     p_sys->i_hog_pid = -1;
238     p_sys->i_stream_id = 0;
239     p_sys->i_stream_index = -1;
240     p_sys->b_revert = false;
241     p_sys->b_changed_mixing = false;
242
243     aout_FormatPrint(p_aout, "VLC is looking for:", fmt);
244
245     if (p_sys->b_selected_dev_is_digital)
246         msg_Dbg(p_aout, "audio device supports digital output");
247
248     msg_Dbg(p_aout, "attempting to use device %i", p_sys->i_selected_dev);
249
250     /* Check if the desired device is alive and usable */
251     i_param_size = sizeof(b_alive);
252     AudioObjectPropertyAddress audioDeviceAliveAddress = { kAudioDevicePropertyDeviceIsAlive,
253                                               kAudioObjectPropertyScopeGlobal,
254                                               kAudioObjectPropertyElementMaster };
255     err = AudioObjectGetPropertyData(p_sys->i_selected_dev, &audioDeviceAliveAddress, 0, NULL, &i_param_size, &b_alive);
256
257     if (err != noErr) {
258         /* Be tolerant, only give a warning here */
259         msg_Warn(p_aout, "could not check whether device [0x%x] is alive: %4.4s",
260                            (unsigned int)p_sys->i_selected_dev, (char *)&err);
261         b_alive = false;
262     }
263
264     if (!b_alive) {
265         msg_Warn(p_aout, "selected audio device is not alive, switching to default device");
266         p_sys->i_selected_dev = p_sys->i_default_dev;
267     }
268
269     /* add a callback to see if the device dies later on */
270     err = AudioObjectAddPropertyListener(p_sys->i_selected_dev, &audioDeviceAliveAddress, HardwareListener, (void *)p_aout);
271     if (err != noErr) {
272         /* Be tolerant, only give a warning here */
273         msg_Warn(p_aout, "could not set alive check callback on device [0x%x]: %4.4s",
274                  (unsigned int)p_sys->i_selected_dev, (char *)&err);
275     }
276
277     AudioObjectPropertyAddress audioDeviceHogModeAddress = { kAudioDevicePropertyHogMode,
278                                   kAudioDevicePropertyScopeOutput,
279                                   kAudioObjectPropertyElementMaster };
280     i_param_size = sizeof(p_sys->i_hog_pid);
281     err = AudioObjectGetPropertyData(p_sys->i_selected_dev, &audioDeviceHogModeAddress, 0, NULL, &i_param_size, &p_sys->i_hog_pid);
282     if (err != noErr) {
283         /* This is not a fatal error. Some drivers simply don't support this property */
284         msg_Warn(p_aout, "could not check whether device is hogged: %4.4s",
285                  (char *)&err);
286         p_sys->i_hog_pid = -1;
287     }
288
289     if (p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid()) {
290         msg_Err(p_aout, "Selected audio device is exclusively in use by another program.");
291         dialog_Fatal(p_aout, _("Audio output failed"), "%s",
292                         _("The selected audio output device is exclusively in "
293                           "use by another program."));
294         goto error;
295     }
296
297     bool b_success = false;
298
299     /* Check for Digital mode or Analog output mode */
300     if (AOUT_FMT_SPDIF (fmt) && p_sys->b_selected_dev_is_digital) {
301         if (StartSPDIF (p_aout, fmt)) {
302             msg_Dbg(p_aout, "digital output successfully opened");
303             b_success = true;
304         }
305     } else {
306         if (StartAnalog(p_aout, fmt)) {
307             msg_Dbg(p_aout, "analog output successfully opened");
308             b_success = true;
309         }
310     }
311
312     if (b_success) {
313         p_aout->play = Play;
314         p_aout->flush = Flush;
315         p_aout->time_get = TimeGet;
316         p_aout->pause = Pause;
317         return VLC_SUCCESS;
318     }
319
320 error:
321     /* If we reach this, this aout has failed */
322     msg_Err(p_aout, "opening auhal output failed");
323     return VLC_EGENERIC;
324 }
325
326 /*
327  * StartAnalog: open and setup a HAL AudioUnit to do PCM audio output
328  */
329 static int StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
330 {
331     struct aout_sys_t           *p_sys = p_aout->sys;
332     OSStatus                    err = noErr;
333     UInt32                      i_param_size = 0;
334     int                         i_original;
335     AudioComponentDescription   desc;
336     AudioStreamBasicDescription DeviceFormat;
337     AudioChannelLayout          *layout;
338     AudioChannelLayout          new_layout;
339     AURenderCallbackStruct      input;
340     p_aout->sys->chans_to_reorder = 0;
341
342     /* Lets go find our Component */
343     desc.componentType = kAudioUnitType_Output;
344     desc.componentSubType = kAudioUnitSubType_HALOutput;
345     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
346     desc.componentFlags = 0;
347     desc.componentFlagsMask = 0;
348
349     p_sys->au_component = AudioComponentFindNext(NULL, &desc);
350     if (p_sys->au_component == NULL) {
351         msg_Warn(p_aout, "we cannot find our HAL component");
352         return false;
353     }
354
355     err = AudioComponentInstanceNew(p_sys->au_component, &p_sys->au_unit);
356     if (err != noErr) {
357         msg_Warn(p_aout, "we cannot open our HAL component");
358         return false;
359     }
360
361     /* Set the device we will use for this output unit */
362     err = AudioUnitSetProperty(p_sys->au_unit,
363                          kAudioOutputUnitProperty_CurrentDevice,
364                          kAudioUnitScope_Global,
365                          0,
366                          &p_sys->i_selected_dev,
367                          sizeof(AudioObjectID));
368
369     if (err != noErr) {
370         msg_Warn(p_aout, "we cannot select the audio device");
371         return false;
372     }
373
374     /* Get the current format */
375     i_param_size = sizeof(AudioStreamBasicDescription);
376
377     err = AudioUnitGetProperty(p_sys->au_unit,
378                                    kAudioUnitProperty_StreamFormat,
379                                    kAudioUnitScope_Output,
380                                    0,
381                                    &DeviceFormat,
382                                    &i_param_size);
383
384     if (err != noErr)
385         return false;
386     else
387         msg_Dbg(p_aout, STREAM_FORMAT_MSG("current format is: ", DeviceFormat));
388
389     /* Get the channel layout of the device side of the unit (vlc -> unit -> device) */
390     err = AudioUnitGetPropertyInfo(p_sys->au_unit,
391                                    kAudioDevicePropertyPreferredChannelLayout,
392                                    kAudioUnitScope_Output,
393                                    0,
394                                    &i_param_size,
395                                    NULL);
396
397     if (err == noErr) {
398         layout = (AudioChannelLayout *)malloc(i_param_size);
399
400         verify_noerr(AudioUnitGetProperty(p_sys->au_unit,
401                                        kAudioDevicePropertyPreferredChannelLayout,
402                                        kAudioUnitScope_Output,
403                                        0,
404                                        layout,
405                                        &i_param_size));
406
407         /* We need to "fill out" the ChannelLayout, because there are multiple ways that it can be set */
408         if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
409             /* bitmap defined channellayout */
410             verify_noerr(AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
411                                     sizeof(UInt32), &layout->mChannelBitmap,
412                                     &i_param_size,
413                                     layout));
414         } else if (layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions)
415         {
416             /* layouttags defined channellayout */
417             verify_noerr(AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
418                                     sizeof(AudioChannelLayoutTag), &layout->mChannelLayoutTag,
419                                     &i_param_size,
420                                     layout));
421         }
422
423         msg_Dbg(p_aout, "layout of AUHAL has %i channels" , layout->mNumberChannelDescriptions);
424
425         if (layout->mNumberChannelDescriptions == 0) {
426             msg_Err(p_aout, "insufficient number of output channels");
427             return false;
428         }
429
430         /* Initialize the VLC core channel count */
431         fmt->i_physical_channels = 0;
432         i_original = fmt->i_original_channels & AOUT_CHAN_PHYSMASK;
433
434         if (i_original == AOUT_CHAN_CENTER || layout->mNumberChannelDescriptions < 2) {
435             /* We only need Mono or cannot output more than 1 channel */
436             fmt->i_physical_channels = AOUT_CHAN_CENTER;
437         } else if (i_original == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) || layout->mNumberChannelDescriptions < 3) {
438             /* We only need Stereo or cannot output more than 2 channels */
439             fmt->i_physical_channels = AOUT_CHANS_STEREO;
440         } else {
441             /* We want more than stereo and we can do that */
442             for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; i++) {
443 #ifndef NDEBUG
444                 msg_Dbg(p_aout, "this is channel: %d", (int)layout->mChannelDescriptions[i].mChannelLabel);
445 #endif
446
447                 switch(layout->mChannelDescriptions[i].mChannelLabel) {
448                     case kAudioChannelLabel_Left:
449                         fmt->i_physical_channels |= AOUT_CHAN_LEFT;
450                         continue;
451                     case kAudioChannelLabel_Right:
452                         fmt->i_physical_channels |= AOUT_CHAN_RIGHT;
453                         continue;
454                     case kAudioChannelLabel_Center:
455                         fmt->i_physical_channels |= AOUT_CHAN_CENTER;
456                         continue;
457                     case kAudioChannelLabel_LFEScreen:
458                         fmt->i_physical_channels |= AOUT_CHAN_LFE;
459                         continue;
460                     case kAudioChannelLabel_LeftSurround:
461                         fmt->i_physical_channels |= AOUT_CHAN_REARLEFT;
462                         continue;
463                     case kAudioChannelLabel_RightSurround:
464                         fmt->i_physical_channels |= AOUT_CHAN_REARRIGHT;
465                         continue;
466                     case kAudioChannelLabel_RearSurroundLeft:
467                         fmt->i_physical_channels |= AOUT_CHAN_MIDDLELEFT;
468                         continue;
469                     case kAudioChannelLabel_RearSurroundRight:
470                         fmt->i_physical_channels |= AOUT_CHAN_MIDDLERIGHT;
471                         continue;
472                     case kAudioChannelLabel_CenterSurround:
473                         fmt->i_physical_channels |= AOUT_CHAN_REARCENTER;
474                         continue;
475                     default:
476                         msg_Warn(p_aout, "unrecognized channel form provided by driver: %d", (int)layout->mChannelDescriptions[i].mChannelLabel);
477                 }
478             }
479             if (fmt->i_physical_channels == 0) {
480                 fmt->i_physical_channels = AOUT_CHANS_STEREO;
481                 msg_Err(p_aout, "You should configure your speaker layout with Audio Midi Setup Utility in /Applications/Utilities. Now using Stereo mode.");
482                 dialog_Fatal(p_aout, _("Audio device is not configured"), "%s",
483                                 _("You should configure your speaker layout with "
484                                   "the \"Audio Midi Setup\" utility in /Applications/"
485                                   "Utilities. Stereo mode is being used now."));
486             }
487         }
488         free(layout);
489     } else {
490         msg_Warn(p_aout, "this driver does not support kAudioDevicePropertyPreferredChannelLayout. BAD DRIVER AUTHOR !!!");
491         fmt->i_physical_channels = AOUT_CHANS_STEREO;
492     }
493
494     msg_Dbg(p_aout, "selected %d physical channels for device output", aout_FormatNbChannels(fmt));
495     msg_Dbg(p_aout, "VLC will output: %s", aout_FormatPrintChannels(fmt));
496     p_sys->i_numberOfChannels = aout_FormatNbChannels(fmt);
497
498     memset (&new_layout, 0, sizeof(new_layout));
499     uint32_t chans_out[AOUT_CHAN_MAX];
500
501     switch(aout_FormatNbChannels(fmt)) {
502         case 1:
503             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
504             break;
505         case 2:
506             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
507             break;
508         case 3:
509             if (fmt->i_physical_channels & AOUT_CHAN_CENTER)
510                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_7; // L R C
511             else if (fmt->i_physical_channels & AOUT_CHAN_LFE)
512                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_4; // L R LFE
513             break;
514         case 4:
515             if (fmt->i_physical_channels & (AOUT_CHAN_CENTER | AOUT_CHAN_LFE))
516                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_10; // L R C LFE
517             else if (fmt->i_physical_channels & (AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT))
518                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3; // L R Ls Rs
519             else if (fmt->i_physical_channels & (AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER))
520                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3; // L R C Cs
521             break;
522         case 5:
523             if (fmt->i_physical_channels & (AOUT_CHAN_CENTER))
524                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_19; // L R Ls Rs C
525             else if (fmt->i_physical_channels & (AOUT_CHAN_LFE))
526                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_18; // L R Ls Rs LFE
527             break;
528         case 6:
529             if (fmt->i_physical_channels & (AOUT_CHAN_LFE))
530                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_20; // L R Ls Rs C LFE
531             else
532                 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_6_0; // L R Ls Rs C Cs
533             break;
534         case 7:
535             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A;
536
537             chans_out[0] = AOUT_CHAN_LEFT;
538             chans_out[1] = AOUT_CHAN_RIGHT;
539             chans_out[2] = AOUT_CHAN_CENTER;
540             chans_out[3] = AOUT_CHAN_LFE;
541             chans_out[4] = AOUT_CHAN_REARLEFT;
542             chans_out[5] = AOUT_CHAN_REARRIGHT;
543             chans_out[6] = AOUT_CHAN_REARCENTER;
544
545             p_aout->sys->chans_to_reorder = aout_CheckChannelReorder(NULL, chans_out, fmt->i_physical_channels, p_aout->sys->chan_table);
546             if (p_aout->sys->chans_to_reorder)
547                 msg_Dbg(p_aout, "channel reordering needed");
548
549             break;
550         case 8:
551             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
552
553             chans_out[0] = AOUT_CHAN_LEFT;
554             chans_out[1] = AOUT_CHAN_RIGHT;
555             chans_out[2] = AOUT_CHAN_CENTER;
556             chans_out[3] = AOUT_CHAN_LFE;
557             chans_out[4] = AOUT_CHAN_MIDDLELEFT;
558             chans_out[5] = AOUT_CHAN_MIDDLERIGHT;
559             chans_out[6] = AOUT_CHAN_REARLEFT;
560             chans_out[7] = AOUT_CHAN_REARRIGHT;
561
562             p_aout->sys->chans_to_reorder = aout_CheckChannelReorder(NULL, chans_out, fmt->i_physical_channels, p_aout->sys->chan_table);
563             if (p_aout->sys->chans_to_reorder)
564                 msg_Dbg(p_aout, "channel reordering needed");
565
566             break;
567     }
568
569     /* Set up the format to be used */
570     DeviceFormat.mSampleRate = fmt->i_rate;
571     DeviceFormat.mFormatID = kAudioFormatLinearPCM;
572     p_sys->i_rate = fmt->i_rate;
573
574     /* We use float 32 since this is VLC's endorsed format */
575     fmt->i_format = VLC_CODEC_FL32;
576     DeviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
577     DeviceFormat.mBitsPerChannel = 32;
578     DeviceFormat.mChannelsPerFrame = aout_FormatNbChannels(fmt);
579
580     /* Calculate framesizes and stuff */
581     DeviceFormat.mFramesPerPacket = 1;
582     DeviceFormat.mBytesPerFrame = DeviceFormat.mBitsPerChannel * DeviceFormat.mChannelsPerFrame / 8;
583     DeviceFormat.mBytesPerPacket = DeviceFormat.mBytesPerFrame * DeviceFormat.mFramesPerPacket;
584
585     /* Set the desired format */
586     i_param_size = sizeof(AudioStreamBasicDescription);
587     verify_noerr(AudioUnitSetProperty(p_sys->au_unit,
588                                    kAudioUnitProperty_StreamFormat,
589                                    kAudioUnitScope_Input,
590                                    0,
591                                    &DeviceFormat,
592                                    i_param_size));
593
594     msg_Dbg(p_aout, STREAM_FORMAT_MSG("we set the AU format: " , DeviceFormat));
595
596     /* Retrieve actual format */
597     verify_noerr(AudioUnitGetProperty(p_sys->au_unit,
598                                    kAudioUnitProperty_StreamFormat,
599                                    kAudioUnitScope_Input,
600                                    0,
601                                    &DeviceFormat,
602                                    &i_param_size));
603
604     msg_Dbg(p_aout, STREAM_FORMAT_MSG("the actual set AU format is " , DeviceFormat));
605
606     /* Do the last VLC aout setups */
607     aout_FormatPrepare(fmt);
608
609     /* set the IOproc callback */
610     input.inputProc = (AURenderCallback) RenderCallbackAnalog;
611     input.inputProcRefCon = p_aout;
612
613     verify_noerr(AudioUnitSetProperty(p_sys->au_unit,
614                             kAudioUnitProperty_SetRenderCallback,
615                             kAudioUnitScope_Input,
616                             0, &input, sizeof(input)));
617
618     /* Set the new_layout as the layout VLC will use to feed the AU unit */
619     verify_noerr(AudioUnitSetProperty(p_sys->au_unit,
620                             kAudioUnitProperty_AudioChannelLayout,
621                             kAudioUnitScope_Output,
622                             0, &new_layout, sizeof(new_layout)));
623
624     if (new_layout.mNumberChannelDescriptions > 0)
625         free(new_layout.mChannelDescriptions);
626
627     /* AU initiliaze */
628     verify_noerr(AudioUnitInitialize(p_sys->au_unit));
629
630     /* Find the difference between device clock and mdate clock */
631     p_sys->clock_diff = - (mtime_t)
632         AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()) / 1000;
633     p_sys->clock_diff += mdate();
634
635     /* setup circular buffer */
636     TPCircularBufferInit(&p_sys->circular_buffer, kBufferLength);
637
638     p_sys->b_got_first_sample = false;
639     p_sys->i_played_length = 0;
640     p_sys->i_last_sample_time = 0;
641
642     /* Set volume for output unit */
643     float volume = var_InheritInteger(p_aout, "auhal-volume") / (float)AOUT_VOLUME_DEFAULT;
644     volume = volume * volume * volume;
645     verify_noerr(AudioUnitSetParameter(p_sys->au_unit,
646                                     kHALOutputParam_Volume,
647                                     kAudioUnitScope_Global,
648                                     0,
649                                     volume,
650                                     0));
651
652     return true;
653 }
654
655 /*
656  * StartSPDIF: Setup an encoded digital stream (SPDIF) output
657  */
658 static int StartSPDIF (audio_output_t * p_aout, audio_sample_format_t *fmt)
659 {
660     struct aout_sys_t       *p_sys = p_aout->sys;
661     OSStatus                err = noErr;
662     UInt32                  i_param_size = 0, b_mix = 0;
663     Boolean                 b_writeable = false;
664     AudioStreamID           *p_streams = NULL;
665     unsigned                i_streams = 0;
666
667     /* Start doing the SPDIF setup proces */
668     p_sys->b_digital = true;
669
670     /* Hog the device */
671     AudioObjectPropertyAddress audioDeviceHogModeAddress = { kAudioDevicePropertyHogMode, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
672     i_param_size = sizeof(p_sys->i_hog_pid);
673     p_sys->i_hog_pid = getpid() ;
674
675     err = AudioObjectSetPropertyData(p_sys->i_selected_dev, &audioDeviceHogModeAddress, 0, NULL, i_param_size, &p_sys->i_hog_pid);
676
677     if (err != noErr) {
678         msg_Err(p_aout, "failed to set hogmode: [%4.4s]", (char *)&err);
679         return false;
680     }
681
682     AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = { kAudioDevicePropertySupportsMixing , kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
683
684     if (AudioObjectHasProperty(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress)) {
685         /* Set mixable to false if we are allowed to */
686         err = AudioObjectIsPropertySettable(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, &b_writeable);
687         err = AudioObjectGetPropertyDataSize(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, &i_param_size);
688         err = AudioObjectGetPropertyData(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, &i_param_size, &b_mix);
689
690         if (err == noErr && b_writeable) {
691             b_mix = 0;
692             err = AudioObjectSetPropertyData(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, i_param_size, &b_mix);
693             p_sys->b_changed_mixing = true;
694         }
695
696         if (err != noErr) {
697             msg_Err(p_aout, "failed to set mixmode: [%4.4s]", (char *)&err);
698             return false;
699         }
700     }
701
702     /* Get a list of all the streams on this device */
703     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
704     err = AudioObjectGetPropertyDataSize(p_sys->i_selected_dev, &streamsAddress, 0, NULL, &i_param_size);
705     if (err != noErr) {
706         msg_Err(p_aout, "could not get number of streams: [%4.4s]", (char *)&err);
707         return false;
708     }
709
710     i_streams = i_param_size / sizeof(AudioStreamID);
711     p_streams = (AudioStreamID *)malloc(i_param_size);
712     if (p_streams == NULL)
713         return false;
714
715     err = AudioObjectGetPropertyData(p_sys->i_selected_dev, &streamsAddress, 0, NULL, &i_param_size, p_streams);
716
717     if (err != noErr) {
718         msg_Err(p_aout, "could not get number of streams: [%4.4s]", (char *)&err);
719         free(p_streams);
720         return false;
721     }
722
723     AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioObjectPropertyScopeGlobal, 0 };
724     for (unsigned i = 0; i < i_streams && p_sys->i_stream_index < 0 ; i++) {
725         /* Find a stream with a cac3 stream */
726         AudioStreamRangedDescription *p_format_list = NULL;
727         int                          i_formats = 0;
728         bool                         b_digital = false;
729
730         /* Retrieve all the stream formats supported by each output stream */
731         err = AudioObjectGetPropertyDataSize(p_streams[i], &physicalFormatsAddress, 0, NULL, &i_param_size);
732         if (err != noErr) {
733             msg_Err(p_aout, "could not get number of streamformats: [%s] (%i)", (char *)&err, (int32_t)err);
734             continue;
735         }
736
737         i_formats = i_param_size / sizeof(AudioStreamRangedDescription);
738         p_format_list = (AudioStreamRangedDescription *)malloc(i_param_size);
739         if (p_format_list == NULL)
740             continue;
741
742         err = AudioObjectGetPropertyData(p_streams[i], &physicalFormatsAddress, 0, NULL, &i_param_size, p_format_list);
743         if (err != noErr) {
744             msg_Err(p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err);
745             free(p_format_list);
746             continue;
747         }
748
749         /* Check if one of the supported formats is a digital format */
750         for (int j = 0; j < i_formats; j++) {
751             if (p_format_list[j].mFormat.mFormatID == 'IAC3' ||
752                p_format_list[j].mFormat.mFormatID == 'iac3' ||
753                p_format_list[j].mFormat.mFormatID == kAudioFormat60958AC3 ||
754                p_format_list[j].mFormat.mFormatID == kAudioFormatAC3) {
755                 b_digital = true;
756                 break;
757             }
758         }
759
760         if (b_digital) {
761             /* if this stream supports a digital (cac3) format, then go set it. */
762             int i_requested_rate_format = -1;
763             int i_current_rate_format = -1;
764             int i_backup_rate_format = -1;
765
766             p_sys->i_stream_id = p_streams[i];
767             p_sys->i_stream_index = i;
768
769             if (!p_sys->b_revert) {
770                 AudioObjectPropertyAddress currentPhysicalFormatAddress = { kAudioStreamPropertyPhysicalFormat, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
771                 /* Retrieve the original format of this stream first if not done so already */
772                 i_param_size = sizeof(p_sys->sfmt_revert);
773                 err = AudioObjectGetPropertyData(p_sys->i_stream_id, &currentPhysicalFormatAddress, 0, NULL, &i_param_size, &p_sys->sfmt_revert);
774                 if (err != noErr) {
775                     msg_Err(p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err);
776                     continue;
777                 }
778                 p_sys->b_revert = true;
779             }
780
781             for (int j = 0; j < i_formats; j++) {
782                 if (p_format_list[j].mFormat.mFormatID == 'IAC3' ||
783                    p_format_list[j].mFormat.mFormatID == 'iac3' ||
784                    p_format_list[j].mFormat.mFormatID == kAudioFormat60958AC3 ||
785                    p_format_list[j].mFormat.mFormatID == kAudioFormatAC3) {
786                     if (p_format_list[j].mFormat.mSampleRate == fmt->i_rate) {
787                         i_requested_rate_format = j;
788                         break;
789                     } else if (p_format_list[j].mFormat.mSampleRate == p_sys->sfmt_revert.mSampleRate)
790                         i_current_rate_format = j;
791                     else {
792                         if (i_backup_rate_format < 0 || p_format_list[j].mFormat.mSampleRate > p_format_list[i_backup_rate_format].mFormat.mSampleRate)
793                             i_backup_rate_format = j;
794                     }
795                 }
796
797             }
798
799             if (i_requested_rate_format >= 0) /* We prefer to output at the samplerate of the original audio */
800                 p_sys->stream_format = p_format_list[i_requested_rate_format].mFormat;
801             else if (i_current_rate_format >= 0) /* If not possible, we will try to use the current samplerate of the device */
802                 p_sys->stream_format = p_format_list[i_current_rate_format].mFormat;
803             else
804                 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) */
805         }
806         free(p_format_list);
807     }
808     free(p_streams);
809
810     /* get notified when we don't have spdif-output anymore */
811     err = AudioObjectAddPropertyListener(p_sys->i_stream_id, &physicalFormatsAddress, HardwareListener, (void *)p_aout);
812     if (err != noErr) {
813         msg_Warn(p_aout, "could not set audio device property streams callback on device: %4.4s",
814                  (char *)&err);
815     }
816
817     msg_Dbg(p_aout, STREAM_FORMAT_MSG("original stream format: ", p_sys->sfmt_revert));
818
819     if (!AudioStreamChangeFormat(p_aout, p_sys->i_stream_id, p_sys->stream_format))
820         return false;
821
822     /* Set the format flags */
823     if (p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian)
824         fmt->i_format = VLC_CODEC_SPDIFB;
825     else
826         fmt->i_format = VLC_CODEC_SPDIFL;
827     fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
828     fmt->i_frame_length = A52_FRAME_NB;
829     fmt->i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
830     p_sys->i_rate = fmt->i_rate;
831     aout_FormatPrepare(fmt);
832
833     /* Add IOProc callback */
834     err = AudioDeviceCreateIOProcID(p_sys->i_selected_dev,
835                                    (AudioDeviceIOProc)RenderCallbackSPDIF,
836                                    (void *)p_aout,
837                                    &p_sys->i_procID);
838     if (err != noErr) {
839         msg_Err(p_aout, "AudioDeviceCreateIOProcID failed: [%4.4s]", (char *)&err);
840         return false;
841     }
842
843     /* Check for the difference between the Device clock and mdate */
844     p_sys->clock_diff = - (mtime_t)
845         AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()) / 1000;
846     p_sys->clock_diff += mdate();
847
848     /* Start device */
849     err = AudioDeviceStart(p_sys->i_selected_dev, p_sys->i_procID);
850     if (err != noErr) {
851         msg_Err(p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err);
852
853         err = AudioDeviceDestroyIOProcID(p_sys->i_selected_dev, p_sys->i_procID);
854         if (err != noErr)
855             msg_Err(p_aout, "AudioDeviceDestroyIOProcID failed: [%4.4s]", (char *)&err);
856
857         return false;
858     }
859
860     /* setup circular buffer */
861     TPCircularBufferInit(&p_sys->circular_buffer, kBufferLength);
862     p_sys->i_played_length = 0;
863     p_sys->i_last_sample_time = 0;
864
865     return true;
866 }
867
868 static void Stop(audio_output_t *p_aout)
869 {
870     struct aout_sys_t   *p_sys = p_aout->sys;
871     OSStatus            err = noErr;
872     UInt32              i_param_size = 0;
873
874     AudioObjectPropertyAddress deviceAliveAddress = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
875     err = AudioObjectRemovePropertyListener(p_sys->i_selected_dev, &deviceAliveAddress, HardwareListener, (void *)p_aout);
876     if (err != noErr)
877         msg_Err(p_aout, "failed to remove audio device life checker: [%4.4s]", (char *)&err);
878
879     if (p_sys->b_digital) {
880         AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioObjectPropertyScopeGlobal, 0 };
881         err = AudioObjectRemovePropertyListener(p_sys->i_stream_id, &physicalFormatsAddress, HardwareListener, (void *)p_aout);
882         if (err != noErr)
883             msg_Err(p_aout, "failed to remove audio device property streams callback: [%4.4s]", (char *)&err);
884     }
885
886     if (p_sys->au_unit) {
887         verify_noerr(AudioOutputUnitStop(p_sys->au_unit));
888         verify_noerr(AudioUnitUninitialize(p_sys->au_unit));
889         verify_noerr(AudioComponentInstanceDispose(p_sys->au_unit));
890     }
891
892     if (p_sys->b_digital) {
893         /* Stop device */
894         err = AudioDeviceStop(p_sys->i_selected_dev,
895                                p_sys->i_procID);
896         if (err != noErr)
897             msg_Err(p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err);
898
899         /* Remove IOProc callback */
900         err = AudioDeviceDestroyIOProcID(p_sys->i_selected_dev,
901                                           p_sys->i_procID);
902         if (err != noErr)
903             msg_Err(p_aout, "AudioDeviceDestroyIOProcID failed: [%4.4s]", (char *)&err);
904
905         if (p_sys->b_revert)
906             AudioStreamChangeFormat(p_aout, p_sys->i_stream_id, p_sys->sfmt_revert);
907
908         if (p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3) {
909             int b_mix;
910             Boolean b_writeable = false;
911             /* Revert mixable to true if we are allowed to */
912             AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = { kAudioDevicePropertySupportsMixing , kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
913             err = AudioObjectIsPropertySettable(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, &b_writeable);
914             err = AudioObjectGetPropertyData(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, &i_param_size, &b_mix);
915
916             if (err == noErr && b_writeable) {
917                 msg_Dbg(p_aout, "mixable is: %d", b_mix);
918                 b_mix = 1;
919                 err = AudioObjectSetPropertyData(p_sys->i_selected_dev, &audioDeviceSupportsMixingAddress, 0, NULL, i_param_size, &b_mix);
920             }
921
922             if (err != noErr)
923                 msg_Err(p_aout, "failed to set mixmode: [%4.4s]", (char *)&err);
924         }
925     }
926
927     AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
928     err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &audioDevicesAddress, HardwareListener, (void *)p_aout);
929
930     if (err != noErr)
931         msg_Err(p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err);
932
933     if (p_sys->i_hog_pid == getpid()) {
934         p_sys->i_hog_pid = -1;
935         i_param_size = sizeof(p_sys->i_hog_pid);
936         AudioObjectPropertyAddress audioDeviceHogModeAddress = { kAudioDevicePropertyHogMode,
937             kAudioDevicePropertyScopeOutput,
938             kAudioObjectPropertyElementMaster };
939         err = AudioObjectSetPropertyData(p_sys->i_selected_dev, &audioDeviceHogModeAddress, 0, NULL, i_param_size, &p_sys->i_hog_pid);
940         if (err != noErr)
941             msg_Err(p_aout, "Could not release hogmode: [%4.4s]", (char *)&err);
942     }
943
944     p_sys->i_played_length = 0;
945     p_sys->i_last_sample_time = 0;
946
947     /* clean-up circular buffer */
948     TPCircularBufferCleanup(&p_sys->circular_buffer);
949 }
950
951 #pragma mark -
952 #pragma mark core interaction
953
954 static int DeviceList(audio_output_t *p_aout, char ***namesp, char ***descsp)
955 {
956     struct aout_sys_t   *p_sys = p_aout->sys;
957     char **names, **descs;
958     unsigned n = 0;
959
960     for (struct audio_device_t *device = p_sys->devices; device != NULL; device = device->next)
961         n++;
962
963     *namesp = names = xmalloc(sizeof(*names) * n);
964     *descsp = descs = xmalloc(sizeof(*descs) * n);
965
966     char deviceid[100];
967     for (struct audio_device_t *device = p_sys->devices; device != NULL; device = device->next) {
968         sprintf(deviceid, "%i", device->deviceid);
969         *(names++) = strdup(deviceid);
970         *(descs++) = strdup(device->name);
971     }
972
973     return n;
974 }
975
976 static void add_device_to_list(audio_output_t * p_aout, UInt32 i_id, char *name)
977 {
978     struct aout_sys_t *p_sys = p_aout->sys;
979
980     struct audio_device_t *device = malloc(sizeof(*device));
981     if (unlikely(device == NULL))
982         return;
983
984     device->next = p_sys->devices;
985     device->deviceid = i_id;
986     device->name = strdup(name);
987
988     p_sys->devices = device;
989 }
990
991 static void RebuildDeviceList(audio_output_t * p_aout)
992 {
993     OSStatus            err = noErr;
994     UInt32              propertySize = 0;
995     AudioObjectID       defaultDeviceID = 0;
996     AudioObjectID       *deviceIDs;
997     UInt32              numberOfDevices;
998
999     struct aout_sys_t   *p_sys = p_aout->sys;
1000
1001     if (p_sys->devices) {
1002         for (struct audio_device_t * device = p_sys->devices, *next; device != NULL; device = next) {
1003             next = device->next;
1004             free(device->name);
1005             free(device);
1006         }
1007     }
1008     p_sys->devices = NULL;
1009
1010     /* Get number of devices */
1011     AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1012     err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &audioDevicesAddress, 0, NULL, &propertySize);
1013     if (err != noErr) {
1014         msg_Err(p_aout, "Could not get number of devices: [%s]", (char *)&err);
1015         return;
1016     }
1017
1018     numberOfDevices = propertySize / sizeof(AudioDeviceID);
1019
1020     if (numberOfDevices < 1) {
1021         msg_Err(p_aout, "No audio output devices were found.");
1022         return;
1023     }
1024     msg_Dbg(p_aout, "found %i audio device(s)", numberOfDevices);
1025
1026     /* Allocate DeviceID array */
1027     deviceIDs = (AudioDeviceID *)calloc(numberOfDevices, sizeof(AudioDeviceID));
1028     if (deviceIDs == NULL)
1029         return;
1030
1031     /* Populate DeviceID array */
1032     err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &audioDevicesAddress, 0, NULL, &propertySize, deviceIDs);
1033     if (err != noErr) {
1034         msg_Err(p_aout, "could not get the device IDs: [%s]", (char *)&err);
1035         return;
1036     }
1037
1038     /* Find the ID of the default Device */
1039     AudioObjectPropertyAddress defaultDeviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
1040     propertySize = sizeof(AudioObjectID);
1041     err= AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultDeviceAddress, 0, NULL, &propertySize, &defaultDeviceID);
1042     if (err != noErr) {
1043         msg_Err(p_aout, "could not get default audio device: [%s]", (char *)&err);
1044         return;
1045     }
1046     p_sys->i_default_dev = defaultDeviceID;
1047
1048     AudioObjectPropertyAddress deviceNameAddress = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1049
1050     for (unsigned int i = 0; i < numberOfDevices; i++) {
1051         CFStringRef device_name_ref;
1052         char *psz_name;
1053         CFIndex length;
1054         bool b_digital = false;
1055         UInt32 i_id = deviceIDs[i];
1056
1057         /* Retrieve the length of the device name */
1058         err = AudioObjectGetPropertyDataSize(deviceIDs[i], &deviceNameAddress, 0, NULL, &propertySize);
1059         if (err != noErr) {
1060             msg_Dbg(p_aout, "failed to get name size for device %i", deviceIDs[i]);
1061             continue;
1062         }
1063
1064         /* Retrieve the name of the device */
1065         err = AudioObjectGetPropertyData(deviceIDs[i], &deviceNameAddress, 0, NULL, &propertySize, &device_name_ref);
1066         if (err != noErr) {
1067             msg_Dbg(p_aout, "failed to get name for device %i", deviceIDs[i]);
1068             continue;
1069         }
1070         length = CFStringGetLength(device_name_ref);
1071         length++;
1072         psz_name = (char *)malloc(length);
1073         CFStringGetCString(device_name_ref, psz_name, length, kCFStringEncodingUTF8);
1074
1075         msg_Dbg(p_aout, "DevID: %i DevName: %s", deviceIDs[i], psz_name);
1076
1077         if (!AudioDeviceHasOutput(deviceIDs[i])) {
1078             msg_Dbg(p_aout, "this '%s' is INPUT only. skipping...", psz_name);
1079             free(psz_name);
1080             continue;
1081         }
1082
1083         add_device_to_list(p_aout, i_id, psz_name);
1084
1085         if (AudioDeviceSupportsDigital(p_aout, deviceIDs[i])) {
1086             b_digital = true;
1087             msg_Dbg(p_aout, "'%s' supports digital output", psz_name);
1088             char *psz_encoded_name = nil;
1089             asprintf(&psz_encoded_name, _("%s (Encoded Output)"), psz_name);
1090             i_id = i_id | AOUT_VAR_SPDIF_FLAG;
1091             add_device_to_list(p_aout, i_id, psz_encoded_name);
1092             free(psz_encoded_name);
1093         }
1094
1095         CFRelease(device_name_ref);
1096         free(psz_name);
1097     }
1098
1099     add_device_to_list(p_aout, 0, _("System Sound Output Device"));
1100
1101     /* Attach a Listener so that we are notified of a change in the Device setup */
1102     err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &audioDevicesAddress, HardwareListener, (void *)p_aout);
1103     if (err != noErr)
1104         msg_Warn(p_aout, "failed to add listener for audio device configuration (%i)", err);
1105
1106     free(deviceIDs);
1107 }
1108
1109 static int SwitchAudioDevice(audio_output_t *p_aout, const char *name)
1110 {
1111     struct aout_sys_t *p_sys = p_aout->sys;
1112
1113     if (name)
1114         p_sys->i_selected_dev = atoi(name);
1115     else
1116         p_sys->i_selected_dev = 0;
1117
1118     bool b_supports_digital = (p_sys->i_selected_dev & AOUT_VAR_SPDIF_FLAG);
1119     if (b_supports_digital)
1120         p_sys->b_selected_dev_is_digital = true;
1121     else
1122         p_sys->b_selected_dev_is_digital = false;
1123
1124     p_sys->i_selected_dev = p_sys->i_selected_dev & ~AOUT_VAR_SPDIF_FLAG;
1125
1126     aout_DeviceReport(p_aout, name);
1127     aout_RestartRequest(p_aout, AOUT_RESTART_OUTPUT);
1128
1129     return 0;
1130 }
1131
1132 static int VolumeSet(audio_output_t * p_aout, float volume)
1133 {
1134     struct aout_sys_t *p_sys = p_aout->sys;
1135     OSStatus ostatus;
1136
1137     aout_VolumeReport(p_aout, volume);
1138
1139     /* Set volume for output unit */
1140     ostatus = AudioUnitSetParameter(p_sys->au_unit,
1141                                     kHALOutputParam_Volume,
1142                                     kAudioUnitScope_Global,
1143                                     0,
1144                                     volume * volume * volume,
1145                                     0);
1146
1147     if (var_InheritBool(p_aout, "volume-save"))
1148         config_PutInt(p_aout, "auhal-volume", lroundf(volume * AOUT_VOLUME_DEFAULT));
1149
1150     return ostatus;
1151 }
1152
1153 static int MuteSet(audio_output_t * p_aout, bool mute)
1154 {
1155     struct   aout_sys_t *p_sys = p_aout->sys;
1156     OSStatus ostatus;
1157
1158     aout_MuteReport(p_aout, mute);
1159
1160     float volume = .0;
1161
1162     if (!mute)
1163         volume = var_InheritInteger(p_aout, "auhal-volume") / (float)AOUT_VOLUME_DEFAULT;
1164
1165     ostatus = AudioUnitSetParameter(p_sys->au_unit,
1166                                     kHALOutputParam_Volume,
1167                                     kAudioUnitScope_Global,
1168                                     0,
1169                                     volume * volume * volume,
1170                                     0);
1171
1172     return ostatus;
1173 }
1174
1175 #pragma mark -
1176 #pragma mark actual playback
1177
1178 static void Play (audio_output_t * p_aout, block_t * p_block)
1179 {
1180     struct aout_sys_t *p_sys = p_aout->sys;
1181
1182     if (p_block->i_nb_samples > 0) {
1183         if (!p_sys->b_got_first_sample) {
1184             /* Start the AU */
1185             verify_noerr(AudioOutputUnitStart(p_sys->au_unit));
1186             p_sys->b_got_first_sample = true;
1187         }
1188
1189         /* Do the channel reordering */
1190         if (p_sys->chans_to_reorder && !p_sys->b_digital) {
1191            aout_ChannelReorder(p_block->p_buffer,
1192                                p_block->i_buffer,
1193                                p_sys->chans_to_reorder,
1194                                p_sys->chan_table,
1195                                VLC_CODEC_FL32);
1196         }
1197
1198         /* keep track of the played data */
1199         p_aout->sys->i_played_length += p_block->i_length;
1200
1201         /* move data to buffer */
1202         if (unlikely(TPCircularBufferProduceBytes(&p_sys->circular_buffer, p_block->p_buffer, p_block->i_buffer) == 0)) {
1203             msg_Warn(p_aout, "Audio buffer was dropped");
1204         }
1205
1206     }
1207
1208     block_Release(p_block);
1209 }
1210
1211 static void Pause (audio_output_t *p_aout, bool pause, mtime_t date)
1212 {
1213     struct aout_sys_t * p_sys = p_aout->sys;
1214     VLC_UNUSED(date);
1215
1216     if (p_aout->sys->b_digital) {
1217         if (pause)
1218             AudioDeviceStop(p_sys->i_selected_dev, p_sys->i_procID);
1219         else
1220             AudioDeviceStart(p_sys->i_selected_dev, p_sys->i_procID);
1221     } else {
1222         if (pause)
1223             AudioOutputUnitStop(p_sys->au_unit);
1224         else
1225             AudioOutputUnitStart(p_sys->au_unit);
1226     }
1227 }
1228
1229 static void Flush(audio_output_t *p_aout, bool wait)
1230 {
1231     struct aout_sys_t * p_sys = p_aout->sys;
1232     VLC_UNUSED(wait);
1233
1234     p_sys->b_got_first_sample = false;
1235
1236     /* flush circular buffer */
1237     AudioOutputUnitStop(p_aout->sys->au_unit);
1238     TPCircularBufferClear(&p_aout->sys->circular_buffer);
1239
1240     p_sys->i_played_length = 0;
1241     p_sys->i_last_sample_time = 0;
1242 }
1243
1244 static int TimeGet(audio_output_t *p_aout, mtime_t *delay)
1245 {
1246     struct aout_sys_t * p_sys = p_aout->sys;
1247
1248     vlc_mutex_lock(&p_sys->lock);
1249     mtime_t i_pos = p_sys->i_last_sample_time * CLOCK_FREQ / p_sys->i_rate;
1250     vlc_mutex_unlock(&p_sys->lock);
1251
1252     if (i_pos > 0) {
1253         *delay = p_aout->sys->i_played_length - i_pos;
1254         return 0;
1255     }
1256     else
1257         return -1;
1258 }
1259
1260 /*****************************************************************************
1261  * RenderCallbackAnalog: This function is called everytime the AudioUnit wants
1262  * us to provide some more audio data.
1263  * Don't print anything during normal playback, calling blocking function from
1264  * this callback is not allowed.
1265  *****************************************************************************/
1266 static OSStatus RenderCallbackAnalog(vlc_object_t *p_obj,
1267                                     AudioUnitRenderActionFlags *ioActionFlags,
1268                                     const AudioTimeStamp *inTimeStamp,
1269                                     UInt32 inBusNumber,
1270                                     UInt32 inNumberFrames,
1271                                     AudioBufferList *ioData) {
1272     VLC_UNUSED(ioActionFlags);
1273     VLC_UNUSED(inTimeStamp);
1274     VLC_UNUSED(inBusNumber);
1275
1276     audio_output_t * p_aout = (audio_output_t *)p_obj;
1277     struct aout_sys_t * p_sys = p_aout->sys;
1278
1279     int bytesToCopy = ioData->mBuffers[0].mDataByteSize;
1280     Float32 *targetBuffer = (Float32*)ioData->mBuffers[0].mData;
1281
1282     /* Pull audio from buffer */
1283     int32_t availableBytes;
1284     Float32 *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
1285
1286     /* check if we have enough data */
1287     if (!availableBytes) {
1288         /* return an empty buffer so silence is played until we have data */
1289         for (UInt32 j = 0; j < inNumberFrames; j++)
1290             targetBuffer[j] = 0.;
1291     } else {
1292         memcpy(targetBuffer, buffer, __MIN(bytesToCopy, availableBytes));
1293         TPCircularBufferConsume(&p_sys->circular_buffer, __MIN(bytesToCopy, availableBytes));
1294         VLC_UNUSED(inNumberFrames);
1295         vlc_mutex_lock(&p_sys->lock);
1296         p_sys->i_last_sample_time = inTimeStamp->mSampleTime;
1297         vlc_mutex_unlock(&p_sys->lock);
1298     }
1299
1300     return noErr;
1301 }
1302
1303 /*
1304  * RenderCallbackSPDIF: callback for SPDIF audio output
1305  */
1306 static OSStatus RenderCallbackSPDIF (AudioDeviceID inDevice,
1307                                     const AudioTimeStamp * inNow,
1308                                     const void * inInputData,
1309                                     const AudioTimeStamp * inInputTime,
1310                                     AudioBufferList * outOutputData,
1311                                     const AudioTimeStamp * inOutputTime,
1312                                     void * threadGlobals)
1313 {
1314     VLC_UNUSED(inNow);
1315     VLC_UNUSED(inDevice);
1316     VLC_UNUSED(inInputData);
1317     VLC_UNUSED(inInputTime);
1318
1319     audio_output_t * p_aout = (audio_output_t *)threadGlobals;
1320     struct aout_sys_t * p_sys = p_aout->sys;
1321
1322     int bytesToCopy = outOutputData->mBuffers[p_sys->i_stream_index].mDataByteSize;
1323     Float32 *targetBuffer = (Float32*)outOutputData->mBuffers[p_sys->i_stream_index].mData;
1324
1325     /* Pull audio from buffer */
1326     int32_t availableBytes;
1327     Float32 *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
1328
1329     /* check if we have enough data */
1330     if (!availableBytes) {
1331         /* return an empty buffer so silence is played until we have data */
1332         memset(targetBuffer, 0, outOutputData->mBuffers[p_sys->i_stream_index].mDataByteSize);
1333     } else {
1334         memcpy(targetBuffer, buffer, __MIN(bytesToCopy, availableBytes));
1335         TPCircularBufferConsume(&p_sys->circular_buffer, __MIN(bytesToCopy, availableBytes));
1336         vlc_mutex_lock(&p_sys->lock);
1337         p_sys->i_last_sample_time = inOutputTime->mSampleTime;
1338         vlc_mutex_unlock(&p_sys->lock);
1339     }
1340
1341     return noErr;
1342 }
1343
1344 #pragma mark -
1345 #pragma mark Stream / Hardware Listeners
1346
1347 /*
1348  * HardwareListener: Warns us of changes in the list of registered devices
1349  */
1350 static OSStatus HardwareListener(AudioObjectID inObjectID,  UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void*inClientData)
1351 {
1352     OSStatus err = noErr;
1353     audio_output_t     *p_aout = (audio_output_t *)inClientData;
1354     VLC_UNUSED(inObjectID);
1355     VLC_UNUSED(inNumberAddresses);
1356     VLC_UNUSED(inAddresses);
1357
1358     if (!p_aout)
1359         return -1;
1360
1361 #ifndef NDEBUG
1362     for (unsigned int i = 0; i < inNumberAddresses; i++) {
1363         switch (inAddresses[i].mSelector) {
1364             case kAudioHardwarePropertyDevices:
1365                 msg_Warn(p_aout, "audio device configuration changed, resetting cache");
1366                 break;
1367
1368             case kAudioDevicePropertyDeviceIsAlive:
1369                 msg_Warn(p_aout, "audio device died, resetting aout");
1370                 break;
1371
1372             case kAudioStreamPropertyAvailablePhysicalFormats:
1373                 msg_Warn(p_aout, "available physical formats for audio device changed, resetting aout");
1374                 break;
1375
1376             default:
1377                 msg_Warn(p_aout, "device reset for unknown reason (%i)", inAddresses[i].mSelector);
1378                 break;
1379         }
1380     }
1381 #endif
1382
1383     RebuildDeviceList(p_aout);
1384     aout_RestartRequest(p_aout, AOUT_RESTART_OUTPUT);
1385
1386     return err;
1387 }
1388
1389 /*
1390  * StreamListener: check whether the device's physical format changes on-the-fly (unlikely)
1391  */
1392 static OSStatus StreamListener(AudioObjectID inObjectID,  UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void*inClientData)
1393 {
1394     OSStatus err = noErr;
1395     struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
1396
1397     VLC_UNUSED(inObjectID);
1398
1399     for (unsigned int i = 0; i < inNumberAddresses; i++) {
1400         if (inAddresses[i].mSelector == kAudioStreamPropertyPhysicalFormat) {
1401             vlc_mutex_lock(&w->lock);
1402             vlc_cond_signal(&w->cond);
1403             vlc_mutex_unlock(&w->lock);
1404             break;
1405         }
1406     }
1407     return err;
1408 }
1409
1410 #pragma mark -
1411 #pragma mark helpers
1412
1413 /*
1414  * AudioDeviceHasOutput: Checks if the device is actually an output device
1415  */
1416 static int AudioDeviceHasOutput(AudioDeviceID i_dev_id)
1417 {
1418     UInt32 dataSize = 0;
1419     OSStatus status;
1420
1421     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
1422     status = AudioObjectGetPropertyDataSize(i_dev_id, &streamsAddress, 0, NULL, &dataSize);
1423
1424     if (dataSize == 0 || status != noErr)
1425         return FALSE;
1426
1427     return TRUE;
1428 }
1429
1430 /*
1431  * AudioDeviceSupportsDigital: Checks if device supports raw bitstreams
1432  */
1433 static int AudioDeviceSupportsDigital(audio_output_t *p_aout, AudioDeviceID i_dev_id)
1434 {
1435     OSStatus                    err = noErr;
1436     UInt32                      i_param_size = 0;
1437     AudioStreamID               *p_streams = NULL;
1438     int                         i_streams = 0;
1439     bool                        b_return = false;
1440
1441     /* Retrieve all the output streams */
1442     AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
1443     err = AudioObjectGetPropertyDataSize(i_dev_id, &streamsAddress, 0, NULL, &i_param_size);
1444     if (err != noErr) {
1445         msg_Err(p_aout, "could not get number of streams: [%s] (%i)", (char *)&err, (int32_t)err);
1446         return false;
1447     }
1448
1449     i_streams = i_param_size / sizeof(AudioStreamID);
1450     p_streams = (AudioStreamID *)malloc(i_param_size);
1451     if (p_streams == NULL)
1452         return VLC_ENOMEM;
1453
1454     err = AudioObjectGetPropertyData(i_dev_id, &streamsAddress, 0, NULL, &i_param_size, p_streams);
1455     if (err != noErr) {
1456         msg_Err(p_aout, "could not get list of streams: [%s]", (char *)&err);
1457         return false;
1458     }
1459
1460     for (int i = 0; i < i_streams; i++) {
1461         if (AudioStreamSupportsDigital(p_aout, p_streams[i]))
1462             b_return = true;
1463     }
1464
1465     free(p_streams);
1466     return b_return;
1467 }
1468
1469 /*
1470  * AudioStreamSupportsDigital: Checks if audio stream is compatible with raw bitstreams
1471  */
1472 static int AudioStreamSupportsDigital(audio_output_t *p_aout, AudioStreamID i_stream_id)
1473 {
1474     OSStatus                    err = noErr;
1475     UInt32                      i_param_size = 0;
1476     AudioStreamRangedDescription *p_format_list = NULL;
1477     int                         i_formats = 0;
1478     bool                        b_return = false;
1479
1480     /* Retrieve all the stream formats supported by each output stream */
1481     AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioObjectPropertyScopeGlobal, 0 };
1482     err = AudioObjectGetPropertyDataSize(i_stream_id, &physicalFormatsAddress, 0, NULL, &i_param_size);
1483     if (err != noErr) {
1484         msg_Err(p_aout, "could not get number of streamformats: [%s] (%i)", (char *)&err, (int32_t)err);
1485         return false;
1486     }
1487
1488     i_formats = i_param_size / sizeof(AudioStreamRangedDescription);
1489     msg_Dbg(p_aout, "found %i stream formats", i_formats);
1490
1491     p_format_list = (AudioStreamRangedDescription *)malloc(i_param_size);
1492     if (p_format_list == NULL)
1493         return false;
1494
1495     err = AudioObjectGetPropertyData(i_stream_id, &physicalFormatsAddress, 0, NULL, &i_param_size, p_format_list);
1496     if (err != noErr) {
1497         msg_Err(p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err);
1498         free(p_format_list);
1499         p_format_list = NULL;
1500         return false;
1501     }
1502
1503     for (int i = 0; i < i_formats; i++) {
1504 #ifndef NDEBUG
1505         msg_Dbg(p_aout, STREAM_FORMAT_MSG("supported format: ", p_format_list[i].mFormat));
1506 #endif
1507
1508         if (p_format_list[i].mFormat.mFormatID == 'IAC3' ||
1509             p_format_list[i].mFormat.mFormatID == 'iac3' ||
1510             p_format_list[i].mFormat.mFormatID == kAudioFormat60958AC3 ||
1511             p_format_list[i].mFormat.mFormatID == kAudioFormatAC3)
1512             b_return = true;
1513     }
1514
1515     free(p_format_list);
1516     return b_return;
1517 }
1518
1519 /*
1520  * AudioStreamChangeFormat: switch stream format based on the provided description
1521  */
1522 static int AudioStreamChangeFormat(audio_output_t *p_aout, AudioStreamID i_stream_id, AudioStreamBasicDescription change_format)
1523 {
1524     OSStatus            err = noErr;
1525     UInt32              i_param_size = 0;
1526
1527     AudioObjectPropertyAddress physicalFormatAddress = { kAudioStreamPropertyPhysicalFormat, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1528
1529     struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
1530
1531     msg_Dbg(p_aout, STREAM_FORMAT_MSG("setting stream format: ", change_format));
1532
1533     /* Condition because SetProperty is asynchronious */
1534     vlc_cond_init(&w.cond);
1535     vlc_mutex_init(&w.lock);
1536     vlc_mutex_lock(&w.lock);
1537
1538     /* Install the callback */
1539     err = AudioObjectAddPropertyListener(i_stream_id, &physicalFormatAddress, StreamListener, (void *)&w);
1540     if (err != noErr) {
1541         msg_Err(p_aout, "AudioObjectAddPropertyListener for kAudioStreamPropertyPhysicalFormat failed: [%4.4s]", (char *)&err);
1542         return false;
1543     }
1544
1545     /* change the format */
1546     err = AudioObjectSetPropertyData(i_stream_id, &physicalFormatAddress, 0, NULL, sizeof(AudioStreamBasicDescription),
1547                                      &change_format);
1548     if (err != noErr) {
1549         msg_Err(p_aout, "could not set the stream format: [%4.4s]", (char *)&err);
1550         return false;
1551     }
1552
1553     /* The AudioStreamSetProperty is not only asynchronious (requiring the locks)
1554      * it is also not atomic in its behaviour.
1555      * Therefore we check 5 times before we really give up.
1556      * FIXME: failing isn't actually implemented yet. */
1557     for (int i = 0; i < 5; i++) {
1558         AudioStreamBasicDescription actual_format;
1559         mtime_t timeout = mdate() + 500000;
1560
1561         if (vlc_cond_timedwait(&w.cond, &w.lock, timeout))
1562             msg_Dbg(p_aout, "reached timeout");
1563
1564         i_param_size = sizeof(AudioStreamBasicDescription);
1565         err = AudioObjectGetPropertyData(i_stream_id, &physicalFormatAddress, 0, NULL, &i_param_size, &actual_format);
1566
1567         msg_Dbg(p_aout, STREAM_FORMAT_MSG("actual format in use: ", actual_format));
1568         if (actual_format.mSampleRate == change_format.mSampleRate &&
1569             actual_format.mFormatID == change_format.mFormatID &&
1570             actual_format.mFramesPerPacket == change_format.mFramesPerPacket) {
1571             /* The right format is now active */
1572             break;
1573         }
1574         /* We need to check again */
1575     }
1576
1577     /* Removing the property listener */
1578     err = AudioObjectRemovePropertyListener(i_stream_id, &physicalFormatAddress, StreamListener, (void *)&w);
1579     if (err != noErr) {
1580         msg_Err(p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err);
1581         return false;
1582     }
1583
1584     /* Destroy the lock and condition */
1585     vlc_mutex_unlock(&w.lock);
1586     vlc_mutex_destroy(&w.lock);
1587     vlc_cond_destroy(&w.cond);
1588
1589     return true;
1590 }