00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <string.h>
00028 #include <stdlib.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/aout.h>
00032
00033 #include "aout_internal.h"
00034
00035 #include <CoreAudio/CoreAudio.h>
00036 #include <CoreAudio/CoreAudioTypes.h>
00037 #include <AudioUnit/AudioUnitProperties.h>
00038 #include <AudioUnit/AudioUnitParameters.h>
00039 #include <AudioUnit/AudioOutputUnit.h>
00040 #include <AudioToolbox/AudioFormat.h>
00041
00042 #define STREAM_FORMAT_MSG( pre, sfm ) \
00043 pre "[%ld][%4.4s][%ld][%ld][%ld][%ld][%ld][%ld]", \
00044 (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
00045 sfm.mFormatFlags, sfm.mBytesPerPacket, \
00046 sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
00047 sfm.mChannelsPerFrame, sfm.mBitsPerChannel
00048
00049 #define STREAM_FORMAT_MSG_FULL( pre, sfm ) \
00050 pre ":\nsamplerate: [%ld]\nFormatID: [%4.4s]\nFormatFlags: [%ld]\nBypesPerPacket: [%ld]\nFramesPerPacket: [%ld]\nBytesPerFrame: [%ld]\nChannelsPerFrame: [%ld]\nBitsPerChannel[%ld]", \
00051 (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
00052 sfm.mFormatFlags, sfm.mBytesPerPacket, \
00053 sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
00054 sfm.mChannelsPerFrame, sfm.mBitsPerChannel
00055
00056 #define BUFSIZE 0xffffff
00057 #define AOUT_VAR_SPDIF_FLAG 0xf00000
00058
00059
00060
00061
00062
00063
00064
00065 struct aout_sys_t
00066 {
00067 AudioDeviceID i_default_dev;
00068 AudioDeviceID i_selected_dev;
00069 UInt32 i_devices;
00070 vlc_bool_t b_supports_digital;
00071 vlc_bool_t b_digital;
00072 mtime_t clock_diff;
00073
00074 Component au_component;
00075 AudioUnit au_unit;
00076 uint8_t p_remainder_buffer[BUFSIZE];
00077 uint32_t i_read_bytes;
00078 uint32_t i_total_bytes;
00079
00080 pid_t i_hog_pid;
00081 AudioStreamID i_stream_id;
00082 int i_stream_index;
00083 AudioStreamBasicDescription stream_format;
00084 AudioStreamBasicDescription sfmt_revert;
00085 vlc_bool_t b_revert;
00086 vlc_bool_t b_changed_mixing;
00087 };
00088
00089
00090
00091
00092 static int Open ( vlc_object_t * );
00093 static int OpenAnalog ( aout_instance_t * );
00094 static int OpenSPDIF ( aout_instance_t * );
00095 static void Close ( vlc_object_t * );
00096
00097 static void Play ( aout_instance_t * );
00098 static void Probe ( aout_instance_t * );
00099
00100 static int AudioDeviceHasOutput ( AudioDeviceID );
00101 static int AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );
00102 static int AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );
00103
00104 static OSStatus RenderCallbackAnalog ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
00105 unsigned int, unsigned int, AudioBufferList *);
00106 static OSStatus RenderCallbackSPDIF ( AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
00107 AudioBufferList *, const AudioTimeStamp *, void * );
00108 static OSStatus HardwareListener ( AudioHardwarePropertyID, void *);
00109 static OSStatus StreamListener ( AudioStreamID, UInt32,
00110 AudioDevicePropertyID, void * );
00111 static int AudioDeviceCallback ( vlc_object_t *, const char *,
00112 vlc_value_t, vlc_value_t, void * );
00113
00114
00115
00116
00117
00118 #define ADEV_TEXT N_("Audio Device")
00119 #define ADEV_LONGTEXT N_("Choose a number corresponding to the number of an " \
00120 "audio device, as listed in your 'Audio Device' menu. This device will " \
00121 "then be used by default for audio playback.")
00122
00123 vlc_module_begin();
00124 set_shortname( "auhal" );
00125 set_description( _("HAL AudioUnit output") );
00126 set_capability( "audio output", 101 );
00127 set_category( CAT_AUDIO );
00128 set_subcategory( SUBCAT_AUDIO_AOUT );
00129 set_callbacks( Open, Close );
00130 add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE );
00131 vlc_module_end();
00132
00133
00134
00135
00136 static int Open( vlc_object_t * p_this )
00137 {
00138 OSStatus err = noErr;
00139 UInt32 i_param_size = 0;
00140 struct aout_sys_t *p_sys = NULL;
00141 vlc_bool_t b_alive = VLC_FALSE;
00142 vlc_value_t val;
00143 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00144
00145
00146 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
00147 if( p_aout->output.p_sys == NULL )
00148 {
00149 msg_Err( p_aout, "out of memory" );
00150 return( VLC_ENOMEM );
00151 }
00152
00153 p_sys = p_aout->output.p_sys;
00154 p_sys->i_default_dev = 0;
00155 p_sys->i_selected_dev = 0;
00156 p_sys->i_devices = 0;
00157 p_sys->b_supports_digital = VLC_FALSE;
00158 p_sys->b_digital = VLC_FALSE;
00159 p_sys->au_component = NULL;
00160 p_sys->au_unit = NULL;
00161 p_sys->clock_diff = (mtime_t) 0;
00162 p_sys->i_read_bytes = 0;
00163 p_sys->i_total_bytes = 0;
00164 p_sys->i_hog_pid = -1;
00165 p_sys->i_stream_id = 0;
00166 p_sys->i_stream_index = 0;
00167 p_sys->b_revert = VLC_FALSE;
00168 p_sys->b_changed_mixing = VLC_FALSE;
00169 memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
00170
00171 p_aout->output.pf_play = Play;
00172
00173 aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output );
00174
00175
00176 if( var_Type( p_aout->p_vlc, "macosx-audio-device" ) == 0 )
00177 {
00178 msg_Dbg( p_aout, "create macosx-audio-device" );
00179 var_Create( p_aout->p_vlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00180 }
00181
00182
00183 if( var_Type( p_aout, "audio-device" ) == 0 )
00184 {
00185 Probe( p_aout );
00186 }
00187
00188
00189 if( var_Get( p_aout, "audio-device", &val ) < 0 )
00190 {
00191 msg_Err( p_aout, "audio-device var does not exist. device probe failed." );
00192 free( p_sys );
00193 return( VLC_ENOVAR );
00194 }
00195
00196 p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG;
00197 p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? VLC_TRUE : VLC_FALSE;
00198
00199
00200 i_param_size = sizeof( b_alive );
00201 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
00202 kAudioDevicePropertyDeviceIsAlive,
00203 &i_param_size, &b_alive );
00204
00205 if( err != noErr )
00206 {
00207 msg_Err( p_aout, "could not check whether device is alive: %4.4s",
00208 (char *)&err );
00209 return VLC_EGENERIC;
00210 }
00211
00212 if( b_alive == VLC_FALSE )
00213 {
00214 msg_Err( p_aout, "Selected audio device is not alive switching to default device" );
00215 p_sys->i_selected_dev = p_sys->i_default_dev;
00216 }
00217
00218 i_param_size = sizeof( p_sys->i_hog_pid );
00219 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
00220 kAudioDevicePropertyHogMode,
00221 &i_param_size, &p_sys->i_hog_pid );
00222
00223 if( err != noErr )
00224 {
00225 msg_Err( p_aout, "could not check whether device is hogged: %4.4s",
00226 (char *)&err );
00227 return VLC_EGENERIC;
00228 }
00229
00230 if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() )
00231 {
00232 msg_Err( p_aout, "Selected audio device is exclusively in use by another program" );
00233 var_Destroy( p_aout, "audio-device" );
00234 free( p_sys );
00235 return VLC_EGENERIC;
00236 }
00237
00238
00239 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && p_sys->b_supports_digital )
00240 {
00241 if( OpenSPDIF( p_aout ) )
00242 return VLC_SUCCESS;
00243 }
00244 else
00245 {
00246 if( OpenAnalog( p_aout ) )
00247 return VLC_SUCCESS;
00248 }
00249
00250
00251 var_Destroy( p_aout, "audio-device" );
00252 free( p_sys );
00253 return VLC_EGENERIC;
00254 }
00255
00256
00257
00258
00259 static int OpenAnalog( aout_instance_t *p_aout )
00260 {
00261 struct aout_sys_t *p_sys = p_aout->output.p_sys;
00262 OSStatus err = noErr;
00263 UInt32 i_param_size = 0, i = 0;
00264 ComponentDescription desc;
00265
00266 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && !p_sys->b_supports_digital )
00267 {
00268 msg_Dbg( p_aout, "we had requested a digital stream, but it's not possible for this device" );
00269 }
00270
00271
00272
00273 desc.componentType = kAudioUnitType_Output;
00274 desc.componentSubType = kAudioUnitSubType_HALOutput;
00275 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
00276 desc.componentFlags = 0;
00277 desc.componentFlagsMask = 0;
00278
00279 p_sys->au_component = FindNextComponent( NULL, &desc );
00280 if( p_sys->au_component == NULL )
00281 {
00282 msg_Err( p_aout, "we cannot find our HAL component" );
00283 return VLC_FALSE;
00284 }
00285
00286 err = OpenAComponent( p_sys->au_component, &p_sys->au_unit );
00287 if( err )
00288 {
00289 msg_Err( p_aout, "we cannot find our HAL component" );
00290 return VLC_FALSE;
00291 }
00292
00293
00294 msg_Dbg( p_aout, "Device: %#x", (int)p_sys->i_selected_dev );
00295
00296
00297 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
00298 kAudioOutputUnitProperty_CurrentDevice,
00299 kAudioUnitScope_Global,
00300 0,
00301 &p_sys->i_selected_dev,
00302 sizeof( AudioDeviceID )));
00303
00304
00305 AudioStreamBasicDescription DeviceFormat;
00306
00307 i_param_size = sizeof(AudioStreamBasicDescription);
00308
00309 verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
00310 kAudioUnitProperty_StreamFormat,
00311 kAudioUnitScope_Input,
00312 0,
00313 &DeviceFormat,
00314 &i_param_size ));
00315
00316 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: " , DeviceFormat ) );
00317
00318
00319 AudioChannelLayout *layout;
00320 verify_noerr( AudioUnitGetPropertyInfo( p_sys->au_unit,
00321 kAudioDevicePropertyPreferredChannelLayout,
00322 kAudioUnitScope_Output,
00323 0,
00324 &i_param_size,
00325 NULL ));
00326
00327 layout = (AudioChannelLayout *)malloc( i_param_size);
00328
00329 verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
00330 kAudioDevicePropertyPreferredChannelLayout,
00331 kAudioUnitScope_Output,
00332 0,
00333 layout,
00334 &i_param_size ));
00335
00336
00337 if( layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
00338 {
00339 msg_Dbg( p_aout, "bitmap defined channellayout" );
00340 verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForBitmap,
00341 sizeof( UInt32), &layout->mChannelBitmap,
00342 &i_param_size,
00343 layout ));
00344 }
00345 else if( layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
00346 {
00347 msg_Dbg( p_aout, "layouttags defined channellayout" );
00348 verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForTag,
00349 sizeof( AudioChannelLayoutTag ), &layout->mChannelLayoutTag,
00350 &i_param_size,
00351 layout ));
00352 }
00353
00354 msg_Dbg( p_aout, "Layout of AUHAL has %d channels" , (int)layout->mNumberChannelDescriptions );
00355
00356 p_aout->output.output.i_physical_channels = 0;
00357 for( i = 0; i < layout->mNumberChannelDescriptions; i++ )
00358 {
00359 msg_Dbg( p_aout, "This is channel: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
00360
00361 switch( layout->mChannelDescriptions[i].mChannelLabel )
00362 {
00363 case kAudioChannelLabel_Left:
00364 p_aout->output.output.i_physical_channels |= AOUT_CHAN_LEFT;
00365 continue;
00366 case kAudioChannelLabel_Right:
00367 p_aout->output.output.i_physical_channels |= AOUT_CHAN_RIGHT;
00368 continue;
00369 case kAudioChannelLabel_Center:
00370 p_aout->output.output.i_physical_channels |= AOUT_CHAN_CENTER;
00371 continue;
00372 case kAudioChannelLabel_LFEScreen:
00373 p_aout->output.output.i_physical_channels |= AOUT_CHAN_LFE;
00374 continue;
00375 case kAudioChannelLabel_LeftSurround:
00376 p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARLEFT;
00377 continue;
00378 case kAudioChannelLabel_RightSurround:
00379 p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARRIGHT;
00380 continue;
00381 case kAudioChannelLabel_RearSurroundLeft:
00382 p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLELEFT;
00383 continue;
00384 case kAudioChannelLabel_RearSurroundRight:
00385 p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLERIGHT;
00386 continue;
00387 case kAudioChannelLabel_CenterSurround:
00388 p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARCENTER;
00389 continue;
00390 default:
00391 msg_Warn( p_aout, "Unrecognized channel form provided by driver: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
00392 if( i == 0 )
00393 {
00394 msg_Warn( p_aout, "Probably no channellayout is set. force based on channelcount" );
00395 switch( layout->mNumberChannelDescriptions )
00396 {
00397
00398
00399 case 1:
00400 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
00401 break;
00402 case 4:
00403 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00404 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00405 break;
00406 case 6:
00407 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00408 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
00409 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00410 break;
00411 case 7:
00412 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00413 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
00414 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_REARCENTER;
00415 break;
00416 case 8:
00417 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00418 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
00419 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
00420 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00421 break;
00422 case 2:
00423 default:
00424 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00425 }
00426 }
00427 break;
00428 }
00429 }
00430 free( layout );
00431
00432 msg_Dbg( p_aout, "defined %d physical channels for vlc core", aout_FormatNbChannels( &p_aout->output.output ) );
00433 msg_Dbg( p_aout, "%s", aout_FormatPrintChannels( &p_aout->output.output ));
00434
00435 AudioChannelLayout new_layout;
00436 memset (&new_layout, 0, sizeof(new_layout));
00437 switch( aout_FormatNbChannels( &p_aout->output.output ) )
00438 {
00439 case 1:
00440 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
00441 break;
00442 case 2:
00443 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
00444 break;
00445 case 3:
00446 if( p_aout->output.output.i_physical_channels & AOUT_CHAN_CENTER )
00447 {
00448 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_7;
00449 }
00450 else if( p_aout->output.output.i_physical_channels & AOUT_CHAN_LFE )
00451 {
00452 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_4;
00453 }
00454 break;
00455 case 4:
00456 if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER | AOUT_CHAN_LFE ) )
00457 {
00458 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_10;
00459 }
00460 else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT ) )
00461 {
00462 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3;
00463 }
00464 else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER ) )
00465 {
00466 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3;
00467 }
00468 break;
00469 case 5:
00470 if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER ) )
00471 {
00472 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_19;
00473 }
00474 else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_LFE ) )
00475 {
00476 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_18;
00477 }
00478 break;
00479 case 6:
00480 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_20;
00481 break;
00482 case 7:
00483
00484 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A;
00485 break;
00486 case 8:
00487
00488 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
00489 break;
00490 }
00491
00492
00493 DeviceFormat.mSampleRate = p_aout->output.output.i_rate;
00494 DeviceFormat.mFormatID = kAudioFormatLinearPCM;
00495
00496
00497 p_aout->output.output.i_format = VLC_FOURCC( 'f','l','3','2');
00498 DeviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
00499 DeviceFormat.mBitsPerChannel = 32;
00500 DeviceFormat.mChannelsPerFrame = aout_FormatNbChannels( &p_aout->output.output );
00501
00502
00503 aout_FormatPrepare( &p_aout->output.output );
00504 DeviceFormat.mFramesPerPacket = 1;
00505 DeviceFormat.mBytesPerFrame = DeviceFormat.mBitsPerChannel * DeviceFormat.mChannelsPerFrame / 8;
00506 DeviceFormat.mBytesPerPacket = DeviceFormat.mBytesPerFrame * DeviceFormat.mFramesPerPacket;
00507
00508 i_param_size = sizeof(AudioStreamBasicDescription);
00509
00510 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
00511 kAudioUnitProperty_StreamFormat,
00512 kAudioUnitScope_Input,
00513 0,
00514 &DeviceFormat,
00515 i_param_size ));
00516
00517 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "we set the AU format: " , DeviceFormat ) );
00518
00519
00520 verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
00521 kAudioUnitProperty_StreamFormat,
00522 kAudioUnitScope_Input,
00523 0,
00524 &DeviceFormat,
00525 &i_param_size ));
00526
00527 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "the actual set AU format is " , DeviceFormat ) );
00528
00529 p_aout->output.i_nb_samples = 2048;
00530 aout_VolumeSoftInit( p_aout );
00531
00532
00533 p_sys->clock_diff = - (mtime_t)
00534 AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
00535 p_sys->clock_diff += mdate();
00536
00537
00538 AURenderCallbackStruct input;
00539 input.inputProc = (AURenderCallback) RenderCallbackAnalog;
00540 input.inputProcRefCon = p_aout;
00541
00542 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
00543 kAudioUnitProperty_SetRenderCallback,
00544 kAudioUnitScope_Input,
00545 0, &input, sizeof( input ) ) );
00546
00547 input.inputProc = (AURenderCallback) RenderCallbackAnalog;
00548 input.inputProcRefCon = p_aout;
00549
00550
00551 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
00552 kAudioUnitProperty_AudioChannelLayout,
00553 kAudioUnitScope_Input,
00554 0, &new_layout, sizeof(new_layout) ) );
00555
00556
00557 verify_noerr( AudioUnitInitialize(p_sys->au_unit) );
00558
00559 verify_noerr( AudioOutputUnitStart(p_sys->au_unit) );
00560
00561 return VLC_TRUE;
00562 }
00563
00564
00565
00566
00567 static int OpenSPDIF( aout_instance_t * p_aout )
00568 {
00569 struct aout_sys_t *p_sys = p_aout->output.p_sys;
00570 OSStatus err = noErr;
00571 UInt32 i_param_size = 0, b_mix = 0;
00572 Boolean b_writeable = VLC_FALSE;
00573 AudioStreamID *p_streams = NULL;
00574 int i = 0, i_streams = 0;
00575
00576 struct timeval now;
00577 struct timespec timeout;
00578 struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
00579
00580
00581 p_sys->b_digital = VLC_TRUE;
00582 msg_Dbg( p_aout, "opening in SPDIF mode" );
00583
00584
00585 i_param_size = sizeof( p_sys->i_hog_pid );
00586 p_sys->i_hog_pid = getpid() ;
00587
00588 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
00589 kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
00590
00591 if( err != noErr )
00592 {
00593 msg_Err( p_aout, "failed to set hogmode: : [%4.4s]", (char *)&err );
00594 return VLC_FALSE;
00595 }
00596
00597
00598 err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
00599 &i_param_size, &b_writeable );
00600
00601 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
00602 &i_param_size, &b_mix );
00603
00604 if( !err && b_writeable )
00605 {
00606 b_mix = 0;
00607 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
00608 kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
00609 p_sys->b_changed_mixing = VLC_TRUE;
00610 }
00611
00612 if( err != noErr )
00613 {
00614 msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
00615 return VLC_FALSE;
00616 }
00617
00618
00619 err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE,
00620 kAudioDevicePropertyStreams,
00621 &i_param_size, NULL );
00622 if( err != noErr )
00623 {
00624 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
00625 return VLC_FALSE;
00626 }
00627
00628 i_streams = i_param_size / sizeof( AudioStreamID );
00629 p_streams = (AudioStreamID *)malloc( i_param_size );
00630 if( p_streams == NULL )
00631 {
00632 msg_Err( p_aout, "Out of memory" );
00633 return VLC_FALSE;
00634 }
00635
00636 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
00637 kAudioDevicePropertyStreams,
00638 &i_param_size, p_streams );
00639
00640 if( err != noErr )
00641 {
00642 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
00643 if( p_streams ) free( p_streams );
00644 return VLC_FALSE;
00645 }
00646
00647 for( i = 0; i < i_streams; i++ )
00648 {
00649
00650 AudioStreamBasicDescription *p_format_list = NULL;
00651 int i_formats = 0, j = 0;
00652
00653
00654 err = AudioStreamGetPropertyInfo( p_streams[i], 0,
00655 kAudioStreamPropertyPhysicalFormats,
00656 &i_param_size, NULL );
00657 if( err != noErr )
00658 {
00659 msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
00660 continue;
00661 }
00662
00663 i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
00664 p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
00665 if( p_format_list == NULL )
00666 {
00667 msg_Err( p_aout, "Could not malloc the memory" );
00668 continue;
00669 }
00670
00671 err = AudioStreamGetProperty( p_streams[i], 0,
00672 kAudioStreamPropertyPhysicalFormats,
00673 &i_param_size, p_format_list );
00674 if( err != noErr )
00675 {
00676 msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
00677 if( p_format_list) free( p_format_list);
00678 continue;
00679 }
00680
00681 for( j = 0; j < i_formats; j++ )
00682 {
00683 if( p_format_list[j].mFormatID == 'IAC3' ||
00684 p_format_list[j].mFormatID == kAudioFormat60958AC3 )
00685 {
00686
00687 p_sys->i_stream_id = p_streams[i];
00688 p_sys->i_stream_index = i;
00689
00690 if( p_sys->b_revert == VLC_FALSE )
00691 {
00692 i_param_size = sizeof( p_sys->sfmt_revert );
00693 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
00694 kAudioStreamPropertyPhysicalFormat,
00695 &i_param_size,
00696 &p_sys->sfmt_revert );
00697 if( err != noErr )
00698 {
00699 msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
00700 continue;
00701 }
00702 p_sys->b_revert = VLC_TRUE;
00703 }
00704 if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
00705 {
00706 p_sys->stream_format = p_format_list[j];
00707 }
00708 }
00709 }
00710 if( p_format_list ) free( p_format_list );
00711 }
00712
00713 if( p_streams ) free( p_streams );
00714
00715 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "original stream format: ", p_sys->sfmt_revert ) );
00716 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->stream_format ) );
00717
00718
00719 err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
00720 kAudioStreamPropertyPhysicalFormat,
00721 StreamListener, (void *)&w );
00722 if( err != noErr )
00723 {
00724 msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
00725 return VLC_FALSE;
00726 }
00727
00728
00729 vlc_cond_init( p_aout, &w.cond );
00730 vlc_mutex_init( p_aout, &w.lock );
00731 vlc_mutex_lock( &w.lock );
00732
00733
00734 err = AudioStreamSetProperty( p_sys->i_stream_id, 0, 0,
00735 kAudioStreamPropertyPhysicalFormat,
00736 sizeof( AudioStreamBasicDescription ),
00737 &p_sys->stream_format );
00738 if( err != noErr )
00739 {
00740 msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
00741 vlc_mutex_unlock( &w.lock );
00742 vlc_mutex_destroy( &w.lock );
00743 vlc_cond_destroy( &w.cond );
00744 return VLC_FALSE;
00745 }
00746
00747 gettimeofday( &now, NULL );
00748 timeout.tv_sec = now.tv_sec;
00749 timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
00750
00751 pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
00752 vlc_mutex_unlock( &w.lock );
00753
00754 err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
00755 kAudioStreamPropertyPhysicalFormat,
00756 StreamListener );
00757 if( err != noErr )
00758 {
00759 msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
00760 vlc_mutex_destroy( &w.lock );
00761 vlc_cond_destroy( &w.cond );
00762 return VLC_FALSE;
00763 }
00764
00765 vlc_mutex_destroy( &w.lock );
00766 vlc_cond_destroy( &w.cond );
00767
00768 i_param_size = sizeof( AudioStreamBasicDescription );
00769 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
00770 kAudioStreamPropertyPhysicalFormat,
00771 &i_param_size,
00772 &p_sys->stream_format );
00773
00774 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
00775
00776
00777 if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
00778 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','b');
00779 else
00780 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
00781 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
00782 p_aout->output.output.i_frame_length = A52_FRAME_NB;
00783 p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
00784 p_aout->output.output.i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
00785
00786 aout_VolumeNoneInit( p_aout );
00787
00788
00789 err = AudioDeviceAddIOProc( p_sys->i_selected_dev,
00790 (AudioDeviceIOProc)RenderCallbackSPDIF,
00791 (void *)p_aout );
00792 if( err != noErr )
00793 {
00794 msg_Err( p_aout, "AudioDeviceAddIOProc failed: [%4.4s]", (char *)&err );
00795 return VLC_FALSE;
00796 }
00797
00798
00799 p_sys->clock_diff = - (mtime_t)
00800 AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
00801 p_sys->clock_diff += mdate();
00802
00803
00804 err = AudioDeviceStart( p_sys->i_selected_dev, (AudioDeviceIOProc)RenderCallbackSPDIF );
00805 if( err != noErr )
00806 {
00807 msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err );
00808
00809 err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
00810 (AudioDeviceIOProc)RenderCallbackSPDIF );
00811 if( err != noErr )
00812 {
00813 msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
00814 }
00815 return VLC_FALSE;
00816 }
00817
00818 return VLC_TRUE;
00819 }
00820
00821
00822
00823
00824
00825 static void Close( vlc_object_t * p_this )
00826 {
00827 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00828 struct aout_sys_t *p_sys = p_aout->output.p_sys;
00829 OSStatus err = noErr;
00830 UInt32 i_param_size = 0;
00831
00832 if( p_sys->au_unit )
00833 {
00834 verify_noerr( AudioOutputUnitStop( p_sys->au_unit ) );
00835 verify_noerr( AudioUnitUninitialize( p_sys->au_unit ) );
00836 verify_noerr( CloseComponent( p_sys->au_unit ) );
00837 }
00838
00839 if( p_sys->b_digital )
00840 {
00841
00842 err = AudioDeviceStop( p_sys->i_selected_dev,
00843 (AudioDeviceIOProc)RenderCallbackSPDIF );
00844 if( err != noErr )
00845 {
00846 msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
00847 }
00848
00849
00850 err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
00851 (AudioDeviceIOProc)RenderCallbackSPDIF );
00852 if( err != noErr )
00853 {
00854 msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
00855 }
00856
00857 if( p_sys->b_revert )
00858 {
00859 struct timeval now;
00860 struct timespec timeout;
00861 struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
00862
00863
00864 err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
00865 kAudioStreamPropertyPhysicalFormat,
00866 StreamListener, (void *)&w );
00867 if( err != noErr )
00868 {
00869 msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
00870 }
00871
00872
00873 vlc_cond_init( p_aout, &w.cond );
00874 vlc_mutex_init( p_aout, &w.lock );
00875 vlc_mutex_lock( &w.lock );
00876
00877 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->sfmt_revert ) );
00878
00879 err = AudioStreamSetProperty( p_sys->i_stream_id, NULL, 0,
00880 kAudioStreamPropertyPhysicalFormat,
00881 sizeof( AudioStreamBasicDescription ),
00882 &p_sys->sfmt_revert );
00883
00884 if( err != noErr )
00885 {
00886 msg_Err( p_aout, "Streamformat reverse failed: [%4.4s]", (char *)&err );
00887 }
00888
00889 gettimeofday( &now, NULL );
00890 timeout.tv_sec = now.tv_sec;
00891 timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
00892
00893 pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
00894 vlc_mutex_unlock( &w.lock );
00895
00896 err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
00897 kAudioStreamPropertyPhysicalFormat,
00898 StreamListener );
00899 if( err != noErr )
00900 {
00901 msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
00902 }
00903
00904 vlc_mutex_destroy( &w.lock );
00905 vlc_cond_destroy( &w.cond );
00906
00907 i_param_size = sizeof( AudioStreamBasicDescription );
00908 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
00909 kAudioStreamPropertyPhysicalFormat,
00910 &i_param_size,
00911 &p_sys->stream_format );
00912
00913 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
00914 }
00915 if( p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3 )
00916 {
00917 int b_mix;
00918 Boolean b_writeable;
00919
00920 err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
00921 &i_param_size, &b_writeable );
00922
00923 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
00924 &i_param_size, &b_mix );
00925
00926 if( !err && b_writeable )
00927 {
00928 msg_Dbg( p_aout, "mixable is: %d", b_mix );
00929 b_mix = 1;
00930 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
00931 kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
00932 }
00933
00934 if( err != noErr )
00935 {
00936 msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
00937 }
00938 }
00939 }
00940
00941 err = AudioHardwareRemovePropertyListener( kAudioHardwarePropertyDevices,
00942 HardwareListener );
00943
00944 if( err != noErr )
00945 {
00946 msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err );
00947 }
00948
00949 if( p_sys->i_hog_pid == getpid() )
00950 {
00951 p_sys->i_hog_pid = -1;
00952 i_param_size = sizeof( p_sys->i_hog_pid );
00953 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
00954 kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
00955 if( err != noErr ) msg_Err( p_aout, "Could not release hogmode: [%4.4s]", (char *)&err );
00956 }
00957
00958 if( p_sys ) free( p_sys );
00959 }
00960
00961
00962
00963
00964 static void Play( aout_instance_t * p_aout )
00965 {
00966 }
00967
00968
00969
00970
00971
00972 static void Probe( aout_instance_t * p_aout )
00973 {
00974 OSStatus err = noErr;
00975 UInt32 i = 0, i_param_size = 0;
00976 AudioDeviceID devid_def = 0;
00977 AudioDeviceID *p_devices = NULL;
00978 vlc_value_t val, text;
00979
00980 struct aout_sys_t *p_sys = p_aout->output.p_sys;
00981
00982
00983 err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
00984 &i_param_size, NULL );
00985 if( err != noErr )
00986 {
00987 msg_Err( p_aout, "could not get number of devices: [%4.4s]", (char *)&err );
00988 goto error;
00989 }
00990
00991 p_sys->i_devices = i_param_size / sizeof( AudioDeviceID );
00992
00993 if( p_sys->i_devices < 1 )
00994 {
00995 msg_Err( p_aout, "no devices found" );
00996 goto error;
00997 }
00998
00999 msg_Dbg( p_aout, "system has [%ld] device(s)", p_sys->i_devices );
01000
01001
01002 p_devices = (AudioDeviceID*)malloc( sizeof(AudioDeviceID) * p_sys->i_devices );
01003 if( p_devices == NULL )
01004 {
01005 msg_Err( p_aout, "out of memory" );
01006 goto error;
01007 }
01008
01009
01010 err = AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
01011 &i_param_size, p_devices );
01012 if( err != noErr )
01013 {
01014 msg_Err( p_aout, "could not get the device ID's: [%4.4s]", (char *)&err );
01015 goto error;
01016 }
01017
01018
01019 i_param_size = sizeof( AudioDeviceID );
01020 err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
01021 &i_param_size, &devid_def );
01022 if( err != noErr )
01023 {
01024 msg_Err( p_aout, "could not get default audio device: [%4.4s]", (char *)&err );
01025 goto error;
01026 }
01027 p_sys->i_default_dev = devid_def;
01028
01029 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE );
01030 text.psz_string = _("Audio Device");
01031 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
01032
01033 for( i = 0; i < p_sys->i_devices; i++ )
01034 {
01035 char *psz_name;
01036 i_param_size = 0;
01037
01038
01039 err = AudioDeviceGetPropertyInfo(
01040 p_devices[i], 0, VLC_FALSE,
01041 kAudioDevicePropertyDeviceName,
01042 &i_param_size, NULL);
01043 if( err ) goto error;
01044
01045
01046 psz_name = (char *)malloc( i_param_size );
01047 err = AudioDeviceGetProperty(
01048 p_devices[i], 0, VLC_FALSE,
01049 kAudioDevicePropertyDeviceName,
01050 &i_param_size, psz_name);
01051 if( err ) goto error;
01052
01053 msg_Dbg( p_aout, "DevID: %lu DevName: %s", p_devices[i], psz_name );
01054
01055 if( !AudioDeviceHasOutput( p_devices[i]) )
01056 {
01057 msg_Dbg( p_aout, "this device is INPUT only. skipping..." );
01058 continue;
01059 }
01060
01061 val.i_int = (int)p_devices[i];
01062 text.psz_string = strdup( psz_name );
01063 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
01064 if( p_sys->i_default_dev == p_devices[i] )
01065 {
01066 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
01067 var_Set( p_aout, "audio-device", val );
01068 }
01069
01070 if( AudioDeviceSupportsDigital( p_aout, p_devices[i] ) )
01071 {
01072 val.i_int = (int)p_devices[i] | AOUT_VAR_SPDIF_FLAG;
01073 asprintf( &text.psz_string, "%s (Encoded Output)", psz_name );
01074 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
01075 if( p_sys->i_default_dev == p_devices[i] && config_GetInt( p_aout, "spdif" ) )
01076 {
01077 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
01078 var_Set( p_aout, "audio-device", val );
01079 }
01080 }
01081
01082 free( psz_name);
01083 }
01084
01085 var_Get( p_aout->p_vlc, "macosx-audio-device", &val );
01086 msg_Dbg( p_aout, "device value override1: %#x", val.i_int );
01087 if( val.i_int > 0 )
01088 {
01089 msg_Dbg( p_aout, "device value override2: %#x", val.i_int );
01090 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
01091 var_Set( p_aout, "audio-device", val );
01092 }
01093
01094 var_AddCallback( p_aout, "audio-device", AudioDeviceCallback, NULL );
01095
01096
01097 err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
01098 HardwareListener,
01099 (void *)p_aout );
01100 if( err )
01101 goto error;
01102
01103 msg_Dbg( p_aout, "succesful finish of deviceslist" );
01104 if( p_devices ) free( p_devices );
01105 return;
01106
01107 error:
01108 var_Destroy( p_aout, "audio-device" );
01109 if( p_devices ) free( p_devices );
01110 return;
01111 }
01112
01113
01114
01115
01116 static int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
01117 {
01118 UInt32 dataSize;
01119 Boolean isWritable;
01120
01121 verify_noerr( AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE, kAudioDevicePropertyStreams, &dataSize, &isWritable) );
01122 if (dataSize == 0) return FALSE;
01123
01124 return TRUE;
01125 }
01126
01127
01128
01129
01130 static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
01131 {
01132 OSStatus err = noErr;
01133 UInt32 i_param_size = 0;
01134 AudioStreamID *p_streams = NULL;
01135 int i = 0, i_streams = 0;
01136 vlc_bool_t b_return = VLC_FALSE;
01137
01138
01139 err = AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE,
01140 kAudioDevicePropertyStreams,
01141 &i_param_size, NULL );
01142 if( err != noErr )
01143 {
01144 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
01145 return VLC_FALSE;
01146 }
01147
01148 i_streams = i_param_size / sizeof( AudioStreamID );
01149 p_streams = (AudioStreamID *)malloc( i_param_size );
01150 if( p_streams == NULL )
01151 {
01152 msg_Err( p_aout, "Out of memory" );
01153 return VLC_ENOMEM;
01154 }
01155
01156 err = AudioDeviceGetProperty( i_dev_id, 0, FALSE,
01157 kAudioDevicePropertyStreams,
01158 &i_param_size, p_streams );
01159
01160 if( err != noErr )
01161 {
01162 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
01163 return VLC_FALSE;
01164 }
01165
01166 for( i = 0; i < i_streams; i++ )
01167 {
01168 if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) )
01169 b_return = VLC_TRUE;
01170 }
01171
01172 if( p_streams ) free( p_streams );
01173 return b_return;
01174 }
01175
01176
01177
01178
01179 static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_stream_id )
01180 {
01181 OSStatus err = noErr;
01182 UInt32 i_param_size = 0;
01183 AudioStreamBasicDescription *p_format_list = NULL;
01184 int i = 0, i_formats = 0;
01185 vlc_bool_t b_return = VLC_FALSE;
01186
01187
01188 err = AudioStreamGetPropertyInfo( i_stream_id, 0,
01189 kAudioStreamPropertyPhysicalFormats,
01190 &i_param_size, NULL );
01191 if( err != noErr )
01192 {
01193 msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
01194 return VLC_FALSE;
01195 }
01196
01197 i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
01198 msg_Dbg( p_aout, "number of formats: %d", i_formats );
01199 p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
01200 if( p_format_list == NULL )
01201 {
01202 msg_Err( p_aout, "Could not malloc the memory" );
01203 return VLC_FALSE;
01204 }
01205
01206 err = AudioStreamGetProperty( i_stream_id, 0,
01207 kAudioStreamPropertyPhysicalFormats,
01208 &i_param_size, p_format_list );
01209 if( err != noErr )
01210 {
01211 msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
01212 free( p_format_list);
01213 p_format_list = NULL;
01214 return VLC_FALSE;
01215 }
01216
01217 for( i = 0; i < i_formats; i++ )
01218 {
01219 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format", p_format_list[i] ) );
01220
01221 if( p_format_list[i].mFormatID == 'IAC3' ||
01222 p_format_list[i].mFormatID == kAudioFormat60958AC3 )
01223 {
01224 b_return = VLC_TRUE;
01225 }
01226 }
01227
01228 if( p_format_list ) free( p_format_list );
01229 return b_return;
01230 }
01231
01232
01233
01234
01235
01236
01237
01238 static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
01239 AudioUnitRenderActionFlags *ioActionFlags,
01240 const AudioTimeStamp *inTimeStamp,
01241 unsigned int inBusNummer,
01242 unsigned int inNumberFrames,
01243 AudioBufferList *ioData )
01244 {
01245 AudioTimeStamp host_time;
01246 mtime_t current_date = 0;
01247 uint32_t i_mData_bytes = 0;
01248
01249 aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
01250 struct aout_sys_t * p_sys = p_aout->output.p_sys;
01251
01252 host_time.mFlags = kAudioTimeStampHostTimeValid;
01253 AudioDeviceTranslateTime( p_sys->i_selected_dev, inTimeStamp, &host_time );
01254
01255
01256 p_sys->clock_diff = - (mtime_t)
01257 AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
01258 p_sys->clock_diff += mdate();
01259
01260 current_date = p_sys->clock_diff +
01261 AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
01262
01263
01264 if( ioData == NULL && ioData->mNumberBuffers < 1 )
01265 {
01266 msg_Err( p_aout, "no iodata or buffers");
01267 return 0;
01268 }
01269 if( ioData->mNumberBuffers > 1 )
01270 msg_Err( p_aout, "well this is weird. seems like there is more than one buffer..." );
01271
01272
01273 if( p_sys->i_total_bytes > 0 )
01274 {
01275 i_mData_bytes = __MIN( p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize );
01276 p_aout->p_vlc->pf_memcpy( ioData->mBuffers[0].mData, &p_sys->p_remainder_buffer[p_sys->i_read_bytes], i_mData_bytes );
01277 p_sys->i_read_bytes += i_mData_bytes;
01278 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
01279 ( i_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output ) );
01280
01281 if( p_sys->i_read_bytes >= p_sys->i_total_bytes )
01282 p_sys->i_read_bytes = p_sys->i_total_bytes = 0;
01283 }
01284
01285 while( i_mData_bytes < ioData->mBuffers[0].mDataByteSize )
01286 {
01287
01288 aout_buffer_t * p_buffer;
01289 p_buffer = aout_OutputNextBuffer( p_aout, current_date , VLC_FALSE );
01290
01291 if( p_buffer != NULL )
01292 {
01293 uint32_t i_second_mData_bytes = __MIN( p_buffer->i_nb_bytes, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
01294
01295 p_aout->p_vlc->pf_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes, p_buffer->p_buffer, i_second_mData_bytes );
01296 i_mData_bytes += i_second_mData_bytes;
01297
01298 if( i_mData_bytes >= ioData->mBuffers[0].mDataByteSize )
01299 {
01300 p_sys->i_total_bytes = p_buffer->i_nb_bytes - i_second_mData_bytes;
01301 p_aout->p_vlc->pf_memcpy( p_sys->p_remainder_buffer, &p_buffer->p_buffer[i_second_mData_bytes], p_sys->i_total_bytes );
01302 }
01303 else
01304 {
01305
01306 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
01307 ( i_second_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output ) );
01308 }
01309 aout_BufferFree( p_buffer );
01310 }
01311 else
01312 {
01313 p_aout->p_vlc->pf_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes, 0, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
01314 i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes;
01315 }
01316 }
01317 return( noErr );
01318 }
01319
01320
01321
01322
01323 static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
01324 const AudioTimeStamp * inNow,
01325 const void * inInputData,
01326 const AudioTimeStamp * inInputTime,
01327 AudioBufferList * outOutputData,
01328 const AudioTimeStamp * inOutputTime,
01329 void * threadGlobals )
01330 {
01331 aout_buffer_t * p_buffer;
01332 mtime_t current_date;
01333
01334 aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
01335 struct aout_sys_t * p_sys = p_aout->output.p_sys;
01336
01337
01338 p_sys->clock_diff = - (mtime_t)
01339 AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
01340 p_sys->clock_diff += mdate();
01341
01342 current_date = p_sys->clock_diff +
01343 AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000;
01344
01345
01346 p_buffer = aout_OutputNextBuffer( p_aout, current_date, VLC_TRUE );
01347
01348 #define BUFFER outOutputData->mBuffers[p_sys->i_stream_index]
01349 if( p_buffer != NULL )
01350 {
01351 if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_nb_bytes)
01352 msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_nb_bytes );
01353
01354
01355 p_aout->p_vlc->pf_memcpy( BUFFER.mData,
01356 p_buffer->p_buffer, p_buffer->i_nb_bytes );
01357 aout_BufferFree( p_buffer );
01358 }
01359 else
01360 {
01361 p_aout->p_vlc->pf_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
01362 }
01363 #undef BUFFER
01364
01365 return( noErr );
01366 }
01367
01368
01369
01370
01371 static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
01372 void * inClientData )
01373 {
01374 OSStatus err = noErr;
01375 aout_instance_t *p_aout = (aout_instance_t *)inClientData;
01376
01377 switch( inPropertyID )
01378 {
01379 case kAudioHardwarePropertyDevices:
01380 {
01381
01382
01383 var_Change( p_aout, "audio-device", VLC_VAR_TRIGGER_CALLBACKS, NULL, NULL );
01384 var_Destroy( p_aout, "audio-device" );
01385 }
01386 break;
01387 }
01388
01389 return( err );
01390 }
01391
01392
01393
01394
01395 static OSStatus StreamListener( AudioStreamID inStream,
01396 UInt32 inChannel,
01397 AudioDevicePropertyID inPropertyID,
01398 void * inClientData )
01399 {
01400 OSStatus err = noErr;
01401 struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
01402
01403 switch( inPropertyID )
01404 {
01405 case kAudioStreamPropertyPhysicalFormat:
01406 vlc_mutex_lock( &w->lock );
01407 vlc_cond_signal( &w->cond );
01408 vlc_mutex_unlock( &w->lock );
01409 break;
01410
01411 default:
01412 break;
01413 }
01414 return( err );
01415 }
01416
01417
01418
01419
01420 static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable,
01421 vlc_value_t old_val, vlc_value_t new_val, void *param )
01422 {
01423 aout_instance_t *p_aout = (aout_instance_t *)p_this;
01424 var_Set( p_aout->p_vlc, "macosx-audio-device", new_val );
01425 msg_Dbg( p_aout, "Set Device: %#x", new_val.i_int );
01426 return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );
01427 }
01428