coreaudio.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:48k
源码类别:

多媒体

开发平台:

MultiPlatform

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