dep/cubeb: Update to dc511c6

This commit is contained in:
Connor McLaughlin
2022-08-05 17:28:17 +10:00
parent 06ecc50797
commit 8f45bf7f27
50 changed files with 5667 additions and 4813 deletions

View File

@ -8,71 +8,71 @@
#define WINVER 0x0501
#undef WIN32_LEAN_AND_MEAN
#include "cubeb-internal.h"
#include "cubeb/cubeb.h"
#include <malloc.h>
#include <windows.h>
#include <mmreg.h>
#include <mmsystem.h>
#include <math.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
#include <windows.h>
/* clang-format off */
/* These need to be included after windows.h */
#include <mmreg.h>
#include <mmsystem.h>
/* clang-format on */
/* This is missing from the MinGW headers. Use a safe fallback. */
#if !defined(MEMORY_ALLOCATION_ALIGNMENT)
#define MEMORY_ALLOCATION_ALIGNMENT 16
#endif
/**This is also missing from the MinGW headers. It also appears to be undocumented by Microsoft.*/
/**This is also missing from the MinGW headers. It also appears to be
* undocumented by Microsoft.*/
#ifndef WAVE_FORMAT_48M08
#define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */
#define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */
#endif
#ifndef WAVE_FORMAT_48M16
#define WAVE_FORMAT_48M16 0x00002000 /* 48 kHz, Mono, 16-bit */
#define WAVE_FORMAT_48M16 0x00002000 /* 48 kHz, Mono, 16-bit */
#endif
#ifndef WAVE_FORMAT_48S08
#define WAVE_FORMAT_48S08 0x00004000 /* 48 kHz, Stereo, 8-bit */
#define WAVE_FORMAT_48S08 0x00004000 /* 48 kHz, Stereo, 8-bit */
#endif
#ifndef WAVE_FORMAT_48S16
#define WAVE_FORMAT_48S16 0x00008000 /* 48 kHz, Stereo, 16-bit */
#define WAVE_FORMAT_48S16 0x00008000 /* 48 kHz, Stereo, 16-bit */
#endif
#ifndef WAVE_FORMAT_96M08
#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
#endif
#ifndef WAVE_FORMAT_96M16
#define WAVE_FORMAT_96M16 0x00020000 /* 96 kHz, Mono, 16-bit */
#define WAVE_FORMAT_96M16 0x00020000 /* 96 kHz, Mono, 16-bit */
#endif
#ifndef WAVE_FORMAT_96S08
#define WAVE_FORMAT_96S08 0x00040000 /* 96 kHz, Stereo, 8-bit */
#define WAVE_FORMAT_96S08 0x00040000 /* 96 kHz, Stereo, 8-bit */
#endif
#ifndef WAVE_FORMAT_96S16
#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
#endif
/**Taken from winbase.h, also not in MinGW.*/
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 // Threads only
#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 // Threads only
#endif
#ifndef DRVM_MAPPER
#define DRVM_MAPPER (0x2000)
#define DRVM_MAPPER (0x2000)
#endif
#ifndef DRVM_MAPPER_PREFERRED_GET
#define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER+21)
#define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER + 21)
#endif
#ifndef DRVM_MAPPER_CONSOLEVOICECOM_GET
#define DRVM_MAPPER_CONSOLEVOICECOM_GET (DRVM_MAPPER+23)
#define DRVM_MAPPER_CONSOLEVOICECOM_GET (DRVM_MAPPER + 23)
#endif
#define CUBEB_STREAM_MAX 32
#define NBUFS 4
const GUID KSDATAFORMAT_SUBTYPE_PCM =
{ 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT =
{ 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
struct cubeb_stream_item {
SLIST_ENTRY head;
cubeb_stream * stream;
@ -110,6 +110,10 @@ struct cubeb_stream {
CRITICAL_SECTION lock;
uint64_t written;
float soft_volume;
/* For position wrap-around handling: */
size_t frame_size;
DWORD prev_pos_lo_dword;
DWORD pos_hi_dword;
};
static size_t
@ -175,7 +179,7 @@ winmm_refill_stream(cubeb_stream * stm)
hdr = winmm_get_next_buffer(stm);
wanted = (DWORD) stm->buffer_size / bytes_per_frame(stm->params);
wanted = (DWORD)stm->buffer_size / bytes_per_frame(stm->params);
/* It is assumed that the caller is holding this lock. It must be dropped
during the callback to avoid deadlocks. */
@ -199,16 +203,16 @@ winmm_refill_stream(cubeb_stream * stm)
if (stm->soft_volume != -1.0) {
if (stm->params.format == CUBEB_SAMPLE_FLOAT32NE) {
float * b = (float *) hdr->lpData;
float * b = (float *)hdr->lpData;
uint32_t i;
for (i = 0; i < got * stm->params.channels; i++) {
b[i] *= stm->soft_volume;
}
} else {
short * b = (short *) hdr->lpData;
short * b = (short *)hdr->lpData;
uint32_t i;
for (i = 0; i < got * stm->params.channels; i++) {
b[i] = (short) (b[i] * stm->soft_volume);
b[i] = (short)(b[i] * stm->soft_volume);
}
}
}
@ -223,10 +227,9 @@ winmm_refill_stream(cubeb_stream * stm)
LeaveCriticalSection(&stm->lock);
}
static unsigned __stdcall
winmm_buffer_thread(void * user_ptr)
static unsigned __stdcall winmm_buffer_thread(void * user_ptr)
{
cubeb * ctx = (cubeb *) user_ptr;
cubeb * ctx = (cubeb *)user_ptr;
XASSERT(ctx);
for (;;) {
@ -242,7 +245,7 @@ winmm_buffer_thread(void * user_ptr)
item = InterlockedFlushSList(ctx->work);
while (item != NULL) {
PSLIST_ENTRY tmp = item;
winmm_refill_stream(((struct cubeb_stream_item *) tmp)->stream);
winmm_refill_stream(((struct cubeb_stream_item *)tmp)->stream);
item = item->Next;
_aligned_free(tmp);
}
@ -256,16 +259,18 @@ winmm_buffer_thread(void * user_ptr)
}
static void CALLBACK
winmm_buffer_callback(HWAVEOUT waveout, UINT msg, DWORD_PTR user_ptr, DWORD_PTR p1, DWORD_PTR p2)
winmm_buffer_callback(HWAVEOUT waveout, UINT msg, DWORD_PTR user_ptr,
DWORD_PTR p1, DWORD_PTR p2)
{
cubeb_stream * stm = (cubeb_stream *) user_ptr;
cubeb_stream * stm = (cubeb_stream *)user_ptr;
struct cubeb_stream_item * item;
if (msg != WOM_DONE) {
return;
}
item = _aligned_malloc(sizeof(struct cubeb_stream_item), MEMORY_ALLOCATION_ALIGNMENT);
item = _aligned_malloc(sizeof(struct cubeb_stream_item),
MEMORY_ALLOCATION_ALIGNMENT);
XASSERT(item);
item->stream = stm;
InterlockedPushEntrySList(stm->context->work, &item->head);
@ -284,7 +289,8 @@ calculate_minimum_latency(void)
return 500;
}
/* Vista's WinMM implementation underruns when less than 200ms of audio is buffered. */
/* Vista's WinMM implementation underruns when less than 200ms of audio is
* buffered. */
memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = 6;
@ -294,14 +300,16 @@ calculate_minimum_latency(void)
VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_EQUAL);
VER_SET_CONDITION(mask, VER_MINORVERSION, VER_EQUAL);
if (VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, mask) != 0) {
if (VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, mask) !=
0) {
return 200;
}
return 100;
}
static void winmm_destroy(cubeb * ctx);
static void
winmm_destroy(cubeb * ctx);
/*static*/ int
winmm_init(cubeb ** context, char const * context_name)
@ -331,7 +339,9 @@ winmm_init(cubeb ** context, char const * context_name)
return CUBEB_ERROR;
}
ctx->thread = (HANDLE) _beginthreadex(NULL, 256 * 1024, winmm_buffer_thread, ctx, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
ctx->thread =
(HANDLE)_beginthreadex(NULL, 256 * 1024, winmm_buffer_thread, ctx,
STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
if (!ctx->thread) {
winmm_destroy(ctx);
return CUBEB_ERROR;
@ -382,18 +392,18 @@ winmm_destroy(cubeb * ctx)
free(ctx);
}
static void winmm_stream_destroy(cubeb_stream * stm);
static void
winmm_stream_destroy(cubeb_stream * stm);
static int
winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
cubeb_devid input_device,
winmm_stream_init(cubeb * context, cubeb_stream ** stream,
char const * stream_name, cubeb_devid input_device,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr)
cubeb_state_callback state_callback, void * user_ptr)
{
MMRESULT r;
WAVEFORMATEXTENSIBLE wfx;
@ -452,8 +462,10 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
return CUBEB_ERROR_INVALID_FORMAT;
}
wfx.Format.nBlockAlign = (wfx.Format.wBitsPerSample * wfx.Format.nChannels) / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.nBlockAlign =
(wfx.Format.wBitsPerSample * wfx.Format.nChannels) / 8;
wfx.Format.nAvgBytesPerSec =
wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
EnterCriticalSection(&context->lock);
@ -485,9 +497,11 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
latency_ms = context->minimum_latency_ms;
}
bufsz = (size_t) (stm->params.rate / 1000.0 * latency_ms * bytes_per_frame(stm->params) / NBUFS);
bufsz = (size_t)(stm->params.rate / 1000.0 * latency_ms *
bytes_per_frame(stm->params) / NBUFS);
if (bufsz % bytes_per_frame(stm->params) != 0) {
bufsz += bytes_per_frame(stm->params) - (bufsz % bytes_per_frame(stm->params));
bufsz +=
bytes_per_frame(stm->params) - (bufsz % bytes_per_frame(stm->params));
}
XASSERT(bufsz % bytes_per_frame(stm->params) == 0);
@ -506,7 +520,7 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
/* winmm_buffer_callback will be called during waveOutOpen, so all
other initialization must be complete before calling it. */
r = waveOutOpen(&stm->waveout, WAVE_MAPPER, &wfx.Format,
(DWORD_PTR) winmm_buffer_callback, (DWORD_PTR) stm,
(DWORD_PTR)winmm_buffer_callback, (DWORD_PTR)stm,
CALLBACK_FUNCTION);
if (r != MMSYSERR_NOERROR) {
winmm_stream_destroy(stm);
@ -536,6 +550,10 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
winmm_refill_stream(stm);
}
stm->frame_size = bytes_per_frame(stm->params);
stm->prev_pos_lo_dword = 0;
stm->pos_hi_dword = 0;
*stream = stm;
return CUBEB_OK;
@ -580,7 +598,8 @@ winmm_stream_destroy(cubeb_stream * stm)
for (i = 0; i < NBUFS; ++i) {
if (stm->buffers[i].dwFlags & WHDR_PREPARED) {
waveOutUnprepareHeader(stm->waveout, &stm->buffers[i], sizeof(stm->buffers[i]));
waveOutUnprepareHeader(stm->waveout, &stm->buffers[i],
sizeof(stm->buffers[i]));
}
}
@ -619,7 +638,8 @@ winmm_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
}
static int
winmm_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency)
winmm_get_min_latency(cubeb * ctx, cubeb_stream_params params,
uint32_t * latency)
{
// 100ms minimum, if we are not in a bizarre configuration.
*latency = ctx->minimum_latency_ms * params.rate / 1000;
@ -686,6 +706,58 @@ winmm_stream_stop(cubeb_stream * stm)
return CUBEB_OK;
}
/*
Microsoft wave audio docs say "samples are the preferred time format in which
to represent the current position", but relying on this causes problems on
Windows XP, the only OS cubeb_winmm is used on.
While the wdmaud.sys driver internally tracks a 64-bit position and ensures no
backward movement, the WinMM API limits the position returned from
waveOutGetPosition() to a 32-bit DWORD (this applies equally to XP x64). The
higher 32 bits are chopped off, and to an API consumer the position can appear
to move backward.
In theory, even a 32-bit TIME_SAMPLES position should provide plenty of
playback time for typical use cases before this pseudo wrap-around, e.g:
(2^32 - 1)/48000 = ~24:51:18 for 48.0 kHz stereo;
(2^32 - 1)/44100 = ~27:03:12 for 44.1 kHz stereo.
In reality, wdmaud.sys doesn't provide a TIME_SAMPLES position at all, only a
32-bit TIME_BYTES position, from which wdmaud.drv derives TIME_SAMPLES:
SamplePos = (BytePos * 8) / BitsPerFrame,
where BitsPerFrame = Channels * BitsPerSample,
Per dom\media\AudioSampleFormat.h, desktop builds always use 32-bit FLOAT32
samples, so the maximum for TIME_SAMPLES should be:
(2^29 - 1)/48000 = ~03:06:25;
(2^29 - 1)/44100 = ~03:22:54.
This might still be OK for typical browser usage, but there's also a bug in the
formula above: BytePos * 8 (BytePos << 3) is done on a 32-bit BytePos, without
first casting it to 64 bits, so the highest 3 bits, if set, would get shifted
out, and the maximum possible TIME_SAMPLES drops unacceptably low:
(2^26 - 1)/48000 = ~00:23:18;
(2^26 - 1)/44100 = ~00:25:22.
To work around these limitations, we just get the position in TIME_BYTES,
recover the 64-bit value, and do our own conversion to samples.
*/
/* Convert chopped 32-bit waveOutGetPosition() into 64-bit true position. */
static uint64_t
update_64bit_position(cubeb_stream * stm, DWORD pos_lo_dword)
{
/* Caller should be holding stm->lock. */
if (pos_lo_dword < stm->prev_pos_lo_dword) {
stm->pos_hi_dword++;
LOG("waveOutGetPosition() has wrapped around: %#lx -> %#lx",
stm->prev_pos_lo_dword, pos_lo_dword);
LOG("Wrap-around count = %#lx", stm->pos_hi_dword);
LOG("Current 64-bit position = %#llx",
(((uint64_t)stm->pos_hi_dword) << 32) | ((uint64_t)pos_lo_dword));
}
stm->prev_pos_lo_dword = pos_lo_dword;
return (((uint64_t)stm->pos_hi_dword) << 32) | ((uint64_t)pos_lo_dword);
}
static int
winmm_stream_get_position(cubeb_stream * stm, uint64_t * position)
{
@ -693,15 +765,17 @@ winmm_stream_get_position(cubeb_stream * stm, uint64_t * position)
MMTIME time;
EnterCriticalSection(&stm->lock);
time.wType = TIME_SAMPLES;
/* See the long comment above for why not just use TIME_SAMPLES here. */
time.wType = TIME_BYTES;
r = waveOutGetPosition(stm->waveout, &time, sizeof(time));
LeaveCriticalSection(&stm->lock);
if (r != MMSYSERR_NOERROR || time.wType != TIME_SAMPLES) {
if (r != MMSYSERR_NOERROR || time.wType != TIME_BYTES) {
LeaveCriticalSection(&stm->lock);
return CUBEB_ERROR;
}
*position = time.u.sample;
*position = update_64bit_position(stm, time.u.cb) / stm->frame_size;
LeaveCriticalSection(&stm->lock);
return CUBEB_OK;
}
@ -711,20 +785,24 @@ winmm_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
{
MMRESULT r;
MMTIME time;
uint64_t written;
uint64_t written, position;
EnterCriticalSection(&stm->lock);
time.wType = TIME_SAMPLES;
/* See the long comment above for why not just use TIME_SAMPLES here. */
time.wType = TIME_BYTES;
r = waveOutGetPosition(stm->waveout, &time, sizeof(time));
written = stm->written;
LeaveCriticalSection(&stm->lock);
if (r != MMSYSERR_NOERROR || time.wType != TIME_SAMPLES) {
if (r != MMSYSERR_NOERROR || time.wType != TIME_BYTES) {
LeaveCriticalSection(&stm->lock);
return CUBEB_ERROR;
}
XASSERT(written - time.u.sample <= UINT32_MAX);
*latency = (uint32_t) (written - time.u.sample);
position = update_64bit_position(stm, time.u.cb);
written = stm->written;
LeaveCriticalSection(&stm->lock);
XASSERT((written - (position / stm->frame_size)) <= UINT32_MAX);
*latency = (uint32_t)(written - (position / stm->frame_size));
return CUBEB_OK;
}
@ -738,11 +816,18 @@ winmm_stream_set_volume(cubeb_stream * stm, float volume)
return CUBEB_OK;
}
#define MM_11025HZ_MASK (WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16)
#define MM_22050HZ_MASK (WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16)
#define MM_44100HZ_MASK (WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16)
#define MM_48000HZ_MASK (WAVE_FORMAT_48M08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48S16)
#define MM_96000HZ_MASK (WAVE_FORMAT_96M08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96S16)
#define MM_11025HZ_MASK \
(WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16)
#define MM_22050HZ_MASK \
(WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16)
#define MM_44100HZ_MASK \
(WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16)
#define MM_48000HZ_MASK \
(WAVE_FORMAT_48M08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S08 | \
WAVE_FORMAT_48S16)
#define MM_96000HZ_MASK \
(WAVE_FORMAT_96M08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S08 | \
WAVE_FORMAT_96S16)
static void
winmm_calculate_device_rate(cubeb_device_info * info, DWORD formats)
{
@ -752,17 +837,20 @@ winmm_calculate_device_rate(cubeb_device_info * info, DWORD formats)
info->max_rate = 11025;
}
if (formats & MM_22050HZ_MASK) {
if (info->min_rate == 0) info->min_rate = 22050;
if (info->min_rate == 0)
info->min_rate = 22050;
info->max_rate = 22050;
info->default_rate = 22050;
}
if (formats & MM_44100HZ_MASK) {
if (info->min_rate == 0) info->min_rate = 44100;
if (info->min_rate == 0)
info->min_rate = 44100;
info->max_rate = 44100;
info->default_rate = 44100;
}
if (formats & MM_48000HZ_MASK) {
if (info->min_rate == 0) info->min_rate = 48000;
if (info->min_rate == 0)
info->min_rate = 48000;
info->max_rate = 48000;
info->default_rate = 48000;
}
@ -775,11 +863,14 @@ winmm_calculate_device_rate(cubeb_device_info * info, DWORD formats)
}
}
#define MM_S16_MASK (WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4M16 | \
WAVE_FORMAT_4S16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16)
#define MM_S16_MASK \
(WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | \
WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_48M16 | \
WAVE_FORMAT_48S16 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16)
static int
winmm_query_supported_formats(UINT devid, DWORD formats,
cubeb_device_fmt * supfmt, cubeb_device_fmt * deffmt)
cubeb_device_fmt * supfmt,
cubeb_device_fmt * deffmt)
{
WAVEFORMATEXTENSIBLE wfx;
@ -793,13 +884,16 @@ winmm_query_supported_formats(UINT devid, DWORD formats,
wfx.Format.nChannels = 2;
wfx.Format.nSamplesPerSec = 44100;
wfx.Format.wBitsPerSample = 32;
wfx.Format.nBlockAlign = (wfx.Format.wBitsPerSample * wfx.Format.nChannels) / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.nBlockAlign =
(wfx.Format.wBitsPerSample * wfx.Format.nChannels) / 8;
wfx.Format.nAvgBytesPerSec =
wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 22;
wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
if (waveOutOpen(NULL, devid, &wfx.Format, 0, 0, WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR)
if (waveOutOpen(NULL, devid, &wfx.Format, 0, 0, WAVE_FORMAT_QUERY) ==
MMSYSERR_NOERROR)
*supfmt = (cubeb_device_fmt)(*supfmt | CUBEB_DEVICE_FMT_F32LE);
return (*deffmt != 0) ? CUBEB_OK : CUBEB_ERROR;
@ -813,10 +907,10 @@ guid_to_cstr(LPGUID guid)
return NULL;
}
_snprintf_s(ret, 40, _TRUNCATE,
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
guid->Data4[6], guid->Data4[7]);
return ret;
}
@ -826,13 +920,15 @@ winmm_query_preferred_out_device(UINT devid)
DWORD mmpref = WAVE_MAPPER, compref = WAVE_MAPPER, status;
cubeb_device_pref ret = CUBEB_DEVICE_PREF_NONE;
if (waveOutMessage((HWAVEOUT) WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
(DWORD_PTR)&mmpref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
if (waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
(DWORD_PTR)&mmpref,
(DWORD_PTR)&status) == MMSYSERR_NOERROR &&
devid == mmpref)
ret |= CUBEB_DEVICE_PREF_MULTIMEDIA | CUBEB_DEVICE_PREF_NOTIFICATION;
if (waveOutMessage((HWAVEOUT) WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
(DWORD_PTR)&compref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
if (waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
(DWORD_PTR)&compref,
(DWORD_PTR)&status) == MMSYSERR_NOERROR &&
devid == compref)
ret |= CUBEB_DEVICE_PREF_VOICE;
@ -851,10 +947,11 @@ device_id_idx(UINT devid)
}
static void
winmm_create_device_from_outcaps2(cubeb_device_info * ret, LPWAVEOUTCAPS2A caps, UINT devid)
winmm_create_device_from_outcaps2(cubeb_device_info * ret, LPWAVEOUTCAPS2A caps,
UINT devid)
{
XASSERT(ret);
ret->devid = (cubeb_devid) devid;
ret->devid = (cubeb_devid)devid;
ret->device_id = device_id_idx(devid);
ret->friendly_name = _strdup(caps->szPname);
ret->group_id = guid_to_cstr(&caps->ProductGuid);
@ -866,8 +963,8 @@ winmm_create_device_from_outcaps2(cubeb_device_info * ret, LPWAVEOUTCAPS2A caps,
ret->max_channels = caps->wChannels;
winmm_calculate_device_rate(ret, caps->dwFormats);
winmm_query_supported_formats(devid, caps->dwFormats,
&ret->format, &ret->default_format);
winmm_query_supported_formats(devid, caps->dwFormats, &ret->format,
&ret->default_format);
/* Hardcoded latency estimates... */
ret->latency_lo = 100 * ret->default_rate / 1000;
@ -875,10 +972,11 @@ winmm_create_device_from_outcaps2(cubeb_device_info * ret, LPWAVEOUTCAPS2A caps,
}
static void
winmm_create_device_from_outcaps(cubeb_device_info * ret, LPWAVEOUTCAPSA caps, UINT devid)
winmm_create_device_from_outcaps(cubeb_device_info * ret, LPWAVEOUTCAPSA caps,
UINT devid)
{
XASSERT(ret);
ret->devid = (cubeb_devid) devid;
ret->devid = (cubeb_devid)devid;
ret->device_id = device_id_idx(devid);
ret->friendly_name = _strdup(caps->szPname);
ret->group_id = NULL;
@ -890,8 +988,8 @@ winmm_create_device_from_outcaps(cubeb_device_info * ret, LPWAVEOUTCAPSA caps, U
ret->max_channels = caps->wChannels;
winmm_calculate_device_rate(ret, caps->dwFormats);
winmm_query_supported_formats(devid, caps->dwFormats,
&ret->format, &ret->default_format);
winmm_query_supported_formats(devid, caps->dwFormats, &ret->format,
&ret->default_format);
/* Hardcoded latency estimates... */
ret->latency_lo = 100 * ret->default_rate / 1000;
@ -904,13 +1002,15 @@ winmm_query_preferred_in_device(UINT devid)
DWORD mmpref = WAVE_MAPPER, compref = WAVE_MAPPER, status;
cubeb_device_pref ret = CUBEB_DEVICE_PREF_NONE;
if (waveInMessage((HWAVEIN) WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
(DWORD_PTR)&mmpref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
if (waveInMessage((HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
(DWORD_PTR)&mmpref,
(DWORD_PTR)&status) == MMSYSERR_NOERROR &&
devid == mmpref)
ret |= CUBEB_DEVICE_PREF_MULTIMEDIA | CUBEB_DEVICE_PREF_NOTIFICATION;
if (waveInMessage((HWAVEIN) WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
(DWORD_PTR)&compref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
if (waveInMessage((HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
(DWORD_PTR)&compref,
(DWORD_PTR)&status) == MMSYSERR_NOERROR &&
devid == compref)
ret |= CUBEB_DEVICE_PREF_VOICE;
@ -918,10 +1018,11 @@ winmm_query_preferred_in_device(UINT devid)
}
static void
winmm_create_device_from_incaps2(cubeb_device_info * ret, LPWAVEINCAPS2A caps, UINT devid)
winmm_create_device_from_incaps2(cubeb_device_info * ret, LPWAVEINCAPS2A caps,
UINT devid)
{
XASSERT(ret);
ret->devid = (cubeb_devid) devid;
ret->devid = (cubeb_devid)devid;
ret->device_id = device_id_idx(devid);
ret->friendly_name = _strdup(caps->szPname);
ret->group_id = guid_to_cstr(&caps->ProductGuid);
@ -933,8 +1034,8 @@ winmm_create_device_from_incaps2(cubeb_device_info * ret, LPWAVEINCAPS2A caps, U
ret->max_channels = caps->wChannels;
winmm_calculate_device_rate(ret, caps->dwFormats);
winmm_query_supported_formats(devid, caps->dwFormats,
&ret->format, &ret->default_format);
winmm_query_supported_formats(devid, caps->dwFormats, &ret->format,
&ret->default_format);
/* Hardcoded latency estimates... */
ret->latency_lo = 100 * ret->default_rate / 1000;
@ -942,10 +1043,11 @@ winmm_create_device_from_incaps2(cubeb_device_info * ret, LPWAVEINCAPS2A caps, U
}
static void
winmm_create_device_from_incaps(cubeb_device_info * ret, LPWAVEINCAPSA caps, UINT devid)
winmm_create_device_from_incaps(cubeb_device_info * ret, LPWAVEINCAPSA caps,
UINT devid)
{
XASSERT(ret);
ret->devid = (cubeb_devid) devid;
ret->devid = (cubeb_devid)devid;
ret->device_id = device_id_idx(devid);
ret->friendly_name = _strdup(caps->szPname);
ret->group_id = NULL;
@ -957,8 +1059,8 @@ winmm_create_device_from_incaps(cubeb_device_info * ret, LPWAVEINCAPSA caps, UIN
ret->max_channels = caps->wChannels;
winmm_calculate_device_rate(ret, caps->dwFormats);
winmm_query_supported_formats(devid, caps->dwFormats,
&ret->format, &ret->default_format);
winmm_query_supported_formats(devid, caps->dwFormats, &ret->format,
&ret->default_format);
/* Hardcoded latency estimates... */
ret->latency_lo = 100 * ret->default_rate / 1000;
@ -989,7 +1091,8 @@ winmm_enumerate_devices(cubeb * context, cubeb_device_type type,
for (i = 0; i < outcount; i++) {
dev = &devices[collection->count];
if (waveOutGetDevCapsA(i, (LPWAVEOUTCAPSA)&woc2, sizeof(woc2)) == MMSYSERR_NOERROR) {
if (waveOutGetDevCapsA(i, (LPWAVEOUTCAPSA)&woc2, sizeof(woc2)) ==
MMSYSERR_NOERROR) {
winmm_create_device_from_outcaps2(dev, &woc2, i);
collection->count += 1;
} else if (waveOutGetDevCapsA(i, &woc, sizeof(woc)) == MMSYSERR_NOERROR) {
@ -1008,7 +1111,8 @@ winmm_enumerate_devices(cubeb * context, cubeb_device_type type,
for (i = 0; i < incount; i++) {
dev = &devices[collection->count];
if (waveInGetDevCapsA(i, (LPWAVEINCAPSA)&wic2, sizeof(wic2)) == MMSYSERR_NOERROR) {
if (waveInGetDevCapsA(i, (LPWAVEINCAPSA)&wic2, sizeof(wic2)) ==
MMSYSERR_NOERROR) {
winmm_create_device_from_incaps2(dev, &wic2, i);
collection->count += 1;
} else if (waveInGetDevCapsA(i, &wic, sizeof(wic)) == MMSYSERR_NOERROR) {
@ -1030,13 +1134,13 @@ winmm_device_collection_destroy(cubeb * ctx,
uint32_t i;
XASSERT(collection);
(void) ctx;
(void)ctx;
for (i = 0; i < collection->count; i++) {
free((void *) collection->device[i].device_id);
free((void *) collection->device[i].friendly_name);
free((void *) collection->device[i].group_id);
free((void *) collection->device[i].vendor_name);
free((void *)collection->device[i].device_id);
free((void *)collection->device[i].friendly_name);
free((void *)collection->device[i].group_id);
free((void *)collection->device[i].vendor_name);
}
free(collection->device);
@ -1044,26 +1148,24 @@ winmm_device_collection_destroy(cubeb * ctx,
}
static struct cubeb_ops const winmm_ops = {
/*.init =*/ winmm_init,
/*.get_backend_id =*/ winmm_get_backend_id,
/*.get_max_channel_count=*/ winmm_get_max_channel_count,
/*.get_min_latency=*/ winmm_get_min_latency,
/*.get_preferred_sample_rate =*/ winmm_get_preferred_sample_rate,
/*.enumerate_devices =*/ winmm_enumerate_devices,
/*.device_collection_destroy =*/ winmm_device_collection_destroy,
/*.destroy =*/ winmm_destroy,
/*.stream_init =*/ winmm_stream_init,
/*.stream_destroy =*/ winmm_stream_destroy,
/*.stream_start =*/ winmm_stream_start,
/*.stream_stop =*/ winmm_stream_stop,
/*.stream_reset_default_device =*/ NULL,
/*.stream_get_position =*/ winmm_stream_get_position,
/*.stream_get_latency = */ winmm_stream_get_latency,
/*.stream_get_input_latency = */ NULL,
/*.stream_set_volume =*/ winmm_stream_set_volume,
/*.stream_set_name =*/ NULL,
/*.stream_get_current_device =*/ NULL,
/*.stream_device_destroy =*/ NULL,
/*.stream_register_device_changed_callback=*/ NULL,
/*.register_device_collection_changed =*/ NULL
};
/*.init =*/winmm_init,
/*.get_backend_id =*/winmm_get_backend_id,
/*.get_max_channel_count=*/winmm_get_max_channel_count,
/*.get_min_latency=*/winmm_get_min_latency,
/*.get_preferred_sample_rate =*/winmm_get_preferred_sample_rate,
/*.enumerate_devices =*/winmm_enumerate_devices,
/*.device_collection_destroy =*/winmm_device_collection_destroy,
/*.destroy =*/winmm_destroy,
/*.stream_init =*/winmm_stream_init,
/*.stream_destroy =*/winmm_stream_destroy,
/*.stream_start =*/winmm_stream_start,
/*.stream_stop =*/winmm_stream_stop,
/*.stream_get_position =*/winmm_stream_get_position,
/*.stream_get_latency = */ winmm_stream_get_latency,
/*.stream_get_input_latency = */ NULL,
/*.stream_set_volume =*/winmm_stream_set_volume,
/*.stream_set_name =*/NULL,
/*.stream_get_current_device =*/NULL,
/*.stream_device_destroy =*/NULL,
/*.stream_register_device_changed_callback=*/NULL,
/*.register_device_collection_changed =*/NULL};