📄 auhal.c
字号:
/***************************************************************************** * auhal.c: AUHAL and Coreaudio output plugin ***************************************************************************** * Copyright (C) 2005 the VideoLAN team * $Id: auhal.c 14997 2006-03-31 15:15:07Z fkuehne $ * * Authors: Derk-Jan Hartman <hartman at videolan dot org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <string.h>#include <stdlib.h>#include <unistd.h>#include <vlc/vlc.h>#include <vlc/aout.h>#include "aout_internal.h"#include <CoreAudio/CoreAudio.h>#include <AudioUnit/AudioUnitProperties.h>#include <AudioUnit/AudioUnitParameters.h>#include <AudioUnit/AudioOutputUnit.h>#include <AudioToolbox/AudioFormat.h>#define STREAM_FORMAT_MSG( pre, sfm ) \ pre "[%ld][%4.4s][%ld][%ld][%ld][%ld][%ld][%ld]", \ (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \ sfm.mFormatFlags, sfm.mBytesPerPacket, \ sfm.mFramesPerPacket, sfm.mBytesPerFrame, \ sfm.mChannelsPerFrame, sfm.mBitsPerChannel#define STREAM_FORMAT_MSG_FULL( pre, sfm ) \ pre ":\nsamplerate: [%ld]\nFormatID: [%4.4s]\nFormatFlags: [%ld]\nBypesPerPacket: [%ld]\nFramesPerPacket: [%ld]\nBytesPerFrame: [%ld]\nChannelsPerFrame: [%ld]\nBitsPerChannel[%ld]", \ (UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \ sfm.mFormatFlags, sfm.mBytesPerPacket, \ sfm.mFramesPerPacket, sfm.mBytesPerFrame, \ sfm.mChannelsPerFrame, sfm.mBitsPerChannel#define BUFSIZE 0xffffff#define AOUT_VAR_SPDIF_FLAG 0xf00000/* * TODO: * - clean up the debug info * - clean up C99'isms * - be better at changing stream setup or devices setup changes while playing. * - fix 6.1 and 7.1 *//***************************************************************************** * aout_sys_t: private audio output method descriptor ***************************************************************************** * This structure is part of the audio output thread descriptor. * It describes the CoreAudio specific properties of an output thread. *****************************************************************************/struct aout_sys_t{ AudioDeviceID i_default_dev; /* Keeps DeviceID of defaultOutputDevice */ AudioDeviceID i_selected_dev; /* Keeps DeviceID of the selected device */ UInt32 i_devices; /* Number of CoreAudio Devices */ vlc_bool_t b_supports_digital;/* Does the currently selected device support digital mode? */ vlc_bool_t b_digital; /* Are we running in digital mode? */ mtime_t clock_diff; /* Difference between VLC clock and Device clock */ /* AUHAL specific */ Component au_component; /* The Audiocomponent we use */ AudioUnit au_unit; /* The AudioUnit we use */ uint8_t p_remainder_buffer[BUFSIZE]; uint32_t i_read_bytes; uint32_t i_total_bytes; /* CoreAudio SPDIF mode specific */ pid_t i_hog_pid; /* The keep the pid of our hog status */ AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */ int i_stream_index; /* The index of i_stream_id in an AudioBufferList */ AudioStreamBasicDescription stream_format; /* The format we changed the stream to */ AudioStreamBasicDescription sfmt_revert; /* The original format of the stream */ vlc_bool_t b_revert; /* Wether we need to revert the stream format */ vlc_bool_t b_changed_mixing;/* Wether we need to set the mixing mode back */};/***************************************************************************** * Local prototypes. *****************************************************************************/static int Open ( vlc_object_t * );static int OpenAnalog ( aout_instance_t * );static int OpenSPDIF ( aout_instance_t * );static void Close ( vlc_object_t * );static void Play ( aout_instance_t * );static void Probe ( aout_instance_t * );static int AudioDeviceHasOutput ( AudioDeviceID );static int AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );static int AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );static int AudioStreamChangeFormat ( aout_instance_t *, AudioStreamID, AudioStreamBasicDescription );static OSStatus RenderCallbackAnalog ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *, unsigned int, unsigned int, AudioBufferList *);static OSStatus RenderCallbackSPDIF ( AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *, AudioBufferList *, const AudioTimeStamp *, void * );static OSStatus HardwareListener ( AudioHardwarePropertyID, void *);static OSStatus StreamListener ( AudioStreamID, UInt32, AudioDevicePropertyID, void * );static int AudioDeviceCallback ( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * );/***************************************************************************** * Module descriptor *****************************************************************************/#define ADEV_TEXT N_("Audio Device")#define ADEV_LONGTEXT N_("Choose a number corresponding to the number of an " \ "audio device, as listed in your 'Audio Device' menu. This device will " \ "then be used by default for audio playback.")vlc_module_begin(); set_shortname( "auhal" ); set_description( _("HAL AudioUnit output") ); set_capability( "audio output", 101 ); set_category( CAT_AUDIO ); set_subcategory( SUBCAT_AUDIO_AOUT ); set_callbacks( Open, Close ); add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE ); vlc_module_end();/***************************************************************************** * Open: open macosx audio output *****************************************************************************/static int Open( vlc_object_t * p_this ){ OSStatus err = noErr; UInt32 i_param_size = 0; struct aout_sys_t *p_sys = NULL; vlc_bool_t b_alive = VLC_FALSE; vlc_value_t val; aout_instance_t *p_aout = (aout_instance_t *)p_this; /* Allocate structure */ p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return( VLC_ENOMEM ); } p_sys = p_aout->output.p_sys; p_sys->i_default_dev = 0; p_sys->i_selected_dev = 0; p_sys->i_devices = 0; p_sys->b_supports_digital = VLC_FALSE; p_sys->b_digital = VLC_FALSE; p_sys->au_component = NULL; p_sys->au_unit = NULL; p_sys->clock_diff = (mtime_t) 0; p_sys->i_read_bytes = 0; p_sys->i_total_bytes = 0; p_sys->i_hog_pid = -1; p_sys->i_stream_id = 0; p_sys->i_stream_index = -1; p_sys->b_revert = VLC_FALSE; p_sys->b_changed_mixing = VLC_FALSE; memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE ); p_aout->output.pf_play = Play; aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output ); /* Persistent device variable */ if( var_Type( p_aout->p_vlc, "macosx-audio-device" ) == 0 ) { var_Create( p_aout->p_vlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); } /* Build a list of devices */ if( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout ); } /* What device do we want? */ if( var_Get( p_aout, "audio-device", &val ) < 0 ) { msg_Err( p_aout, "audio-device var does not exist. device probe failed." ); goto error; } p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG; /* remove SPDIF flag to get the true DeviceID */ p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? VLC_TRUE : VLC_FALSE; /* Check if the desired device is alive and usable */ /* TODO: add a callback to the device to alert us if the device dies */ i_param_size = sizeof( b_alive ); err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertyDeviceIsAlive, &i_param_size, &b_alive ); if( err != noErr ) { msg_Err( p_aout, "could not check whether device is alive: %4.4s", (char *)&err ); goto error; } if( b_alive == VLC_FALSE ) { msg_Warn( p_aout, "selected audio device is not alive, switching to default device" ); p_sys->i_selected_dev = p_sys->i_default_dev; } i_param_size = sizeof( p_sys->i_hog_pid ); err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertyHogMode, &i_param_size, &p_sys->i_hog_pid ); if( err != noErr ) { /* This is not a fatal error. Some drivers simply don't support this property */ msg_Warn( p_aout, "could not check whether device is hogged: %4.4s", (char *)&err ); p_sys->i_hog_pid = -1; } if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() ) { msg_Err( p_aout, "Selected audio device is exclusively in use by another program." ); goto error; } /* Check for Digital mode or Analog output mode */ if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && p_sys->b_supports_digital ) { if( OpenSPDIF( p_aout ) ) return VLC_SUCCESS; } else { if( OpenAnalog( p_aout ) ) return VLC_SUCCESS; }error: /* If we reach this, this aout has failed */ var_Destroy( p_aout, "audio-device" ); if( p_sys ) free( p_sys ); return VLC_EGENERIC;}/***************************************************************************** * Open: open and setup a HAL AudioUnit to do analog (multichannel) audio output *****************************************************************************/static int OpenAnalog( aout_instance_t *p_aout ){ struct aout_sys_t *p_sys = p_aout->output.p_sys; OSStatus err = noErr; UInt32 i_param_size = 0, i = 0; int i_original; ComponentDescription desc; AudioStreamBasicDescription DeviceFormat; AudioChannelLayout *layout; AudioChannelLayout new_layout; AURenderCallbackStruct input; /* Lets go find our Component */ desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; p_sys->au_component = FindNextComponent( NULL, &desc ); if( p_sys->au_component == NULL ) { msg_Warn( p_aout, "we cannot find our HAL component" ); return VLC_FALSE; } err = OpenAComponent( p_sys->au_component, &p_sys->au_unit ); if( err != noErr ) { msg_Warn( p_aout, "we cannot open our HAL component" ); return VLC_FALSE; } /* Set the device we will use for this output unit */ err = AudioUnitSetProperty( p_sys->au_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &p_sys->i_selected_dev, sizeof( AudioDeviceID )); if( err != noErr ) { msg_Warn( p_aout, "we cannot select the audio device" ); return VLC_FALSE; } /* Get the current format */ i_param_size = sizeof(AudioStreamBasicDescription); err = AudioUnitGetProperty( p_sys->au_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &DeviceFormat, &i_param_size ); if( err != noErr ) return VLC_FALSE; else msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: ", DeviceFormat ) ); /* Get the channel layout of the device side of the unit (vlc -> unit -> device) */ err = AudioUnitGetPropertyInfo( p_sys->au_unit, kAudioDevicePropertyPreferredChannelLayout, kAudioUnitScope_Output, 0, &i_param_size, NULL ); if( err == noErr ) { layout = (AudioChannelLayout *)malloc( i_param_size); verify_noerr( AudioUnitGetProperty( p_sys->au_unit, kAudioDevicePropertyPreferredChannelLayout, kAudioUnitScope_Output, 0, layout, &i_param_size )); /* We need to "fill out" the ChannelLayout, because there are multiple ways that it can be set */ if( layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { /* bitmap defined channellayout */ verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForBitmap, sizeof( UInt32), &layout->mChannelBitmap, &i_param_size, layout )); } else if( layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions ) { /* layouttags defined channellayout */ verify_noerr( AudioFormatGetProperty( kAudioFormatProperty_ChannelLayoutForTag, sizeof( AudioChannelLayoutTag ), &layout->mChannelLayoutTag, &i_param_size, layout )); } msg_Dbg( p_aout, "layout of AUHAL has %d channels" , (int)layout->mNumberChannelDescriptions );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -