]> git.sesse.net Git - vlc/blob - modules/gui/macosx/aout.m
f9f6071720a62983cd9acf16e062699c11ec8a32
[vlc] / modules / gui / macosx / aout.m
1 /*****************************************************************************
2  * aout.m: CoreAudio output plugin
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: aout.m,v 1.25 2003/03/14 00:06:02 massiot Exp $
6  *
7  * Authors: Colin Delacroix <colin@zoy.org>
8  *          Jon Lech Johansen <jon-vl@nanocrew.net>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *          Heiko Panther <heiko.panther@web.de>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/aout.h>
35
36 #include "aout_internal.h"
37
38 #include <Carbon/Carbon.h>
39 #include <CoreAudio/HostTime.h>
40 #include <CoreAudio/AudioHardware.h>
41
42 #define A52_FRAME_NB 1536
43
44 #define STREAM_FORMAT_MSG( pre, sfm ) \
45     pre ": [%ld][%4.4s][%ld][%ld][%ld][%ld][%ld][%ld]", \
46     (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
47     sfm.mFormatFlags, sfm.mBytesPerPacket, \
48     sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
49     sfm.mChannelsPerFrame, sfm.mBitsPerChannel
50
51 /*****************************************************************************
52  * aout_class_t 
53  ****************************************************************************/
54 enum AudioDeviceClass
55 {
56     AudioDeviceClassA52     = 1 << 0,
57     AudioDeviceClassPCM2    = 1 << 1,
58     AudioDeviceClassPCM4    = 1 << 2,
59     AudioDeviceClassPCM6    = 1 << 3, 
60     AudioDeviceClassPCM8    = 1 << 4
61 };
62
63 static struct aout_class_t
64 {
65     UInt32 mFormatID;
66     UInt32 mChannelsPerFrame;
67     enum AudioDeviceClass class;
68     const char * psz_class;
69 }
70 aout_classes[] =
71 {
72     { /* old A/52 format type */
73         'IAC3', 
74         2, 
75         AudioDeviceClassA52, 
76         "Digital A/52" 
77     },
78
79     { /* new A/52 format type */
80         kAudioFormat60958AC3, 
81         2, 
82         AudioDeviceClassA52, 
83         "Digital A/52"
84     },
85
86     {
87         kAudioFormatLinearPCM, 
88         2, 
89         AudioDeviceClassPCM2, 
90         "Stereo PCM"
91     },
92
93     {
94         kAudioFormatLinearPCM,
95         4,
96         AudioDeviceClassPCM4,
97         "4 Channel PCM"
98     },
99
100     {
101         kAudioFormatLinearPCM, 
102         6, 
103         AudioDeviceClassPCM6, 
104         "6 Channel PCM"
105     },
106
107     {
108         kAudioFormatLinearPCM,
109         8,
110         AudioDeviceClassPCM8,
111         "8 Channel PCM"
112     }
113 }; 
114
115 #define N_AOUT_CLASSES (sizeof(aout_classes)/sizeof(aout_classes[0]))
116
117 /*****************************************************************************
118  * aout_option_t
119  ****************************************************************************/
120 struct aout_option_t
121 {
122     char sz_option[64];
123     UInt32 i_dev, i_idx;
124     UInt32 i_sdx, i_cdx;
125     AudioStreamID i_sid;
126 };
127
128 /*****************************************************************************
129  * aout_dev_t
130  ****************************************************************************/
131 struct aout_dev_t
132 {
133     AudioDeviceID devid;
134     char * psz_device_name;
135     UInt32 i_streams;
136     UInt32 * pi_streams;
137     AudioStreamBasicDescription ** pp_streams;
138 };
139
140 /*****************************************************************************
141  * aout_sys_t: private audio output method descriptor
142  *****************************************************************************
143  * This structure is part of the audio output thread descriptor.
144  * It describes the CoreAudio specific properties of an output thread.
145  *****************************************************************************/
146 struct aout_sys_t
147 {
148     vlc_mutex_t                 lock;
149     vlc_bool_t                  b_hwinfo;
150     UInt32                      i_def_dev;
151     UInt32                      i_devices;
152     struct aout_dev_t *         p_devices;
153     UInt32                      i_sel_opt;
154     UInt32                      i_options;
155     struct aout_option_t *      p_options;
156
157     AudioDeviceID               devid;
158     AudioStreamBasicDescription stream_format;
159     UInt32                      b_dev_alive;
160
161     UInt32                      i_buffer_size;
162     mtime_t                     clock_diff;
163 };
164
165 /*****************************************************************************
166  * Local prototypes.
167  *****************************************************************************/
168 static int      InitHardwareInfo ( aout_instance_t * p_aout );
169 static int      InitDeviceInfo   ( UInt32 i_dev, aout_instance_t * p_aout ); 
170 static void     FreeDeviceInfo   ( UInt32 i_dev, aout_instance_t * p_aout ); 
171 static void     FreeHardwareInfo ( aout_instance_t * p_aout );
172 static int      InitDevice       ( aout_instance_t * p_aout );
173 static void     FreeDevice       ( aout_instance_t * p_aout );
174 static int      GetStreamID      ( AudioDeviceID devid, UInt32 i_idx,
175                                    AudioStreamID * p_sid );
176 static int      InitStreamInfo   ( UInt32 i_dev, aout_instance_t * p_aout,
177                                    UInt32 i_idx );
178 static void     FreeStreamInfo   ( UInt32 i_dev, aout_instance_t * p_aout,
179                                    UInt32 i_idx );
180 static void     InitDeviceVar    ( aout_instance_t * p_aout, int i_option,
181                                    vlc_bool_t b_change );
182
183 static void     Play             ( aout_instance_t * p_aout );
184
185 static OSStatus IOCallback       ( AudioDeviceID inDevice,
186                                    const AudioTimeStamp * inNow, 
187                                    const void * inInputData, 
188                                    const AudioTimeStamp * inInputTime,
189                                    AudioBufferList * outOutputData, 
190                                    const AudioTimeStamp * inOutputTime, 
191                                    void * threadGlobals );
192
193 static OSStatus HardwareListener ( AudioHardwarePropertyID inPropertyID,
194                                    void * inClientData );
195
196 static OSStatus DeviceListener   ( AudioDeviceID inDevice,
197                                    UInt32 inChannel,
198                                    Boolean isInput,
199                                    AudioDevicePropertyID inPropertyID,
200                                    void * inClientData );
201
202 static OSStatus StreamListener   ( AudioStreamID inStream,
203                                    UInt32 inChannel,
204                                    AudioDevicePropertyID inPropertyID,
205                                    void * inClientData );
206
207 /*****************************************************************************
208  * Open: open a CoreAudio HAL device
209  *****************************************************************************/
210 int E_(OpenAudio)( vlc_object_t * p_this )
211 {
212     OSStatus err;
213     UInt32 i_param_size;
214     struct aout_sys_t * p_sys;
215     aout_instance_t * p_aout = (aout_instance_t *)p_this;
216
217     /* Allocate structure */
218     p_sys = (struct aout_sys_t *)malloc( sizeof( struct aout_sys_t ) );
219     if( p_sys == NULL )
220     {
221         msg_Err( p_aout, "out of memory" );
222         return( VLC_ENOMEM );
223     }
224
225     memset( p_sys, 0, sizeof( struct aout_sys_t ) );
226
227     p_aout->output.p_sys = p_sys;
228     p_aout->output.pf_play = Play;
229
230     vlc_mutex_init( p_aout, &p_sys->lock );
231
232     if( InitHardwareInfo( p_aout ) )
233     {
234         msg_Err( p_aout, "InitHardwareInfo failed" );
235         vlc_mutex_destroy( &p_sys->lock );
236         free( (void *)p_sys );
237         return( VLC_EGENERIC );
238     } 
239
240     if( var_Type( p_aout, "audio-device" ) == 0 )
241     {
242         InitDeviceVar( p_aout, config_GetInt( p_aout, "macosx-adev" ),
243                        VLC_FALSE );
244     }
245
246     if( InitDevice( p_aout ) )
247     {
248         msg_Err( p_aout, "InitDevice failed" );
249         FreeHardwareInfo( p_aout );
250         vlc_mutex_destroy( &p_sys->lock );
251         free( (void *)p_sys );
252         return( VLC_EGENERIC );
253     } 
254
255     /* Get a description of the stream format */
256     i_param_size = sizeof( AudioStreamBasicDescription ); 
257     err = AudioDeviceGetProperty( p_sys->devid, 0, FALSE, 
258                                   kAudioDevicePropertyStreamFormat,
259                                   &i_param_size, &p_sys->stream_format );
260     if( err != noErr )
261     {
262         msg_Err( p_aout, "failed to get stream format: [%4.4s]", 
263                  (char *)&err );
264         FreeDevice( p_aout );
265         FreeHardwareInfo( p_aout );
266         vlc_mutex_destroy( &p_sys->lock );
267         free( (void *)p_sys );
268         return( VLC_EGENERIC );
269     }
270
271     /* Set the output sample rate */
272     p_aout->output.output.i_rate = 
273         (unsigned int)p_sys->stream_format.mSampleRate;
274
275     msg_Dbg( p_aout, STREAM_FORMAT_MSG( "using format",
276                                         p_sys->stream_format ) );
277
278     /* Get the buffer size */
279     i_param_size = sizeof( p_sys->i_buffer_size );
280     err = AudioDeviceGetProperty( p_sys->devid, 0, FALSE, 
281                                   kAudioDevicePropertyBufferSize, 
282                                   &i_param_size, &p_sys->i_buffer_size );
283     if( err != noErr )
284     {
285         msg_Err( p_aout, "failed to get buffer size: [%4.4s]", 
286                  (char *)&err );
287         FreeDevice( p_aout );
288         FreeHardwareInfo( p_aout );
289         vlc_mutex_destroy( &p_sys->lock );
290         free( (void *)p_sys );
291         return( VLC_EGENERIC );
292     }
293
294     msg_Dbg( p_aout, "device buffer size: [%ld]", p_sys->i_buffer_size );
295
296     /* If we do AC3 over SPDIF, set buffer size to one AC3 frame */
297     if( ( p_sys->stream_format.mFormatID == kAudioFormat60958AC3 ||
298           p_sys->stream_format.mFormatID == 'IAC3' ) &&
299         p_sys->i_buffer_size != AOUT_SPDIF_SIZE )
300     {
301         p_sys->i_buffer_size = AOUT_SPDIF_SIZE;
302         i_param_size = sizeof( p_sys->i_buffer_size );
303         err = AudioDeviceSetProperty( p_sys->devid, 0, 0, FALSE,
304                                       kAudioDevicePropertyBufferSize,
305                                       i_param_size, &p_sys->i_buffer_size );
306         if( err != noErr )
307         {
308             msg_Err( p_aout, "failed to set buffer size: [%4.4s]", 
309                      (char *)&err );
310             FreeDevice( p_aout );
311             FreeHardwareInfo( p_aout );
312             vlc_mutex_destroy( &p_sys->lock );
313             free( (void *)p_sys );
314             return( VLC_EGENERIC );
315         }
316
317         msg_Dbg( p_aout, "device buffer size set to: [%ld]", 
318                  p_sys->i_buffer_size );
319     }
320
321     switch( p_sys->stream_format.mFormatID )
322     {
323     case kAudioFormatLinearPCM:
324         p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
325
326         switch( p_sys->stream_format.mChannelsPerFrame )
327         {
328         case 1:
329             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
330             break;
331
332         case 2:
333             p_aout->output.output.i_physical_channels =
334                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
335             break;
336
337         case 4:
338             p_aout->output.output.i_physical_channels =
339                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
340                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
341             break;
342
343         case 6:
344             p_aout->output.output.i_physical_channels =
345                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
346                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
347                 AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
348             break;
349
350         case 8:
351             p_aout->output.output.i_physical_channels =
352                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
353                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
354                 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
355                 AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT;
356             break;
357
358         default:
359             msg_Err( p_aout, "unknown channel count: [%ld]",
360                      p_sys->stream_format.mChannelsPerFrame ); 
361             FreeDevice( p_aout );
362             FreeHardwareInfo( p_aout );
363             vlc_mutex_destroy( &p_sys->lock );
364             free( (void *)p_sys );
365             return( VLC_EGENERIC );
366         }
367
368         p_aout->output.i_nb_samples = (int)( p_sys->i_buffer_size /
369                                       p_sys->stream_format.mBytesPerFrame );
370
371         aout_VolumeSoftInit( p_aout );
372         break;
373
374     case 'IAC3':
375     case kAudioFormat60958AC3:
376         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
377         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
378         p_aout->output.output.i_frame_length = A52_FRAME_NB;
379         p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
380
381         aout_VolumeNoneInit( p_aout );
382         break;
383
384     default:
385         msg_Err( p_aout, "unknown hardware format: [%4.4s]", 
386                  (char *)&p_sys->stream_format.mFormatID );
387         FreeDevice( p_aout );
388         FreeHardwareInfo( p_aout );
389         vlc_mutex_destroy( &p_sys->lock );
390         free( (void *)p_sys );
391         return( VLC_EGENERIC );
392     }
393
394     /* Set buffer frame size */
395     i_param_size = sizeof( p_aout->output.i_nb_samples );
396     err = AudioDeviceSetProperty( p_sys->devid, 0, 0, FALSE,
397                                   kAudioDevicePropertyBufferFrameSize,
398                                   i_param_size,
399                                   &p_aout->output.i_nb_samples );
400     if( err != noErr )
401     {
402         msg_Err( p_aout, "failed to set buffer frame size: [%4.4s]", 
403                  (char *)&err );
404         FreeDevice( p_aout );
405         FreeHardwareInfo( p_aout );
406         vlc_mutex_destroy( &p_sys->lock );
407         free( (void *)p_sys );
408         return( VLC_EGENERIC );
409     }
410
411     msg_Dbg( p_aout, "device buffer frame size set to: [%d]",
412              p_aout->output.i_nb_samples );
413
414     /* Add callback */
415     err = AudioDeviceAddIOProc( p_sys->devid,
416                                 (AudioDeviceIOProc)IOCallback,
417                                 (void *)p_aout );
418     if( err != noErr )
419     {
420         msg_Err( p_aout, "AudioDeviceAddIOProc failed: [%4.4s]",
421                  (char *)&err );
422         FreeDevice( p_aout );
423         FreeHardwareInfo( p_aout );
424         vlc_mutex_destroy( &p_sys->lock );
425         free( (void *)p_sys );
426         return( VLC_EGENERIC );
427     }
428  
429     /* Start device */
430     err = AudioDeviceStart( p_sys->devid, (AudioDeviceIOProc)IOCallback ); 
431     if( err != noErr )
432     {
433         msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]",
434                  (char *)&err );
435
436         err = AudioDeviceRemoveIOProc( p_sys->devid, 
437                                        (AudioDeviceIOProc)IOCallback );
438         if( err != noErr )
439         {
440             msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]",
441                      (char *)&err );
442         }
443
444         FreeDevice( p_aout );
445         FreeHardwareInfo( p_aout );
446         vlc_mutex_destroy( &p_sys->lock );
447         free( (void *)p_sys );
448
449         return( VLC_EGENERIC );
450     }
451
452     err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
453                                             HardwareListener, 
454                                             (void *)p_aout ); 
455     if( err != noErr )
456     {
457         msg_Err( p_aout, "AudioHardwareAddPropertyListener failed: %4.4s",
458                  (char *)&err );
459
460         /* Stop device */
461         err = AudioDeviceStop( p_sys->devid, 
462                                (AudioDeviceIOProc)IOCallback ); 
463         if( err != noErr )
464         {
465             msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]",
466                      (char *)&err );
467         }
468
469         /* Remove callback */
470         err = AudioDeviceRemoveIOProc( p_sys->devid,
471                                        (AudioDeviceIOProc)IOCallback );
472         if( err != noErr )
473         {
474             msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]",
475                      (char *)&err );
476         }
477
478         FreeDevice( p_aout );
479         FreeHardwareInfo( p_aout );
480         vlc_mutex_destroy( &p_sys->lock );
481         free( (void *)p_sys );
482
483         return( VLC_EGENERIC );
484     }
485
486     /* Let's pray for the following operation to be atomic... */
487     p_sys->clock_diff = - (mtime_t)
488         AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000; 
489     p_sys->clock_diff += mdate();
490
491     return( VLC_SUCCESS );
492 }
493
494 /*****************************************************************************
495  * Close: close the CoreAudio HAL device
496  *****************************************************************************/
497 void E_(CloseAudio)( aout_instance_t * p_aout )
498 {
499     OSStatus err; 
500     struct aout_sys_t * p_sys = p_aout->output.p_sys;
501
502     if( p_sys->b_dev_alive )
503     {
504         /* Stop device */
505         err = AudioDeviceStop( p_sys->devid, 
506                                (AudioDeviceIOProc)IOCallback ); 
507         if( err != noErr )
508         {
509             msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]",
510                      (char *)&err );
511         }
512
513         /* Remove callback */
514         err = AudioDeviceRemoveIOProc( p_sys->devid,
515                                        (AudioDeviceIOProc)IOCallback );
516         if( err != noErr )
517         {
518             msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]",
519                      (char *)&err );
520         }
521
522         FreeDevice( p_aout );
523     }
524
525     err = AudioHardwareRemovePropertyListener( kAudioHardwarePropertyDevices,
526                                                HardwareListener );
527     if( err != noErr )
528     {
529         msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]",
530                  (char *)&err );
531     }
532
533     FreeHardwareInfo( p_aout );
534
535     vlc_mutex_destroy( &p_sys->lock );
536
537     free( p_sys );
538 }
539
540 /*****************************************************************************
541  * Play: nothing to do
542  *****************************************************************************/
543 static void Play( aout_instance_t * p_aout )
544 {
545 }
546
547 /*****************************************************************************
548  * IOCallback: callback for audio output
549  *****************************************************************************/
550 static OSStatus IOCallback( AudioDeviceID inDevice,
551                             const AudioTimeStamp * inNow, 
552                             const void * inInputData,
553                             const AudioTimeStamp * inInputTime, 
554                             AudioBufferList * outOutputData,
555                             const AudioTimeStamp * inOutputTime, 
556                             void * threadGlobals )
557 {
558     aout_buffer_t * p_buffer;
559     AudioTimeStamp  host_time;
560     mtime_t         current_date;
561
562     aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
563     struct aout_sys_t * p_sys = p_aout->output.p_sys;
564
565     host_time.mFlags = kAudioTimeStampHostTimeValid;
566     AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time );
567     current_date = p_sys->clock_diff +
568                    AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
569
570 #define B_SPDI (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i'))
571     p_buffer = aout_OutputNextBuffer( p_aout, current_date, B_SPDI );
572 #undef B_SPDI
573
574     if( p_buffer != NULL )
575     {
576         /* move data into output data buffer */
577         BlockMoveData( p_buffer->p_buffer, 
578                        outOutputData->mBuffers[ 0 ].mData, 
579                        p_sys->i_buffer_size );
580
581         aout_BufferFree( p_buffer );
582     }
583     else
584     {
585         if( p_aout->output.output.i_format == VLC_FOURCC('f','l','3','2') )
586         {
587             UInt32 i, i_size = p_sys->i_buffer_size / sizeof(float);
588             float * p = (float *)outOutputData->mBuffers[ 0 ].mData;
589
590             for( i = 0; i < i_size; i++ )
591             {
592                 *p++ = 0.0;
593             }
594         }
595         else
596         {
597             memset( outOutputData->mBuffers[ 0 ].mData, 
598                     0, p_sys->i_buffer_size );
599         }
600     }
601
602     return( noErr );     
603 }
604
605 /*****************************************************************************
606  * InitHardwareInfo
607  *****************************************************************************/
608 static int InitHardwareInfo( aout_instance_t * p_aout )
609 {
610     OSStatus err;
611     UInt32 i, i_param_size;
612     AudioDeviceID devid_def; 
613     AudioDeviceID * p_devices;
614
615     struct aout_sys_t * p_sys = p_aout->output.p_sys;
616
617     vlc_mutex_lock( &p_sys->lock );
618
619     /* Get number of devices */
620     err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
621                                         &i_param_size, NULL );
622     if( err != noErr )
623     {
624         msg_Err( p_aout, "AudioHardwareGetPropertyInfo failed: [%4.4s]",
625                  (char *)&err );
626         vlc_mutex_unlock( &p_sys->lock );
627         return( VLC_EGENERIC );
628     }
629
630     p_sys->i_devices = i_param_size / sizeof( AudioDeviceID );
631
632     if( p_sys->i_devices < 1 )
633     {
634         msg_Err( p_aout, "no devices found" );
635         vlc_mutex_unlock( &p_sys->lock );
636         return( VLC_EGENERIC );
637     }
638
639     msg_Dbg( p_aout, "system has [%ld] device(s)", p_sys->i_devices );
640
641     /* Allocate DeviceID array */
642     p_devices = (AudioDeviceID *)malloc( i_param_size );
643     if( p_devices == NULL )
644     {
645         msg_Err( p_aout, "out of memory" );
646         vlc_mutex_unlock( &p_sys->lock );
647         return( VLC_ENOMEM );
648     }
649
650     /* Populate DeviceID array */
651     err = AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
652                                     &i_param_size, (void *)p_devices );
653     if( err != noErr )
654     {
655         msg_Err( p_aout, "AudioHardwareGetProperty failed: [%4.4s]",
656                  (char *)&err );
657         free( (void *)p_devices );
658         vlc_mutex_unlock( &p_sys->lock );
659         return( VLC_EGENERIC );
660     }
661
662     i_param_size = sizeof( AudioDeviceID );
663     err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
664                                     &i_param_size, (void *)&devid_def );
665     if( err != noErr )
666     {
667         msg_Err( p_aout, "AudioHardwareGetProperty failed: [%4.4s]",
668                  (char *)&err );
669         free( (void *)p_devices );
670         vlc_mutex_unlock( &p_sys->lock );
671         return( VLC_EGENERIC );
672     }
673
674     p_sys->p_devices = (struct aout_dev_t *)
675         malloc( sizeof( struct aout_dev_t ) * p_sys->i_devices ); 
676     if( p_sys->p_devices == NULL )
677     {
678         msg_Err( p_aout, "out of memory" );
679         free( (void *)p_devices );
680         vlc_mutex_unlock( &p_sys->lock );
681         return( VLC_ENOMEM );
682     }    
683
684     p_sys->i_options = 0;
685     p_sys->p_options = NULL;
686
687     for( i = 0; i < p_sys->i_devices; i++ )
688     {
689         p_sys->p_devices[i].devid = p_devices[i];
690
691         if( p_devices[i] == devid_def )
692         {
693             p_sys->i_def_dev = i;
694         }
695
696         if( InitDeviceInfo( i, p_aout ) )
697         {
698             UInt32 j;
699
700             msg_Err( p_aout, "InitDeviceInfo(%ld) failed", i );
701
702             for( j = 0; j < i; j++ )
703             {
704                 FreeDeviceInfo( j, p_aout );
705             }
706     
707             free( (void *)p_sys->p_devices );
708             free( (void *)p_devices );
709
710             vlc_mutex_unlock( &p_sys->lock );
711
712             return( VLC_EGENERIC );
713         }
714     }
715
716     free( (void *)p_devices );
717
718     p_sys->b_hwinfo = VLC_TRUE;
719
720     vlc_mutex_unlock( &p_sys->lock );
721
722     return( VLC_SUCCESS );
723 }
724
725 /*****************************************************************************
726  * InitDeviceInfo
727  *****************************************************************************/
728 static int InitDeviceInfo( UInt32 i_dev, aout_instance_t * p_aout ) 
729 {
730     OSStatus err;
731     UInt32 i, i_param_size;
732     AudioBufferList * p_buffer_list;
733
734     struct aout_sys_t * p_sys = p_aout->output.p_sys;
735     struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
736
737     /* Get length of device name */
738     err = AudioDeviceGetPropertyInfo( p_dev->devid, 0, FALSE, 
739                                       kAudioDevicePropertyDeviceName,
740                                       &i_param_size, NULL ); 
741     if( err != noErr )
742     {
743         msg_Err( p_aout, "AudioDeviceGetPropertyInfo failed: [%4.4s]",
744                  (char *)&err ); 
745         return( VLC_EGENERIC );
746     }
747
748     /* Allocate memory for device name */
749     p_dev->psz_device_name = (char *)malloc( i_param_size );
750     if( p_dev->psz_device_name == NULL )
751     {
752         msg_Err( p_aout, "out of memory" );
753         return( VLC_ENOMEM );
754     }
755
756     /* Get device name */
757     err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
758                                   kAudioDevicePropertyDeviceName,
759                                   &i_param_size, p_dev->psz_device_name ); 
760     if( err != noErr )
761     {
762         msg_Err( p_aout, "AudioDeviceGetProperty failed: [%4.4s]",
763                  (char *)&err );
764         free( (void *)p_dev->psz_device_name );
765         return( VLC_EGENERIC );
766     }
767
768     msg_Dbg( p_aout, "device [%ld] has name [%s]",
769              i_dev, p_dev->psz_device_name );
770
771     err = AudioDeviceGetPropertyInfo( p_dev->devid, 0, FALSE,
772                                       kAudioDevicePropertyStreamConfiguration,
773                                       &i_param_size, NULL );
774     if( err != noErr )
775     {
776         msg_Err( p_aout, "AudioDeviceGetPropertyInfo failed: [%4.4s]",
777                  (char *)&err );
778         free( (void *)p_dev->psz_device_name );
779         return( VLC_EGENERIC );
780     }
781
782     p_buffer_list = (AudioBufferList *)malloc( i_param_size );
783     if( p_buffer_list == NULL )
784     {
785         msg_Err( p_aout, "out of memory" );
786         free( (void *)p_dev->psz_device_name );
787         return( VLC_ENOMEM );
788     }
789
790     err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
791                                   kAudioDevicePropertyStreamConfiguration,
792                                   &i_param_size, p_buffer_list );
793     if( err != noErr )
794     {
795         msg_Err( p_aout, "AudioDeviceGetProperty failed: [%4.4s]",
796                  (char *)&err );
797         free( (void *)p_dev->psz_device_name );
798         free( (void *)p_buffer_list );
799         return( VLC_EGENERIC );
800     }
801
802     p_dev->i_streams = p_buffer_list->mNumberBuffers;
803     free( (void *)p_buffer_list );
804
805     msg_Dbg( p_aout, "device [%ld] has [%ld] streams", 
806              i_dev, p_dev->i_streams ); 
807
808     p_dev->pi_streams = (UInt32 *)malloc( p_dev->i_streams *
809                                           sizeof( *p_dev->pi_streams ) );
810     if( p_dev->pi_streams == NULL )
811     {
812         msg_Err( p_aout, "out of memory" );
813         free( (void *)p_dev->psz_device_name );
814         return( VLC_ENOMEM );
815     }
816
817     p_dev->pp_streams = (AudioStreamBasicDescription **) 
818                         malloc( p_dev->i_streams * 
819                                 sizeof( *p_dev->pp_streams ) );
820     if( p_dev->pp_streams == NULL )
821     {
822         msg_Err( p_aout, "out of memory" );
823         free( (void *)p_dev->psz_device_name );
824         free( (void *)p_dev->pi_streams );
825         return( VLC_ENOMEM );
826     } 
827
828     for( i = 0; i < p_dev->i_streams; i++ )
829     {
830         if( InitStreamInfo( i_dev, p_aout, i ) )
831         {
832             UInt32 j;
833
834             msg_Err( p_aout, "InitStreamInfo(%ld, %ld) failed", i_dev, i );
835
836             for( j = 0; j < i; j++ )
837             {
838                 FreeStreamInfo( i_dev, p_aout, j );
839             }
840
841             free( (void *)p_dev->psz_device_name );
842             free( (void *)p_dev->pi_streams );
843             free( (void *)p_dev->pp_streams );
844
845             return( VLC_EGENERIC );
846         }
847     }
848
849     return( VLC_SUCCESS );
850 }
851
852 /*****************************************************************************
853  * FreeDeviceInfo
854  *****************************************************************************/
855 static void FreeDeviceInfo( UInt32 i_dev, aout_instance_t * p_aout )
856 {
857     UInt32 i;
858
859     struct aout_sys_t * p_sys = p_aout->output.p_sys;
860     struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
861
862     for( i = 0; i < p_dev->i_streams; i++ )
863     {
864         FreeStreamInfo( i_dev, p_aout, i );
865     }
866
867     free( (void *)p_dev->pp_streams );
868     free( (void *)p_dev->pi_streams );
869     free( (void *)p_dev->psz_device_name );
870 }
871
872 /*****************************************************************************
873  * FreeHardwareInfo
874  *****************************************************************************/
875 static void FreeHardwareInfo( aout_instance_t * p_aout )
876 {
877     UInt32 i;
878
879     struct aout_sys_t * p_sys = p_aout->output.p_sys;
880
881     vlc_mutex_lock( &p_sys->lock );
882
883     if( !p_sys->b_hwinfo )
884     {
885         vlc_mutex_unlock( &p_sys->lock );
886         return;
887     }
888
889     for( i = 0; i < p_sys->i_devices; i++ )
890     {
891         FreeDeviceInfo( i, p_aout );
892     }
893
894     free( (void *)p_sys->p_options );
895     free( (void *)p_sys->p_devices );
896
897     p_sys->b_hwinfo = VLC_FALSE;
898
899     vlc_mutex_unlock( &p_sys->lock );
900 }
901
902 /*****************************************************************************
903  * GetStreamID 
904  *****************************************************************************/
905 static int GetStreamID( AudioDeviceID devid, UInt32 i_idx,
906                         AudioStreamID * p_sid )
907 {
908     OSStatus err;
909     UInt32 i_param_size;
910     AudioStreamID * p_stream_list;
911
912     err = AudioDeviceGetPropertyInfo( devid, 0, FALSE,
913                                       kAudioDevicePropertyStreams,
914                                       &i_param_size, NULL );
915     if( err != noErr )
916     {
917         return( VLC_EGENERIC );
918     }
919
920     p_stream_list = (AudioStreamID *)malloc( i_param_size );
921     if( p_stream_list == NULL )
922     {
923         return( VLC_ENOMEM );
924     }
925
926     err = AudioDeviceGetProperty( devid, 0, FALSE,
927                                   kAudioDevicePropertyStreams,
928                                   &i_param_size, p_stream_list );
929     if( err != noErr )
930     {
931         free( (void *)p_stream_list );
932         return( VLC_EGENERIC );
933     }
934
935     *p_sid = p_stream_list[i_idx - 1];
936
937     free( (void *)p_stream_list );
938
939     return( VLC_SUCCESS );
940 }
941
942 /*****************************************************************************
943  * InitStreamInfo
944  *****************************************************************************/
945 static int InitStreamInfo( UInt32 i_dev, aout_instance_t * p_aout,
946                            UInt32 i_idx )
947 {
948     OSStatus err;
949     AudioStreamID i_sid;
950     UInt32 i, j, i_param_size;
951
952     struct aout_sys_t * p_sys = p_aout->output.p_sys;
953     struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
954
955     if( GetStreamID( p_dev->devid, i_idx + 1, &i_sid ) )
956     {
957         msg_Err( p_aout, "GetStreamID(%ld, %ld) failed", i_dev, i_idx );
958         return( VLC_EGENERIC );
959     }
960
961     err = AudioStreamGetPropertyInfo( i_sid, 0,
962                                       kAudioStreamPropertyPhysicalFormats,
963                                       &i_param_size, NULL );
964     if( err != noErr )
965     {
966         msg_Err( p_aout, "AudioStreamGetPropertyInfo failed: [%4.4s]",
967                  (char *)&err );
968         return( VLC_EGENERIC );
969     }
970
971 #define P_STREAMS p_dev->pp_streams[i_idx]
972 #define I_STREAMS p_dev->pi_streams[i_idx]
973
974     I_STREAMS = i_param_size / sizeof( AudioStreamBasicDescription );
975
976     P_STREAMS = (AudioStreamBasicDescription *)malloc( i_param_size );
977     if( P_STREAMS == NULL )
978     {
979         msg_Err( p_aout, "out of memory" );
980         return( VLC_ENOMEM );
981     }
982
983     memset( P_STREAMS, 0, i_param_size );
984
985     err = AudioStreamGetProperty( i_sid, 0,
986                                   kAudioStreamPropertyPhysicalFormats,
987                                   &i_param_size, P_STREAMS );
988     if( err != noErr )
989     {
990         msg_Err( p_aout, "AudioStreamGetProperty failed: [%4.4s]",
991                  (char *)&err );
992         free( (void *)P_STREAMS );
993         return( VLC_EGENERIC );
994     }
995
996     for( j = 0; j < N_AOUT_CLASSES; j++ )
997     {
998         vlc_bool_t b_found = 0;
999
1000         for( i = 0; i < I_STREAMS; i++ )
1001         {
1002             if( j == 0 )
1003             {
1004                 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format",
1005                                                     P_STREAMS[i] ) );
1006             }
1007
1008             if( ( P_STREAMS[i].mFormatID == 'IAC3' ||
1009                   P_STREAMS[i].mFormatID == kAudioFormat60958AC3 ) &&
1010                 !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) 
1011             {
1012                 continue;
1013             }
1014
1015             if( ( P_STREAMS[i].mFormatID != aout_classes[j].mFormatID ) ||
1016                 ( P_STREAMS[i].mChannelsPerFrame != 
1017                   aout_classes[j].mChannelsPerFrame ) )
1018             {
1019                 continue;
1020             }
1021
1022             b_found = 1;
1023             break;
1024         }
1025
1026         if( b_found )
1027         {
1028             p_sys->p_options = (struct aout_option_t *)
1029                                realloc( p_sys->p_options, 
1030                                         ( p_sys->i_options + 1 ) *
1031                                         sizeof( struct aout_option_t ) ); 
1032             if( p_sys->p_options == NULL )
1033             {
1034                 msg_Err( p_aout, "out of memory" );
1035                 free( (void *)P_STREAMS );
1036                 return( VLC_ENOMEM );
1037             }
1038
1039 #define AOUT_OPTION p_sys->p_options[p_sys->i_options]
1040
1041             snprintf( AOUT_OPTION.sz_option,
1042                       sizeof( AOUT_OPTION.sz_option ) / 
1043                       sizeof( AOUT_OPTION.sz_option[0] ) - 1,
1044                       "%ld: %s (%s)", 
1045                       p_sys->i_options,
1046                       p_dev->psz_device_name, 
1047                       aout_classes[j].psz_class );
1048
1049             AOUT_OPTION.i_sid = i_sid;
1050             AOUT_OPTION.i_dev = i_dev; 
1051             AOUT_OPTION.i_idx = i_idx;
1052             AOUT_OPTION.i_sdx = i;
1053             AOUT_OPTION.i_cdx = j;
1054
1055 #undef AOUT_OPTION
1056
1057             p_sys->i_options++;
1058         } 
1059     }
1060
1061 #undef I_STREAMS
1062 #undef P_STREAMS
1063
1064     return( VLC_SUCCESS );
1065 }
1066
1067 /*****************************************************************************
1068  * FreeStreamInfo
1069  *****************************************************************************/
1070 static void FreeStreamInfo( UInt32 i_dev, aout_instance_t * p_aout,
1071                             UInt32 i_idx )
1072 {
1073     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1074     struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
1075
1076     free( (void *)p_dev->pp_streams[i_idx] );
1077 }
1078
1079 /*****************************************************************************
1080  * InitDevice 
1081  *****************************************************************************/
1082 static int InitDevice( aout_instance_t * p_aout ) 
1083 {
1084     OSStatus err;
1085     vlc_value_t val;
1086     unsigned int i_option;
1087     vlc_bool_t b_found = VLC_FALSE;
1088     UInt32 i, i_stream, i_param_size;
1089     AudioStreamBasicDescription desc;
1090
1091     struct aout_dev_t * p_dev;
1092     struct aout_option_t * p_option;
1093     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1094
1095     if( var_Get( p_aout, "audio-device", &val ) < 0 )
1096     {
1097         msg_Err( p_aout, "audio-device var does not exist" );
1098         return( VLC_ENOVAR );
1099     }
1100
1101     if( !sscanf( val.psz_string, "%d:", &i_option ) ||
1102         p_sys->i_options <= i_option )
1103     {
1104         i_option = 0;
1105     }
1106
1107     free( (void *)val.psz_string );
1108
1109     p_option = &p_sys->p_options[i_option];
1110     p_dev = &p_sys->p_devices[p_option->i_dev];
1111
1112     msg_Dbg( p_aout, "getting device [%ld]", p_option->i_dev );
1113
1114     i_param_size = sizeof( p_sys->b_dev_alive );
1115     err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
1116                                   kAudioDevicePropertyDeviceIsAlive,
1117                                   &i_param_size, &p_sys->b_dev_alive );
1118     if( err != noErr )
1119     {
1120         msg_Err( p_aout, "AudioDeviceGetProperty failed: %4.4s",
1121                  (char *)&err );
1122         return( VLC_EGENERIC );
1123     }
1124
1125 #define P_STREAMS p_dev->pp_streams[p_option->i_idx]
1126 #define I_STREAMS p_dev->pi_streams[p_option->i_idx]
1127
1128     for( i = 0; i < I_STREAMS; i++ )
1129     {
1130         if( P_STREAMS[i].mFormatID == 
1131             aout_classes[p_option->i_cdx].mFormatID &&
1132             P_STREAMS[i].mSampleRate == p_aout->output.output.i_rate )  
1133         {
1134             b_found = VLC_TRUE;
1135             break;
1136         }
1137     } 
1138
1139     i_stream = b_found ? i : p_option->i_sdx;
1140
1141     i_param_size = sizeof( desc );
1142     memset( &desc, 0, i_param_size );
1143     err = AudioStreamGetProperty( p_option->i_sid, 0,
1144                                   kAudioStreamPropertyPhysicalFormat,
1145                                   &i_param_size, (void *)&desc );
1146     if( err != noErr )
1147     {
1148         msg_Err( p_aout, "AudioStreamGetPropertyInfo failed: [%4.4s]",
1149                  (char *)&err );
1150         return( VLC_EGENERIC ); 
1151     }
1152
1153     if( memcmp( &P_STREAMS[i_stream], &desc, sizeof( desc ) ) != 0 ) 
1154     {
1155         struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
1156
1157         vlc_cond_init( p_aout, &w.cond );
1158         vlc_mutex_init( p_aout, &w.lock );
1159
1160         err = AudioStreamAddPropertyListener( p_option->i_sid, 0,
1161                                           kAudioStreamPropertyPhysicalFormat,
1162                                           StreamListener, (void *)&w );
1163         if( err != noErr )
1164         {
1165             msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]",
1166                      (char *)&err );
1167             vlc_mutex_destroy( &w.lock );
1168             vlc_cond_destroy( &w.cond );
1169             return( VLC_EGENERIC ); 
1170         }
1171
1172         vlc_mutex_lock( &w.lock );
1173
1174         msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting format",
1175                                             P_STREAMS[i_stream] ) );
1176
1177         err = AudioStreamSetProperty( p_option->i_sid, 0, 0,
1178                                       kAudioStreamPropertyPhysicalFormat,
1179                                       sizeof( P_STREAMS[i_stream] ),
1180                                       &P_STREAMS[i_stream] ); 
1181         if( err != noErr )
1182         {
1183             msg_Err( p_aout, "AudioStreamSetProperty failed: [%4.4s]",
1184                      (char *)&err );
1185             vlc_mutex_unlock( &w.lock );
1186             vlc_mutex_destroy( &w.lock );
1187             vlc_cond_destroy( &w.cond );
1188             return( VLC_EGENERIC );
1189         }
1190
1191         vlc_cond_wait( &w.cond, &w.lock );
1192         vlc_mutex_unlock( &w.lock );
1193
1194         vlc_mutex_destroy( &w.lock );
1195         vlc_cond_destroy( &w.cond );
1196
1197         if( GetStreamID( p_dev->devid, p_option->i_idx + 1, 
1198                          &p_option->i_sid ) )
1199         {
1200             msg_Err( p_aout, "GetStreamID(%ld, %ld) failed", 
1201                      p_option->i_dev, p_option->i_idx );
1202             return( VLC_EGENERIC );
1203         }
1204
1205         err = AudioStreamRemovePropertyListener( p_option->i_sid, 0,
1206                 kAudioStreamPropertyPhysicalFormat, StreamListener );
1207         if( err != noErr )
1208         {
1209             msg_Err( p_aout, 
1210                     "AudioStreamRemovePropertyListener failed: [%4.4s]",
1211                     (char *)&err );
1212
1213             return( VLC_EGENERIC );
1214         }
1215     }
1216
1217 #undef I_STREAMS
1218 #undef P_STREAMS
1219
1220     err = AudioDeviceAddPropertyListener( p_dev->devid, 0, FALSE,
1221                                           kAudioDevicePropertyDeviceIsAlive,
1222                                           DeviceListener, (void *)p_aout );
1223     if( err != noErr )
1224     {
1225         msg_Err( p_aout, "AudioDeviceAddPropertyListener failed: [%4.4s]",
1226                  (char *)&err );
1227         return( VLC_EGENERIC );
1228     } 
1229
1230     config_PutInt( p_aout, "macosx-adev", i_option );
1231
1232     p_sys->i_sel_opt = i_option;
1233     p_sys->devid = p_dev->devid;
1234
1235     return( VLC_SUCCESS );
1236
1237
1238 /*****************************************************************************
1239  * FreeDevice 
1240  *****************************************************************************/
1241 static void FreeDevice( aout_instance_t * p_aout ) 
1242 {
1243     OSStatus err;
1244
1245     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1246
1247     err = AudioDeviceRemovePropertyListener( p_sys->devid, 0, FALSE,
1248                                              kAudioDevicePropertyDeviceIsAlive,
1249                                              DeviceListener );
1250     if( err != noErr )
1251     {
1252         msg_Err( p_aout, "AudioDeviceRemovePropertyListener failed: [%4.4s]",
1253                  (char *)&err );
1254     } 
1255 }
1256
1257 /*****************************************************************************
1258  * HardwareListener 
1259  *****************************************************************************/
1260 static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
1261                                   void * inClientData )
1262 {
1263     OSStatus err = noErr;
1264
1265     aout_instance_t * p_aout = (aout_instance_t *)inClientData;
1266     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1267
1268     switch( inPropertyID )
1269     {
1270         case kAudioHardwarePropertyDevices:
1271         {
1272             UInt32 i_idx = 0;
1273             UInt32 i_sdx = 0;
1274             int i_option = -1;
1275
1276             if( p_sys->b_dev_alive )
1277             {
1278                 i_idx = p_sys->p_options[p_sys->i_sel_opt].i_idx;
1279                 i_sdx = p_sys->p_options[p_sys->i_sel_opt].i_sdx;
1280             }
1281
1282             FreeHardwareInfo( p_aout );
1283
1284             if( InitHardwareInfo( p_aout ) )
1285             {
1286                 msg_Err( p_aout, "InitHardwareInfo failed" );
1287                 break;
1288             }
1289
1290             if( p_sys->b_dev_alive )
1291             {
1292                 UInt32 i;
1293
1294                 for( i = 0; i < p_sys->i_options; i++ )
1295                 {
1296                     if( p_sys->p_devices[p_sys->p_options[i].i_dev].devid ==
1297                         p_sys->devid && p_sys->p_options[i].i_idx == i_idx &&
1298                         p_sys->p_options[i].i_sdx == i_sdx )
1299                     {
1300                         i_option = i;
1301                         break;
1302                     }
1303                 }
1304             }
1305
1306             var_Destroy( p_aout, "audio-device" );
1307             InitDeviceVar( p_aout, i_option, !p_sys->b_dev_alive );
1308         }
1309         break;
1310     }
1311
1312     return( err );
1313 }
1314
1315 /*****************************************************************************
1316  * DeviceListener 
1317  *****************************************************************************/
1318 static OSStatus DeviceListener( AudioDeviceID inDevice,
1319                                 UInt32 inChannel,
1320                                 Boolean isInput,
1321                                 AudioDevicePropertyID inPropertyID,
1322                                 void *inClientData )
1323 {
1324     UInt32 i_param_size;
1325     OSStatus err = noErr;
1326
1327     aout_instance_t * p_aout = (aout_instance_t *)inClientData;
1328     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1329
1330     switch( inPropertyID )
1331     {
1332         case kAudioDevicePropertyDeviceIsAlive:
1333         {
1334             i_param_size = sizeof( p_sys->b_dev_alive );
1335             err = AudioDeviceGetProperty( p_sys->devid, 0, FALSE, 
1336                                           kAudioDevicePropertyDeviceIsAlive,
1337                                           &i_param_size, &p_sys->b_dev_alive );
1338             if( err != noErr )
1339             {
1340                 msg_Err( p_aout, "AudioDeviceGetProperty failed: %4.4s",
1341                          (char *)&err );
1342             }
1343         }
1344         break;
1345     }
1346
1347     return( err );
1348 }
1349
1350 /*****************************************************************************
1351  * StreamListener 
1352  *****************************************************************************/
1353 static OSStatus StreamListener( AudioStreamID inStream,
1354                                 UInt32 inChannel,
1355                                 AudioDevicePropertyID inPropertyID,
1356                                 void * inClientData )
1357 {
1358     OSStatus err = noErr;
1359
1360     struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
1361
1362     switch( inPropertyID )
1363     {
1364         case kAudioStreamPropertyPhysicalFormat:
1365             vlc_mutex_lock( &w->lock );
1366             vlc_cond_signal( &w->cond );
1367             vlc_mutex_unlock( &w->lock ); 
1368             break;
1369
1370         default:
1371             break;
1372     }
1373
1374     return( err );
1375 }
1376
1377 /*****************************************************************************
1378  * InitDeviceVar
1379  *****************************************************************************/
1380 static void InitDeviceVar( aout_instance_t * p_aout, int i_option,
1381                            vlc_bool_t b_change )
1382
1383     UInt32 i;
1384     vlc_value_t val;
1385
1386     struct aout_sys_t * p_sys = p_aout->output.p_sys;
1387
1388     if( i_option == -1 || i_option >= (int)p_sys->i_options )
1389     {
1390         for( i = 0; i < p_sys->i_options; i++ )
1391         {
1392             if( p_sys->p_options[i].i_dev == p_sys->i_def_dev )
1393             {
1394                 i_option = i;
1395                 break;
1396             }
1397         }
1398     }
1399
1400     var_Create( p_aout, "audio-device", VLC_VAR_STRING | 
1401                                         VLC_VAR_HASCHOICE );
1402
1403     for( i = 0; i < p_sys->i_options; i++ )
1404     {
1405         val.psz_string = p_sys->p_options[i].sz_option;
1406         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
1407
1408         if( !b_change && i == (UInt32)i_option )
1409         {
1410             p_sys->i_sel_opt = i;
1411             var_Set( p_aout, "audio-device", val );
1412             config_PutInt( p_aout, "macosx-adev", i_option );
1413         }
1414     }
1415
1416     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart,
1417                      NULL );
1418
1419     if( b_change )
1420     {
1421         val.psz_string = p_sys->p_options[i_option].sz_option;
1422         var_Set( p_aout, "audio-device", val );
1423     }
1424
1425     val.b_bool = VLC_TRUE;
1426     var_Set( p_aout, "intf-change", val );
1427 }