📄 auhal.c
字号:
kAudioDevicePropertyStreams, &i_param_size, p_streams ); if( err != noErr ) { msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err ); return VLC_FALSE; } for( i = 0; i < i_streams; i++ ) { if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) ) b_return = VLC_TRUE; } if( p_streams ) free( p_streams ); return b_return;}/***************************************************************************** * AudioStreamSupportsDigital: Check i_stream_id for digital stream support. *****************************************************************************/static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_stream_id ){ OSStatus err = noErr; UInt32 i_param_size = 0; AudioStreamBasicDescription *p_format_list = NULL; int i = 0, i_formats = 0; vlc_bool_t b_return = VLC_FALSE; /* Retrieve all the stream formats supported by each output stream */ err = AudioStreamGetPropertyInfo( i_stream_id, 0, kAudioStreamPropertyPhysicalFormats, &i_param_size, NULL ); if( err != noErr ) { msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err ); return VLC_FALSE; } i_formats = i_param_size / sizeof( AudioStreamBasicDescription ); p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size ); if( p_format_list == NULL ) { msg_Err( p_aout, "could not malloc the memory" ); return VLC_FALSE; } err = AudioStreamGetProperty( i_stream_id, 0, kAudioStreamPropertyPhysicalFormats, &i_param_size, p_format_list ); if( err != noErr ) { msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err ); free( p_format_list); p_format_list = NULL; return VLC_FALSE; } for( i = 0; i < i_formats; i++ ) { msg_Dbg( p_aout, STREAM_FORMAT_MSG( "supported format: ", p_format_list[i] ) ); if( p_format_list[i].mFormatID == 'IAC3' || p_format_list[i].mFormatID == kAudioFormat60958AC3 ) { b_return = VLC_TRUE; } } if( p_format_list ) free( p_format_list ); return b_return;}/***************************************************************************** * AudioStreamChangeFormat: Change i_stream_id to change_format *****************************************************************************/static int AudioStreamChangeFormat( aout_instance_t *p_aout, AudioStreamID i_stream_id, AudioStreamBasicDescription change_format ){ OSStatus err = noErr; UInt32 i_param_size = 0; int i; struct timeval now; struct timespec timeout; struct { vlc_mutex_t lock; vlc_cond_t cond; } w; msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", change_format ) ); /* Condition because SetProperty is asynchronious */ vlc_cond_init( p_aout, &w.cond ); vlc_mutex_init( p_aout, &w.lock ); vlc_mutex_lock( &w.lock ); /* Install the callback */ err = AudioStreamAddPropertyListener( i_stream_id, 0, kAudioStreamPropertyPhysicalFormat, StreamListener, (void *)&w ); if( err != noErr ) { msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err ); return VLC_FALSE; } /* change the format */ err = AudioStreamSetProperty( i_stream_id, 0, 0, kAudioStreamPropertyPhysicalFormat, sizeof( AudioStreamBasicDescription ), &change_format ); if( err != noErr ) { msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err ); return VLC_FALSE; } /* The AudioStreamSetProperty is not only asynchronious (requiring the locks) * it is also not Atomic, in it's behaviour. * Therefore we check 5 times before we really give up. * FIXME: failing isn't actually implemented yet. */ for( i = 0; i < 5; i++ ) { AudioStreamBasicDescription actual_format; gettimeofday( &now, NULL ); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = (now.tv_usec + 500000) * 1000; if( pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout ) ) { msg_Dbg( p_aout, "reached timeout" ); } i_param_size = sizeof( AudioStreamBasicDescription ); err = AudioStreamGetProperty( i_stream_id, 0, kAudioStreamPropertyPhysicalFormat, &i_param_size, &actual_format ); msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", actual_format ) ); if( actual_format.mSampleRate == change_format.mSampleRate && actual_format.mFormatID == change_format.mFormatID && actual_format.mFramesPerPacket == change_format.mFramesPerPacket ) { /* The right format is now active */ break; } /* We need to check again */ } /* Removing the property listener */ err = AudioStreamRemovePropertyListener( i_stream_id, 0, kAudioStreamPropertyPhysicalFormat, StreamListener ); if( err != noErr ) { msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err ); return VLC_FALSE; } /* Destroy the lock and condition */ vlc_mutex_unlock( &w.lock ); vlc_mutex_destroy( &w.lock ); vlc_cond_destroy( &w.cond ); return VLC_TRUE;}/***************************************************************************** * RenderCallbackAnalog: This function is called everytime the AudioUnit wants * us to provide some more audio data. * Don't print anything during normal playback, calling blocking function from * this callback is not allowed. *****************************************************************************/static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, unsigned int inBusNummer, unsigned int inNumberFrames, AudioBufferList *ioData ){ AudioTimeStamp host_time; mtime_t current_date = 0; uint32_t i_mData_bytes = 0; aout_instance_t * p_aout = (aout_instance_t *)_p_aout; struct aout_sys_t * p_sys = p_aout->output.p_sys; host_time.mFlags = kAudioTimeStampHostTimeValid; AudioDeviceTranslateTime( p_sys->i_selected_dev, inTimeStamp, &host_time ); /* Check for the difference between the Device clock and mdate */ p_sys->clock_diff = - (mtime_t) AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000; p_sys->clock_diff += mdate(); current_date = p_sys->clock_diff + AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000; //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere if( ioData == NULL && ioData->mNumberBuffers < 1 ) { msg_Err( p_aout, "no iodata or buffers"); return 0; } if( ioData->mNumberBuffers > 1 ) msg_Err( p_aout, "well this is weird. seems like there is more than one buffer..." ); if( p_sys->i_total_bytes > 0 ) { i_mData_bytes = __MIN( p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize ); p_aout->p_vlc->pf_memcpy( ioData->mBuffers[0].mData, &p_sys->p_remainder_buffer[p_sys->i_read_bytes], i_mData_bytes ); p_sys->i_read_bytes += i_mData_bytes; current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) * ( i_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output ) ); // 4 is fl32 specific if( p_sys->i_read_bytes >= p_sys->i_total_bytes ) p_sys->i_read_bytes = p_sys->i_total_bytes = 0; } while( i_mData_bytes < ioData->mBuffers[0].mDataByteSize ) { /* We don't have enough data yet */ aout_buffer_t * p_buffer; p_buffer = aout_OutputNextBuffer( p_aout, current_date , VLC_FALSE ); if( p_buffer != NULL ) { uint32_t i_second_mData_bytes = __MIN( p_buffer->i_nb_bytes, ioData->mBuffers[0].mDataByteSize - i_mData_bytes ); p_aout->p_vlc->pf_memcpy( (uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes, p_buffer->p_buffer, i_second_mData_bytes ); i_mData_bytes += i_second_mData_bytes; if( i_mData_bytes >= ioData->mBuffers[0].mDataByteSize ) { p_sys->i_total_bytes = p_buffer->i_nb_bytes - i_second_mData_bytes; p_aout->p_vlc->pf_memcpy( p_sys->p_remainder_buffer, &p_buffer->p_buffer[i_second_mData_bytes], p_sys->i_total_bytes ); } else { /* update current_date */ current_date += (mtime_t) ( (mtime_t) 1000000 / p_aout->output.output.i_rate ) * ( i_second_mData_bytes / 4 / aout_FormatNbChannels( &p_aout->output.output ) ); // 4 is fl32 specific } aout_BufferFree( p_buffer ); } else { p_aout->p_vlc->pf_memset( (uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes, 0, ioData->mBuffers[0].mDataByteSize - i_mData_bytes ); i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes; } } return( noErr ); }/***************************************************************************** * RenderCallbackSPDIF: callback for SPDIF audio output *****************************************************************************/static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice, const AudioTimeStamp * inNow, const void * inInputData, const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData, const AudioTimeStamp * inOutputTime, void * threadGlobals ){ aout_buffer_t * p_buffer; mtime_t current_date; aout_instance_t * p_aout = (aout_instance_t *)threadGlobals; struct aout_sys_t * p_sys = p_aout->output.p_sys; /* Check for the difference between the Device clock and mdate */ p_sys->clock_diff = - (mtime_t) AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000; p_sys->clock_diff += mdate(); current_date = p_sys->clock_diff + AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000; //- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere p_buffer = aout_OutputNextBuffer( p_aout, current_date, VLC_TRUE );#define BUFFER outOutputData->mBuffers[p_sys->i_stream_index] if( p_buffer != NULL ) { if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_nb_bytes) msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_nb_bytes ); /* move data into output data buffer */ p_aout->p_vlc->pf_memcpy( BUFFER.mData, p_buffer->p_buffer, p_buffer->i_nb_bytes ); aout_BufferFree( p_buffer ); } else { p_aout->p_vlc->pf_memset( BUFFER.mData, 0, BUFFER.mDataByteSize ); }#undef BUFFER return( noErr ); }/***************************************************************************** * HardwareListener: Warns us of changes in the list of registered devices *****************************************************************************/static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID, void * inClientData ){ OSStatus err = noErr; aout_instance_t *p_aout = (aout_instance_t *)inClientData; switch( inPropertyID ) { case kAudioHardwarePropertyDevices: { /* something changed in the list of devices */ /* We trigger the audio-device's aout_ChannelsRestart callback */ var_Change( p_aout, "audio-device", VLC_VAR_TRIGGER_CALLBACKS, NULL, NULL ); var_Destroy( p_aout, "audio-device" ); } break; } return( err );}/***************************************************************************** * StreamListener *****************************************************************************/static OSStatus StreamListener( AudioStreamID inStream, UInt32 inChannel, AudioDevicePropertyID inPropertyID, void * inClientData ){ OSStatus err = noErr; struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData; switch( inPropertyID ) { case kAudioStreamPropertyPhysicalFormat: vlc_mutex_lock( &w->lock ); vlc_cond_signal( &w->cond ); vlc_mutex_unlock( &w->lock ); break; default: break; } return( err );}/***************************************************************************** * AudioDeviceCallback: Callback triggered when the audio-device variable is changed *****************************************************************************/static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable, vlc_value_t old_val, vlc_value_t new_val, void *param ){ aout_instance_t *p_aout = (aout_instance_t *)p_this; var_Set( p_aout->p_vlc, "macosx-audio-device", new_val ); msg_Dbg( p_aout, "Set Device: %#x", new_val.i_int ); return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -