37 |
|
|
38 |
/* #define DEBUG_DSOUND */ |
/* #define DEBUG_DSOUND */ |
39 |
|
|
|
struct full_fmt { |
|
|
int freq; |
|
|
int nchannels; |
|
|
audfmt_e fmt; |
|
|
}; |
|
|
|
|
40 |
static struct { |
static struct { |
41 |
int lock_retries; |
int lock_retries; |
42 |
int restore_retries; |
int restore_retries; |
44 |
int set_primary; |
int set_primary; |
45 |
int bufsize_in; |
int bufsize_in; |
46 |
int bufsize_out; |
int bufsize_out; |
47 |
struct full_fmt full_fmt; |
audsettings_t settings; |
48 |
int latency_millis; |
int latency_millis; |
49 |
} conf = { |
} conf = { |
50 |
1, |
1, |
65 |
LPDIRECTSOUND dsound; |
LPDIRECTSOUND dsound; |
66 |
LPDIRECTSOUNDCAPTURE dsound_capture; |
LPDIRECTSOUNDCAPTURE dsound_capture; |
67 |
LPDIRECTSOUNDBUFFER dsound_primary_buffer; |
LPDIRECTSOUNDBUFFER dsound_primary_buffer; |
68 |
struct full_fmt fmt; |
audsettings_t settings; |
69 |
} dsound; |
} dsound; |
70 |
|
|
71 |
static dsound glob_dsound; |
static dsound glob_dsound; |
253 |
{ |
{ |
254 |
va_list ap; |
va_list ap; |
255 |
|
|
256 |
AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); |
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); |
257 |
va_start (ap, fmt); |
va_start (ap, fmt); |
258 |
AUD_vlog (AUDIO_CAP, fmt, ap); |
AUD_vlog (AUDIO_CAP, fmt, ap); |
259 |
va_end (ap); |
va_end (ap); |
295 |
continue; |
continue; |
296 |
|
|
297 |
default: |
default: |
298 |
dsound_logerr (hr, "Can not restore playback buffer\n"); |
dsound_logerr (hr, "Could not restore playback buffer\n"); |
299 |
return -1; |
return -1; |
300 |
} |
} |
301 |
} |
} |
304 |
return -1; |
return -1; |
305 |
} |
} |
306 |
|
|
307 |
static int waveformat_from_full_fmt (WAVEFORMATEX *wfx, |
static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as) |
|
struct full_fmt *full_fmt) |
|
308 |
{ |
{ |
309 |
memset (wfx, 0, sizeof (*wfx)); |
memset (wfx, 0, sizeof (*wfx)); |
310 |
|
|
311 |
wfx->wFormatTag = WAVE_FORMAT_PCM; |
wfx->wFormatTag = WAVE_FORMAT_PCM; |
312 |
wfx->nChannels = full_fmt->nchannels; |
wfx->nChannels = as->nchannels; |
313 |
wfx->nSamplesPerSec = full_fmt->freq; |
wfx->nSamplesPerSec = as->freq; |
314 |
wfx->nAvgBytesPerSec = full_fmt->freq << (full_fmt->nchannels == 2); |
wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2); |
315 |
wfx->nBlockAlign = 1 << (full_fmt->nchannels == 2); |
wfx->nBlockAlign = 1 << (as->nchannels == 2); |
316 |
wfx->cbSize = 0; |
wfx->cbSize = 0; |
317 |
|
|
318 |
switch (full_fmt->fmt) { |
switch (as->fmt) { |
319 |
case AUD_FMT_S8: |
case AUD_FMT_S8: |
320 |
wfx->wBitsPerSample = 8; |
wfx->wBitsPerSample = 8; |
321 |
break; |
break; |
337 |
break; |
break; |
338 |
|
|
339 |
default: |
default: |
340 |
dolog ("Internal logic error: Bad audio format %d\n", |
dolog ("Internal logic error: Bad audio format %d\n", as->freq); |
|
full_fmt->freq); |
|
341 |
return -1; |
return -1; |
342 |
} |
} |
343 |
|
|
344 |
return 0; |
return 0; |
345 |
} |
} |
346 |
|
|
347 |
static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, |
static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as) |
|
struct full_fmt *full_fmt) |
|
348 |
{ |
{ |
349 |
if (wfx->wFormatTag != WAVE_FORMAT_PCM) { |
if (wfx->wFormatTag != WAVE_FORMAT_PCM) { |
350 |
dolog ("Invalid wave format, tag is not PCM, but %d\n", |
dolog ("Invalid wave format, tag is not PCM, but %d\n", |
356 |
dolog ("Invalid wave format, frequency is zero\n"); |
dolog ("Invalid wave format, frequency is zero\n"); |
357 |
return -1; |
return -1; |
358 |
} |
} |
359 |
full_fmt->freq = wfx->nSamplesPerSec; |
as->freq = wfx->nSamplesPerSec; |
360 |
|
|
361 |
switch (wfx->nChannels) { |
switch (wfx->nChannels) { |
362 |
case 1: |
case 1: |
363 |
full_fmt->nchannels = 1; |
as->nchannels = 1; |
364 |
break; |
break; |
365 |
|
|
366 |
case 2: |
case 2: |
367 |
full_fmt->nchannels = 2; |
as->nchannels = 2; |
368 |
break; |
break; |
369 |
|
|
370 |
default: |
default: |
377 |
|
|
378 |
switch (wfx->wBitsPerSample) { |
switch (wfx->wBitsPerSample) { |
379 |
case 8: |
case 8: |
380 |
full_fmt->fmt = AUD_FMT_U8; |
as->fmt = AUD_FMT_U8; |
381 |
break; |
break; |
382 |
|
|
383 |
case 16: |
case 16: |
384 |
full_fmt->fmt = AUD_FMT_S16; |
as->fmt = AUD_FMT_S16; |
385 |
break; |
break; |
386 |
|
|
387 |
default: |
default: |
406 |
for (i = 0; i < conf.getstatus_retries; ++i) { |
for (i = 0; i < conf.getstatus_retries; ++i) { |
407 |
hr = IDirectSoundBuffer_GetStatus (dsb, statusp); |
hr = IDirectSoundBuffer_GetStatus (dsb, statusp); |
408 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
409 |
dsound_logerr (hr, "Can not get playback buffer status\n"); |
dsound_logerr (hr, "Could not get playback buffer status\n"); |
410 |
return -1; |
return -1; |
411 |
} |
} |
412 |
|
|
429 |
|
|
430 |
hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp); |
hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp); |
431 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
432 |
dsound_logerr (hr, "Can not get capture buffer status\n"); |
dsound_logerr (hr, "Could not get capture buffer status\n"); |
433 |
return -1; |
return -1; |
434 |
} |
} |
435 |
|
|
511 |
if (s->dsound_primary_buffer) { |
if (s->dsound_primary_buffer) { |
512 |
hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer); |
hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer); |
513 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
514 |
dsound_logerr (hr, "Can not release primary buffer\n"); |
dsound_logerr (hr, "Could not release primary buffer\n"); |
515 |
} |
} |
516 |
s->dsound_primary_buffer = NULL; |
s->dsound_primary_buffer = NULL; |
517 |
} |
} |
533 |
); |
); |
534 |
|
|
535 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
536 |
dsound_logerr (hr, "Can not set cooperative level for window %p\n", |
dsound_logerr (hr, "Could not set cooperative level for window %p\n", |
537 |
hwnd); |
hwnd); |
538 |
return -1; |
return -1; |
539 |
} |
} |
542 |
return 0; |
return 0; |
543 |
} |
} |
544 |
|
|
545 |
err = waveformat_from_full_fmt (&wfx, &conf.full_fmt); |
err = waveformat_from_audio_settings (&wfx, &conf.settings); |
546 |
if (err) { |
if (err) { |
547 |
return -1; |
return -1; |
548 |
} |
} |
560 |
NULL |
NULL |
561 |
); |
); |
562 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
563 |
dsound_logerr (hr, "Can not create primary playback buffer\n"); |
dsound_logerr (hr, "Could not create primary playback buffer\n"); |
564 |
return -1; |
return -1; |
565 |
} |
} |
566 |
|
|
567 |
hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); |
hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); |
568 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
569 |
dsound_logerr (hr, "Can not set primary playback buffer format\n"); |
dsound_logerr (hr, "Could not set primary playback buffer format\n"); |
570 |
} |
} |
571 |
|
|
572 |
hr = IDirectSoundBuffer_GetFormat ( |
hr = IDirectSoundBuffer_GetFormat ( |
576 |
NULL |
NULL |
577 |
); |
); |
578 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
579 |
dsound_logerr (hr, "Can not get primary playback buffer format\n"); |
dsound_logerr (hr, "Could not get primary playback buffer format\n"); |
580 |
goto fail0; |
goto fail0; |
581 |
} |
} |
582 |
|
|
585 |
print_wave_format (&wfx); |
print_wave_format (&wfx); |
586 |
#endif |
#endif |
587 |
|
|
588 |
err = waveformat_to_full_fmt (&wfx, &s->fmt); |
err = waveformat_to_audio_settings (&wfx, &s->settings); |
589 |
if (err) { |
if (err) { |
590 |
goto fail0; |
goto fail0; |
591 |
} |
} |
616 |
} |
} |
617 |
|
|
618 |
if (status & DSBSTATUS_PLAYING) { |
if (status & DSBSTATUS_PLAYING) { |
619 |
dolog ("warning: voice is already playing\n"); |
dolog ("warning: Voice is already playing\n"); |
620 |
return 0; |
return 0; |
621 |
} |
} |
622 |
|
|
624 |
|
|
625 |
hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING); |
hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING); |
626 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
627 |
dsound_logerr (hr, "Can not start playing buffer\n"); |
dsound_logerr (hr, "Could not start playing buffer\n"); |
628 |
return -1; |
return -1; |
629 |
} |
} |
630 |
break; |
break; |
637 |
if (status & DSBSTATUS_PLAYING) { |
if (status & DSBSTATUS_PLAYING) { |
638 |
hr = IDirectSoundBuffer_Stop (dsb); |
hr = IDirectSoundBuffer_Stop (dsb); |
639 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
640 |
dsound_logerr (hr, "Can not stop playing buffer\n"); |
dsound_logerr (hr, "Could not stop playing buffer\n"); |
641 |
return -1; |
return -1; |
642 |
} |
} |
643 |
} |
} |
644 |
else { |
else { |
645 |
dolog ("warning: voice is not playing\n"); |
dolog ("warning: Voice is not playing\n"); |
646 |
} |
} |
647 |
break; |
break; |
648 |
} |
} |
666 |
DWORD decr; |
DWORD decr; |
667 |
DWORD wpos, ppos, old_pos; |
DWORD wpos, ppos, old_pos; |
668 |
LPVOID p1, p2; |
LPVOID p1, p2; |
669 |
|
int bufsize; |
670 |
|
|
671 |
if (!dsb) { |
if (!dsb) { |
672 |
dolog ("Attempt to run empty with playback buffer\n"); |
dolog ("Attempt to run empty with playback buffer\n"); |
674 |
} |
} |
675 |
|
|
676 |
hwshift = hw->info.shift; |
hwshift = hw->info.shift; |
677 |
|
bufsize = hw->samples << hwshift; |
678 |
|
|
679 |
live = audio_pcm_hw_get_live_out (hw); |
live = audio_pcm_hw_get_live_out (hw); |
680 |
|
|
684 |
ds->first_time ? &wpos : NULL |
ds->first_time ? &wpos : NULL |
685 |
); |
); |
686 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
687 |
dsound_logerr (hr, "Can not get playback buffer position\n"); |
dsound_logerr (hr, "Could not get playback buffer position\n"); |
688 |
return 0; |
return 0; |
689 |
} |
} |
690 |
|
|
692 |
|
|
693 |
if (ds->first_time) { |
if (ds->first_time) { |
694 |
if (conf.latency_millis) { |
if (conf.latency_millis) { |
695 |
DWORD cur_blat = audio_ring_dist (wpos, ppos, hw->bufsize); |
DWORD cur_blat; |
696 |
|
|
697 |
|
cur_blat = audio_ring_dist (wpos, ppos, bufsize); |
698 |
ds->first_time = 0; |
ds->first_time = 0; |
699 |
old_pos = wpos; |
old_pos = wpos; |
700 |
old_pos += |
old_pos += |
701 |
millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat; |
millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat; |
702 |
old_pos %= hw->bufsize; |
old_pos %= bufsize; |
703 |
old_pos &= ~hw->info.align; |
old_pos &= ~hw->info.align; |
704 |
} |
} |
705 |
else { |
else { |
728 |
len = ppos - old_pos; |
len = ppos - old_pos; |
729 |
} |
} |
730 |
else { |
else { |
731 |
if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->bufsize))) { |
if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) { |
732 |
len = hw->bufsize - old_pos + ppos; |
len = bufsize - old_pos + ppos; |
733 |
} |
} |
734 |
} |
} |
735 |
|
|
736 |
if (audio_bug (AUDIO_FUNC, len < 0 || len > hw->bufsize)) { |
if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) { |
737 |
dolog ("len=%d hw->bufsize=%d old_pos=%ld ppos=%ld\n", |
dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n", |
738 |
len, hw->bufsize, old_pos, ppos); |
len, bufsize, old_pos, ppos); |
739 |
return 0; |
return 0; |
740 |
} |
} |
741 |
|
|
773 |
} |
} |
774 |
|
|
775 |
dsound_unlock_out (dsb, p1, p2, blen1, blen2); |
dsound_unlock_out (dsb, p1, p2, blen1, blen2); |
776 |
ds->old_pos = (old_pos + (decr << hwshift)) % hw->bufsize; |
ds->old_pos = (old_pos + (decr << hwshift)) % bufsize; |
777 |
|
|
778 |
#ifdef DEBUG_DSOUND |
#ifdef DEBUG_DSOUND |
779 |
ds->mixed += decr << hwshift; |
ds->mixed += decr << hwshift; |
806 |
} |
} |
807 |
|
|
808 |
if (status & DSCBSTATUS_CAPTURING) { |
if (status & DSCBSTATUS_CAPTURING) { |
809 |
dolog ("warning: voice is already capturing\n"); |
dolog ("warning: Voice is already capturing\n"); |
810 |
return 0; |
return 0; |
811 |
} |
} |
812 |
|
|
814 |
|
|
815 |
hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING); |
hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING); |
816 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
817 |
dsound_logerr (hr, "Can not start capturing\n"); |
dsound_logerr (hr, "Could not start capturing\n"); |
818 |
return -1; |
return -1; |
819 |
} |
} |
820 |
break; |
break; |
827 |
if (status & DSCBSTATUS_CAPTURING) { |
if (status & DSCBSTATUS_CAPTURING) { |
828 |
hr = IDirectSoundCaptureBuffer_Stop (dscb); |
hr = IDirectSoundCaptureBuffer_Stop (dscb); |
829 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
830 |
dsound_logerr (hr, "Can not stop capturing\n"); |
dsound_logerr (hr, "Could not stop capturing\n"); |
831 |
return -1; |
return -1; |
832 |
} |
} |
833 |
} |
} |
834 |
else { |
else { |
835 |
dolog ("warning: voice is not capturing\n"); |
dolog ("warning: Voice is not capturing\n"); |
836 |
} |
} |
837 |
break; |
break; |
838 |
} |
} |
877 |
ds->first_time ? &rpos : NULL |
ds->first_time ? &rpos : NULL |
878 |
); |
); |
879 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
880 |
dsound_logerr (hr, "Can not get capture buffer position\n"); |
dsound_logerr (hr, "Could not get capture buffer position\n"); |
881 |
return 0; |
return 0; |
882 |
} |
} |
883 |
|
|
884 |
if (ds->first_time) { |
if (ds->first_time) { |
885 |
ds->first_time = 0; |
ds->first_time = 0; |
886 |
if (rpos & hw->info.align) { |
if (rpos & hw->info.align) { |
887 |
ldebug ("warning: misaligned capture read position %ld(%d)\n", |
ldebug ("warning: Misaligned capture read position %ld(%d)\n", |
888 |
rpos, hw->info.align); |
rpos, hw->info.align); |
889 |
} |
} |
890 |
hw->wpos = rpos >> hwshift; |
hw->wpos = rpos >> hwshift; |
891 |
} |
} |
892 |
|
|
893 |
if (cpos & hw->info.align) { |
if (cpos & hw->info.align) { |
894 |
ldebug ("warning: misaligned capture position %ld(%d)\n", |
ldebug ("warning: Misaligned capture position %ld(%d)\n", |
895 |
cpos, hw->info.align); |
cpos, hw->info.align); |
896 |
} |
} |
897 |
cpos >>= hwshift; |
cpos >>= hwshift; |
945 |
|
|
946 |
hr = IDirectSound_Release (s->dsound); |
hr = IDirectSound_Release (s->dsound); |
947 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
948 |
dsound_logerr (hr, "Can not release DirectSound\n"); |
dsound_logerr (hr, "Could not release DirectSound\n"); |
949 |
} |
} |
950 |
s->dsound = NULL; |
s->dsound = NULL; |
951 |
|
|
955 |
|
|
956 |
hr = IDirectSoundCapture_Release (s->dsound_capture); |
hr = IDirectSoundCapture_Release (s->dsound_capture); |
957 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
958 |
dsound_logerr (hr, "Can not release DirectSoundCapture\n"); |
dsound_logerr (hr, "Could not release DirectSoundCapture\n"); |
959 |
} |
} |
960 |
s->dsound_capture = NULL; |
s->dsound_capture = NULL; |
961 |
} |
} |
968 |
|
|
969 |
hr = CoInitialize (NULL); |
hr = CoInitialize (NULL); |
970 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
971 |
dsound_logerr (hr, "Can not initialize COM\n"); |
dsound_logerr (hr, "Could not initialize COM\n"); |
972 |
return NULL; |
return NULL; |
973 |
} |
} |
974 |
|
|
980 |
(void **) &s->dsound |
(void **) &s->dsound |
981 |
); |
); |
982 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
983 |
dsound_logerr (hr, "Can not create DirectSound instance\n"); |
dsound_logerr (hr, "Could not create DirectSound instance\n"); |
984 |
return NULL; |
return NULL; |
985 |
} |
} |
986 |
|
|
987 |
hr = IDirectSound_Initialize (s->dsound, NULL); |
hr = IDirectSound_Initialize (s->dsound, NULL); |
988 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
989 |
dsound_logerr (hr, "Can not initialize DirectSound\n"); |
dsound_logerr (hr, "Could not initialize DirectSound\n"); |
990 |
return NULL; |
return NULL; |
991 |
} |
} |
992 |
|
|
998 |
(void **) &s->dsound_capture |
(void **) &s->dsound_capture |
999 |
); |
); |
1000 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
1001 |
dsound_logerr (hr, "Can not create DirectSoundCapture instance\n"); |
dsound_logerr (hr, "Could not create DirectSoundCapture instance\n"); |
1002 |
} |
} |
1003 |
else { |
else { |
1004 |
hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); |
hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); |
1005 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
1006 |
dsound_logerr (hr, "Can not initialize DirectSoundCapture\n"); |
dsound_logerr (hr, "Could not initialize DirectSoundCapture\n"); |
1007 |
|
|
1008 |
hr = IDirectSoundCapture_Release (s->dsound_capture); |
hr = IDirectSoundCapture_Release (s->dsound_capture); |
1009 |
if (FAILED (hr)) { |
if (FAILED (hr)) { |
1010 |
dsound_logerr (hr, "Can not release DirectSoundCapture\n"); |
dsound_logerr (hr, "Could not release DirectSoundCapture\n"); |
1011 |
} |
} |
1012 |
s->dsound_capture = NULL; |
s->dsound_capture = NULL; |
1013 |
} |
} |
1033 |
"Set the parameters of primary buffer", NULL, 0}, |
"Set the parameters of primary buffer", NULL, 0}, |
1034 |
{"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis, |
{"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis, |
1035 |
"(undocumented)", NULL, 0}, |
"(undocumented)", NULL, 0}, |
1036 |
{"PRIMARY_FREQ", AUD_OPT_INT, &conf.full_fmt.freq, |
{"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq, |
1037 |
"Primary buffer frequency", NULL, 0}, |
"Primary buffer frequency", NULL, 0}, |
1038 |
{"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.full_fmt.nchannels, |
{"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, |
1039 |
"Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, |
"Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, |
1040 |
{"PRIMARY_FMT", AUD_OPT_FMT, &conf.full_fmt.fmt, |
{"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt, |
1041 |
"Primary buffer format", NULL, 0}, |
"Primary buffer format", NULL, 0}, |
1042 |
{"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, |
{"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, |
1043 |
"(undocumented)", NULL, 0}, |
"(undocumented)", NULL, 0}, |