📄 ao_dsound.c
字号:
/********************************************** * Dawn Light Player * * ao_dsound.c * * Created by qwdu * 17:44:23 03/18/08 CST * * $Id: ao_dsound.c 168 2008-03-21 02:50:01Z kf701 $ **********************************************/#if ENABLE_AO_DSOUND#include <windows.h>#include <dsound.h>#include <math.h>#include "avoutput.h"#include "global.h"static pthread_mutex_t ao_mutex;static void ao_lock_init(){ pthread_mutex_init(&ao_mutex,NULL);}static void ao_lock_free(){ pthread_mutex_destroy(&ao_mutex);}static void ao_lock(){ pthread_mutex_lock(&ao_mutex);}static void ao_unlock(){ pthread_mutex_unlock(&ao_mutex);}#ifndef _WAVEFORMATEXTENSIBLE_typedef struct{ WAVEFORMATEX Format; union { WORD wValidBitsPerSample; WORD wSamplesPerBlock; WORD wReserved; } Samples; DWORD dwChannelMask; GUID SubFormat;} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;#endifstatic HINSTANCE hdsound_dll = NULL;static LPDIRECTSOUND hds = NULL;static LPDIRECTSOUNDBUFFER hdspribuf = NULL;static LPDIRECTSOUNDBUFFER hdsbuf = NULL;static int buffer_size = 0;static int write_offset = 0;static int min_free_space = 0;static int device_num = 0;static GUID device;static void dsound_reset(void){ ao_lock(); IDirectSoundBuffer_Stop(hdsbuf); IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0); write_offset=0; ao_unlock();}static void dsound_pause(void){ ao_lock(); IDirectSoundBuffer_Stop(hdsbuf); ao_unlock();}static void dsound_resume(void){ ao_lock(); IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING); ao_unlock();}static void UninitDirectSound(void){ if (hds) { IDirectSound_Release(hds); hds = NULL; } if (hdsound_dll) { FreeLibrary(hdsound_dll); hdsound_dll = NULL; }}static BOOL CALLBACK DirectSoundEnum(LPGUID guid,LPCSTR desc,LPCSTR module,LPVOID context){ int* device_index=context; if (device_num==*device_index) { if (guid) memcpy(&device,guid,sizeof(GUID)); } (*device_index)++; return TRUE;}static int InitDirectSound(void){ DSCAPS dscaps; HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID); int device_index=0; hdsound_dll = LoadLibrary("DSOUND.DLL"); if (hdsound_dll == NULL) { av_log(NULL, AV_LOG_ERROR, "LoadLibrary DSOUND.DLL error\n"); return -1; } OurDirectSoundCreate = (void*)GetProcAddress(hdsound_dll, "DirectSoundCreate"); OurDirectSoundEnumerate = (void*)GetProcAddress(hdsound_dll, "DirectSoundEnumerateA"); if (OurDirectSoundCreate == NULL || OurDirectSoundEnumerate == NULL) { FreeLibrary(hdsound_dll); av_log(NULL, AV_LOG_ERROR, "GetProcAddress error\n"); return -1; } OurDirectSoundEnumerate(DirectSoundEnum,&device_index); if FAILED(OurDirectSoundCreate((device_num)?&device:NULL, &hds, NULL )) { FreeLibrary(hdsound_dll); av_log(NULL, AV_LOG_ERROR, "Create Device error\n"); return -1; } if (IDirectSound_SetCooperativeLevel(hds, GetDesktopWindow(), DSSCL_EXCLUSIVE)) { IDirectSound_Release(hds); FreeLibrary(hdsound_dll); av_log(NULL, AV_LOG_ERROR, "IDirectSound_SetCooperativeLevel error\n"); return -1; } memset(&dscaps, 0, sizeof(DSCAPS)); dscaps.dwSize = sizeof(DSCAPS); IDirectSound_GetCaps(hds, &dscaps); return 0;}static void DestroyBuffer(void){ if (hdsbuf) { IDirectSoundBuffer_Release(hdsbuf); hdsbuf = NULL; } if (hdspribuf) { IDirectSoundBuffer_Release(hdspribuf); hdspribuf = NULL; }}static int write_buffer(unsigned char *data, int len){ HRESULT res; LPVOID lpvPtr1; DWORD dwBytes1; LPVOID lpvPtr2; DWORD dwBytes2; res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); if (DSERR_BUFFERLOST == res) { IDirectSoundBuffer_Restore(hdsbuf); res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); } if ( SUCCEEDED(res) ) { if ( NULL != lpvPtr1 ) memcpy(lpvPtr1,data,dwBytes1); if ( NULL != lpvPtr2 ) memcpy( lpvPtr2,data+dwBytes1,dwBytes2 ) ; write_offset += dwBytes1 + dwBytes2 ; if ( write_offset >= buffer_size ) write_offset = dwBytes2 ; res = IDirectSoundBuffer_Unlock(hdsbuf,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); if ( SUCCEEDED(res) ) { DWORD status; IDirectSoundBuffer_GetStatus(hdsbuf, &status); if (!(status & DSBSTATUS_PLAYING)) res = IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING); return dwBytes1 + dwBytes2 ; } } return 0;}static int dsound_control(int cmd, void *arg){ int left, right; DWORD volume; switch (cmd) { case AO_GET_VOLUME: IDirectSoundBuffer_GetVolume(hdsbuf, &volume); left = right = pow(10.0, (float)(volume+10000) / 5000.0); return left; case AO_ADD_VOLUME: IDirectSoundBuffer_GetVolume(hdsbuf, &volume); left = right = pow(10.0, (float)(volume+10000) / 5000.0); left = left + 5; left = left > 100 ? 100 : left; volume = (DWORD)(log10(left) * 5000.0) - 10000; IDirectSoundBuffer_SetVolume(hdsbuf, volume); av_log(NULL, AV_LOG_INFO, "Change Volume to %d \r", left); break; case AO_SUB_VOLUME: IDirectSoundBuffer_GetVolume(hdsbuf, &volume); left = right = pow(10.0, (float)(volume+10000) / 5000.0); left = left - 5; left = left < 0 ? 0 : left; volume = (DWORD)(log10(left) * 5000.0) - 10000; IDirectSoundBuffer_SetVolume(hdsbuf, volume); av_log(NULL, AV_LOG_INFO, "Change Volume to %d \r", left); break; case AO_PAUSE: dsound_pause(); break; case AO_RESUME: dsound_resume(); break; default: av_log(NULL, AV_LOG_INFO, "Dsound Not Support the CMD now!\n"); break; } return -1;}static int sample_size( int fmt ){ switch (fmt) { case SAMPLE_FMT_U8: return 8; case SAMPLE_FMT_S16: return 16; case SAMPLE_FMT_S24: return 24; case SAMPLE_FMT_S32: return 32; case SAMPLE_FMT_FLT: return 64; } return 16;}static int dsound_init(void){ int srate = dlpctxp->sample_rate; int channels = dlpctxp->channels; int format = dlpctxp->sample_fmt; int res, bits_per_sample, outburst, bytes_per_second; WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; if ( InitDirectSound() < 0 ) { av_log(NULL, AV_LOG_ERROR, "InitDirectSound error\n"); return -1; } bits_per_sample = sample_size(format); bytes_per_second = channels * srate * bits_per_sample / 8; //fill waveformatex ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); wformat.Format.cbSize = 0; wformat.Format.nChannels = channels; wformat.Format.nSamplesPerSec = srate; wformat.Format.wFormatTag = WAVE_FORMAT_PCM; wformat.Format.wBitsPerSample = bits_per_sample; wformat.Format.nBlockAlign = channels * bits_per_sample / 8 ; // fill in primary sound buffer descriptor memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC)); dsbpridesc.dwSize = sizeof(DSBUFFERDESC); dsbpridesc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbpridesc.dwBufferBytes = 0; dsbpridesc.lpwfxFormat = NULL; // fill in the secondary sound buffer (=stream buffer) descriptor memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */ | DSBCAPS_GLOBALFOCUS /** Allows background playing */ | DSBCAPS_CTRLVOLUME; /** volume control enabled */ wformat.Format.nAvgBytesPerSec = srate * wformat.Format.nBlockAlign; dsbdesc.dwBufferBytes = bytes_per_second; dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat; buffer_size = dsbdesc.dwBufferBytes; write_offset = 0; min_free_space = wformat.Format.nBlockAlign; outburst = wformat.Format.nBlockAlign * 512; res = IDirectSound_CreateSoundBuffer( hds, &dsbpridesc, &hdspribuf, NULL ); if ( res != DS_OK ) { UninitDirectSound(); av_log(NULL, AV_LOG_ERROR, "IDirectSound_CreateSoundBuffer error\n"); return -1; } res = IDirectSoundBuffer_SetFormat( hdspribuf, (WAVEFORMATEX *)&wformat ); if ( res != DS_OK ) av_log(NULL, AV_LOG_ERROR, "IDirectSoundBuffer_SetFormat\n"); res = IDirectSound_CreateSoundBuffer(hds, &dsbdesc, &hdsbuf, NULL); if (res != DS_OK) { if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) { dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; res = IDirectSound_CreateSoundBuffer(hds, &dsbdesc, &hdsbuf, NULL); } if (res != DS_OK) { UninitDirectSound(); av_log(NULL, AV_LOG_ERROR, "IDirectSound_CreateSoundBuffer stream buffer error\n"); return -1; } } ao_lock_init(); av_log(NULL, AV_LOG_INFO, "dsound: buffersize=%d, srate=%d, \ bits_per_sample=%d, bytes_per_second=%d, outburst=%d\n", buffer_size, srate, bits_per_sample, bytes_per_second, outburst); return 0;}static int dsound_uninit(void){ DWORD status; ao_lock(); IDirectSoundBuffer_Play(hdsbuf, 0, 0, 0); while ( !IDirectSoundBuffer_GetStatus(hdsbuf,&status) && (status&DSBSTATUS_PLAYING) ) usleep( 20* 1000 ); DestroyBuffer(); UninitDirectSound(); ao_lock_free(); return 0;}static int dsound_getspace(void){ int space, ret; DWORD play_offset; ao_lock(); IDirectSoundBuffer_GetCurrentPosition( hdsbuf,&play_offset,NULL ); space = buffer_size - ( write_offset - play_offset ); if (space > buffer_size) space -= buffer_size; if (space < min_free_space) ret = 0; ret = space - min_free_space; ao_unlock(); return ret;}static void dsound_play(AVSample *s){ uint8_t *data = s->data; int len = s->size; while ( dsound_getspace() < len ) /* must wait */ usleep(1000); ao_lock(); write_buffer(data, len); ao_unlock();}ao_t ao_dsound ={ .id = AO_ID_DSOUND, .name = "dsound", .ao_init = dsound_init, .ao_uninit = dsound_uninit, .ao_play = dsound_play, .ao_getspace = dsound_getspace, .ao_control = dsound_control,};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -