1 /*****************************************************************************
2 * auhal.c: AUHAL output plugin
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Derk-Jan Hartman <hartman at videolan dot org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
33 #include "aout_internal.h"
35 #include <CoreAudio/CoreAudio.h>
36 #include <CoreAudio/CoreAudioTypes.h>
37 #include <AudioUnit/AudioUnitProperties.h>
38 #include <AudioUnit/AudioUnitParameters.h>
39 #include <AudioUnit/AudioOutputUnit.h>
40 #include <AudioToolbox/AudioFormat.h>
42 #define STREAM_FORMAT_MSG( pre, sfm ) \
43 pre "[%ld][%4.4s][%ld][%ld][%ld][%ld][%ld][%ld]", \
44 (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
45 sfm.mFormatFlags, sfm.mBytesPerPacket, \
46 sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
47 sfm.mChannelsPerFrame, sfm.mBitsPerChannel
49 #define STREAM_FORMAT_MSG_FULL( pre, sfm ) \
50 pre ":\nsamplerate: [%ld]\nFormatID: [%4.4s]\nFormatFlags: [%ld]\nBypesPerPacket: [%ld]\nFramesPerPacket: [%ld]\nBytesPerFrame: [%ld]\nChannelsPerFrame: [%ld]\nBitsPerChannel[%ld]", \
51 (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
52 sfm.mFormatFlags, sfm.mBytesPerPacket, \
53 sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
54 sfm.mChannelsPerFrame, sfm.mBitsPerChannel
56 #define BUFSIZE 0xffffff
57 #define AOUT_VAR_SPDIF_FLAG 0xf00000
59 /*****************************************************************************
60 * aout_sys_t: private audio output method descriptor
61 *****************************************************************************
62 * This structure is part of the audio output thread descriptor.
63 * It describes the CoreAudio specific properties of an output thread.
64 *****************************************************************************/
67 AudioDeviceID i_default_dev; /* Keeps DeviceID of defaultOutputDevice */
68 AudioDeviceID i_selected_dev; /* Keeps DeviceID of the selected device */
69 UInt32 i_devices; /* Number of CoreAudio Devices */
70 vlc_bool_t b_supports_digital;/* Does the currently selected device support digital mode? */
71 vlc_bool_t b_digital; /* Are we running in digital mode? */
72 mtime_t clock_diff; /* Difference between VLC clock and Device clock */
74 Component au_component; /* The Audiocomponent we use */
75 AudioUnit au_unit; /* The AudioUnit we use */
76 uint8_t p_remainder_buffer[BUFSIZE];
77 uint32_t i_read_bytes;
78 uint32_t i_total_bytes;
79 /* CoreAudio SPDIF mode specific */
80 pid_t i_hog_pid; /* The keep the pid of our hog status */
81 AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */
82 int i_stream_index; /* The index of i_stream_id in an AudioBufferList */
83 AudioStreamBasicDescription stream_format; /* The format we changed the to */
84 AudioStreamBasicDescription sfmt_revert; /* The original format of the stream */
85 vlc_bool_t b_revert; /* Wether we need to revert the stream format */
86 vlc_bool_t b_changed_mixing;/* Wether we need to set the mixing mode back */
89 /*****************************************************************************
91 *****************************************************************************/
92 static int Open ( vlc_object_t * );
93 static int OpenAnalog ( aout_instance_t * );
94 static int OpenSPDIF ( aout_instance_t * );
95 static void Close ( vlc_object_t * );
97 static void Play ( aout_instance_t * );
98 static void Probe ( aout_instance_t * );
100 static int AudioDeviceHasOutput ( AudioDeviceID );
101 static int AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );
102 static int AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );
104 static OSStatus RenderCallbackAnalog ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
105 unsigned int, unsigned int, AudioBufferList *);
106 static OSStatus RenderCallbackSPDIF ( AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
107 AudioBufferList *, const AudioTimeStamp *, void * );
108 static OSStatus HardwareListener ( AudioHardwarePropertyID, void *);
109 static OSStatus StreamListener ( AudioStreamID, UInt32,
110 AudioDevicePropertyID, void * );
111 static int AudioDeviceCallback ( vlc_object_t *, const char *,
112 vlc_value_t, vlc_value_t, void * );
115 /*****************************************************************************
117 *****************************************************************************/
118 #define ADEV_TEXT N_("Audio Device")
119 #define ADEV_LONGTEXT N_("Choose a number corresponding to the number of an " \
120 "audio device, as listed in your 'Audio Device' menu. This device will " \
121 "then be used by default for audio playback.")
124 set_shortname( "auhal" );
125 set_description( _("HAL AudioUnit output") );
126 set_capability( "audio output", 101 );
127 set_category( CAT_AUDIO );
128 set_subcategory( SUBCAT_AUDIO_AOUT );
129 set_callbacks( Open, Close );
130 add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE );
133 /*****************************************************************************
134 * Open: open macosx audio output
135 *****************************************************************************/
136 static int Open( vlc_object_t * p_this )
138 OSStatus err = noErr;
139 UInt32 i_param_size = 0;
140 struct aout_sys_t *p_sys = NULL;
141 vlc_bool_t b_alive = VLC_FALSE;
143 aout_instance_t *p_aout = (aout_instance_t *)p_this;
145 /* Allocate structure */
146 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
147 if( p_aout->output.p_sys == NULL )
149 msg_Err( p_aout, "out of memory" );
150 return( VLC_ENOMEM );
153 p_sys = p_aout->output.p_sys;
154 p_sys->i_default_dev = 0;
155 p_sys->i_selected_dev = 0;
156 p_sys->i_devices = 0;
157 p_sys->b_supports_digital = VLC_FALSE;
158 p_sys->b_digital = VLC_FALSE;
159 p_sys->au_component = NULL;
160 p_sys->au_unit = NULL;
161 p_sys->clock_diff = (mtime_t) 0;
162 p_sys->i_read_bytes = 0;
163 p_sys->i_total_bytes = 0;
164 p_sys->i_hog_pid = -1;
165 p_sys->i_stream_id = 0;
166 p_sys->i_stream_index = 0;
167 p_sys->b_revert = VLC_FALSE;
168 p_sys->b_changed_mixing = VLC_FALSE;
169 memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
171 p_aout->output.pf_play = Play;
173 aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output );
175 /* Persistent device variable */
176 if( var_Type( p_aout->p_vlc, "macosx-audio-device" ) == 0 )
178 msg_Dbg( p_aout, "create macosx-audio-device" );
179 var_Create( p_aout->p_vlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
182 /* Build a list of devices */
183 if( var_Type( p_aout, "audio-device" ) == 0 )
188 /* What device do we want? */
189 if( var_Get( p_aout, "audio-device", &val ) < 0 )
191 msg_Err( p_aout, "audio-device var does not exist. device probe failed." );
193 return( VLC_ENOVAR );
196 p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG;
197 p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? VLC_TRUE : VLC_FALSE;
199 /* Check if the desired device is alive and usable */
200 i_param_size = sizeof( b_alive );
201 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
202 kAudioDevicePropertyDeviceIsAlive,
203 &i_param_size, &b_alive );
207 msg_Err( p_aout, "could not check whether device is alive: %4.4s",
212 if( b_alive == VLC_FALSE )
214 msg_Err( p_aout, "Selected audio device is not alive switching to default device" );
215 p_sys->i_selected_dev = p_sys->i_default_dev;
218 i_param_size = sizeof( p_sys->i_hog_pid );
219 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
220 kAudioDevicePropertyHogMode,
221 &i_param_size, &p_sys->i_hog_pid );
225 msg_Err( p_aout, "could not check whether device is hogged: %4.4s",
230 if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() )
232 msg_Err( p_aout, "Selected audio device is exclusively in use by another program" );
233 var_Destroy( p_aout, "audio-device" );
238 /* Check for Digital mode or Analog output mode */
239 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && p_sys->b_supports_digital )
241 if( OpenSPDIF( p_aout ) )
246 if( OpenAnalog( p_aout ) )
250 /* If we reach this, the Open* failed */
251 var_Destroy( p_aout, "audio-device" );
256 /*****************************************************************************
257 * Open: open and setup a HAL AudioUnit
258 *****************************************************************************/
259 static int OpenAnalog( aout_instance_t *p_aout )
261 struct aout_sys_t *p_sys = p_aout->output.p_sys;
262 OSStatus err = noErr;
263 UInt32 i_param_size = 0, i = 0;
264 ComponentDescription desc;
266 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && !p_sys->b_supports_digital )
268 msg_Dbg( p_aout, "we had requested a digital stream, but it's not possible for this device" );
271 /* If analog only start setting up AUHAL */
272 /* Lets go find our Component */
273 desc.componentType = kAudioUnitType_Output;
274 desc.componentSubType = kAudioUnitSubType_HALOutput;
275 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
276 desc.componentFlags = 0;
277 desc.componentFlagsMask = 0;
279 p_sys->au_component = FindNextComponent( NULL, &desc );
280 if( p_sys->au_component == NULL )
282 msg_Err( p_aout, "we cannot find our HAL component" );
286 err = OpenAComponent( p_sys->au_component, &p_sys->au_unit );
289 msg_Err( p_aout, "we cannot find our HAL component" );
293 /* Enable IO for the component */
294 msg_Dbg( p_aout, "Device: %#x", (int)p_sys->i_selected_dev );
297 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
298 kAudioOutputUnitProperty_CurrentDevice,
299 kAudioUnitScope_Global,
301 &p_sys->i_selected_dev,
302 sizeof( AudioDeviceID )));
304 /* Get the current format */
305 AudioStreamBasicDescription DeviceFormat;
307 i_param_size = sizeof(AudioStreamBasicDescription);
309 verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
310 kAudioUnitProperty_StreamFormat,
311 kAudioUnitScope_Input,
316 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: " , DeviceFormat ) );
318 /* Get the channel layout */
319 AudioChannelLayout *layout;
320 verify_noerr( AudioUnitGetPropertyInfo( p_sys->au_unit,
321 kAudioDevicePropertyPreferredChannelLayout,
322 kAudioUnitScope_Output,
327 layout = (AudioChannelLayout *)malloc( i_param_size);
329 verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
330 kAudioDevicePropertyPreferredChannelLayout,
331 kAudioUnitScope_Output,
336 /* Lets fill out the ChannelLayout */
337 if( layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
339 msg_Dbg( p_aout, "bitmap defined channellayout" );
340 verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForBitmap,
341 sizeof( UInt32), &layout->mChannelBitmap,
345 else if( layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
347 msg_Dbg( p_aout, "layouttags defined channellayout" );
348 verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForTag,
349 sizeof( AudioChannelLayoutTag ), &layout->mChannelLayoutTag,
354 msg_Dbg( p_aout, "Layout of AUHAL has %d channels" , (int)layout->mNumberChannelDescriptions );
356 p_aout->output.output.i_physical_channels = 0;
357 for( i = 0; i < layout->mNumberChannelDescriptions; i++ )
359 msg_Dbg( p_aout, "This is channel: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
361 switch( layout->mChannelDescriptions[i].mChannelLabel )
363 case kAudioChannelLabel_Left:
364 p_aout->output.output.i_physical_channels |= AOUT_CHAN_LEFT;
366 case kAudioChannelLabel_Right:
367 p_aout->output.output.i_physical_channels |= AOUT_CHAN_RIGHT;
369 case kAudioChannelLabel_Center:
370 p_aout->output.output.i_physical_channels |= AOUT_CHAN_CENTER;
372 case kAudioChannelLabel_LFEScreen:
373 p_aout->output.output.i_physical_channels |= AOUT_CHAN_LFE;
375 case kAudioChannelLabel_LeftSurround:
376 p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARLEFT;
378 case kAudioChannelLabel_RightSurround:
379 p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARRIGHT;
381 case kAudioChannelLabel_RearSurroundLeft:
382 p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLELEFT;
384 case kAudioChannelLabel_RearSurroundRight:
385 p_aout->output.output.i_physical_channels |= AOUT_CHAN_MIDDLERIGHT;
387 case kAudioChannelLabel_CenterSurround:
388 p_aout->output.output.i_physical_channels |= AOUT_CHAN_REARCENTER;
391 msg_Warn( p_aout, "Unrecognized channel form provided by driver: %d", (int)layout->mChannelDescriptions[i].mChannelLabel );
394 msg_Warn( p_aout, "Probably no channellayout is set. force based on channelcount" );
395 switch( layout->mNumberChannelDescriptions )
397 /* We make assumptions based on number of channels here.
398 * Unfortunatly Apple has provided no 100% method to retrieve the speaker configuration */
400 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
403 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
404 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
407 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
408 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
409 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
412 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
413 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
414 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_REARCENTER;
417 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
418 AOUT_CHAN_CENTER | AOUT_CHAN_LFE |
419 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
420 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
424 p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
432 msg_Dbg( p_aout, "defined %d physical channels for vlc core", aout_FormatNbChannels( &p_aout->output.output ) );
433 msg_Dbg( p_aout, "%s", aout_FormatPrintChannels( &p_aout->output.output ));
435 AudioChannelLayout new_layout;
436 memset (&new_layout, 0, sizeof(new_layout));
437 switch( aout_FormatNbChannels( &p_aout->output.output ) )
440 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
443 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
446 if( p_aout->output.output.i_physical_channels & AOUT_CHAN_CENTER )
448 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_7; // L R C
450 else if( p_aout->output.output.i_physical_channels & AOUT_CHAN_LFE )
452 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_4; // L R LFE
456 if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER | AOUT_CHAN_LFE ) )
458 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_10; // L R C LFE
460 else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT ) )
462 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3; // L R Ls Rs
464 else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER ) )
466 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_3; // L R C Cs
470 if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_CENTER ) )
472 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_19; // L R Ls Rs C
474 else if( p_aout->output.output.i_physical_channels & ( AOUT_CHAN_LFE ) )
476 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_18; // L R Ls Rs LFE
480 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_20; // L R Ls Rs C LFE
483 /* FIXME: This is incorrect. VLC uses the internal ordering: L R Lm Rm Lr Rr C LFE but this is wrong */
484 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A; // L R C LFE Ls Rs Cs
487 /* FIXME: This is incorrect. VLC uses the internal ordering: L R Lm Rm Lr Rr C LFE but this is wrong */
488 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A; // L R C LFE Ls Rs Lc Rc
492 /* Set up the format to be used */
493 DeviceFormat.mSampleRate = p_aout->output.output.i_rate;
494 DeviceFormat.mFormatID = kAudioFormatLinearPCM;
496 /* We use float 32. It's the best supported format by both VLC and Coreaudio */
497 p_aout->output.output.i_format = VLC_FOURCC( 'f','l','3','2');
498 DeviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
499 DeviceFormat.mBitsPerChannel = 32;
500 DeviceFormat.mChannelsPerFrame = aout_FormatNbChannels( &p_aout->output.output );
502 /* Calculate framesizes and stuff */
503 aout_FormatPrepare( &p_aout->output.output );
504 DeviceFormat.mFramesPerPacket = 1;
505 DeviceFormat.mBytesPerFrame = DeviceFormat.mBitsPerChannel * DeviceFormat.mChannelsPerFrame / 8;
506 DeviceFormat.mBytesPerPacket = DeviceFormat.mBytesPerFrame * DeviceFormat.mFramesPerPacket;
508 i_param_size = sizeof(AudioStreamBasicDescription);
509 /* Set desired format (Use CAStreamBasicDescription )*/
510 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
511 kAudioUnitProperty_StreamFormat,
512 kAudioUnitScope_Input,
517 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "we set the AU format: " , DeviceFormat ) );
519 /* Retrieve actual format??? */
520 verify_noerr( AudioUnitGetProperty( p_sys->au_unit,
521 kAudioUnitProperty_StreamFormat,
522 kAudioUnitScope_Input,
527 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "the actual set AU format is " , DeviceFormat ) );
529 p_aout->output.i_nb_samples = 2048;
530 aout_VolumeSoftInit( p_aout );
532 /* Find the difference between device clock and mdate clock */
533 p_sys->clock_diff = - (mtime_t)
534 AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
535 p_sys->clock_diff += mdate();
537 /* set the IOproc callback */
538 AURenderCallbackStruct input;
539 input.inputProc = (AURenderCallback) RenderCallbackAnalog;
540 input.inputProcRefCon = p_aout;
542 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
543 kAudioUnitProperty_SetRenderCallback,
544 kAudioUnitScope_Input,
545 0, &input, sizeof( input ) ) );
547 input.inputProc = (AURenderCallback) RenderCallbackAnalog;
548 input.inputProcRefCon = p_aout;
550 /* Set the new_layout as the layout VLC feeds to the AU unit */
551 verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
552 kAudioUnitProperty_AudioChannelLayout,
553 kAudioUnitScope_Input,
554 0, &new_layout, sizeof(new_layout) ) );
557 verify_noerr( AudioUnitInitialize(p_sys->au_unit) );
559 verify_noerr( AudioOutputUnitStart(p_sys->au_unit) );
564 /*****************************************************************************
565 * Setup a encoded digital stream (SPDIF)
566 *****************************************************************************/
567 static int OpenSPDIF( aout_instance_t * p_aout )
569 struct aout_sys_t *p_sys = p_aout->output.p_sys;
570 OSStatus err = noErr;
571 UInt32 i_param_size = 0, b_mix = 0;
572 Boolean b_writeable = VLC_FALSE;
573 AudioStreamID *p_streams = NULL;
574 int i = 0, i_streams = 0;
577 struct timespec timeout;
578 struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
580 /* Start doing the SPDIF setup proces */
581 p_sys->b_digital = VLC_TRUE;
582 msg_Dbg( p_aout, "opening in SPDIF mode" );
585 i_param_size = sizeof( p_sys->i_hog_pid );
586 p_sys->i_hog_pid = getpid() ;
588 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
589 kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
593 msg_Err( p_aout, "failed to set hogmode: : [%4.4s]", (char *)&err );
597 /* Set mixable to false if we are allowed to */
598 err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
599 &i_param_size, &b_writeable );
601 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
602 &i_param_size, &b_mix );
604 if( !err && b_writeable )
607 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
608 kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
609 p_sys->b_changed_mixing = VLC_TRUE;
614 msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
618 // Find stream_id of selected device with a cac3 stream
619 err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE,
620 kAudioDevicePropertyStreams,
621 &i_param_size, NULL );
624 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
628 i_streams = i_param_size / sizeof( AudioStreamID );
629 p_streams = (AudioStreamID *)malloc( i_param_size );
630 if( p_streams == NULL )
632 msg_Err( p_aout, "Out of memory" );
636 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
637 kAudioDevicePropertyStreams,
638 &i_param_size, p_streams );
642 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
643 if( p_streams ) free( p_streams );
647 for( i = 0; i < i_streams; i++ )
649 // Find a stream with a cac3 stream
650 AudioStreamBasicDescription *p_format_list = NULL;
651 int i_formats = 0, j = 0;
653 /* Retrieve all the stream formats supported by each output stream */
654 err = AudioStreamGetPropertyInfo( p_streams[i], 0,
655 kAudioStreamPropertyPhysicalFormats,
656 &i_param_size, NULL );
659 msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
663 i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
664 p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
665 if( p_format_list == NULL )
667 msg_Err( p_aout, "Could not malloc the memory" );
671 err = AudioStreamGetProperty( p_streams[i], 0,
672 kAudioStreamPropertyPhysicalFormats,
673 &i_param_size, p_format_list );
676 msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
677 if( p_format_list) free( p_format_list);
681 for( j = 0; j < i_formats; j++ )
683 if( p_format_list[j].mFormatID == 'IAC3' ||
684 p_format_list[j].mFormatID == kAudioFormat60958AC3 )
686 // found a cac3 format
687 p_sys->i_stream_id = p_streams[i];
688 p_sys->i_stream_index = i;
690 if( p_sys->b_revert == VLC_FALSE )
692 i_param_size = sizeof( p_sys->sfmt_revert );
693 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
694 kAudioStreamPropertyPhysicalFormat,
696 &p_sys->sfmt_revert );
699 msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
702 p_sys->b_revert = VLC_TRUE;
704 if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
706 p_sys->stream_format = p_format_list[j];
710 if( p_format_list ) free( p_format_list );
713 if( p_streams ) free( p_streams );
715 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "original stream format: ", p_sys->sfmt_revert ) );
716 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->stream_format ) );
718 /* Install the callback */
719 err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
720 kAudioStreamPropertyPhysicalFormat,
721 StreamListener, (void *)&w );
724 msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
728 /* Condition because SetProperty is asynchronious */
729 vlc_cond_init( p_aout, &w.cond );
730 vlc_mutex_init( p_aout, &w.lock );
731 vlc_mutex_lock( &w.lock );
733 /* change the format */
734 err = AudioStreamSetProperty( p_sys->i_stream_id, 0, 0,
735 kAudioStreamPropertyPhysicalFormat,
736 sizeof( AudioStreamBasicDescription ),
737 &p_sys->stream_format );
740 msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
741 vlc_mutex_unlock( &w.lock );
742 vlc_mutex_destroy( &w.lock );
743 vlc_cond_destroy( &w.cond );
747 gettimeofday( &now, NULL );
748 timeout.tv_sec = now.tv_sec;
749 timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
751 pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
752 vlc_mutex_unlock( &w.lock );
754 err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
755 kAudioStreamPropertyPhysicalFormat,
759 msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
760 vlc_mutex_destroy( &w.lock );
761 vlc_cond_destroy( &w.cond );
765 vlc_mutex_destroy( &w.lock );
766 vlc_cond_destroy( &w.cond );
768 i_param_size = sizeof( AudioStreamBasicDescription );
769 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
770 kAudioStreamPropertyPhysicalFormat,
772 &p_sys->stream_format );
774 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
776 /* set the format flags */
777 if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
778 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','b');
780 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
781 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
782 p_aout->output.output.i_frame_length = A52_FRAME_NB;
783 p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
784 p_aout->output.output.i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
786 aout_VolumeNoneInit( p_aout );
788 /* Add IOProc callback */
789 err = AudioDeviceAddIOProc( p_sys->i_selected_dev,
790 (AudioDeviceIOProc)RenderCallbackSPDIF,
794 msg_Err( p_aout, "AudioDeviceAddIOProc failed: [%4.4s]", (char *)&err );
798 /* Check for the difference between the Device clock and mdate */
799 p_sys->clock_diff = - (mtime_t)
800 AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
801 p_sys->clock_diff += mdate();
804 err = AudioDeviceStart( p_sys->i_selected_dev, (AudioDeviceIOProc)RenderCallbackSPDIF );
807 msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err );
809 err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
810 (AudioDeviceIOProc)RenderCallbackSPDIF );
813 msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
822 /*****************************************************************************
823 * Close: Close HAL AudioUnit
824 *****************************************************************************/
825 static void Close( vlc_object_t * p_this )
827 aout_instance_t *p_aout = (aout_instance_t *)p_this;
828 struct aout_sys_t *p_sys = p_aout->output.p_sys;
829 OSStatus err = noErr;
830 UInt32 i_param_size = 0;
834 verify_noerr( AudioOutputUnitStop( p_sys->au_unit ) );
835 verify_noerr( AudioUnitUninitialize( p_sys->au_unit ) );
836 verify_noerr( CloseComponent( p_sys->au_unit ) );
839 if( p_sys->b_digital )
842 err = AudioDeviceStop( p_sys->i_selected_dev,
843 (AudioDeviceIOProc)RenderCallbackSPDIF );
846 msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
849 /* Remove callback */
850 err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
851 (AudioDeviceIOProc)RenderCallbackSPDIF );
854 msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
857 if( p_sys->b_revert )
860 struct timespec timeout;
861 struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
863 /* Install the callback */
864 err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
865 kAudioStreamPropertyPhysicalFormat,
866 StreamListener, (void *)&w );
869 msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
872 /* Condition because SetProperty is asynchronious */
873 vlc_cond_init( p_aout, &w.cond );
874 vlc_mutex_init( p_aout, &w.lock );
875 vlc_mutex_lock( &w.lock );
877 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->sfmt_revert ) );
879 err = AudioStreamSetProperty( p_sys->i_stream_id, NULL, 0,
880 kAudioStreamPropertyPhysicalFormat,
881 sizeof( AudioStreamBasicDescription ),
882 &p_sys->sfmt_revert );
886 msg_Err( p_aout, "Streamformat reverse failed: [%4.4s]", (char *)&err );
889 gettimeofday( &now, NULL );
890 timeout.tv_sec = now.tv_sec;
891 timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
893 pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
894 vlc_mutex_unlock( &w.lock );
896 err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
897 kAudioStreamPropertyPhysicalFormat,
901 msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
904 vlc_mutex_destroy( &w.lock );
905 vlc_cond_destroy( &w.cond );
907 i_param_size = sizeof( AudioStreamBasicDescription );
908 err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
909 kAudioStreamPropertyPhysicalFormat,
911 &p_sys->stream_format );
913 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
915 if( p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3 )
919 /* Revert mixable to true if we are allowed to */
920 err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
921 &i_param_size, &b_writeable );
923 err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
924 &i_param_size, &b_mix );
926 if( !err && b_writeable )
928 msg_Dbg( p_aout, "mixable is: %d", b_mix );
930 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
931 kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
936 msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
941 err = AudioHardwareRemovePropertyListener( kAudioHardwarePropertyDevices,
946 msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err );
949 if( p_sys->i_hog_pid == getpid() )
951 p_sys->i_hog_pid = -1;
952 i_param_size = sizeof( p_sys->i_hog_pid );
953 err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
954 kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
955 if( err != noErr ) msg_Err( p_aout, "Could not release hogmode: [%4.4s]", (char *)&err );
958 if( p_sys ) free( p_sys );
961 /*****************************************************************************
962 * Play: nothing to do
963 *****************************************************************************/
964 static void Play( aout_instance_t * p_aout )
969 /*****************************************************************************
971 *****************************************************************************/
972 static void Probe( aout_instance_t * p_aout )
974 OSStatus err = noErr;
975 UInt32 i = 0, i_param_size = 0;
976 AudioDeviceID devid_def = 0;
977 AudioDeviceID *p_devices = NULL;
978 vlc_value_t val, text;
980 struct aout_sys_t *p_sys = p_aout->output.p_sys;
982 /* Get number of devices */
983 err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
984 &i_param_size, NULL );
987 msg_Err( p_aout, "could not get number of devices: [%4.4s]", (char *)&err );
991 p_sys->i_devices = i_param_size / sizeof( AudioDeviceID );
993 if( p_sys->i_devices < 1 )
995 msg_Err( p_aout, "no devices found" );
999 msg_Dbg( p_aout, "system has [%ld] device(s)", p_sys->i_devices );
1001 /* Allocate DeviceID array */
1002 p_devices = (AudioDeviceID*)malloc( sizeof(AudioDeviceID) * p_sys->i_devices );
1003 if( p_devices == NULL )
1005 msg_Err( p_aout, "out of memory" );
1009 /* Populate DeviceID array */
1010 err = AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
1011 &i_param_size, p_devices );
1014 msg_Err( p_aout, "could not get the device ID's: [%4.4s]", (char *)&err );
1018 /* Find the ID of the default Device */
1019 i_param_size = sizeof( AudioDeviceID );
1020 err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
1021 &i_param_size, &devid_def );
1024 msg_Err( p_aout, "could not get default audio device: [%4.4s]", (char *)&err );
1027 p_sys->i_default_dev = devid_def;
1029 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE );
1030 text.psz_string = _("Audio Device");
1031 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
1033 for( i = 0; i < p_sys->i_devices; i++ )
1038 /* Retrieve the length of the device name */
1039 err = AudioDeviceGetPropertyInfo(
1040 p_devices[i], 0, VLC_FALSE,
1041 kAudioDevicePropertyDeviceName,
1042 &i_param_size, NULL);
1043 if( err ) goto error;
1045 /* Retrieve the name of the device */
1046 psz_name = (char *)malloc( i_param_size );
1047 err = AudioDeviceGetProperty(
1048 p_devices[i], 0, VLC_FALSE,
1049 kAudioDevicePropertyDeviceName,
1050 &i_param_size, psz_name);
1051 if( err ) goto error;
1053 msg_Dbg( p_aout, "DevID: %lu DevName: %s", p_devices[i], psz_name );
1055 if( !AudioDeviceHasOutput( p_devices[i]) )
1057 msg_Dbg( p_aout, "this device is INPUT only. skipping..." );
1061 val.i_int = (int)p_devices[i];
1062 text.psz_string = strdup( psz_name );
1063 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
1064 if( p_sys->i_default_dev == p_devices[i] )
1066 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1067 var_Set( p_aout, "audio-device", val );
1070 if( AudioDeviceSupportsDigital( p_aout, p_devices[i] ) )
1072 val.i_int = (int)p_devices[i] | AOUT_VAR_SPDIF_FLAG;
1073 asprintf( &text.psz_string, "%s (Encoded Output)", psz_name );
1074 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
1075 if( p_sys->i_default_dev == p_devices[i] && config_GetInt( p_aout, "spdif" ) )
1077 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1078 var_Set( p_aout, "audio-device", val );
1085 var_Get( p_aout->p_vlc, "macosx-audio-device", &val );
1086 msg_Dbg( p_aout, "device value override1: %#x", val.i_int );
1089 msg_Dbg( p_aout, "device value override2: %#x", val.i_int );
1090 var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
1091 var_Set( p_aout, "audio-device", val );
1094 var_AddCallback( p_aout, "audio-device", AudioDeviceCallback, NULL );
1096 /* attach a Listener so that we are notified of a change in the Device setup */
1097 err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
1103 msg_Dbg( p_aout, "succesful finish of deviceslist" );
1104 if( p_devices ) free( p_devices );
1108 var_Destroy( p_aout, "audio-device" );
1109 if( p_devices ) free( p_devices );
1113 /*****************************************************************************
1114 * AudioDeviceHasOutput: Checks if the Device actually provides any outputs at all
1115 *****************************************************************************/
1116 static int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
1121 verify_noerr( AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE, kAudioDevicePropertyStreams, &dataSize, &isWritable) );
1122 if (dataSize == 0) return FALSE;
1127 /*****************************************************************************
1128 * AudioDeviceSupportsDigital: Check i_dev_id for digital stream support.
1129 *****************************************************************************/
1130 static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
1132 OSStatus err = noErr;
1133 UInt32 i_param_size = 0;
1134 AudioStreamID *p_streams = NULL;
1135 int i = 0, i_streams = 0;
1136 vlc_bool_t b_return = VLC_FALSE;
1138 /* Retrieve all the output streams */
1139 err = AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE,
1140 kAudioDevicePropertyStreams,
1141 &i_param_size, NULL );
1144 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
1148 i_streams = i_param_size / sizeof( AudioStreamID );
1149 p_streams = (AudioStreamID *)malloc( i_param_size );
1150 if( p_streams == NULL )
1152 msg_Err( p_aout, "Out of memory" );
1156 err = AudioDeviceGetProperty( i_dev_id, 0, FALSE,
1157 kAudioDevicePropertyStreams,
1158 &i_param_size, p_streams );
1162 msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
1166 for( i = 0; i < i_streams; i++ )
1168 if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) )
1169 b_return = VLC_TRUE;
1172 if( p_streams ) free( p_streams );
1176 /*****************************************************************************
1177 * AudioStreamSupportsDigital: Check i_stream_id for digital stream support.
1178 *****************************************************************************/
1179 static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_stream_id )
1181 OSStatus err = noErr;
1182 UInt32 i_param_size = 0;
1183 AudioStreamBasicDescription *p_format_list = NULL;
1184 int i = 0, i_formats = 0;
1185 vlc_bool_t b_return = VLC_FALSE;
1187 /* Retrieve all the stream formats supported by each output stream */
1188 err = AudioStreamGetPropertyInfo( i_stream_id, 0,
1189 kAudioStreamPropertyPhysicalFormats,
1190 &i_param_size, NULL );
1193 msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
1197 i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
1198 msg_Dbg( p_aout, "number of formats: %d", i_formats );
1199 p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
1200 if( p_format_list == NULL )
1202 msg_Err( p_aout, "Could not malloc the memory" );
1206 err = AudioStreamGetProperty( i_stream_id, 0,
1207 kAudioStreamPropertyPhysicalFormats,
1208 &i_param_size, p_format_list );
1211 msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
1212 free( p_format_list);
1213 p_format_list = NULL;
1217 for( i = 0; i < i_formats; i++ )
1219 msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format", p_format_list[i] ) );
1221 if( p_format_list[i].mFormatID == 'IAC3' ||
1222 p_format_list[i].mFormatID == kAudioFormat60958AC3 )
1224 b_return = VLC_TRUE;
1228 if( p_format_list ) free( p_format_list );
1232 /*****************************************************************************
1233 * RenderCallbackAnalog: This function is called everytime the AudioUnit wants
1234 * us to provide some more audio data.
1235 * Don't print anything during normal playback, calling blocking function from
1236 * this callback is not allowed.
1237 *****************************************************************************/
1238 static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
1239 AudioUnitRenderActionFlags *ioActionFlags,
1240 const AudioTimeStamp *inTimeStamp,
1241 unsigned int inBusNummer,
1242 unsigned int inNumberFrames,
1243 AudioBufferList *ioData )
1245 AudioTimeStamp host_time;
1246 mtime_t current_date = 0;
1247 uint32_t i_mData_bytes = 0;
1249 aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
1250 struct aout_sys_t * p_sys = p_aout->output.p_sys;
1252 host_time.mFlags = kAudioTimeStampHostTimeValid;
1253 AudioDeviceTranslateTime( p_sys->i_selected_dev, inTimeStamp, &host_time );
1255 /* Check for the difference between the Device clock and mdate */
1256 p_sys->clock_diff = - (mtime_t)
1257 AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
1258 p_sys->clock_diff += mdate();
1260 current_date = p_sys->clock_diff +
1261 AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
1262 //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
1264 if( ioData == NULL && ioData->mNumberBuffers < 1 )
1266 msg_Err( p_aout, "no iodata or buffers");
1269 if( ioData->mNumberBuffers > 1 )
1270 msg_Err( p_aout, "well this is weird. seems like there is more than one buffer..." );
1273 if( p_sys->i_total_bytes > 0 )
1275 i_mData_bytes = __MIN( p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize );
1276 p_aout->p_vlc->pf_memcpy( ioData->mBuffers[0].mData, &p_sys->p_remainder_buffer[p_sys->i_read_bytes], i_mData_bytes );
1277 p_sys->i_read_bytes += i_mData_bytes;
1278 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
1279 ( i_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output ) ); // 4 is fl32 specific
1281 if( p_sys->i_read_bytes >= p_sys->i_total_bytes )
1282 p_sys->i_read_bytes = p_sys->i_total_bytes = 0;
1285 while( i_mData_bytes < ioData->mBuffers[0].mDataByteSize )
1287 /* We don't have enough data yet */
1288 aout_buffer_t * p_buffer;
1289 p_buffer = aout_OutputNextBuffer( p_aout, current_date , VLC_FALSE );
1291 if( p_buffer != NULL )
1293 uint32_t i_second_mData_bytes = __MIN( p_buffer->i_nb_bytes, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
1295 p_aout->p_vlc->pf_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes, p_buffer->p_buffer, i_second_mData_bytes );
1296 i_mData_bytes += i_second_mData_bytes;
1298 if( i_mData_bytes >= ioData->mBuffers[0].mDataByteSize )
1300 p_sys->i_total_bytes = p_buffer->i_nb_bytes - i_second_mData_bytes;
1301 p_aout->p_vlc->pf_memcpy( p_sys->p_remainder_buffer, &p_buffer->p_buffer[i_second_mData_bytes], p_sys->i_total_bytes );
1305 // update current_date
1306 current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) *
1307 ( i_second_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output ) ); // 4 is fl32 specific
1309 aout_BufferFree( p_buffer );
1313 p_aout->p_vlc->pf_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes, 0, ioData->mBuffers[0].mDataByteSize - i_mData_bytes );
1314 i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes;
1320 /*****************************************************************************
1321 * RenderCallbackSPDIF: callback for SPDIF audio output
1322 *****************************************************************************/
1323 static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
1324 const AudioTimeStamp * inNow,
1325 const void * inInputData,
1326 const AudioTimeStamp * inInputTime,
1327 AudioBufferList * outOutputData,
1328 const AudioTimeStamp * inOutputTime,
1329 void * threadGlobals )
1331 aout_buffer_t * p_buffer;
1332 mtime_t current_date;
1334 aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
1335 struct aout_sys_t * p_sys = p_aout->output.p_sys;
1337 /* Check for the difference between the Device clock and mdate */
1338 p_sys->clock_diff = - (mtime_t)
1339 AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
1340 p_sys->clock_diff += mdate();
1342 current_date = p_sys->clock_diff +
1343 AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000;
1344 //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
1346 p_buffer = aout_OutputNextBuffer( p_aout, current_date, VLC_TRUE );
1348 #define BUFFER outOutputData->mBuffers[p_sys->i_stream_index]
1349 if( p_buffer != NULL )
1351 if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_nb_bytes)
1352 msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_nb_bytes );
1354 /* move data into output data buffer */
1355 p_aout->p_vlc->pf_memcpy( BUFFER.mData,
1356 p_buffer->p_buffer, p_buffer->i_nb_bytes );
1357 aout_BufferFree( p_buffer );
1361 p_aout->p_vlc->pf_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
1368 /*****************************************************************************
1369 * HardwareListener: Warns us of changes in the list of registered devices
1370 *****************************************************************************/
1371 static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
1372 void * inClientData )
1374 OSStatus err = noErr;
1375 aout_instance_t *p_aout = (aout_instance_t *)inClientData;
1377 switch( inPropertyID )
1379 case kAudioHardwarePropertyDevices:
1381 /* something changed in the list of devices */
1382 /* We trigger the audio-device's aout_ChannelsRestart callback */
1383 var_Change( p_aout, "audio-device", VLC_VAR_TRIGGER_CALLBACKS, NULL, NULL );
1384 var_Destroy( p_aout, "audio-device" );
1392 /*****************************************************************************
1394 *****************************************************************************/
1395 static OSStatus StreamListener( AudioStreamID inStream,
1397 AudioDevicePropertyID inPropertyID,
1398 void * inClientData )
1400 OSStatus err = noErr;
1401 struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
1403 switch( inPropertyID )
1405 case kAudioStreamPropertyPhysicalFormat:
1406 vlc_mutex_lock( &w->lock );
1407 vlc_cond_signal( &w->cond );
1408 vlc_mutex_unlock( &w->lock );
1417 /*****************************************************************************
1418 * AudioDeviceCallback: Callback triggered when the audio-device variable is changed
1419 *****************************************************************************/
1420 static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable,
1421 vlc_value_t old_val, vlc_value_t new_val, void *param )
1423 aout_instance_t *p_aout = (aout_instance_t *)p_this;
1424 var_Set( p_aout->p_vlc, "macosx-audio-device", new_val );
1425 msg_Dbg( p_aout, "Set Device: %#x", new_val.i_int );
1426 return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );