winsndds.cpp 32.2 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of 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 of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 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"

26 27 28 29
extern void find_filters(MSList **filters, MSFilter *f );

#define UNICODE

aymeric's avatar
aymeric committed
30 31 32 33 34 35 36 37
#include <mmsystem.h>
#ifdef _MSC_VER
#include <mmreg.h>
#endif
#include <msacm.h>

#include <dsound.h>

38 39
const GUID GUID_DSCFX_MS_AEC = {0xcdebb919, 0x379a, 0x488a, {0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40}};
const GUID GUID_DSCFX_CLASS_AEC = {0xBF963D80L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}}; 
40

aymeric's avatar
aymeric committed
41 42 43 44 45 46 47
#define WINSNDDS_MINIMUMBUFFER 5

static 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 *);
48

aymeric's avatar
aymeric committed
49
static HRESULT (WINAPI *ms_DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
50 51
static HRESULT (WINAPI *ms_DirectSoundEnumerate)(LPDSENUMCALLBACKW, LPVOID);

aymeric's avatar
aymeric committed
52
static HRESULT (WINAPI *ms_DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
53
static HRESULT (WINAPI *ms_DirectSoundCaptureEnumerate)(LPDSENUMCALLBACKW, LPVOID);
aymeric's avatar
aymeric committed
54

55
static HRESULT (WINAPI *ms_DirectSoundFullDuplexCreate)(LPCGUID , LPCGUID ,
56 57 58
														LPCDSCBUFFERDESC , LPCDSBUFFERDESC , HWND ,
														DWORD , LPDIRECTSOUNDFULLDUPLEX* , LPDIRECTSOUNDCAPTUREBUFFER8 *,
														LPDIRECTSOUNDBUFFER8 *, LPUNKNOWN );
59

aymeric's avatar
aymeric committed
60 61 62 63 64 65 66 67
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){
aymeric's avatar
aymeric committed
68 69 70
	MMRESULT mr = MMSYSERR_NOERROR;
	WinSndDsCard *d=(WinSndDsCard*)card->data;
	LONG dWvolume = 10000-percent*(-DSBVOLUME_MIN)/100;
71
	DSBUFFERDESC bufferDesc;
72
	DSCBUFFERDESC captureDesc;
aymeric's avatar
aymeric committed
73 74
	WAVEFORMATEX wfx;
	HRESULT hr;
75 76 77 78
	LPDIRECTSOUND slDirectSound;
	LPDIRECTSOUNDBUFFER  slDirectSoundOutputBuffer;

	LPDIRECTSOUNDCAPTURE slDirectSoundCapture;
79
	LPDIRECTSOUNDCAPTUREBUFFER slDirectSoundInputBuffer;
80 81 82 83 84 85 86 87

	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.cbSize = 0;
	wfx.nAvgBytesPerSec = 16000;
	wfx.nBlockAlign = 2;
	wfx.nChannels = 1;
	wfx.nSamplesPerSec = 8000;
	wfx.wBitsPerSample = 16;
aymeric's avatar
aymeric committed
88 89

	switch(e){
aymeric's avatar
aymeric committed
90
		case MS_SND_CARD_PLAYBACK:
aymeric's avatar
aymeric committed
91

92
			ms_DirectSoundCreate( &d->out_guid, &slDirectSound, NULL );
aymeric's avatar
aymeric committed
93

94 95 96 97 98 99 100
			ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC));
			bufferDesc.dwSize = sizeof(DSBUFFERDESC);
			bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME;
			bufferDesc.dwBufferBytes = 0;
			bufferDesc.lpwfxFormat = NULL;
			if ((hr = IDirectSound_CreateSoundBuffer( slDirectSound,
				&bufferDesc, &slDirectSoundOutputBuffer, NULL)) != DS_OK)
aymeric's avatar
aymeric committed
101
			{
102 103 104
				IDirectSound_Release( slDirectSound );
				slDirectSound=NULL;
				slDirectSoundOutputBuffer=NULL;
aymeric's avatar
aymeric committed
105 106 107
				return ;
			}

108
			if ((hr = IDirectSoundBuffer_SetVolume(slDirectSoundOutputBuffer, -dWvolume)) != DS_OK)
aymeric's avatar
aymeric committed
109 110 111 112
			{
				ms_warning("winsnddscard_set_level: No playback volume control.");
			}

113 114 115 116
			IDirectSoundBuffer_Release( slDirectSoundOutputBuffer );
			slDirectSoundOutputBuffer=NULL;
			IDirectSound_Release( slDirectSound );
			slDirectSound=NULL;
aymeric's avatar
aymeric committed
117
			break;
aymeric's avatar
aymeric committed
118
		case MS_SND_CARD_MASTER:
aymeric's avatar
aymeric committed
119 120 121
			ms_warning("winsnddscard_set_level: No master volume control.");
			break;
		case MS_SND_CARD_CAPTURE:
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

			ms_DirectSoundCaptureCreate( &d->in_guid, &slDirectSoundCapture, NULL );

			ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
			captureDesc.dwSize = sizeof(DSCBUFFERDESC);
			captureDesc.dwFlags = DSBCAPS_CTRLVOLUME;
			captureDesc.dwBufferBytes = wfx.nAvgBytesPerSec/4;
			captureDesc.lpwfxFormat = &wfx;

			if ((hr = IDirectSoundCapture_CreateCaptureBuffer( slDirectSoundCapture,
				&captureDesc, &slDirectSoundInputBuffer, NULL)) != DS_OK)
			{
				IDirectSoundCapture_Release( slDirectSoundCapture );
				return;
			}

			//if ((hr = IDirectSoundCaptureBuffer_SetVolume(slDirectSoundInputBuffer, -dWvolume)) != DS_OK)
			{
				ms_warning("winsnddscard_set_level: No mic volume control.");
			}

			IDirectSoundCaptureBuffer_Release( slDirectSoundInputBuffer );
			slDirectSoundInputBuffer=NULL;
			IDirectSoundCapture_Release( slDirectSoundCapture );
			slDirectSoundCapture=NULL;
aymeric's avatar
aymeric committed
147 148 149
			break;
		default:
			ms_warning("winsnddscard_set_level: unsupported command.");
aymeric's avatar
aymeric committed
150 151 152 153
	}
}

static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){
aymeric's avatar
aymeric committed
154 155 156
	WinSndDsCard *d=(WinSndDsCard*)card->data;
	LONG dWvolume = 10000;
	DSBUFFERDESC primaryDesc;
157
	DSCBUFFERDESC captureDesc;
aymeric's avatar
aymeric committed
158 159
	WAVEFORMATEX wfx;
	HRESULT hr;
160 161 162 163
	LPDIRECTSOUND slDirectSound;
	LPDIRECTSOUNDBUFFER  slDirectSoundOutputBuffer;

	LPDIRECTSOUNDCAPTURE slDirectSoundCapture;
164
	LPDIRECTSOUNDCAPTUREBUFFER slDirectSoundInputBuffer;
165 166 167 168 169 170 171 172

	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.cbSize = 0;
	wfx.nAvgBytesPerSec = 16000;
	wfx.nBlockAlign = 2;
	wfx.nChannels = 1;
	wfx.nSamplesPerSec = 8000;
	wfx.wBitsPerSample = 16;
aymeric's avatar
aymeric committed
173

aymeric's avatar
aymeric committed
174 175
	switch(e){
		case MS_SND_CARD_PLAYBACK:
aymeric's avatar
aymeric committed
176

177
			ms_DirectSoundCreate( &d->out_guid, &slDirectSound, NULL );
aymeric's avatar
aymeric committed
178 179 180 181 182 183

			ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
			primaryDesc.dwSize = sizeof(DSBUFFERDESC);
			primaryDesc.dwFlags =  DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME;
			primaryDesc.dwBufferBytes = 0;
			primaryDesc.lpwfxFormat = NULL;
184 185
			if ((hr = IDirectSound_CreateSoundBuffer( slDirectSound,
				&primaryDesc, &slDirectSoundOutputBuffer, NULL)) != DS_OK)
aymeric's avatar
aymeric committed
186
			{
187
				IDirectSound_Release( slDirectSound );
aymeric's avatar
aymeric committed
188 189 190
				return -1;
			}

191
			if ((hr = IDirectSoundBuffer_GetVolume(slDirectSoundOutputBuffer, &dWvolume)) != DS_OK)
aymeric's avatar
aymeric committed
192 193 194 195
			{
				ms_warning("winsnddscard_get_level: No playback volume control.");
			}

196 197 198 199
			IDirectSoundBuffer_Release( slDirectSoundOutputBuffer );
			slDirectSoundOutputBuffer=NULL;
			IDirectSound_Release( slDirectSound );
			slDirectSound=NULL;
aymeric's avatar
aymeric committed
200 201 202 203 204 205

			return 100-dWvolume *100/(-DSBVOLUME_MIN);
		case MS_SND_CARD_MASTER:
			ms_warning("winsnddscard_get_level: No master volume control.");
			break;
		case MS_SND_CARD_CAPTURE:
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
			ms_DirectSoundCaptureCreate( &d->in_guid, &slDirectSoundCapture, NULL );

			ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
			captureDesc.dwSize = sizeof(DSCBUFFERDESC);
			captureDesc.dwFlags = DSBCAPS_CTRLVOLUME;
			captureDesc.dwBufferBytes = wfx.nAvgBytesPerSec/4;
			captureDesc.lpwfxFormat = &wfx;

			if ((hr = IDirectSoundCapture_CreateCaptureBuffer( slDirectSoundCapture,
				&captureDesc, &slDirectSoundInputBuffer, NULL)) != DS_OK)
			{
				ms_error("winsnddscard_get_level: No mic volume control.");
				IDirectSoundCapture_Release( slDirectSoundCapture );
				return -1;
			}

			//if ((hr = IDirectSoundCaptureBuffer_GetVolume(slDirectSoundInputBuffer, &dWvolume)) != DS_OK)
			{
				ms_error("winsnddscard_get_level: No mic volume control.");
			}

			IDirectSoundCaptureBuffer_Release( slDirectSoundInputBuffer );
			slDirectSoundInputBuffer=NULL;
			IDirectSoundCapture_Release( slDirectSoundCapture );
			slDirectSoundCapture=NULL;
			return 100-dWvolume *100/(-DSBVOLUME_MIN);
aymeric's avatar
aymeric committed
232
		default:
aymeric's avatar
aymeric committed
233
			ms_warning("winsnddscard_get_level: unsupported command.");
aymeric's avatar
aymeric committed
234 235 236 237 238 239 240 241 242
			return -1;
	}
	return -1;
}

static void winsnddscard_set_source(MSSndCard *card, MSSndCardCapture source){

	switch(source){
		case MS_SND_CARD_MIC:
aymeric's avatar
aymeric committed
243
			break;
aymeric's avatar
aymeric committed
244
		case MS_SND_CARD_LINE:
aymeric's avatar
aymeric committed
245
			break;
aymeric's avatar
aymeric committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
	}	
}

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,
268 269
	NULL,
	NULL,
aymeric's avatar
aymeric committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	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));
			}
336 337
			if (d->in_devid!=-1 && d->out_devid!=-1)
				ms_message("DS: new full duplex card %s", name);
aymeric's avatar
aymeric committed
338 339 340 341 342 343 344 345
			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,
346 347 348
														LPCWSTR lpszDesc,
														LPCWSTR lpszDrvName,
														LPVOID lpContext )
aymeric's avatar
aymeric committed
349 350 351 352 353
{
	MSSndCardManager *m = (MSSndCardManager*)lpContext;
	static int dev_index=0;

	if ( lpGUID == NULL ) /* primary device */
354 355 356 357 358 359 360
	{
		char szName[256];
		wchar_t snd_card_name[256];
		swprintf(snd_card_name, 256, L"DS: %s", lpszDesc);
		WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);

		add_or_update_card(m,szName,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE);
aymeric's avatar
aymeric committed
361
		dev_index++;
362 363 364 365 366 367 368 369 370
	}
	else
	{
		char szName[256];
		wchar_t snd_card_name[256];
		swprintf(snd_card_name, 256, L"DS: %s", lpszDesc);
		WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);

		add_or_update_card(m,szName,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE);
aymeric's avatar
aymeric committed
371
		dev_index++;
372
	}
aymeric's avatar
aymeric committed
373 374 375 376 377

	return true;
}

static BOOL CALLBACK enumerate_playback_devices_callback(LPGUID lpGUID,
378 379 380
														 LPCWSTR lpszDesc,
														 LPCWSTR lpszDrvName,
														 LPVOID lpContext )
aymeric's avatar
aymeric committed
381 382 383 384 385
{
	MSSndCardManager *m = (MSSndCardManager*)lpContext;
	static int dev_index=0;

	if ( lpGUID == NULL ) /* primary device */
386 387 388 389 390
	{
		char szName[256];
		wchar_t snd_card_name[256];
		swprintf(snd_card_name, 256, L"DS: %s", lpszDesc);
		WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);
aymeric's avatar
aymeric committed
391

392
		add_or_update_card(m,szName,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK);
aymeric's avatar
aymeric committed
393
		dev_index++;
394 395 396 397 398 399 400
	}
	else
	{
		char szName[256];
		wchar_t snd_card_name[256];
		swprintf(snd_card_name, 256, L"DS: %s", lpszDesc);
		WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);
aymeric's avatar
aymeric committed
401

402
		add_or_update_card(m,szName,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK);
aymeric's avatar
aymeric committed
403
		dev_index++;
404
	}
aymeric's avatar
aymeric committed
405 406 407 408 409

	return true;
}

static void winsnddscard_detect(MSSndCardManager *m){
410
	MMRESULT mr = NOERROR;
aymeric's avatar
aymeric committed
411 412 413 414 415 416 417

	if (ms_lib_instance==NULL)
	{
		ms_lib_instance = LoadLibrary("dsound.dll");
		if( ms_lib_instance == NULL )
		{
			/* error */
aymeric's avatar
aymeric committed
418
			ms_debug("winsnddscard_detect: no support for dsound (missing dsound.dll)\n");
aymeric's avatar
aymeric committed
419 420 421 422
			return;
		}

		ms_DllGetClassObject =(HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *))
423
			GetProcAddress( ms_lib_instance, "DllGetClassObject" );
aymeric's avatar
aymeric committed
424 425

		ms_DirectSoundCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
426
			GetProcAddress( ms_lib_instance, "DirectSoundCreate" );
aymeric's avatar
aymeric committed
427

428 429
		ms_DirectSoundEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
			GetProcAddress( ms_lib_instance, "DirectSoundEnumerateW" );
aymeric's avatar
aymeric committed
430 431

		ms_DirectSoundCaptureCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
432
			GetProcAddress( ms_lib_instance, "DirectSoundCaptureCreate" );
aymeric's avatar
aymeric committed
433

434 435
		ms_DirectSoundCaptureEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
			GetProcAddress( ms_lib_instance, "DirectSoundCaptureEnumerateW" );
aymeric's avatar
aymeric committed
436

437
		ms_DirectSoundFullDuplexCreate =(HRESULT (WINAPI *)(LPCGUID , LPCGUID ,
438 439 440 441 442
			LPCDSCBUFFERDESC , LPCDSBUFFERDESC , HWND ,
			DWORD , LPDIRECTSOUNDFULLDUPLEX* , LPDIRECTSOUNDCAPTUREBUFFER8 *,
			LPDIRECTSOUNDBUFFER8 *, LPUNKNOWN))
			GetProcAddress( ms_lib_instance, "DirectSoundFullDuplexCreate" );

aymeric's avatar
aymeric committed
443 444 445 446 447 448 449
		if( ms_DllGetClassObject == NULL ||
			ms_DirectSoundCreate == NULL ||
			ms_DirectSoundEnumerate == NULL ||
			ms_DirectSoundCaptureEnumerate == NULL ||
			ms_DirectSoundCaptureCreate == NULL )
		{
			/* error */
aymeric's avatar
aymeric committed
450
			ms_debug("winsnddscard_detect: no support for dsound\n");
aymeric's avatar
aymeric committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
			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;
470
	LPDIRECTSOUNDFULLDUPLEX lpDirectSoundFullDuplex;
aymeric's avatar
aymeric committed
471
	LPDIRECTSOUND lpDirectSound;
472 473 474
	LPDIRECTSOUNDBUFFER  lpDirectSoundOutputBuffer;
	double               dsw_framesWritten;
	UINT                 writeOffset;      /* last read position */
aymeric's avatar
aymeric committed
475 476

	LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
477 478
	LPDIRECTSOUNDCAPTUREBUFFER  lpDirectSoundInputBuffer;
	UINT                 readOffset;      /* last read position */
aymeric's avatar
aymeric committed
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

	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;

}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;
523
		if( filled < 0 ) filled += d->framesPerDSBuffer;
aymeric's avatar
aymeric committed
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
		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;
549
			/* ms_message("bytesFilled=%i\n",bytesFilled); */
aymeric's avatar
aymeric committed
550 551 552 553 554 555 556 557 558 559 560
		}
		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;
561
			/* ms_message("bytesFilled=%i\n",bytesFilled); */
aymeric's avatar
aymeric committed
562 563
		}

564
		d->readOffset = (d->readOffset + bytesFilled) % d->framesPerDSBuffer;
aymeric's avatar
aymeric committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

		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){
	WinSndDs *d=(WinSndDs*)data;
	uint64_t curtime=((uint64_t)d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec;
	return curtime;
}


static void winsndds_init(MSFilter *f){
	WinSndDs *d=(WinSndDs *)ms_new0(WinSndDs,1);
	d->wfx.wFormatTag = WAVE_FORMAT_PCM;
	d->wfx.cbSize = 0;
	d->wfx.nAvgBytesPerSec = 16000;
	d->wfx.nBlockAlign = 2;
	d->wfx.nChannels = 1;
	d->wfx.nSamplesPerSec = 8000;
	d->wfx.wBitsPerSample = 16;
	qinit(&d->rq);
	ms_mutex_init(&d->mutex,NULL);
	f->data=d;

	d->stat_input=0;
	d->stat_output=0;
	d->stat_notplayed=0;

606
	d->framesPerDSBuffer = 320 * (8000 / 1000);
aymeric's avatar
aymeric committed
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631

	d->thread = NULL;
	ms_mutex_init(&d->thread_lock,NULL);
	ms_cond_init(&d->thread_cond,NULL);
	d->thread_running = FALSE;

	ms_bufferizer_init(&d->output_buff);
}

static void winsndds_uninit(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;

	d->thread = NULL;
	d->thread_running = FALSE;
	ms_cond_destroy(&d->thread_cond);
	ms_mutex_destroy(&d->thread_lock);
	ms_bufferizer_uninit(&d->output_buff);

	flushq(&d->rq,0);
	ms_mutex_destroy(&d->mutex);
	ms_free(f->data);
}

static void winsndds_read_preprocess(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;
632
	DSCBUFFERDESC  captureDesc;
aymeric's avatar
aymeric committed
633 634 635 636 637 638
	HRESULT hr;

	d->stat_input=0;
	d->stat_output=0;
	d->stat_notplayed=0;

aymeric's avatar
aymeric committed
639
	d->framesPerDSBuffer = d->wfx.nAvgBytesPerSec/4;
aymeric's avatar
aymeric committed
640
	winsndds_apply_settings(d);
641
	ms_message("full duplex and echo canceller! (%x)" ,d->lpDirectSound);
aymeric's avatar
aymeric committed
642 643 644
	ms_DirectSoundCaptureCreate( &d->in_guid, &d->lpDirectSoundCapture, NULL );

	ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
645 646 647
	captureDesc.dwSize = sizeof(DSCBUFFERDESC);
	captureDesc.dwFlags =  0;
	captureDesc.dwBufferBytes = d->framesPerDSBuffer;
aymeric's avatar
aymeric committed
648
	captureDesc.lpwfxFormat = &d->wfx;
649

aymeric's avatar
aymeric committed
650 651 652
	if ((hr = IDirectSoundCapture_CreateCaptureBuffer( d->lpDirectSoundCapture,
		&captureDesc, &d->lpDirectSoundInputBuffer, NULL)) != DS_OK)
	{
653
		return;
aymeric's avatar
aymeric committed
654
	}
655
	d->readOffset = 0;
aymeric's avatar
aymeric committed
656

657
	hr = IDirectSoundCaptureBuffer_Start( d->lpDirectSoundInputBuffer, DSCBSTART_LOOPING );
658

aymeric's avatar
aymeric committed
659 660 661 662 663 664 665 666
	ms_ticker_set_time_func(f->ticker,winsndds_get_cur_time,d);

	d->thread_running=TRUE;
	ms_thread_create(&d->thread,NULL,winsndds_read_thread,d);
	ms_mutex_lock(&d->thread_lock);
	ms_cond_wait(&d->thread_cond,&d->thread_lock);
	ms_mutex_unlock(&d->thread_lock);

667
	return;
aymeric's avatar
aymeric committed
668 669 670 671 672 673 674 675 676 677 678 679 680
}

static void winsndds_read_postprocess(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;

	ms_mutex_lock(&d->thread_lock);
	d->thread_running=FALSE;
	ms_cond_wait(&d->thread_cond,&d->thread_lock);
	ms_mutex_unlock(&d->thread_lock);
	ms_thread_join(d->thread,NULL);

	ms_ticker_set_time_func(f->ticker,NULL,NULL);

681 682 683 684 685 686
	if( d->lpDirectSoundInputBuffer )
	{
		IDirectSoundCaptureBuffer_Stop( d->lpDirectSoundInputBuffer );
		IDirectSoundCaptureBuffer_Release( d->lpDirectSoundInputBuffer );
		d->lpDirectSoundInputBuffer = NULL;
	}
aymeric's avatar
aymeric committed
687

688 689 690 691 692
	if( d->lpDirectSoundCapture )
	{
		IDirectSoundCapture_Release( d->lpDirectSoundCapture );
		d->lpDirectSoundCapture = NULL;
	}
aymeric's avatar
aymeric committed
693 694 695 696 697 698 699 700

	ms_message("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->stat_input - d->stat_output, d->stat_notplayed);
	flushq(&d->rq,0);
}

static void winsndds_read_process(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;
	mblk_t *m;
701

aymeric's avatar
aymeric committed
702 703 704 705 706 707 708 709 710 711
	ms_mutex_lock(&d->mutex);
	while((m=getq(&d->rq))!=NULL){
		ms_queue_put(f->outputs[0],m);
	}
	ms_mutex_unlock(&d->mutex);
}

static void winsndds_write_preprocess(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;

712 713 714 715
	DWORD          dwDataLen;
	DWORD          playCursor;
	HWND           hWnd;
	HRESULT        hr;
aymeric's avatar
aymeric committed
716
	LPDIRECTSOUNDBUFFER pPrimaryBuffer;
717 718 719 720
	DSBUFFERDESC   primaryDesc;
	DSBUFFERDESC   secondaryDesc;
	unsigned char* pDSBuffData;
	DWORD outputBufferWriteOffsetBytes;
aymeric's avatar
aymeric committed
721

722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
	MSList *filters=NULL;
	MSFilter *f_capture_filter=NULL;
	WinSndDs *d_capture_filter=NULL;

	find_filters(&filters, f);
	if (filters!=NULL)
	{
		MSList *it;
		/* search for another winsndds filter */
		for(it=filters;it!=NULL;it=it->next)
		{
			MSFilter *f_tmp = (MSFilter*)it->data;
			f_tmp->seen = FALSE;
			if (f_tmp->desc->id == MS_WINSNDDS_READ_ID)
			{
				/* found */
				f_capture_filter = f_tmp;
				d_capture_filter=(WinSndDs*)f_capture_filter->data;
			}
		}
	}
aymeric's avatar
aymeric committed
743 744 745 746 747

	d->stat_input=0;
	d->stat_output=0;
	d->stat_notplayed=0;

aymeric's avatar
aymeric committed
748
	d->framesPerDSBuffer = d->wfx.nAvgBytesPerSec/4;
aymeric's avatar
aymeric committed
749 750
	winsndds_apply_settings(d);

751 752 753
	if (d_capture_filter!=NULL
		&& d_capture_filter->lpDirectSoundCapture!=NULL
		&& IsEqualIID(d_capture_filter->in_guid, d->in_guid))
754
	{
755
		DSCBUFFERDESC captureDesc;
756

757
		winsndds_read_postprocess(f_capture_filter);
758 759 760 761 762 763 764 765 766 767

		DSCEFFECTDESC dscfx[1];
		ZeroMemory( &dscfx[0], sizeof( DSCEFFECTDESC ) );
		dscfx[0].dwSize = sizeof( DSCEFFECTDESC );
		dscfx[0].dwFlags = DSCFX_LOCSOFTWARE ;
		dscfx[0].guidDSCFXClass = GUID_DSCFX_CLASS_AEC;
		dscfx[0].guidDSCFXInstance = GUID_DSCFX_MS_AEC;
		dscfx[0].dwReserved1 = 0;
		dscfx[0].dwReserved2 = 0;

768 769 770
		d_capture_filter->framesPerDSBuffer = d_capture_filter->wfx.nAvgBytesPerSec/4;
		winsndds_apply_settings(d_capture_filter);

771 772 773
		ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
		captureDesc.dwSize = sizeof(DSCBUFFERDESC);
		captureDesc.dwFlags =  DSCBCAPS_CTRLFX;
774 775
		captureDesc.dwBufferBytes = d_capture_filter->framesPerDSBuffer;
		captureDesc.lpwfxFormat = &d_capture_filter->wfx;
776
		captureDesc.dwFXCount = 1;
777
		captureDesc.lpDSCFXDesc = dscfx;
778 779 780 781 782 783 784 785 786

		ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
		secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
		secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2
			| DSBCAPS_LOCSOFTWARE;
		secondaryDesc.dwBufferBytes = d->framesPerDSBuffer;
		secondaryDesc.lpwfxFormat = &d->wfx;

		hWnd = GetDesktopWindow();
787
		hr = ms_DirectSoundFullDuplexCreate(&d_capture_filter->in_guid,
788 789 790 791 792 793
			&d->out_guid,
			&captureDesc,
			&secondaryDesc,
			hWnd,
			DSSCL_NORMAL,
			&d->lpDirectSoundFullDuplex,
794 795
			(LPDIRECTSOUNDCAPTUREBUFFER8*)&d_capture_filter->lpDirectSoundInputBuffer,
			(LPDIRECTSOUNDBUFFER8*)&d->lpDirectSoundOutputBuffer,
796 797 798 799 800 801 802
			NULL);

		if (hr!=DS_OK)
		{
			ms_message("full duplex and echo canceller: disabled!");
			captureDesc.dwFlags =  0;
			captureDesc.dwFXCount = 0;
803
			captureDesc.lpDSCFXDesc = NULL;
804

805
			hr = ms_DirectSoundFullDuplexCreate(&d_capture_filter->in_guid,
806 807 808 809 810 811
				&d->out_guid,
				&captureDesc,
				&secondaryDesc,
				hWnd,
				DSSCL_NORMAL,
				&d->lpDirectSoundFullDuplex,
812 813
				(LPDIRECTSOUNDCAPTUREBUFFER8*)&d_capture_filter->lpDirectSoundInputBuffer,
				(LPDIRECTSOUNDBUFFER8*)&d->lpDirectSoundOutputBuffer,
814 815 816 817 818 819 820 821
				NULL);
		}
		if (hr!=DS_OK)
		{
			ms_message("full duplex and echo canceller: disabled!");
			return;
		}
		ms_message("full duplex and echo canceller: activated!");
aymeric's avatar
aymeric committed
822

823
		d_capture_filter->readOffset = 0;
aymeric's avatar
aymeric committed
824

825
		hr = IDirectSoundCaptureBuffer_Start( d_capture_filter->lpDirectSoundInputBuffer, DSCBSTART_LOOPING );
aymeric's avatar
aymeric committed
826

827
		ms_ticker_set_time_func(f_capture_filter->ticker,winsndds_get_cur_time,d_capture_filter);
aymeric's avatar
aymeric committed
828

829 830 831 832 833
		d_capture_filter->thread_running=TRUE;
		ms_thread_create(&d_capture_filter->thread,NULL,winsndds_read_thread,d_capture_filter);
		ms_mutex_lock(&d_capture_filter->thread_lock);
		ms_cond_wait(&d_capture_filter->thread_cond,&d_capture_filter->thread_lock);
		ms_mutex_unlock(&d_capture_filter->thread_lock);
aymeric's avatar
aymeric committed
834
	}
835
	else
aymeric's avatar
aymeric committed
836
	{
837 838 839 840 841 842 843
		ms_DirectSoundCreate( &d->out_guid, &d->lpDirectSound, NULL );


		hWnd = GetDesktopWindow();
		if ((hr = IDirectSound_SetCooperativeLevel( d->lpDirectSound,
			hWnd, DSSCL_PRIORITY)) != DS_OK) //DSSCL_EXCLUSIVE)) != DS_OK)
		{
844
			return ;
845 846 847 848 849 850 851 852
		}

		ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
		primaryDesc.dwSize        = sizeof(DSBUFFERDESC);
		primaryDesc.dwFlags       = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_PRIMARYBUFFER;
		primaryDesc.dwBufferBytes = 0;
		primaryDesc.lpwfxFormat   = NULL;
		if ((hr = IDirectSound_CreateSoundBuffer( d->lpDirectSound,
853
			&primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK)
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
		{
			return ;
		}

		if ((hr = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &d->wfx)) != DS_OK)
		{
			return ;
		}
		IDirectSoundBuffer_Release(pPrimaryBuffer);

		ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
		secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
		secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
		secondaryDesc.dwBufferBytes = d->framesPerDSBuffer;
		secondaryDesc.lpwfxFormat = &d->wfx;
		if ((hr = IDirectSound_CreateSoundBuffer( d->lpDirectSound,
870
			&secondaryDesc, &d->lpDirectSoundOutputBuffer, NULL)) != DS_OK)
871 872 873
		{
			return ;
		}
aymeric's avatar
aymeric committed
874 875 876
	}

	if ((hr = IDirectSoundBuffer_Lock( d->lpDirectSoundOutputBuffer, 0,
877
		d->framesPerDSBuffer,
aymeric's avatar
aymeric committed
878 879 880
		(LPVOID*)&pDSBuffData,
		&dwDataLen, NULL, 0, 0)) != DS_OK)
	{
881
		return ;
aymeric's avatar
aymeric committed
882 883
	}

884
	ZeroMemory(pDSBuffData, dwDataLen);
aymeric's avatar
aymeric committed
885 886 887
	if ((hr = IDirectSoundBuffer_Unlock( d->lpDirectSoundOutputBuffer,
		pDSBuffData, dwDataLen, NULL, 0)) != DS_OK)
	{
888
		return ;
aymeric's avatar
aymeric committed
889 890 891
	}

	hr = IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer,
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
		&playCursor, &outputBufferWriteOffsetBytes );
	if( hr != DS_OK )
	{
		return ;
	}

	hr = IDirectSoundBuffer_SetCurrentPosition( d->lpDirectSoundOutputBuffer, 0 );
	if( hr != DS_OK )
	{
		return ;
	}

	hr = IDirectSoundBuffer_Play( d->lpDirectSoundOutputBuffer, 0, 0, DSBPLAY_LOOPING);
	if( hr != DS_OK )
	{
		return ;
	}
909
	d->writeOffset=-1;
910

911
	return ;
aymeric's avatar
aymeric committed
912 913 914 915 916
}

static void winsndds_write_postprocess(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;

917 918 919 920 921 922
	if( d->lpDirectSoundOutputBuffer )
	{
		IDirectSoundBuffer_Stop( d->lpDirectSoundOutputBuffer );
		IDirectSoundBuffer_Release( d->lpDirectSoundOutputBuffer );
		d->lpDirectSoundOutputBuffer = NULL;
	}
aymeric's avatar
aymeric committed
923

924 925 926 927 928
	if( d->lpDirectSound )
	{
		IDirectSound_Release( d->lpDirectSound );
		d->lpDirectSound = NULL;
	}
aymeric's avatar
aymeric committed
929

930
	if( d->lpDirectSoundFullDuplex )
931 932 933 934
	{
		IDirectSoundFullDuplex_Release( d->lpDirectSoundFullDuplex );
		d->lpDirectSoundFullDuplex = NULL;
	}
935

aymeric's avatar
aymeric committed
936
	ms_message("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->stat_input - d->stat_output, d->stat_notplayed);
937
	d->writeOffset=-1;
aymeric's avatar
aymeric committed
938 939 940 941 942
}

static void winsndds_write_process(MSFilter *f){
	WinSndDs *d=(WinSndDs*)f->data;
	int discarded=0;
aymeric's avatar
aymeric committed
943 944
	DWORD dwStatus;
	HRESULT hr;
aymeric's avatar
aymeric committed
945

946
	if (d->lpDirectSoundOutputBuffer==NULL) {
aymeric's avatar
aymeric committed
947 948 949 950 951 952
		ms_queue_flush(f->inputs[0]);
		return;
	}

	ms_bufferizer_put_from_queue(&d->output_buff,f->inputs[0]);

953
	if (d->writeOffset==-1)
aymeric's avatar
aymeric committed
954
	{
aymeric's avatar
aymeric committed
955
		if (ms_bufferizer_get_avail(&d->output_buff)>=d->framesPerDSBuffer)
aymeric's avatar
aymeric committed
956
		{
957
			DWORD playCursor;
958
			DWORD outputBufferWriteOffsetBytes;
959
			IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer,
960
				&playCursor, &outputBufferWriteOffsetBytes );
961
			d->writeOffset = outputBufferWriteOffsetBytes;
aymeric's avatar
aymeric committed
962
		}
963 964
		else
			return;
aymeric's avatar
aymeric committed
965 966
	}

aymeric's avatar
aymeric committed
967 968 969 970
	DWORD current_playOffset;
	long msize_max = 0;
	DWORD currentWriteOffset;
	IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer,
971
		&current_playOffset, &currentWriteOffset );
aymeric's avatar
aymeric committed
972 973 974 975 976 977 978 979

	msize_max = current_playOffset - currentWriteOffset;
	if( msize_max < 0 ) msize_max += d->framesPerDSBuffer;

	/* write from d->writeOffset up to current_playOffset */
	msize_max=current_playOffset-d->writeOffset;
	if( msize_max < 0 ) msize_max += d->framesPerDSBuffer;

aymeric's avatar
aymeric committed
980 981
	//ms_message("DS information: last_writeOffset=%i current_playOffset=%i current_writeOffset=%i max_writable=%i",
	//	d->writeOffset, current_playOffset, currentWriteOffset, msize_max);
aymeric's avatar
aymeric committed
982 983 984 985 986 987 988 989 990 991

	hr = IDirectSoundBuffer_GetStatus (d->lpDirectSoundOutputBuffer, &dwStatus);
	if (dwStatus & DSBSTATUS_BUFFERLOST) {
		hr = IDirectSoundBuffer_Restore (d->lpDirectSoundOutputBuffer);
		d->writeOffset = 0;
		ms_message("DSBSTATUS_BUFFERLOST: restoring buffer");
	}

	if (msize_max==0)
		return;
992
	int msize=d->framesPerDSBuffer/4;
aymeric's avatar
aymeric committed
993 994
	if (msize>msize_max)
		msize = msize_max;
aymeric's avatar
aymeric committed
995 996 997 998 999 1000
	while (ms_bufferizer_get_avail(&d->output_buff)>=msize)
	{
		LPBYTE lpOutBuf1 = NULL;
		LPBYTE lpOutBuf2 = NULL;
		DWORD  dwOutSize1 = 0;
		DWORD  dwOutSize2 = 0;
1001
		char input[15360];
aymeric's avatar
aymeric committed
1002 1003

		hr = IDirectSoundBuffer_Lock ( d->lpDirectSoundOutputBuffer,
1004
			d->writeOffset, msize,
aymeric's avatar
aymeric committed
1005
			(void **) &lpOutBuf1, &dwOutSize1,
1006
			(void **) &lpOutBuf2, &dwOutSize2, 0); /* DSBLOCK_FROMWRITECURSOR); */
aymeric's avatar
aymeric committed
1007 1008 1009
		if (hr != DS_OK)
		{
			ms_error("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n", hr);
aymeric's avatar
aymeric committed
1010
			break;
aymeric's avatar
aymeric committed
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
		}

		if (dwOutSize1==0)
		{
			ms_error("no free room to play sample\n");
		}
		else if (dwOutSize1+dwOutSize2!=msize)
		{
			ms_bufferizer_read(&d->output_buff,(uint8_t*)input,dwOutSize1+dwOutSize2);
			memcpy(lpOutBuf1, input, dwOutSize1);
			memcpy(lpOutBuf2, input+dwOutSize1, dwOutSize2);
		}
		else if (dwOutSize1>=msize)
		{
			ms_bufferizer_read(&d->output_buff,(uint8_t*)input,msize);
			memcpy(lpOutBuf1, input, msize);
		}
		else
		{
			ms_bufferizer_read(&d->output_buff,(uint8_t*)input,msize);
			memcpy(lpOutBuf1, input, dwOutSize1);
			memcpy(lpOutBuf2, input+dwOutSize1, dwOutSize2);
		}

1035
		d->writeOffset=(d->writeOffset+dwOutSize1+dwOutSize2) % d->framesPerDSBuffer;
aymeric's avatar
aymeric committed
1036 1037 1038
		msize_max = msize_max - (dwOutSize1+dwOutSize2);
		if (msize>msize_max)
			msize = msize_max;
1039
		IDirectSoundBuffer_Unlock( d->lpDirectSoundOutputBuffer,
aymeric's avatar
aymeric committed
1040 1041 1042 1043 1044 1045
			lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
		if (dwOutSize1==0)
			break;
		if (dwOutSize1+dwOutSize2!=msize)
			break;
	}
1046 1047 1048 1049 1050 1051 1052 1053 1054
	if (msize==0)
	{
		if (ms_bufferizer_get_avail(&d->output_buff)>=3*d->wfx.nSamplesPerSec/50)
		{
			ms_warning("Removing extra data for sound card %i", ms_bufferizer_get_avail(&d->output_buff));
			ms_bufferizer_uninit(&d->output_buff);
			ms_bufferizer_init(&d->output_buff);
		}
	}
aymeric's avatar
aymeric committed
1055 1056 1057 1058 1059

	if (discarded>0)
		ms_warning("Extra data for sound card removed (%i buf), (playing: %i) (input-output: %i)", discarded, d->nbufs_playing, d->stat_input - d->stat_output);
}

aymeric's avatar
aymeric committed
1060 1061 1062 1063 1064 1065
static int get_rate(MSFilter *f, void *arg){
	WinSndDs *d=(WinSndDs*)f->data;
	*((int*)arg)=d->wfx.nSamplesPerSec;
	return 0;
}

aymeric's avatar
aymeric committed
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
static int set_rate(MSFilter *f, void *arg){
	WinSndDs *d=(WinSndDs*)f->data;
	d->wfx.nSamplesPerSec=*((int*)arg);
	return 0;
}

static int set_nchannels(MSFilter *f, void *arg){
	WinSndDs *d=(WinSndDs*)f->data;
	d->wfx.nChannels=*((int*)arg);
	return 0;
}

static int winsndds_get_stat_input(MSFilter *f, void *arg){
	WinSndDs *d=(WinSndDs*)f->data;
	return d->stat_input;
}

static int winsndds_get_stat_ouptut(MSFilter *f, void *arg){
	WinSndDs *d=(WinSndDs*)f->data;

	return d->stat_output;
}

static int winsndds_get_stat_discarded(MSFilter *f, void *arg){
	WinSndDs *d=(WinSndDs*)f->data;

	return d->stat_notplayed;
}

static MSFilterMethod winsndds_methods[]={
aymeric's avatar
aymeric committed
1096
	{	MS_FILTER_GET_SAMPLE_RATE	, get_rate	},
aymeric's avatar
aymeric committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
	{	MS_FILTER_SET_SAMPLE_RATE	, set_rate	},
	{	MS_FILTER_SET_NCHANNELS		, set_nchannels	},
	{	MS_FILTER_GET_STAT_INPUT, winsndds_get_stat_input },
	{	MS_FILTER_GET_STAT_OUTPUT, winsndds_get_stat_ouptut },
	{	MS_FILTER_GET_STAT_DISCARDED, winsndds_get_stat_discarded },
	{	0				, NULL		}
};

MSFilterDesc winsndds_read_desc={
	MS_WINSNDDS_READ_ID,
aymeric's avatar
aymeric committed
1107
	"MSWinSndDsRead",
aymeric's avatar
aymeric committed
1108 1109 1110
	"Sound capture filter for Windows Sound drivers",
	MS_FILTER_OTHER,
	NULL,
1111
	0,
aymeric's avatar
aymeric committed
1112 1113
	1,
	winsndds_init,
1114
	winsndds_read_preprocess,
aymeric's avatar
aymeric committed
1115 1116
	winsndds_read_process,
	winsndds_read_postprocess,
1117
	winsndds_uninit,
aymeric's avatar
aymeric committed
1118 1119 1120 1121 1122 1123
	winsndds_methods
};


MSFilterDesc winsndds_write_desc={
	MS_WINSNDDS_WRITE_ID,
aymeric's avatar
aymeric committed
1124
	"MSWinSndDsWrite",
aymeric's avatar
aymeric committed
1125 1126 1127
	"Sound playback filter for Windows Sound drivers",
	MS_FILTER_OTHER,
	NULL,
1128
	1,
aymeric's avatar
aymeric committed
1129 1130
	0,
	winsndds_init,
1131
	winsndds_write_preprocess,
aymeric's avatar
aymeric committed
1132 1133 1134
	winsndds_write_process,
	winsndds_write_postprocess,
	winsndds_uninit,
1135
	winsndds_methods
aymeric's avatar
aymeric committed
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
};

MSFilter *ms_winsndds_read_new(MSSndCard *card){
	MSFilter *f=ms_filter_new_from_desc(&winsndds_read_desc);
	WinSndDsCard *wc=(WinSndDsCard*)card->data;
	WinSndDs *d=(WinSndDs*)f->data;
	d->dev_id=wc->in_devid;
	memcpy(&d->in_guid, &wc->in_guid, sizeof(GUID));
	memcpy(&d->out_guid, &wc->out_guid, sizeof(GUID));
	return f;
}


MSFilter *ms_winsndds_write_new(MSSndCard *card){
	MSFilter *f=ms_filter_new_from_desc(&winsndds_write_desc);
	WinSndDsCard *wc=(WinSndDsCard*)card->data;
	WinSndDs *d=(WinSndDs*)f->data;
	d->dev_id=wc->out_devid;
	memcpy(&d->in_guid, &wc->in_guid, sizeof(GUID));
	memcpy(&d->out_guid, &wc->out_guid, sizeof(GUID));
	return f;
}

MS_FILTER_DESC_EXPORT(winsndds_read_desc)
MS_FILTER_DESC_EXPORT(winsndds_write_desc)

#endif