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