📄 winsndds.cpp
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#ifdef __DIRECTSOUND_ENABLED__#include "mediastreamer2/mssndcard.h"#include "mediastreamer2/msfilter.h"#include "mediastreamer2/msticker.h"#include <mmsystem.h>#ifdef _MSC_VER#include <mmreg.h>#endif#include <msacm.h>#include <dsound.h>#define WINSNDDS_NBUFS 10#define WINSNDDS_NSAMPLES 160#define WINSNDDS_MINIMUMBUFFER 5static MSFilter *ms_winsndds_read_new(MSSndCard *card);static MSFilter *ms_winsndds_write_new(MSSndCard *card);static HMODULE ms_lib_instance=NULL;static HRESULT (WINAPI *ms_DllGetClassObject)(REFCLSID , REFIID , LPVOID *); static HRESULT (WINAPI *ms_DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);static HRESULT (WINAPI *ms_DirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID); static HRESULT (WINAPI *ms_DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);static HRESULT (WINAPI *ms_DirectSoundCaptureEnumerate)(LPDSENUMCALLBACKA, LPVOID);typedef struct WinSndDsCard{ int in_devid; int out_devid; GUID in_guid; GUID out_guid;}WinSndDsCard;static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){ MMRESULT mr = MMSYSERR_NOERROR; DWORD dwVolume = 0xFFFF; dwVolume = ((0xFFFF) * percent) / 100; switch(e){ case MS_SND_CARD_MASTER: /*mr = waveOutSetVolume(d->waveoutdev, dwVolume); */ if (mr != MMSYSERR_NOERROR) { ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr); return; } break; case MS_SND_CARD_CAPTURE: break; case MS_SND_CARD_PLAYBACK: break; default: ms_warning("winsndds_card_set_level: unsupported command."); }}static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){ switch(e){ case MS_SND_CARD_MASTER: /*mr=waveOutGetVolume(d->waveoutdev, &dwVolume);*/ /* Transform to 0 to 100 scale*/ /*dwVolume = (dwVolume *100) / (0xFFFF);*/ return 60; break; case MS_SND_CARD_CAPTURE: break; case MS_SND_CARD_PLAYBACK: break; default: ms_warning("winsndds_card_get_level: unsupported command."); return -1; } return -1;}static void winsnddscard_set_source(MSSndCard *card, MSSndCardCapture source){ switch(source){ case MS_SND_CARD_MIC: break; case MS_SND_CARD_LINE: break; } }static void winsnddscard_init(MSSndCard *card){ WinSndDsCard *c=(WinSndDsCard *)ms_new(WinSndDsCard,1); card->data=c;}static void winsnddscard_uninit(MSSndCard *card){ ms_free(card->data);}static void winsnddscard_detect(MSSndCardManager *m);static MSSndCard *winsnddscard_dup(MSSndCard *obj);MSSndCardDesc winsndds_card_desc={ "WINSNDDS", winsnddscard_detect, winsnddscard_init, winsnddscard_set_level, winsnddscard_get_level, winsnddscard_set_source, ms_winsndds_read_new, ms_winsndds_write_new, winsnddscard_uninit, winsnddscard_dup};static MSSndCard *winsnddscard_dup(MSSndCard *obj){ MSSndCard *card=ms_snd_card_new(&winsndds_card_desc); card->name=ms_strdup(obj->name); card->data=ms_new(WinSndDsCard,1); memcpy(card->data,obj->data,sizeof(WinSndDsCard)); return card;}static MSSndCard *winsnddscard_new(const char *name, LPGUID lpguid, int in_dev, int out_dev, unsigned cap){ MSSndCard *card=ms_snd_card_new(&winsndds_card_desc); WinSndDsCard *d=(WinSndDsCard*)card->data; card->name=ms_strdup(name); d->in_devid=in_dev; d->out_devid=out_dev; card->capabilities=cap; if (out_dev!=-1) { if (lpguid!=NULL) memcpy(&d->out_guid, lpguid, sizeof(GUID)); else memset(&d->out_guid, 0, sizeof(GUID)); } else { if (lpguid!=NULL) memcpy(&d->in_guid, lpguid, sizeof(GUID)); else memset(&d->in_guid, 0, sizeof(GUID)); } return card;}static void add_or_update_card(MSSndCardManager *m, const char *name, LPGUID lpguid, int indev, int outdev, unsigned int capability){ MSSndCard *card; const MSList *elem=ms_snd_card_manager_get_list(m); for(;elem!=NULL;elem=elem->next){ card=(MSSndCard*)elem->data; if (strcmp(card->name,name)==0){ /*update already entered card */ WinSndDsCard *d=(WinSndDsCard*)card->data; card->capabilities|=capability; if (indev!=-1) d->in_devid=indev; if (outdev!=-1) d->out_devid=outdev; if (outdev!=-1) { if (lpguid!=NULL) memcpy(&d->out_guid, lpguid, sizeof(GUID)); else memset(&d->out_guid, 0, sizeof(GUID)); } if (indev!=-1) { if (lpguid!=NULL) memcpy(&d->in_guid, lpguid, sizeof(GUID)); else memset(&d->in_guid, 0, sizeof(GUID)); } return; } } /* add this new card:*/ ms_snd_card_manager_add_card(m,winsnddscard_new(name,lpguid, indev,outdev,capability));}static BOOL CALLBACK enumerate_capture_devices_callback(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ){ MSSndCardManager *m = (MSSndCardManager*)lpContext; static int dev_index=0; if ( lpGUID == NULL ) /* primary device */ { char snd_card_name[256]; snprintf(snd_card_name, 256, "ds: %s", lpszDesc); add_or_update_card(m,snd_card_name,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE); dev_index++; } else { char snd_card_name[256]; snprintf(snd_card_name, 256, "ds: %s", lpszDesc); add_or_update_card(m,snd_card_name,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE); dev_index++; } return true;}static BOOL CALLBACK enumerate_playback_devices_callback(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ){ MSSndCardManager *m = (MSSndCardManager*)lpContext; static int dev_index=0; if ( lpGUID == NULL ) /* primary device */ { char snd_card_name[256]; snprintf(snd_card_name, 256, "ds: %s", lpszDesc); add_or_update_card(m,snd_card_name,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK); dev_index++; } else { char snd_card_name[256]; snprintf(snd_card_name, 256, "ds: %s", lpszDesc); add_or_update_card(m,snd_card_name,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK); dev_index++; } return true;}static void winsnddscard_detect(MSSndCardManager *m){ MMRESULT mr = NOERROR; if (ms_lib_instance==NULL) { ms_lib_instance = LoadLibrary("dsound.dll"); if( ms_lib_instance == NULL ) { /* error */ ms_debug("winsnddscard_init: no support for dsound (missing dsound.dll)\n"); return; } ms_DllGetClassObject =(HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *)) GetProcAddress( ms_lib_instance, "DllGetClassObject" ); ms_DirectSoundCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN)) GetProcAddress( ms_lib_instance, "DirectSoundCreate" ); ms_DirectSoundEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) GetProcAddress( ms_lib_instance, "DirectSoundEnumerateA" ); ms_DirectSoundCaptureCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN)) GetProcAddress( ms_lib_instance, "DirectSoundCaptureCreate" ); ms_DirectSoundCaptureEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) GetProcAddress( ms_lib_instance, "DirectSoundCaptureEnumerateA" ); if( ms_DllGetClassObject == NULL || ms_DirectSoundCreate == NULL || ms_DirectSoundEnumerate == NULL || ms_DirectSoundCaptureEnumerate == NULL || ms_DirectSoundCaptureCreate == NULL ) { /* error */ ms_debug("winsnddscard_init: no support for dsound\n"); return; } } ms_DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)enumerate_capture_devices_callback, (void *)m ); ms_DirectSoundEnumerate( (LPDSENUMCALLBACK)enumerate_playback_devices_callback, (void *)m );}typedef struct WinSndDs{ int dev_id; GUID in_guid; GUID out_guid; ms_thread_t thread; ms_mutex_t thread_lock; ms_cond_t thread_cond; bool_t thread_running; MSBufferizer output_buff; LPDIRECTSOUND lpDirectSound; LPDIRECTSOUNDBUFFER lpDirectSoundOutputBuffer; DWORD outputBufferWriteOffsetBytes; /* last write position */ double dsw_framesWritten; LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; LPDIRECTSOUNDCAPTUREBUFFER lpDirectSoundInputBuffer; UINT readOffset; /* last read position */ UINT inputSize; int framesPerDSBuffer; WAVEFORMATEX wfx; queue_t rq; ms_mutex_t mutex; unsigned int bytes_read; unsigned int nbufs_playing; int32_t stat_input; int32_t stat_output; int32_t stat_notplayed; int32_t stat_minimumbuffer;}WinSndDs;void * winsndds_read_thread(void *arg){ WinSndDs *d=(WinSndDs*)arg; ms_mutex_lock(&d->thread_lock); ms_cond_signal(&d->thread_cond); ms_mutex_unlock(&d->thread_lock); while(d->thread_running) { HRESULT hr; DWORD capturePos; DWORD readPos; long filled = 0; long bytesFilled = 0; LPBYTE lpInBuf1 = NULL; LPBYTE lpInBuf2 = NULL; DWORD dwInSize1 = 0; DWORD dwInSize2 = 0; hr = IDirectSoundCaptureBuffer_GetCurrentPosition( d->lpDirectSoundInputBuffer, &capturePos, &readPos ); if( hr != DS_OK ) { continue; } filled = readPos - d->readOffset; if( filled < 0 ) filled += d->inputSize; // unwrap offset bytesFilled = filled; hr = IDirectSoundCaptureBuffer_Lock ( d->lpDirectSoundInputBuffer, d->readOffset, bytesFilled, (void **) &lpInBuf1, &dwInSize1, (void **) &lpInBuf2, &dwInSize2, 0); if (hr != DS_OK) { Sleep(10); continue; } if (dwInSize1==0) { Sleep(10); } else if (dwInSize1>=bytesFilled) { mblk_t *m=allocb(bytesFilled,0); memcpy(m->b_rptr, lpInBuf1, bytesFilled); m->b_wptr+=bytesFilled; ms_mutex_lock(&d->mutex); putq(&d->rq,m); ms_mutex_unlock(&d->mutex); d->bytes_read+=bytesFilled; } else { mblk_t *m=allocb(bytesFilled,0); memcpy(m->b_rptr, lpInBuf1, dwInSize1); memcpy(m->b_rptr+dwInSize1, lpInBuf2, dwInSize2); m->b_wptr+=bytesFilled; ms_mutex_lock(&d->mutex); putq(&d->rq,m); ms_mutex_unlock(&d->mutex); d->bytes_read+=bytesFilled; } d->readOffset = (d->readOffset + bytesFilled) % d->inputSize; IDirectSoundCaptureBuffer_Unlock( d->lpDirectSoundInputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2); } ms_mutex_lock(&d->thread_lock); ms_cond_signal(&d->thread_cond); ms_mutex_unlock(&d->thread_lock); ms_thread_exit(NULL); return NULL;}static void winsndds_apply_settings(WinSndDs *d){ d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8; d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign;}static uint64_t winsndds_get_cur_time( void *data){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -