📄 directx.c
字号:
} vlc_object_attach( p_aout->output.p_sys->p_notif, p_aout ); return VLC_SUCCESS; error: CloseAudio( VLC_OBJECT(p_aout) ); return VLC_EGENERIC;}/***************************************************************************** * Probe: probe the audio device for available formats and channels *****************************************************************************/static void Probe( aout_instance_t * p_aout ){ vlc_value_t val, text; int i_format; unsigned int i_physical_channels; DWORD ui_speaker_config; var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Device"); var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL ); /* Test for 5.1 support */ i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; if( p_aout->output.output.i_physical_channels == i_physical_channels ) { if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 6, p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { val.i_int = AOUT_VAR_5_1; text.psz_string = N_("5.1"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 5.1 channels" ); } } /* Test for 3 Front 2 Rear support */ i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; if( p_aout->output.output.i_physical_channels == i_physical_channels ) { if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 5, p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { val.i_int = AOUT_VAR_3F2R; text.psz_string = N_("3 Front 2 Rear"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 5 channels" ); } } /* Test for 2 Front 2 Rear support */ i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; if( ( p_aout->output.output.i_physical_channels & i_physical_channels ) == i_physical_channels ) { if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 4, p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { val.i_int = AOUT_VAR_2F2R; text.psz_string = N_("2 Front 2 Rear"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 4 channels" ); } } /* Test for stereo support */ i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 2, p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { val.i_int = AOUT_VAR_STEREO; text.psz_string = N_("Stereo"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL ); msg_Dbg( p_aout, "device supports 2 channels" ); } /* Test for mono support */ i_physical_channels = AOUT_CHAN_CENTER; if( CreateDSBufferPCM( p_aout, &i_format, i_physical_channels, 1, p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { val.i_int = AOUT_VAR_MONO; text.psz_string = N_("Mono"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 1 channel" ); } /* Check the speaker configuration to determine which channel config should * be the default */ if FAILED( IDirectSound_GetSpeakerConfig( p_aout->output.p_sys->p_dsobject, &ui_speaker_config ) ) { ui_speaker_config = DSSPEAKER_STEREO; } switch( DSSPEAKER_CONFIG(ui_speaker_config) ) { case DSSPEAKER_5POINT1: val.i_int = AOUT_VAR_5_1; break; case DSSPEAKER_QUAD: val.i_int = AOUT_VAR_2F2R; break;#if 0 /* Lots of people just get their settings wrong and complain that * this is a problem with VLC so just don't ever set mono by default. */ case DSSPEAKER_MONO: val.i_int = AOUT_VAR_MONO; break;#endif case DSSPEAKER_SURROUND: case DSSPEAKER_STEREO: default: val.i_int = AOUT_VAR_STEREO; break; } var_Set( p_aout, "audio-device", val ); /* Test for SPDIF support */ if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { if( CreateDSBuffer( p_aout, VLC_FOURCC('s','p','d','i'), p_aout->output.output.i_physical_channels, aout_FormatNbChannels( &p_aout->output.output ), p_aout->output.output.i_rate, AOUT_SPDIF_SIZE, VLC_TRUE ) == VLC_SUCCESS ) { msg_Dbg( p_aout, "device supports A/52 over S/PDIF" ); val.i_int = AOUT_VAR_SPDIF; text.psz_string = N_("A/52 over S/PDIF"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); if( config_GetInt( p_aout, "spdif" ) ) var_Set( p_aout, "audio-device", val ); } } var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL ); if( val.i_int <= 0 ) { /* Probe() has failed. */ var_Destroy( p_aout, "audio-device" ); return; } var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); val.b_bool = VLC_TRUE; var_Set( p_aout, "intf-change", val );}/***************************************************************************** * Play: we'll start playing the directsound buffer here because at least here * we know the first buffer has been put in the aout fifo and we also * know its date. *****************************************************************************/static void Play( aout_instance_t *p_aout ){ if( !p_aout->output.p_sys->b_playing ) { aout_buffer_t *p_buffer; p_aout->output.p_sys->b_playing = 1; /* get the playing date of the first aout buffer */ p_aout->output.p_sys->p_notif->start_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo ); /* fill in the first samples */ p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); FillBuffer( p_aout, 0, p_buffer ); /* wake up the audio output thread */ SetEvent( p_aout->output.p_sys->p_notif->p_events[0].hEventNotify ); }}/***************************************************************************** * CloseAudio: close the audio device *****************************************************************************/static void CloseAudio( vlc_object_t *p_this ){ aout_instance_t * p_aout = (aout_instance_t *)p_this; aout_sys_t *p_sys = p_aout->output.p_sys; msg_Dbg( p_aout, "CloseAudio" ); /* kill the position notification thread, if any */ if( p_sys->p_notif ) { vlc_object_detach( p_sys->p_notif ); if( p_sys->p_notif->b_thread ) { p_sys->p_notif->b_die = 1; if( !p_sys->b_playing ) /* wake up the audio thread */ SetEvent( p_sys->p_notif->p_events[0].hEventNotify ); vlc_thread_join( p_sys->p_notif ); } vlc_object_destroy( p_sys->p_notif ); } /* release the secondary buffer */ DestroyDSBuffer( p_aout ); /* finally release the DirectSound object */ if( p_sys->p_dsobject ) IDirectSound_Release( p_sys->p_dsobject ); /* free DSOUND.DLL */ if( p_sys->hdsound_dll ) FreeLibrary( p_sys->hdsound_dll ); if( p_aout->output.p_sys->p_device_guid ) free( p_aout->output.p_sys->p_device_guid ); free( p_sys );}/***************************************************************************** * CallBackDirectSoundEnum: callback to enumerate available devices *****************************************************************************/static int CALLBACK CallBackDirectSoundEnum( LPGUID p_guid, LPCSTR psz_desc, LPCSTR psz_mod, LPVOID _p_aout ){ aout_instance_t *p_aout = (aout_instance_t *)_p_aout; msg_Dbg( p_aout, "found device: %s", psz_desc ); if( p_aout->output.p_sys->i_device_id == 0 && p_guid ) { p_aout->output.p_sys->p_device_guid = malloc( sizeof( GUID ) ); *p_aout->output.p_sys->p_device_guid = *p_guid; msg_Dbg( p_aout, "using device: %s", psz_desc ); } p_aout->output.p_sys->i_device_id--; return 1;}/***************************************************************************** * InitDirectSound: handle all the gory details of DirectSound initialisation *****************************************************************************/static int InitDirectSound( aout_instance_t *p_aout ){ HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACK, LPVOID); p_aout->output.p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL"); if( p_aout->output.p_sys->hdsound_dll == NULL ) { msg_Warn( p_aout, "cannot open DSOUND.DLL" ); goto error; } OurDirectSoundCreate = (void *) GetProcAddress( p_aout->output.p_sys->hdsound_dll, "DirectSoundCreate" ); if( OurDirectSoundCreate == NULL ) { msg_Warn( p_aout, "GetProcAddress FAILED" ); goto error; } /* Get DirectSoundEnumerate */ OurDirectSoundEnumerate = (void *) GetProcAddress( p_aout->output.p_sys->hdsound_dll, "DirectSoundEnumerateA" ); if( OurDirectSoundEnumerate ) { /* Attempt enumeration */ if( FAILED( OurDirectSoundEnumerate( CallBackDirectSoundEnum, p_aout ) ) ) { msg_Dbg( p_aout, "enumeration of DirectSound devices failed" ); } } /* Create the direct sound object */ if FAILED( OurDirectSoundCreate( p_aout->output.p_sys->p_device_guid, &p_aout->output.p_sys->p_dsobject, NULL ) ) { msg_Warn( p_aout, "cannot create a direct sound device" ); goto error; } /* Set DirectSound Cooperative level, ie what control we want over Windows * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the * settings of the primary buffer, but also that only the sound of our * application will be hearable when it will have the focus. * !!! (this is not really working as intended yet because to set the * cooperative level you need the window handle of your application, and * I don't know of any easy way to get it. Especially since we might play * sound without any video, and so what window handle should we use ??? * The hack for now is to use the Desktop window handle - it seems to be * working */ if( IDirectSound_SetCooperativeLevel( p_aout->output.p_sys->p_dsobject, GetDesktopWindow(), DSSCL_EXCLUSIVE) ) { msg_Warn( p_aout, "cannot set direct sound cooperative level" ); } return VLC_SUCCESS; error: p_aout->output.p_sys->p_dsobject = NULL; if( p_aout->output.p_sys->hdsound_dll ) { FreeLibrary( p_aout->output.p_sys->hdsound_dll ); p_aout->output.p_sys->hdsound_dll = NULL; } return VLC_EGENERIC;}/***************************************************************************** * CreateDSBuffer: Creates a direct sound buffer of the required format. ***************************************************************************** * This function creates the buffer we'll use to play audio. * In DirectSound there are two kinds of buffers: * - the primary buffer: which is the actual buffer that the soundcard plays * - the secondary buffer(s): these buffers are the one actually used by * applications and DirectSound takes care of mixing them into the primary. * * Once you create a secondary buffer, you cannot change its format anymore so * you have to release the current one and create another. *****************************************************************************/static int CreateDSBuffer( aout_instance_t *p_aout, int i_format, int i_channels, int i_nb_channels, int i_rate, int i_bytes_per_frame, vlc_bool_t b_probe ){ WAVEFORMATEXTENSIBLE waveformat; DSBUFFERDESC dsbdesc; unsigned int i; /* First set the sound buffer format */ waveformat.dwChannelMask = 0; for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ ) { if( i_channels & pi_channels_src[i] ) waveformat.dwChannelMask |= pi_channels_in[i]; } switch( i_format ) { case VLC_FOURCC('s','p','d','i'): i_nb_channels = 2; /* To prevent channel re-ordering */ waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; waveformat.Format.wBitsPerSample = 16; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF; break; case VLC_FOURCC('f','l','3','2'): waveformat.Format.wBitsPerSample = sizeof(float) * 8; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; break; case VLC_FOURCC('s','1','6','l'): waveformat.Format.wBitsPerSample = 16; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_PCM; waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -