📄 waveout.c
字号:
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" ); } /* Test for SPDIF support */ if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { if( OpenWaveOut( 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, 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: play a sound buffer ***************************************************************************** * This doesn't actually play the buffer. This just stores the buffer so it * can be played by the callback thread. *****************************************************************************/static void Play( aout_instance_t *_p_aout ){}/***************************************************************************** * Close: close the audio device *****************************************************************************/static void Close( 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; /* Before calling waveOutClose we must reset the device */ p_aout->b_die = VLC_TRUE; waveOutReset( p_sys->h_waveout ); /* wake up the audio thread */ SetEvent( p_sys->event ); vlc_thread_join( p_sys->p_notif ); vlc_object_destroy( p_sys->p_notif ); CloseHandle( p_sys->event ); /* Close the device */ if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR ) { msg_Err( p_aout, "waveOutClose failed" ); } free( p_sys->p_silence_buffer ); free( p_sys );}/***************************************************************************** * OpenWaveOut: open the waveout sound device ****************************************************************************/static int OpenWaveOut( aout_instance_t *p_aout, int i_format, int i_channels, int i_nb_channels, int i_rate, vlc_bool_t b_probe ){ MMRESULT result; unsigned int i; /* Set sound format */#define waveformat p_aout->output.p_sys->waveformat 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; } waveformat.Format.nChannels = i_nb_channels; waveformat.Format.nSamplesPerSec = i_rate; waveformat.Format.nBlockAlign = waveformat.Format.wBitsPerSample / 8 * i_nb_channels; waveformat.Format.nAvgBytesPerSec = waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign; /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ if( i_nb_channels <= 2 ) { waveformat.Format.cbSize = 0; } else { waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; waveformat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); } /* Open the device */ result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER, (WAVEFORMATEX *)&waveformat, (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout, CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) ); if( result == WAVERR_BADFORMAT ) { msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" ); return VLC_EGENERIC; } if( result == MMSYSERR_ALLOCATED ) { msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" ); return VLC_EGENERIC; } if( result != MMSYSERR_NOERROR ) { msg_Warn( p_aout, "waveOutOpen failed" ); return VLC_EGENERIC; } p_aout->output.p_sys->b_chan_reorder = aout_CheckChannelReorder( pi_channels_in, pi_channels_out, waveformat.dwChannelMask, i_nb_channels, p_aout->output.p_sys->pi_chan_table ); if( p_aout->output.p_sys->b_chan_reorder ) { msg_Dbg( p_aout, "channel reordering needed" ); } return VLC_SUCCESS;#undef waveformat}/***************************************************************************** * OpenWaveOutPCM: open a PCM waveout sound device ****************************************************************************/static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format, int i_channels, int i_nb_channels, int i_rate, vlc_bool_t b_probe ){ vlc_value_t val; var_Get( p_aout, "waveout-float32", &val ); if( !val.b_bool || OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'), i_channels, i_nb_channels, i_rate, b_probe ) != VLC_SUCCESS ) { if ( OpenWaveOut( p_aout, VLC_FOURCC('s','1','6','l'), i_channels, i_nb_channels, i_rate, b_probe ) != VLC_SUCCESS ) { return VLC_EGENERIC; } else { *i_format = VLC_FOURCC('s','1','6','l'); return VLC_SUCCESS; } } else { *i_format = VLC_FOURCC('f','l','3','2'); return VLC_SUCCESS; }}/***************************************************************************** * PlayWaveOut: play a buffer through the WaveOut device *****************************************************************************/static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout, WAVEHDR *p_waveheader, aout_buffer_t *p_buffer ){ MMRESULT result; /* Prepare the buffer */ if( p_buffer != NULL ) p_waveheader->lpData = p_buffer->p_buffer; else /* Use silence buffer instead */ p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer; p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1; p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size; p_waveheader->dwFlags = 0; result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) ); if( result != MMSYSERR_NOERROR ) { msg_Err( p_aout, "waveOutPrepareHeader failed" ); return VLC_EGENERIC; } /* Send the buffer to the waveOut queue */ result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) ); if( result != MMSYSERR_NOERROR ) { msg_Err( p_aout, "waveOutWrite failed" ); return VLC_EGENERIC; } return VLC_SUCCESS;}/***************************************************************************** * WaveOutCallback: what to do once WaveOut has played its sound samples *****************************************************************************/static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg, DWORD _p_aout, DWORD dwParam1, DWORD dwParam2 ){ aout_instance_t *p_aout = (aout_instance_t *)_p_aout; int i, i_queued_frames = 0; if( uMsg != WOM_DONE ) return; if( p_aout->b_die ) return; /* Find out the current latency */ for( i = 0; i < FRAMES_NUM; i++ ) { /* Check if frame buf is available */ if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) ) { i_queued_frames++; } } /* Don't wake up the thread too much */ if( i_queued_frames < FRAMES_NUM / 2 ) SetEvent( p_aout->output.p_sys->event );}/***************************************************************************** * WaveOutThread: this thread will capture play notification events. ***************************************************************************** * We use this thread to feed new audio samples to the sound card because * we are not authorized to use waveOutWrite() directly in the waveout * callback. *****************************************************************************/static void WaveOutThread( notification_thread_t *p_notif ){ aout_instance_t *p_aout = p_notif->p_aout; aout_sys_t *p_sys = p_aout->output.p_sys; aout_buffer_t *p_buffer = NULL; WAVEHDR *p_waveheader = p_sys->waveheader; int i, i_queued_frames; vlc_bool_t b_sleek; /* We don't want any resampling when using S/PDIF */ b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i'); while( 1 ) { WaitForSingleObject( p_sys->event, INFINITE ); /* Cleanup and find out the current latency */ i_queued_frames = 0; for( i = 0; i < FRAMES_NUM; i++ ) { if( (p_waveheader[i].dwFlags & WHDR_DONE) && p_waveheader[i].dwUser ) { /* Unprepare and free the buffers which has just been played */ waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i], sizeof(WAVEHDR) ); if( p_waveheader[i].dwUser != 1 ) aout_BufferFree( (aout_buffer_t *)p_waveheader[i].dwUser ); p_waveheader[i].dwUser = 0; } /* Check if frame buf is available */ if( !(p_waveheader[i].dwFlags & WHDR_DONE) ) { i_queued_frames++; } } if( p_aout->b_die ) return; /* Try to fill in as many frame buffers as possible */ for( i = 0; i < FRAMES_NUM; i++ ) { /* Check if frame buf is available */ if( p_waveheader[i].dwFlags & WHDR_DONE ) { /* Take into account the latency */ p_buffer = aout_OutputNextBuffer( p_aout, mdate() + 1000000 * i_queued_frames / p_aout->output.output.i_rate * p_aout->output.i_nb_samples, b_sleek ); if( !p_buffer && i_queued_frames ) { /* We aren't late so no need to play a blank sample */ break; } /* Do the channel reordering */ if( p_buffer && p_sys->b_chan_reorder ) { aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes, p_sys->waveformat.Format.nChannels, p_sys->pi_chan_table, p_sys->waveformat.Format.wBitsPerSample ); } PlayWaveOut( p_aout, p_sys->h_waveout, &p_waveheader[i], p_buffer ); i_queued_frames++; } } }}static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft ){ *pi_soft = AOUT_VOLUME_MAX / 2; return 0;}static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ){ DWORD i_waveout_vol;#ifdef UNDER_CE waveOutGetVolume( 0, &i_waveout_vol );#else waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );#endif i_waveout_vol &= 0xFFFF; *pi_volume = p_aout->output.i_volume = i_waveout_vol * AOUT_VOLUME_MAX / 2 / 0xFFFF; return 0;}static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume ){ unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX; i_waveout_vol |= (i_waveout_vol << 16);#ifdef UNDER_CE waveOutSetVolume( 0, i_waveout_vol );#else waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );#endif p_aout->output.i_volume = i_volume; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -