winealsa: Move is_format_supported to the unixlib.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7920275c56
commit
d2339bb4c9
|
@ -453,6 +453,27 @@ static NTSTATUS get_endpoint_ids(void *args)
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt)
|
||||||
|
{
|
||||||
|
WAVEFORMATEXTENSIBLE *ret;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
||||||
|
size = sizeof(WAVEFORMATEXTENSIBLE);
|
||||||
|
else
|
||||||
|
size = sizeof(WAVEFORMATEX);
|
||||||
|
|
||||||
|
ret = malloc(size);
|
||||||
|
if(!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(ret, fmt, size);
|
||||||
|
|
||||||
|
ret->Format.cbSize = size - sizeof(WAVEFORMATEX);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
|
static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
|
||||||
snd_pcm_hw_params_t **hw_params)
|
snd_pcm_hw_params_t **hw_params)
|
||||||
{
|
{
|
||||||
|
@ -486,6 +507,78 @@ static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static snd_pcm_format_t alsa_format(const WAVEFORMATEX *fmt)
|
||||||
|
{
|
||||||
|
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
|
||||||
|
const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
|
||||||
|
|
||||||
|
if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
|
||||||
|
(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||||
|
IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
|
||||||
|
if(fmt->wBitsPerSample == 8)
|
||||||
|
format = SND_PCM_FORMAT_U8;
|
||||||
|
else if(fmt->wBitsPerSample == 16)
|
||||||
|
format = SND_PCM_FORMAT_S16_LE;
|
||||||
|
else if(fmt->wBitsPerSample == 24)
|
||||||
|
format = SND_PCM_FORMAT_S24_3LE;
|
||||||
|
else if(fmt->wBitsPerSample == 32)
|
||||||
|
format = SND_PCM_FORMAT_S32_LE;
|
||||||
|
else
|
||||||
|
WARN("Unsupported bit depth: %u\n", fmt->wBitsPerSample);
|
||||||
|
if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||||
|
fmt->wBitsPerSample != fmtex->Samples.wValidBitsPerSample){
|
||||||
|
if(fmtex->Samples.wValidBitsPerSample == 20 && fmt->wBitsPerSample == 24)
|
||||||
|
format = SND_PCM_FORMAT_S20_3LE;
|
||||||
|
else
|
||||||
|
WARN("Unsupported ValidBits: %u\n", fmtex->Samples.wValidBitsPerSample);
|
||||||
|
}
|
||||||
|
}else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
|
||||||
|
(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||||
|
IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
|
||||||
|
if(fmt->wBitsPerSample == 32)
|
||||||
|
format = SND_PCM_FORMAT_FLOAT_LE;
|
||||||
|
else if(fmt->wBitsPerSample == 64)
|
||||||
|
format = SND_PCM_FORMAT_FLOAT64_LE;
|
||||||
|
else
|
||||||
|
WARN("Unsupported float size: %u\n", fmt->wBitsPerSample);
|
||||||
|
}else
|
||||||
|
WARN("Unknown wave format: %04x\n", fmt->wFormatTag);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alsa_channel_index(DWORD flag)
|
||||||
|
{
|
||||||
|
switch(flag){
|
||||||
|
case SPEAKER_FRONT_LEFT:
|
||||||
|
return 0;
|
||||||
|
case SPEAKER_FRONT_RIGHT:
|
||||||
|
return 1;
|
||||||
|
case SPEAKER_BACK_LEFT:
|
||||||
|
return 2;
|
||||||
|
case SPEAKER_BACK_RIGHT:
|
||||||
|
return 3;
|
||||||
|
case SPEAKER_FRONT_CENTER:
|
||||||
|
return 4;
|
||||||
|
case SPEAKER_LOW_FREQUENCY:
|
||||||
|
return 5;
|
||||||
|
case SPEAKER_SIDE_LEFT:
|
||||||
|
return 6;
|
||||||
|
case SPEAKER_SIDE_RIGHT:
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL need_remapping(const WAVEFORMATEX *fmt, int *map)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for(i = 0; i < fmt->nChannels; ++i){
|
||||||
|
if(map[i] != i)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD get_channel_mask(unsigned int channels)
|
static DWORD get_channel_mask(unsigned int channels)
|
||||||
{
|
{
|
||||||
switch(channels){
|
switch(channels){
|
||||||
|
@ -512,6 +605,203 @@ static DWORD get_channel_mask(unsigned int channels)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT map_channels(EDataFlow flow, const WAVEFORMATEX *fmt, int *alsa_channels, int *map)
|
||||||
|
{
|
||||||
|
BOOL need_remap;
|
||||||
|
|
||||||
|
if(flow != eCapture && (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE || fmt->nChannels > 2) ){
|
||||||
|
WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
|
||||||
|
DWORD mask, flag = SPEAKER_FRONT_LEFT;
|
||||||
|
UINT i = 0;
|
||||||
|
|
||||||
|
if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||||
|
fmtex->dwChannelMask != 0)
|
||||||
|
mask = fmtex->dwChannelMask;
|
||||||
|
else
|
||||||
|
mask = get_channel_mask(fmt->nChannels);
|
||||||
|
|
||||||
|
*alsa_channels = 0;
|
||||||
|
|
||||||
|
while(i < fmt->nChannels && !(flag & SPEAKER_RESERVED)){
|
||||||
|
if(mask & flag){
|
||||||
|
map[i] = alsa_channel_index(flag);
|
||||||
|
TRACE("Mapping mmdevapi channel %u (0x%x) to ALSA channel %d\n",
|
||||||
|
i, flag, map[i]);
|
||||||
|
if(map[i] >= *alsa_channels)
|
||||||
|
*alsa_channels = map[i] + 1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
flag <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(i < fmt->nChannels){
|
||||||
|
map[i] = *alsa_channels;
|
||||||
|
TRACE("Mapping mmdevapi channel %u to ALSA channel %d\n",
|
||||||
|
i, map[i]);
|
||||||
|
++*alsa_channels;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < fmt->nChannels; ++i){
|
||||||
|
if(map[i] == -1){
|
||||||
|
map[i] = *alsa_channels;
|
||||||
|
++*alsa_channels;
|
||||||
|
TRACE("Remapping mmdevapi channel %u to ALSA channel %d\n",
|
||||||
|
i, map[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
need_remap = need_remapping(fmt, map);
|
||||||
|
}else{
|
||||||
|
*alsa_channels = fmt->nChannels;
|
||||||
|
|
||||||
|
need_remap = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("need_remapping: %u, alsa_channels: %d\n", need_remap, *alsa_channels);
|
||||||
|
|
||||||
|
return need_remap ? S_OK : S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS is_format_supported(void *args)
|
||||||
|
{
|
||||||
|
struct is_format_supported_params *params = args;
|
||||||
|
const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in;
|
||||||
|
snd_pcm_t *pcm_handle;
|
||||||
|
snd_pcm_hw_params_t *hw_params;
|
||||||
|
snd_pcm_format_mask_t *formats = NULL;
|
||||||
|
snd_pcm_format_t format;
|
||||||
|
WAVEFORMATEXTENSIBLE *closest = NULL;
|
||||||
|
unsigned int max = 0, min = 0;
|
||||||
|
int err;
|
||||||
|
int alsa_channels, alsa_channel_map[32];
|
||||||
|
|
||||||
|
params->result = S_OK;
|
||||||
|
|
||||||
|
if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
|
||||||
|
params->result = E_POINTER;
|
||||||
|
else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
|
||||||
|
params->result = E_INVALIDARG;
|
||||||
|
else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
|
||||||
|
if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
|
||||||
|
params->result = E_INVALIDARG;
|
||||||
|
else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 ||
|
||||||
|
(fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample))
|
||||||
|
params->result = E_INVALIDARG;
|
||||||
|
}
|
||||||
|
if(FAILED(params->result))
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if(params->fmt_in->nChannels == 0){
|
||||||
|
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
params->result = alsa_open_device(params->alsa_name, params->flow, &pcm_handle, &hw_params);
|
||||||
|
if(FAILED(params->result))
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
|
||||||
|
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
formats = calloc(1, snd_pcm_format_mask_sizeof());
|
||||||
|
if(!formats){
|
||||||
|
params->result = E_OUTOFMEMORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_pcm_hw_params_get_format_mask(hw_params, formats);
|
||||||
|
format = alsa_format(params->fmt_in);
|
||||||
|
if (format == SND_PCM_FORMAT_UNKNOWN ||
|
||||||
|
!snd_pcm_format_mask_test(formats, format)){
|
||||||
|
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
closest = clone_format(params->fmt_in);
|
||||||
|
if(!closest){
|
||||||
|
params->result = E_OUTOFMEMORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((err = snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL)) < 0){
|
||||||
|
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
|
||||||
|
WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL)) < 0){
|
||||||
|
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
|
||||||
|
WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(params->fmt_in->nSamplesPerSec < min || params->fmt_in->nSamplesPerSec > max){
|
||||||
|
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((err = snd_pcm_hw_params_get_channels_min(hw_params, &min)) < 0){
|
||||||
|
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
|
||||||
|
WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max)) < 0){
|
||||||
|
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
|
||||||
|
WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if(params->fmt_in->nChannels > max){
|
||||||
|
params->result = S_FALSE;
|
||||||
|
closest->Format.nChannels = max;
|
||||||
|
}else if(params->fmt_in->nChannels < min){
|
||||||
|
params->result = S_FALSE;
|
||||||
|
closest->Format.nChannels = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_channels(params->flow, params->fmt_in, &alsa_channels, alsa_channel_map);
|
||||||
|
|
||||||
|
if(alsa_channels > max){
|
||||||
|
params->result = S_FALSE;
|
||||||
|
closest->Format.nChannels = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
||||||
|
closest->dwChannelMask = get_channel_mask(closest->Format.nChannels);
|
||||||
|
|
||||||
|
if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 ||
|
||||||
|
params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec ||
|
||||||
|
(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||||
|
fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample))
|
||||||
|
params->result = S_FALSE;
|
||||||
|
|
||||||
|
if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE && params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
|
||||||
|
if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)
|
||||||
|
params->result = S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(params->result == S_FALSE && !params->fmt_out)
|
||||||
|
params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
|
||||||
|
if(params->result == S_FALSE && params->fmt_out) {
|
||||||
|
closest->Format.nBlockAlign = closest->Format.nChannels * closest->Format.wBitsPerSample / 8;
|
||||||
|
closest->Format.nAvgBytesPerSec = closest->Format.nBlockAlign * closest->Format.nSamplesPerSec;
|
||||||
|
if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
||||||
|
closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample;
|
||||||
|
memcpy(params->fmt_out, closest, closest->Format.cbSize);
|
||||||
|
}
|
||||||
|
free(closest);
|
||||||
|
free(formats);
|
||||||
|
free(hw_params);
|
||||||
|
snd_pcm_close(pcm_handle);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS get_mix_format(void *args)
|
static NTSTATUS get_mix_format(void *args)
|
||||||
{
|
{
|
||||||
struct get_mix_format_params *params = args;
|
struct get_mix_format_params *params = args;
|
||||||
|
@ -632,5 +922,6 @@ exit:
|
||||||
unixlib_entry_t __wine_unix_call_funcs[] =
|
unixlib_entry_t __wine_unix_call_funcs[] =
|
||||||
{
|
{
|
||||||
get_endpoint_ids,
|
get_endpoint_ids,
|
||||||
|
is_format_supported,
|
||||||
get_mix_format,
|
get_mix_format,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1296,150 +1296,30 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
|
||||||
WAVEFORMATEX **out)
|
WAVEFORMATEX **out)
|
||||||
{
|
{
|
||||||
ACImpl *This = impl_from_IAudioClient3(iface);
|
ACImpl *This = impl_from_IAudioClient3(iface);
|
||||||
snd_pcm_format_mask_t *formats = NULL;
|
struct is_format_supported_params params;
|
||||||
snd_pcm_format_t format;
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
WAVEFORMATEX *closest = NULL;
|
|
||||||
unsigned int max = 0, min = 0;
|
|
||||||
int err;
|
|
||||||
int alsa_channels, alsa_channel_map[32];
|
|
||||||
|
|
||||||
TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
|
TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
|
||||||
|
if(fmt) dump_fmt(fmt);
|
||||||
|
|
||||||
if(!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
|
params.alsa_name = This->alsa_name;
|
||||||
return E_POINTER;
|
params.flow = This->dataflow;
|
||||||
|
params.share = mode;
|
||||||
if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
|
params.fmt_in = fmt;
|
||||||
return E_INVALIDARG;
|
params.fmt_out = NULL;
|
||||||
|
|
||||||
if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
|
||||||
fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
|
|
||||||
return E_INVALIDARG;
|
|
||||||
|
|
||||||
dump_fmt(fmt);
|
|
||||||
|
|
||||||
if(out){
|
if(out){
|
||||||
*out = NULL;
|
*out = NULL;
|
||||||
if(mode != AUDCLNT_SHAREMODE_SHARED)
|
if(mode == AUDCLNT_SHAREMODE_SHARED)
|
||||||
out = NULL;
|
params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
|
||||||
}
|
}
|
||||||
|
ALSA_CALL(is_format_supported, ¶ms);
|
||||||
|
|
||||||
if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
if(params.result == S_FALSE)
|
||||||
(fmt->nAvgBytesPerSec == 0 ||
|
*out = ¶ms.fmt_out->Format;
|
||||||
fmt->nBlockAlign == 0 ||
|
else
|
||||||
((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample > fmt->wBitsPerSample))
|
CoTaskMemFree(params.fmt_out);
|
||||||
return E_INVALIDARG;
|
|
||||||
|
|
||||||
if(fmt->nChannels == 0)
|
return params.result;
|
||||||
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
|
||||||
|
|
||||||
EnterCriticalSection(&This->lock);
|
|
||||||
|
|
||||||
if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
|
|
||||||
hr = AUDCLNT_E_DEVICE_INVALIDATED;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
||||||
snd_pcm_format_mask_sizeof());
|
|
||||||
if(!formats){
|
|
||||||
hr = E_OUTOFMEMORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
|
|
||||||
format = alsa_format(fmt);
|
|
||||||
if (format == SND_PCM_FORMAT_UNKNOWN ||
|
|
||||||
!snd_pcm_format_mask_test(formats, format)){
|
|
||||||
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
closest = clone_format(fmt);
|
|
||||||
if(!closest){
|
|
||||||
hr = E_OUTOFMEMORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = snd_pcm_hw_params_get_rate_min(This->stream->hw_params, &min, NULL)) < 0){
|
|
||||||
hr = AUDCLNT_E_DEVICE_INVALIDATED;
|
|
||||||
WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max, NULL)) < 0){
|
|
||||||
hr = AUDCLNT_E_DEVICE_INVALIDATED;
|
|
||||||
WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fmt->nSamplesPerSec < min || fmt->nSamplesPerSec > max){
|
|
||||||
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = snd_pcm_hw_params_get_channels_min(This->stream->hw_params, &min)) < 0){
|
|
||||||
hr = AUDCLNT_E_DEVICE_INVALIDATED;
|
|
||||||
WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params, &max)) < 0){
|
|
||||||
hr = AUDCLNT_E_DEVICE_INVALIDATED;
|
|
||||||
WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if(fmt->nChannels > max){
|
|
||||||
hr = S_FALSE;
|
|
||||||
closest->nChannels = max;
|
|
||||||
}else if(fmt->nChannels < min){
|
|
||||||
hr = S_FALSE;
|
|
||||||
closest->nChannels = min;
|
|
||||||
}
|
|
||||||
|
|
||||||
map_channels(This, fmt, &alsa_channels, alsa_channel_map);
|
|
||||||
|
|
||||||
if(alsa_channels > max){
|
|
||||||
hr = S_FALSE;
|
|
||||||
closest->nChannels = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
|
||||||
((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = get_channel_mask(closest->nChannels);
|
|
||||||
|
|
||||||
if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
|
|
||||||
fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
|
|
||||||
(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
|
||||||
((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample < fmt->wBitsPerSample))
|
|
||||||
hr = S_FALSE;
|
|
||||||
|
|
||||||
if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
|
|
||||||
fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
|
|
||||||
if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
|
|
||||||
((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
|
|
||||||
hr = S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
LeaveCriticalSection(&This->lock);
|
|
||||||
HeapFree(GetProcessHeap(), 0, formats);
|
|
||||||
|
|
||||||
if(hr == S_FALSE && !out)
|
|
||||||
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
|
||||||
|
|
||||||
if(hr == S_FALSE && out) {
|
|
||||||
closest->nBlockAlign =
|
|
||||||
closest->nChannels * closest->wBitsPerSample / 8;
|
|
||||||
closest->nAvgBytesPerSec =
|
|
||||||
closest->nBlockAlign * closest->nSamplesPerSec;
|
|
||||||
if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
|
||||||
((WAVEFORMATEXTENSIBLE*)closest)->Samples.wValidBitsPerSample = closest->wBitsPerSample;
|
|
||||||
*out = closest;
|
|
||||||
} else
|
|
||||||
CoTaskMemFree(closest);
|
|
||||||
|
|
||||||
TRACE("returning: %08x\n", hr);
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
|
static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
|
||||||
|
|
|
@ -67,6 +67,16 @@ struct get_endpoint_ids_params
|
||||||
unsigned int default_idx;
|
unsigned int default_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct is_format_supported_params
|
||||||
|
{
|
||||||
|
const char *alsa_name;
|
||||||
|
EDataFlow flow;
|
||||||
|
AUDCLNT_SHAREMODE share;
|
||||||
|
const WAVEFORMATEX *fmt_in;
|
||||||
|
WAVEFORMATEXTENSIBLE *fmt_out;
|
||||||
|
HRESULT result;
|
||||||
|
};
|
||||||
|
|
||||||
struct get_mix_format_params
|
struct get_mix_format_params
|
||||||
{
|
{
|
||||||
const char *alsa_name;
|
const char *alsa_name;
|
||||||
|
@ -78,6 +88,7 @@ struct get_mix_format_params
|
||||||
enum alsa_funcs
|
enum alsa_funcs
|
||||||
{
|
{
|
||||||
alsa_get_endpoint_ids,
|
alsa_get_endpoint_ids,
|
||||||
|
alsa_is_format_supported,
|
||||||
alsa_get_mix_format,
|
alsa_get_mix_format,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue