📄 winsnd.c
字号:
/*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.*/#if defined(_WIN32_WCE)#define DISABLE_SPEEX#endif#ifndef WINSND_BUFLEN#define WINSND_BUFLEN 320#endif#ifndef MAX_WAVEHDR#define MAX_WAVEHDR 6#endif#ifndef DISABLE_SPEEX#include <speex/speex_preprocess.h>#endif#include "mediastreamer2/mssndcard.h"#include "mediastreamer2/msfilter.h"#include "mediastreamer2/msticker.h"#ifdef WIN32#include <malloc.h> /* for alloca */#endif#include <mmsystem.h>#ifdef _MSC_VER#include <mmreg.h>#endif#include <msacm.h>MSFilter *ms_winsnd_read_new(MSSndCard *card);MSFilter *ms_winsnd_write_new(MSSndCard *card);typedef struct WinSndData{ char *pcmdev; char *mixdev; int devid; int sound_err; WAVEFORMATEX wfx;#ifdef CONTROLVOLUME DWORD dwOldVolume;#endif WAVEHDR waveouthdr[30]; char waveoutbuffer[30][3200]; HWAVEOUT waveoutdev; int buffer_playing; int pos_whdr; WAVEHDR waveinhdr[30]; HWAVEIN waveindev; char waveinbuffer[30][3200]; int rate; int bits; ms_thread_t thread; ms_mutex_t mutex; queue_t rq; MSBufferizer * bufferizer; bool_t read_started; bool_t write_started; bool_t stereo;#ifndef DISABLE_SPEEX SpeexPreprocessState *pst;#endif uint64_t bytes_read; int32_t stat_input; int32_t stat_output; int32_t stat_notplayed;} WinSndData;static uint64_t winsnd_get_cur_time( void *data){ WinSndData *d=(WinSndData*)data; uint64_t curtime=(d->bytes_read*1000)/(d->rate*(d->bits/8)*((d->stereo==FALSE) ? 1 : 2)); ms_debug("winsnd_get_cur_time: bytes_read=%lu, rate=%i, bits=%i, stereo=%i return %lu\n", (unsigned long)d->bytes_read,d->rate,d->bits,d->stereo,(unsigned long)curtime); return curtime;}static void CALLBACKSpeakerCallback (HWAVEOUT _waveoutdev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2){ WAVEHDR *wHdr; WinSndData *device; switch (uMsg) { case WOM_OPEN: ms_message("SpeakerCallback : WOM_OPEN"); break; case WOM_CLOSE: ms_message("SpeakerCallback : WOM_CLOSE"); break; case WOM_DONE: wHdr = (WAVEHDR *) dwParam1; device = (WinSndData *)dwInstance; device->buffer_playing--; if (device->stat_output==0) { device->stat_input=1; /* reset */ device->stat_notplayed=0; } device->stat_output++; break; default: break; }}static void CALLBACKWaveInCallback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2){ WAVEHDR *wHdr; MMRESULT mr = NOERROR; WinSndData *device; device = (WinSndData *)dwInstance; switch (uMsg) { case MM_WOM_DONE: wHdr = (WAVEHDR *) dwParam1; /* A waveform-audio data block has been played and can now be freed. */ ms_message("WaveInCallback : MM_WOM_DONE"); waveInUnprepareHeader (waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR)); break; case WIM_OPEN: ms_message("WaveInCallback : WIM_OPEN"); break; case WIM_CLOSE: ms_message("WaveInCallback : WIM_CLOSE"); break; case WIM_DATA: wHdr = (WAVEHDR *) dwParam1; device->bytes_read+=wHdr->dwBytesRecorded; if (!device->read_started && !device->write_started) { mr = waveInUnprepareHeader (device->waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR)); ms_warning("WaveInCallback : unprepare header (waveInUnprepareHeader:0x%i)", mr); return; } if (wHdr->dwBufferLength!=wHdr->dwBytesRecorded) { mr = waveInAddBuffer (device->waveindev, wHdr, sizeof (device->waveinhdr[wHdr->dwUser])); if (mr != MMSYSERR_NOERROR) { ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr); } return; } ms_mutex_lock(&device->mutex); if (device->read_started) { mblk_t *rm=NULL; if (rm==NULL) rm=allocb(wHdr->dwBufferLength,0); memcpy(rm->b_wptr,wHdr->lpData, wHdr->dwBufferLength);#ifndef DISABLE_SPEEX if (device->pst!=NULL) { int vad; //memset(rm->b_wptr,0, wHdr->dwBufferLength); vad = speex_preprocess(device->pst, (short*)rm->b_wptr, NULL);#if 0 if (vad!=1) ms_message("WaveInCallback : %d", vad);#endif }#endif rm->b_wptr+=wHdr->dwBufferLength; putq(&device->rq,rm); device->stat_input++; rm=NULL; } ms_mutex_unlock(&device->mutex); mr = waveInAddBuffer (device->waveindev, wHdr, sizeof (device->waveinhdr[wHdr->dwUser])); if (mr != MMSYSERR_NOERROR) { ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr); return; } }}static int winsnd_open(WinSndData *device, int devnumber, int bits,int stereo, int rate, int *minsz){ MMRESULT mr = NOERROR; DWORD dwFlag; int i; int channel = 1; if (stereo>0) channel = stereo; device->wfx.wFormatTag = WAVE_FORMAT_PCM; device->wfx.cbSize = 0; device->wfx.nAvgBytesPerSec = 16000; device->wfx.nBlockAlign = 2; device->wfx.nChannels = channel; device->wfx.nSamplesPerSec = rate; /* 8000; */ device->wfx.wBitsPerSample = bits; dwFlag = CALLBACK_FUNCTION; if (devnumber != WAVE_MAPPER) dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION; mr = waveOutOpen (&(device->waveoutdev), devnumber, &(device->wfx), (DWORD) SpeakerCallback, (DWORD)device, dwFlag); if (mr != NOERROR) { ms_warning("Failed to open device: trying default device. (waveOutOpen:0x%i)", mr); dwFlag = CALLBACK_FUNCTION; mr = waveOutOpen (&(device->waveoutdev), WAVE_MAPPER, &(device->wfx), (DWORD) SpeakerCallback, (DWORD)device, dwFlag); } if (mr != NOERROR) { ms_warning("Failed to open windows sound device. (waveOutOpen:0x%i)", mr); return -1; }#if 0#define MM_WOM_SETSECONDARYGAINCLASS (WM_USER)#define MM_WOM_SETSECONDARYGAINLIMIT (WM_USER+1)#define MM_WOM_FORCESPEAKER (WM_USER+2) bool bSpeaker=TRUE; mr = waveOutMessage(device->waveoutdev, MM_WOM_FORCESPEAKER, bSpeaker, 0); if (mr != NOERROR) { ms_warning("Failed to use earphone. (waveOutMessage:0x%i)", mr); return -1; } typedef HRESULT (* _SetSpeakerMode)(DWORD mode); _SetSpeakerMode pfnSetSpeakerMode; HINSTANCE hDll = LoadLibrary(L"\\windows\\ossvcs.dll"); //_debug(L"ossvcs.dll h=%X",hDll); pfnSetSpeakerMode = (_SetSpeakerMode)GetProcAddress(hDll,(LPCTSTR)218); if (pfnSetSpeakerMode) { //_debug(L"SetSpeakerMode imported."); DWORD sm = 0; //_debug(L"SpeakerMode set to %d", sm); pfnSetSpeakerMode(sm); } //else //_debug(L"pfnSetSpeakerMode import failed."); FreeLibrary(hDll);#endif#ifdef CONTROLVOLUME mr = waveOutGetVolume(device->waveoutdev, &device->dwOldVolume); if (mr != NOERROR) { ms_warning("Failed to get volume device. (waveOutGetVolume:0x%i)", mr); } mr = waveOutSetVolume(device->waveoutdev, 0xFFFFFFFF); if (mr != NOERROR) { ms_warning("Failed to set volume device. (waveOutSetVolume:0x%i)", mr); }#endif /* prepare windows buffers */ for (i = 0; i < MAX_WAVEHDR; i++) { memset (&(device->waveouthdr[i]), 0, sizeof (device->waveouthdr[i])); device->waveouthdr[i].lpData = device->waveoutbuffer[i]; /* BUG: on ne connait pas la taille des frames a recevoir... on utilise enc_frame_per_packet au lien de dec_frame_per_packet */ device->waveouthdr[i].dwBufferLength = device->rate/8000 * WINSND_BUFLEN; /* 480 pour 98 (speex) */ device->waveouthdr[i].dwFlags = 0; device->waveouthdr[i].dwUser = i; mr = waveOutPrepareHeader (device->waveoutdev, &(device->waveouthdr[i]), sizeof (device->waveouthdr[i])); if (mr != MMSYSERR_NOERROR){ ms_warning("Failed to prepare windows sound device. (waveOutPrepareHeader:0x%i)", mr); } else { ms_message("Sound Header prepared %i for windows sound device. (waveOutPrepareHeader)", i); } } /* Init Microphone device */ dwFlag = CALLBACK_FUNCTION; if (devnumber != WAVE_MAPPER) dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION; mr = waveInOpen (&(device->waveindev), devnumber, &(device->wfx), (DWORD) WaveInCallback, (DWORD)device, dwFlag); if (mr != NOERROR) { ms_warning("Failed to open device: trying default device. (waveInOpen:0x%i)", mr); dwFlag = CALLBACK_FUNCTION; mr = waveInOpen (&(device->waveindev), WAVE_MAPPER, &(device->wfx), (DWORD) WaveInCallback, (DWORD)device, dwFlag); } if (mr != NOERROR) { ms_warning("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr); return -1; } for (i = 0; i < MAX_WAVEHDR; i++) { memset (&(device->waveinhdr[i]), 0, sizeof (device->waveinhdr[i])); device->waveinhdr[i].lpData = device->waveinbuffer[i]; /* frameSize */ device->waveinhdr[i].dwBufferLength = device->rate/8000 * WINSND_BUFLEN; device->waveinhdr[i].dwFlags = 0; device->waveinhdr[i].dwUser = i; mr = waveInPrepareHeader (device->waveindev, &(device->waveinhdr[i]), sizeof (device->waveinhdr[i])); if (mr == MMSYSERR_NOERROR){ mr = waveInAddBuffer (device->waveindev, &(device->waveinhdr[i]), sizeof (device->waveinhdr[i])); if (mr == MMSYSERR_NOERROR) { ms_message("Sound Header prepared %i for windows sound device. (waveInAddBuffer)", i); } else { ms_warning("Failed to prepare windows sound device. (waveInAddBuffer:0x%i)", mr); } } else { ms_warning("Failed to prepare windows sound device. (waveInPrepareHeader:0x%i)", mr); } }#ifndef DISABLE_SPEEX#if 0 device->pst = speex_preprocess_state_init((device->rate/8000 * 320)/2, device->rate); if (device->pst!=NULL) { float f; i=1; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_VAD, &i); i=1; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DENOISE, &i); i=0; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC, &i); f=8000; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); i=0; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i); f=.4; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); f=.3; speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); }#endif#endif mr = waveInStart (device->waveindev); if (mr != MMSYSERR_NOERROR) { ms_warning("Failed to start recording on windows sound device. (waveInStart:0x%i)", mr); return -1; } *minsz=device->rate/8000 * 320; return 0;}static void winsnd_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){ WinSndData *d=(WinSndData*)card->data; MMRESULT mr = NOERROR; DWORD dwVolume = 0xFFFF; dwVolume = ((0xFFFF) * percent) / 100; if (d->mixdev==NULL) return; 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; } return; break;#if 0 case MS_SND_CARD_CAPTURE: wincmd=SOUND_MIXER_IGAIN; break; case MS_SND_CARD_PLAYBACK: wincmd=SOUND_MIXER_PCM; break;#endif default: ms_warning("winsnd_card_set_level: unsupported command."); return; }}static int winsnd_get_level(MSSndCard *card, MSSndCardMixerElem e){ WinSndData *d=(WinSndData*)card->data; MMRESULT mr = NOERROR; DWORD dwVolume = 0x0000; if (d->mixdev==NULL) return -1; 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;#if 0 case MS_SND_CARD_CAPTURE: osscmd=SOUND_MIXER_IGAIN; break; case MS_SND_CARD_PLAYBACK: osscmd=SOUND_MIXER_PCM; break;#endif default: ms_warning("winsnd_card_get_level: unsupported command."); return -1; } return -1;}static void winsnd_set_source(MSSndCard *card, MSSndCardCapture source){ WinSndData *d=(WinSndData*)card->data; if (d->mixdev==NULL) return; switch(source){ case MS_SND_CARD_MIC: break; case MS_SND_CARD_LINE: break; } }static void winsnd_init(MSSndCard *card){ WinSndData *d=(WinSndData*)ms_new(WinSndData,1); memset(d, 0, sizeof(WinSndData));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -