[PATCH v2 1/6] winealsa: Add a temporary write_best_effort syscall.
Huw Davies
huw at codeweavers.com
Wed Mar 2 04:53:15 CST 2022
This will allow the timing loop to move over without needing
to move "start" at the same time.
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/winealsa.drv/alsa.c | 237 ++++++++++++++++++++++++++++++++++-
dlls/winealsa.drv/mmdevdrv.c | 230 +--------------------------------
dlls/winealsa.drv/unixlib.h | 10 ++
3 files changed, 252 insertions(+), 225 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index c73490ebfe6..73971c0f8bb 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -970,7 +970,7 @@ static NTSTATUS release_stream(void *args)
size = 0;
NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
}
- /* free(stream->remapping_buf); */
+ free(stream->remapping_buf);
free(stream->silence_buf);
free(stream->hw_params);
free(stream->fmt);
@@ -982,6 +982,239 @@ static NTSTATUS release_stream(void *args)
return STATUS_SUCCESS;
}
+static BYTE *remap_channels(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
+{
+ snd_pcm_uframes_t i;
+ UINT c;
+ UINT bytes_per_sample = stream->fmt->wBitsPerSample / 8;
+
+ if(!stream->need_remapping)
+ return buf;
+
+ if(stream->remapping_buf_frames < frames){
+ stream->remapping_buf = realloc(stream->remapping_buf,
+ bytes_per_sample * stream->alsa_channels * frames);
+ stream->remapping_buf_frames = frames;
+ }
+
+ snd_pcm_format_set_silence(stream->alsa_format, stream->remapping_buf,
+ frames * stream->alsa_channels);
+
+ switch(stream->fmt->wBitsPerSample){
+ case 8: {
+ UINT8 *tgt_buf, *src_buf;
+ tgt_buf = stream->remapping_buf;
+ src_buf = buf;
+ for(i = 0; i < frames; ++i){
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
+ tgt_buf += stream->alsa_channels;
+ src_buf += stream->fmt->nChannels;
+ }
+ break;
+ }
+ case 16: {
+ UINT16 *tgt_buf, *src_buf;
+ tgt_buf = (UINT16*)stream->remapping_buf;
+ src_buf = (UINT16*)buf;
+ for(i = 0; i < frames; ++i){
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
+ tgt_buf += stream->alsa_channels;
+ src_buf += stream->fmt->nChannels;
+ }
+ }
+ break;
+ case 32: {
+ UINT32 *tgt_buf, *src_buf;
+ tgt_buf = (UINT32*)stream->remapping_buf;
+ src_buf = (UINT32*)buf;
+ for(i = 0; i < frames; ++i){
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
+ tgt_buf += stream->alsa_channels;
+ src_buf += stream->fmt->nChannels;
+ }
+ }
+ break;
+ default: {
+ BYTE *tgt_buf, *src_buf;
+ tgt_buf = stream->remapping_buf;
+ src_buf = buf;
+ for(i = 0; i < frames; ++i){
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ memcpy(&tgt_buf[stream->alsa_channel_map[c] * bytes_per_sample],
+ &src_buf[c * bytes_per_sample], bytes_per_sample);
+ tgt_buf += stream->alsa_channels * bytes_per_sample;
+ src_buf += stream->fmt->nChannels * bytes_per_sample;
+ }
+ }
+ break;
+ }
+
+ return stream->remapping_buf;
+}
+
+static void adjust_buffer_volume(const struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
+{
+ BOOL adjust = FALSE;
+ UINT32 i, channels, mute = 0;
+ BYTE *end;
+
+ if (stream->vol_adjusted_frames >= frames)
+ return;
+ channels = stream->fmt->nChannels;
+
+ /* Adjust the buffer based on the volume for each channel */
+ for (i = 0; i < channels; i++)
+ {
+ adjust |= stream->vols[i] != 1.0f;
+ if (stream->vols[i] == 0.0f)
+ mute++;
+ }
+
+ if (mute == channels)
+ {
+ int err = snd_pcm_format_set_silence(stream->alsa_format, buf, frames * channels);
+ if (err < 0)
+ WARN("Setting buffer to silence failed: %d (%s)\n", err, snd_strerror(err));
+ return;
+ }
+ if (!adjust) return;
+
+ /* Skip the frames we've already adjusted before */
+ end = buf + frames * stream->fmt->nBlockAlign;
+ buf += stream->vol_adjusted_frames * stream->fmt->nBlockAlign;
+
+ switch (stream->alsa_format)
+ {
+#ifndef WORDS_BIGENDIAN
+#define PROCESS_BUFFER(type) do \
+{ \
+ type *p = (type*)buf; \
+ do \
+ { \
+ for (i = 0; i < channels; i++) \
+ p[i] = p[i] * stream->vols[i]; \
+ p += i; \
+ } while ((BYTE*)p != end); \
+} while (0)
+ case SND_PCM_FORMAT_S16_LE:
+ PROCESS_BUFFER(INT16);
+ break;
+ case SND_PCM_FORMAT_S32_LE:
+ PROCESS_BUFFER(INT32);
+ break;
+ case SND_PCM_FORMAT_FLOAT_LE:
+ PROCESS_BUFFER(float);
+ break;
+ case SND_PCM_FORMAT_FLOAT64_LE:
+ PROCESS_BUFFER(double);
+ break;
+#undef PROCESS_BUFFER
+ case SND_PCM_FORMAT_S20_3LE:
+ case SND_PCM_FORMAT_S24_3LE:
+ {
+ /* Do it 12 bytes at a time until it is no longer possible */
+ UINT32 *q = (UINT32*)buf, mask = ~0xff;
+ BYTE *p;
+
+ /* After we adjust the volume, we need to mask out low bits */
+ if (stream->alsa_format == SND_PCM_FORMAT_S20_3LE)
+ mask = ~0x0fff;
+
+ i = 0;
+ while (end - (BYTE*)q >= 12)
+ {
+ UINT32 v[4], k;
+ v[0] = q[0] << 8;
+ v[1] = q[1] << 16 | (q[0] >> 16 & ~0xff);
+ v[2] = q[2] << 24 | (q[1] >> 8 & ~0xff);
+ v[3] = q[2] & ~0xff;
+ for (k = 0; k < 4; k++)
+ {
+ v[k] = (INT32)((INT32)v[k] * stream->vols[i]);
+ v[k] &= mask;
+ if (++i == channels) i = 0;
+ }
+ *q++ = v[0] >> 8 | v[1] << 16;
+ *q++ = v[1] >> 16 | v[2] << 8;
+ *q++ = v[2] >> 24 | v[3];
+ }
+ p = (BYTE*)q;
+ while (p != end)
+ {
+ UINT32 v = (INT32)((INT32)(p[0] << 8 | p[1] << 16 | p[2] << 24) * stream->vols[i]);
+ v &= mask;
+ *p++ = v >> 8 & 0xff;
+ *p++ = v >> 16 & 0xff;
+ *p++ = v >> 24;
+ if (++i == channels) i = 0;
+ }
+ break;
+ }
+#endif
+ case SND_PCM_FORMAT_U8:
+ {
+ UINT8 *p = (UINT8*)buf;
+ do
+ {
+ for (i = 0; i < channels; i++)
+ p[i] = (int)((p[i] - 128) * stream->vols[i]) + 128;
+ p += i;
+ } while ((BYTE*)p != end);
+ break;
+ }
+ default:
+ TRACE("Unhandled format %i, not adjusting volume.\n", stream->alsa_format);
+ break;
+ }
+}
+
+static snd_pcm_sframes_t alsa_write_best_effort(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
+{
+ snd_pcm_sframes_t written;
+
+ adjust_buffer_volume(stream, buf, frames);
+
+ /* Mark the frames we've already adjusted */
+ if (stream->vol_adjusted_frames < frames)
+ stream->vol_adjusted_frames = frames;
+
+ buf = remap_channels(stream, buf, frames);
+
+ written = snd_pcm_writei(stream->pcm_handle, buf, frames);
+ if(written < 0){
+ int ret;
+
+ if(written == -EAGAIN)
+ /* buffer full */
+ return 0;
+
+ WARN("writei failed, recovering: %ld (%s)\n", written,
+ snd_strerror(written));
+
+ ret = snd_pcm_recover(stream->pcm_handle, written, 0);
+ if(ret < 0){
+ WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
+ return ret;
+ }
+
+ written = snd_pcm_writei(stream->pcm_handle, buf, frames);
+ }
+
+ if (written > 0)
+ stream->vol_adjusted_frames -= written;
+ return written;
+}
+
+static NTSTATUS write_best_effort(void *args)
+{
+ struct write_best_effort_tmp_params *params = args;
+ *params->written = alsa_write_best_effort(params->stream, params->buf, params->frames);
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS is_format_supported(void *args)
{
struct is_format_supported_params *params = args;
@@ -1294,4 +1527,6 @@ unixlib_entry_t __wine_unix_call_funcs[] =
get_buffer_size,
get_latency,
get_current_padding,
+
+ write_best_effort /* temporary */
};
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index a4ab0e179d1..c06b08709f2 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -256,9 +256,6 @@ static HRESULT alsa_stream_release(struct alsa_stream *stream)
{
struct release_stream_params params;
- /* FIXME: to be moved with remap_channels() */
- HeapFree(GetProcessHeap(), 0, stream->remapping_buf);
-
params.stream = stream;
ALSA_CALL(release_stream, ¶ms);
@@ -969,233 +966,18 @@ static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
return S_OK;
}
-static BYTE *remap_channels(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
-{
- snd_pcm_uframes_t i;
- UINT c;
- UINT bytes_per_sample = stream->fmt->wBitsPerSample / 8;
-
- if(!stream->need_remapping)
- return buf;
-
- if(!stream->remapping_buf){
- stream->remapping_buf = HeapAlloc(GetProcessHeap(), 0,
- bytes_per_sample * stream->alsa_channels * frames);
- stream->remapping_buf_frames = frames;
- }else if(stream->remapping_buf_frames < frames){
- stream->remapping_buf = HeapReAlloc(GetProcessHeap(), 0, stream->remapping_buf,
- bytes_per_sample * stream->alsa_channels * frames);
- stream->remapping_buf_frames = frames;
- }
-
- snd_pcm_format_set_silence(stream->alsa_format, stream->remapping_buf,
- frames * stream->alsa_channels);
-
- switch(stream->fmt->wBitsPerSample){
- case 8: {
- UINT8 *tgt_buf, *src_buf;
- tgt_buf = stream->remapping_buf;
- src_buf = buf;
- for(i = 0; i < frames; ++i){
- for(c = 0; c < stream->fmt->nChannels; ++c)
- tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
- tgt_buf += stream->alsa_channels;
- src_buf += stream->fmt->nChannels;
- }
- break;
- }
- case 16: {
- UINT16 *tgt_buf, *src_buf;
- tgt_buf = (UINT16*)stream->remapping_buf;
- src_buf = (UINT16*)buf;
- for(i = 0; i < frames; ++i){
- for(c = 0; c < stream->fmt->nChannels; ++c)
- tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
- tgt_buf += stream->alsa_channels;
- src_buf += stream->fmt->nChannels;
- }
- }
- break;
- case 32: {
- UINT32 *tgt_buf, *src_buf;
- tgt_buf = (UINT32*)stream->remapping_buf;
- src_buf = (UINT32*)buf;
- for(i = 0; i < frames; ++i){
- for(c = 0; c < stream->fmt->nChannels; ++c)
- tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
- tgt_buf += stream->alsa_channels;
- src_buf += stream->fmt->nChannels;
- }
- }
- break;
- default: {
- BYTE *tgt_buf, *src_buf;
- tgt_buf = stream->remapping_buf;
- src_buf = buf;
- for(i = 0; i < frames; ++i){
- for(c = 0; c < stream->fmt->nChannels; ++c)
- memcpy(&tgt_buf[stream->alsa_channel_map[c] * bytes_per_sample],
- &src_buf[c * bytes_per_sample], bytes_per_sample);
- tgt_buf += stream->alsa_channels * bytes_per_sample;
- src_buf += stream->fmt->nChannels * bytes_per_sample;
- }
- }
- break;
- }
-
- return stream->remapping_buf;
-}
-
-static void adjust_buffer_volume(const struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
-{
- BOOL adjust = FALSE;
- UINT32 i, channels, mute = 0;
- BYTE *end;
-
- if (stream->vol_adjusted_frames >= frames)
- return;
- channels = stream->fmt->nChannels;
-
- /* Adjust the buffer based on the volume for each channel */
- for (i = 0; i < channels; i++)
- {
- adjust |= stream->vols[i] != 1.0f;
- if (stream->vols[i] == 0.0f)
- mute++;
- }
-
- if (mute == channels)
- {
- int err = snd_pcm_format_set_silence(stream->alsa_format, buf, frames * channels);
- if (err < 0)
- WARN("Setting buffer to silence failed: %d (%s)\n", err, snd_strerror(err));
- return;
- }
- if (!adjust) return;
-
- /* Skip the frames we've already adjusted before */
- end = buf + frames * stream->fmt->nBlockAlign;
- buf += stream->vol_adjusted_frames * stream->fmt->nBlockAlign;
-
- switch (stream->alsa_format)
- {
-#ifndef WORDS_BIGENDIAN
-#define PROCESS_BUFFER(type) do \
-{ \
- type *p = (type*)buf; \
- do \
- { \
- for (i = 0; i < channels; i++) \
- p[i] = p[i] * stream->vols[i]; \
- p += i; \
- } while ((BYTE*)p != end); \
-} while (0)
- case SND_PCM_FORMAT_S16_LE:
- PROCESS_BUFFER(INT16);
- break;
- case SND_PCM_FORMAT_S32_LE:
- PROCESS_BUFFER(INT32);
- break;
- case SND_PCM_FORMAT_FLOAT_LE:
- PROCESS_BUFFER(float);
- break;
- case SND_PCM_FORMAT_FLOAT64_LE:
- PROCESS_BUFFER(double);
- break;
-#undef PROCESS_BUFFER
- case SND_PCM_FORMAT_S20_3LE:
- case SND_PCM_FORMAT_S24_3LE:
- {
- /* Do it 12 bytes at a time until it is no longer possible */
- UINT32 *q = (UINT32*)buf, mask = ~0xff;
- BYTE *p;
-
- /* After we adjust the volume, we need to mask out low bits */
- if (stream->alsa_format == SND_PCM_FORMAT_S20_3LE)
- mask = ~0x0fff;
-
- i = 0;
- while (end - (BYTE*)q >= 12)
- {
- UINT32 v[4], k;
- v[0] = q[0] << 8;
- v[1] = q[1] << 16 | (q[0] >> 16 & ~0xff);
- v[2] = q[2] << 24 | (q[1] >> 8 & ~0xff);
- v[3] = q[2] & ~0xff;
- for (k = 0; k < 4; k++)
- {
- v[k] = (INT32)((INT32)v[k] * stream->vols[i]);
- v[k] &= mask;
- if (++i == channels) i = 0;
- }
- *q++ = v[0] >> 8 | v[1] << 16;
- *q++ = v[1] >> 16 | v[2] << 8;
- *q++ = v[2] >> 24 | v[3];
- }
- p = (BYTE*)q;
- while (p != end)
- {
- UINT32 v = (INT32)((INT32)(p[0] << 8 | p[1] << 16 | p[2] << 24) * stream->vols[i]);
- v &= mask;
- *p++ = v >> 8 & 0xff;
- *p++ = v >> 16 & 0xff;
- *p++ = v >> 24;
- if (++i == channels) i = 0;
- }
- break;
- }
-#endif
- case SND_PCM_FORMAT_U8:
- {
- UINT8 *p = (UINT8*)buf;
- do
- {
- for (i = 0; i < channels; i++)
- p[i] = (int)((p[i] - 128) * stream->vols[i]) + 128;
- p += i;
- } while ((BYTE*)p != end);
- break;
- }
- default:
- TRACE("Unhandled format %i, not adjusting volume.\n", stream->alsa_format);
- break;
- }
-}
-
static snd_pcm_sframes_t alsa_write_best_effort(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
{
+ struct write_best_effort_tmp_params params;
snd_pcm_sframes_t written;
- adjust_buffer_volume(stream, buf, frames);
-
- /* Mark the frames we've already adjusted */
- if (stream->vol_adjusted_frames < frames)
- stream->vol_adjusted_frames = frames;
-
- buf = remap_channels(stream, buf, frames);
-
- written = snd_pcm_writei(stream->pcm_handle, buf, frames);
- if(written < 0){
- int ret;
-
- if(written == -EAGAIN)
- /* buffer full */
- return 0;
-
- WARN("writei failed, recovering: %ld (%s)\n", written,
- snd_strerror(written));
-
- ret = snd_pcm_recover(stream->pcm_handle, written, 0);
- if(ret < 0){
- WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
- return ret;
- }
+ params.stream = stream;
+ params.buf = buf;
+ params.frames = frames;
+ params.written = &written;
- written = snd_pcm_writei(stream->pcm_handle, buf, frames);
- }
+ ALSA_CALL(write_best_effort_tmp, ¶ms);
- if (written > 0)
- stream->vol_adjusted_frames -= written;
return written;
}
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index 2484fca8c90..3fd6d2a73ee 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -129,6 +129,14 @@ struct get_current_padding_params
UINT32 *padding;
};
+struct write_best_effort_tmp_params
+{
+ struct alsa_stream *stream;
+ BYTE *buf;
+ snd_pcm_uframes_t frames;
+ snd_pcm_sframes_t *written;
+};
+
enum alsa_funcs
{
alsa_get_endpoint_ids,
@@ -139,6 +147,8 @@ enum alsa_funcs
alsa_get_buffer_size,
alsa_get_latency,
alsa_get_current_padding,
+
+ alsa_write_best_effort_tmp
};
extern unixlib_handle_t alsa_handle;
--
2.25.1
More information about the wine-devel
mailing list