[PATCH 3/8] winealsa: Introduce a stream structure.

Andrew Eikum aeikum at codeweavers.com
Thu Feb 17 09:25:24 CST 2022


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>

On Wed, Feb 16, 2022 at 09:34:49AM +0000, Huw Davies wrote:
> Signed-off-by: Huw Davies <huw at codeweavers.com>
> ---
>  dlls/winealsa.drv/mmdevdrv.c | 691 ++++++++++++++++++-----------------
>  dlls/winealsa.drv/unixlib.h  |  35 ++
>  2 files changed, 385 insertions(+), 341 deletions(-)
> 
> diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
> index 0549752dc3f..f1bc2fd0247 100644
> --- a/dlls/winealsa.drv/mmdevdrv.c
> +++ b/dlls/winealsa.drv/mmdevdrv.c
> @@ -101,42 +101,17 @@ struct ACImpl {
>  
>      LONG ref;
>  
> -    snd_pcm_t *pcm_handle;
> -    snd_pcm_uframes_t alsa_bufsize_frames, alsa_period_frames, safe_rewind_frames;
> -    snd_pcm_hw_params_t *hw_params; /* does not hold state between calls */
> -    snd_pcm_format_t alsa_format;
> -
> -    LARGE_INTEGER last_period_time;
> -
>      IMMDevice *parent;
>      IUnknown *pUnkFTMarshal;
>  
>      EDataFlow dataflow;
> -    WAVEFORMATEX *fmt;
> -    DWORD flags;
> -    AUDCLNT_SHAREMODE share;
> -    HANDLE event;
>      float *vols;
>      UINT32 channel_count;
> +    struct alsa_stream *stream;
>  
> -    BOOL need_remapping;
> -    int alsa_channels;
> -    int alsa_channel_map[32];
> -
> -    BOOL initted, started;
> -    REFERENCE_TIME mmdev_period_rt;
> -    UINT64 written_frames, last_pos_frames;
> -    UINT32 bufsize_frames, held_frames, tmp_buffer_frames, mmdev_period_frames;
> -    snd_pcm_uframes_t remapping_buf_frames;
> -    UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
> -    UINT32 wri_offs_frames; /* where to write fresh data in local_buffer */
> -    UINT32 hidden_frames;   /* ALSA reserve to ensure continuous rendering */
> -    UINT32 vol_adjusted_frames; /* Frames we've already adjusted the volume of but didn't write yet */
> -    UINT32 data_in_alsa_frames;
> +    BOOL initted;
>  
>      HANDLE timer;
> -    BYTE *local_buffer, *tmp_buffer, *remapping_buf, *silence_buf;
> -    LONG32 getbuf_last; /* <0 when using tmp_buffer */
>  
>      CRITICAL_SECTION lock;
>  
> @@ -505,8 +480,15 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
>      This->dataflow = dataflow;
>      memcpy(This->alsa_name, alsa_name, len + 1);
>  
> -    err = snd_pcm_open(&This->pcm_handle, alsa_name, alsa_get_direction(dataflow), SND_PCM_NONBLOCK);
> +    This->stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
> +    if(!This->stream){
> +        HeapFree(GetProcessHeap(), 0, This);
> +        return E_OUTOFMEMORY;
> +    }
> +
> +    err = snd_pcm_open(&This->stream->pcm_handle, alsa_name, alsa_get_direction(dataflow), SND_PCM_NONBLOCK);
>      if(err < 0){
> +        HeapFree(GetProcessHeap(), 0, This->stream);
>          HeapFree(GetProcessHeap(), 0, This);
>          WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
>          switch(err){
> @@ -517,10 +499,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
>          }
>      }
>  
> -    This->hw_params = HeapAlloc(GetProcessHeap(), 0,
> +    This->stream->hw_params = HeapAlloc(GetProcessHeap(), 0,
>              snd_pcm_hw_params_sizeof());
> -    if(!This->hw_params){
> -        snd_pcm_close(This->pcm_handle);
> +    if(!This->stream->hw_params){
> +        snd_pcm_close(This->stream->pcm_handle);
> +        HeapFree(GetProcessHeap(), 0, This->stream);
>          HeapFree(GetProcessHeap(), 0, This);
>          return E_OUTOFMEMORY;
>      }
> @@ -574,6 +557,7 @@ static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
>  static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>      ULONG ref;
>  
>      ref = InterlockedDecrement(&This->ref);
> @@ -595,20 +579,21 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
>          IUnknown_Release(This->pUnkFTMarshal);
>          This->lock.DebugInfo->Spare[0] = 0;
>          DeleteCriticalSection(&This->lock);
> -        snd_pcm_drop(This->pcm_handle);
> -        snd_pcm_close(This->pcm_handle);
> +        snd_pcm_drop(stream->pcm_handle);
> +        snd_pcm_close(stream->pcm_handle);
>          if(This->initted){
>              EnterCriticalSection(&g_sessions_lock);
>              list_remove(&This->entry);
>              LeaveCriticalSection(&g_sessions_lock);
>          }
>          HeapFree(GetProcessHeap(), 0, This->vols);
> -        HeapFree(GetProcessHeap(), 0, This->local_buffer);
> -        HeapFree(GetProcessHeap(), 0, This->remapping_buf);
> -        HeapFree(GetProcessHeap(), 0, This->silence_buf);
> -        HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
> -        HeapFree(GetProcessHeap(), 0, This->hw_params);
> -        CoTaskMemFree(This->fmt);
> +        HeapFree(GetProcessHeap(), 0, stream->local_buffer);
> +        HeapFree(GetProcessHeap(), 0, stream->remapping_buf);
> +        HeapFree(GetProcessHeap(), 0, stream->silence_buf);
> +        HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
> +        HeapFree(GetProcessHeap(), 0, stream->hw_params);
> +        CoTaskMemFree(stream->fmt);
> +        HeapFree(GetProcessHeap(), 0, stream);
>          HeapFree(GetProcessHeap(), 0, This);
>      }
>      return ref;
> @@ -904,16 +889,16 @@ static HRESULT map_channels(ACImpl *This, const WAVEFORMATEX *fmt, int *alsa_cha
>      return need_remap ? S_OK : S_FALSE;
>  }
>  
> -static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
> +static void silence_buffer(struct alsa_stream *stream, BYTE *buffer, UINT32 frames)
>  {
> -    WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
> -    if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
> -            (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
> +    WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
> +    if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
> +            (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
>               IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
> -            This->fmt->wBitsPerSample == 8)
> -        memset(buffer, 128, frames * This->fmt->nBlockAlign);
> +            stream->fmt->wBitsPerSample == 8)
> +        memset(buffer, 128, frames * stream->fmt->nBlockAlign);
>      else
> -        memset(buffer, 0, frames * This->fmt->nBlockAlign);
> +        memset(buffer, 0, frames * stream->fmt->nBlockAlign);
>  }
>  
>  static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
> @@ -922,6 +907,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>          const GUID *sessionguid)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>      snd_pcm_sw_params_t *sw_params = NULL;
>      snd_pcm_format_t format;
>      unsigned int rate, alsa_period_us;
> @@ -990,15 +976,15 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>  
>      dump_fmt(fmt);
>  
> -    This->need_remapping = map_channels(This, fmt, &This->alsa_channels, This->alsa_channel_map) == S_OK;
> +    stream->need_remapping = map_channels(This, fmt, &stream->alsa_channels, stream->alsa_channel_map) == S_OK;
>  
> -    if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
> +    if((err = snd_pcm_hw_params_any(stream->pcm_handle, stream->hw_params)) < 0){
>          WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_set_access(This->pcm_handle, This->hw_params,
> +    if((err = snd_pcm_hw_params_set_access(stream->pcm_handle, stream->hw_params,
>                  SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
>          WARN("Unable to set access: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
> @@ -1011,7 +997,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_set_format(This->pcm_handle, This->hw_params,
> +    if((err = snd_pcm_hw_params_set_format(stream->pcm_handle, stream->hw_params,
>                  format)) < 0){
>          WARN("Unable to set ALSA format to %u: %d (%s)\n", format, err,
>                  snd_strerror(err));
> @@ -1019,10 +1005,10 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    This->alsa_format = format;
> +    stream->alsa_format = format;
>  
>      rate = fmt->nSamplesPerSec;
> -    if((err = snd_pcm_hw_params_set_rate_near(This->pcm_handle, This->hw_params,
> +    if((err = snd_pcm_hw_params_set_rate_near(stream->pcm_handle, stream->hw_params,
>                  &rate, NULL)) < 0){
>          WARN("Unable to set rate to %u: %d (%s)\n", rate, err,
>                  snd_strerror(err));
> @@ -1030,52 +1016,52 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_set_channels(This->pcm_handle, This->hw_params,
> -                This->alsa_channels)) < 0){
> +    if((err = snd_pcm_hw_params_set_channels(stream->pcm_handle, stream->hw_params,
> +               stream->alsa_channels)) < 0){
>          WARN("Unable to set channels to %u: %d (%s)\n", fmt->nChannels, err,
>                  snd_strerror(err));
>          hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
>          goto exit;
>      }
>  
> -    This->mmdev_period_rt = period;
> -    alsa_period_us = This->mmdev_period_rt / 10;
> -    if((err = snd_pcm_hw_params_set_period_time_near(This->pcm_handle,
> -                This->hw_params, &alsa_period_us, NULL)) < 0)
> +    stream->mmdev_period_rt = period;
> +    alsa_period_us = stream->mmdev_period_rt / 10;
> +    if((err = snd_pcm_hw_params_set_period_time_near(stream->pcm_handle,
> +                stream->hw_params, &alsa_period_us, NULL)) < 0)
>          WARN("Unable to set period time near %u: %d (%s)\n", alsa_period_us,
>                  err, snd_strerror(err));
>      /* ALSA updates the output variable alsa_period_us */
>  
> -    This->mmdev_period_frames = MulDiv(fmt->nSamplesPerSec,
> -            This->mmdev_period_rt, 10000000);
> +    stream->mmdev_period_frames = MulDiv(fmt->nSamplesPerSec,
> +            stream->mmdev_period_rt, 10000000);
>  
>      /* Buffer 4 ALSA periods if large enough, else 4 mmdevapi periods */
> -    This->alsa_bufsize_frames = This->mmdev_period_frames * 4;
> +    stream->alsa_bufsize_frames = stream->mmdev_period_frames * 4;
>      if(err < 0 || alsa_period_us < period / 10)
> -        err = snd_pcm_hw_params_set_buffer_size_near(This->pcm_handle,
> -                This->hw_params, &This->alsa_bufsize_frames);
> +        err = snd_pcm_hw_params_set_buffer_size_near(stream->pcm_handle,
> +                stream->hw_params, &stream->alsa_bufsize_frames);
>      else{
>          unsigned int periods = 4;
> -        err = snd_pcm_hw_params_set_periods_near(This->pcm_handle, This->hw_params, &periods, NULL);
> +        err = snd_pcm_hw_params_set_periods_near(stream->pcm_handle, stream->hw_params, &periods, NULL);
>      }
>      if(err < 0)
>          WARN("Unable to set buffer size: %d (%s)\n", err, snd_strerror(err));
>  
> -    if((err = snd_pcm_hw_params(This->pcm_handle, This->hw_params)) < 0){
> +    if((err = snd_pcm_hw_params(stream->pcm_handle, stream->hw_params)) < 0){
>          WARN("Unable to set hw params: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_get_period_size(This->hw_params,
> -                    &This->alsa_period_frames, NULL)) < 0){
> +    if((err = snd_pcm_hw_params_get_period_size(stream->hw_params,
> +                    &stream->alsa_period_frames, NULL)) < 0){
>          WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_get_buffer_size(This->hw_params,
> -                    &This->alsa_bufsize_frames)) < 0){
> +    if((err = snd_pcm_hw_params_get_buffer_size(stream->hw_params,
> +                    &stream->alsa_bufsize_frames)) < 0){
>          WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
> @@ -1087,34 +1073,34 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_sw_params_current(This->pcm_handle, sw_params)) < 0){
> +    if((err = snd_pcm_sw_params_current(stream->pcm_handle, sw_params)) < 0){
>          WARN("Unable to get sw_params: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_sw_params_set_start_threshold(This->pcm_handle,
> +    if((err = snd_pcm_sw_params_set_start_threshold(stream->pcm_handle,
>                      sw_params, 1)) < 0){
>          WARN("Unable set start threshold to 1: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_sw_params_set_stop_threshold(This->pcm_handle,
> -                    sw_params, This->alsa_bufsize_frames)) < 0){
> +    if((err = snd_pcm_sw_params_set_stop_threshold(stream->pcm_handle,
> +                    sw_params, stream->alsa_bufsize_frames)) < 0){
>          WARN("Unable set stop threshold to %lu: %d (%s)\n",
> -                This->alsa_bufsize_frames, err, snd_strerror(err));
> +                stream->alsa_bufsize_frames, err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_sw_params(This->pcm_handle, sw_params)) < 0){
> +    if((err = snd_pcm_sw_params(stream->pcm_handle, sw_params)) < 0){
>          WARN("Unable to set sw params: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
> +    if((err = snd_pcm_prepare(stream->pcm_handle)) < 0){
>          WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>          goto exit;
> @@ -1125,42 +1111,42 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>       * or surprising rounding as seen with 22050x8x1 with Pulse:
>       * ALSA period 220 vs.  221 frames in mmdevapi and
>       *      buffer 883 vs. 2205 frames in mmdevapi! */
> -    This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
> +    stream->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
>      if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
> -        This->bufsize_frames -= This->bufsize_frames % This->mmdev_period_frames;
> -    This->hidden_frames = This->alsa_period_frames + This->mmdev_period_frames +
> +        stream->bufsize_frames -= stream->bufsize_frames % stream->mmdev_period_frames;
> +    stream->hidden_frames = stream->alsa_period_frames + stream->mmdev_period_frames +
>          MulDiv(fmt->nSamplesPerSec, EXTRA_SAFE_RT, 10000000);
>      /* leave no less than about 1.33ms or 256 bytes of data after a rewind */
> -    This->safe_rewind_frames = max(256 / fmt->nBlockAlign, MulDiv(133, fmt->nSamplesPerSec, 100000));
> +    stream->safe_rewind_frames = max(256 / fmt->nBlockAlign, MulDiv(133, fmt->nSamplesPerSec, 100000));
>  
>      /* Check if the ALSA buffer is so small that it will run out before
>       * the next MMDevAPI period tick occurs. Allow a little wiggle room
>       * with 120% of the period time. */
> -    if(This->alsa_bufsize_frames < 1.2 * This->mmdev_period_frames)
> +    if(stream->alsa_bufsize_frames < 1.2 * stream->mmdev_period_frames)
>          FIXME("ALSA buffer time is too small. Expect underruns. (%lu < %u * 1.2)\n",
> -                This->alsa_bufsize_frames, This->mmdev_period_frames);
> +                stream->alsa_bufsize_frames, stream->mmdev_period_frames);
>  
> -    This->fmt = clone_format(fmt);
> -    if(!This->fmt){
> +    stream->fmt = clone_format(fmt);
> +    if(!stream->fmt){
>          hr = E_OUTOFMEMORY;
>          goto exit;
>      }
>  
> -    This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
> -            This->bufsize_frames * fmt->nBlockAlign);
> -    if(!This->local_buffer){
> +    stream->local_buffer = HeapAlloc(GetProcessHeap(), 0,
> +            stream->bufsize_frames * fmt->nBlockAlign);
> +    if(!stream->local_buffer){
>          hr = E_OUTOFMEMORY;
>          goto exit;
>      }
> -    silence_buffer(This, This->local_buffer, This->bufsize_frames);
> +    silence_buffer(stream, stream->local_buffer, stream->bufsize_frames);
>  
> -    This->silence_buf = HeapAlloc(GetProcessHeap(), 0,
> -            This->alsa_period_frames * This->fmt->nBlockAlign);
> -    if(!This->silence_buf){
> +    stream->silence_buf = HeapAlloc(GetProcessHeap(), 0,
> +            stream->alsa_period_frames * stream->fmt->nBlockAlign);
> +    if(!stream->silence_buf){
>          hr = E_OUTOFMEMORY;
>          goto exit;
>      }
> -    silence_buffer(This, This->silence_buf, This->alsa_period_frames);
> +    silence_buffer(stream, stream->silence_buf, stream->alsa_period_frames);
>  
>      This->channel_count = fmt->nChannels;
>      This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
> @@ -1172,8 +1158,8 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>      for(i = 0; i < This->channel_count; ++i)
>          This->vols[i] = 1.f;
>  
> -    This->share = mode;
> -    This->flags = flags;
> +    stream->share = mode;
> +    stream->flags = flags;
>  
>      hr = get_audio_session(sessionguid, This->parent, This->channel_count,
>              &This->session);
> @@ -1184,18 +1170,18 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>  
>      This->initted = TRUE;
>  
> -    TRACE("ALSA period: %lu frames\n", This->alsa_period_frames);
> -    TRACE("ALSA buffer: %lu frames\n", This->alsa_bufsize_frames);
> -    TRACE("MMDevice period: %u frames\n", This->mmdev_period_frames);
> -    TRACE("MMDevice buffer: %u frames\n", This->bufsize_frames);
> +    TRACE("ALSA period: %lu frames\n", stream->alsa_period_frames);
> +    TRACE("ALSA buffer: %lu frames\n", stream->alsa_bufsize_frames);
> +    TRACE("MMDevice period: %u frames\n", stream->mmdev_period_frames);
> +    TRACE("MMDevice buffer: %u frames\n", stream->bufsize_frames);
>  
>  exit:
>      HeapFree(GetProcessHeap(), 0, sw_params);
>      if(FAILED(hr)){
> -        HeapFree(GetProcessHeap(), 0, This->local_buffer);
> -        This->local_buffer = NULL;
> -        CoTaskMemFree(This->fmt);
> -        This->fmt = NULL;
> +        HeapFree(GetProcessHeap(), 0, stream->local_buffer);
> +        stream->local_buffer = NULL;
> +        CoTaskMemFree(stream->fmt);
> +        stream->fmt = NULL;
>          HeapFree(GetProcessHeap(), 0, This->vols);
>          This->vols = NULL;
>      }
> @@ -1210,6 +1196,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
>          UINT32 *out)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p)\n", This, out);
>  
> @@ -1223,7 +1210,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
>          return AUDCLNT_E_NOT_INITIALIZED;
>      }
>  
> -    *out = This->bufsize_frames;
> +    *out = stream->bufsize_frames;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -1234,6 +1221,7 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
>          REFERENCE_TIME *latency)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p)\n", This, latency);
>  
> @@ -1253,10 +1241,10 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
>       * + EXTRA_SAFE (~4ms) to allow for late callback invocation / fluctuation;
>       * + alsa_period such that ALSA always has at least one period to play. */
>      if(This->dataflow == eRender)
> -        *latency = MulDiv(This->hidden_frames, 10000000, This->fmt->nSamplesPerSec);
> +        *latency = MulDiv(stream->hidden_frames, 10000000, stream->fmt->nSamplesPerSec);
>      else
> -        *latency = MulDiv(This->alsa_period_frames, 10000000, This->fmt->nSamplesPerSec)
> -                 + This->mmdev_period_rt;
> +        *latency = MulDiv(stream->alsa_period_frames, 10000000, stream->fmt->nSamplesPerSec)
> +                 + stream->mmdev_period_rt;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -1267,6 +1255,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
>          UINT32 *out)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p)\n", This, out);
>  
> @@ -1281,7 +1270,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
>      }
>  
>      /* padding is solely updated at callback time in shared mode */
> -    *out = This->held_frames;
> +    *out = stream->held_frames;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -1334,7 +1323,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
>  
>      EnterCriticalSection(&This->lock);
>  
> -    if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
> +    if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
>          hr = AUDCLNT_E_DEVICE_INVALIDATED;
>          goto exit;
>      }
> @@ -1346,7 +1335,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
> +    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)){
> @@ -1360,13 +1349,13 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_get_rate_min(This->hw_params, &min, NULL)) < 0){
> +    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->hw_params, &max, NULL)) < 0){
> +    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;
> @@ -1377,13 +1366,13 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_get_channels_min(This->hw_params, &min)) < 0){
> +    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->hw_params, &max)) < 0){
> +    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;
> @@ -1469,13 +1458,13 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
>  
>      EnterCriticalSection(&This->lock);
>  
> -    if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
> +    if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
>          WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_DEVICE_INVALIDATED;
>          goto exit;
>      }
>  
> -    snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
> +    snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
>  
>      fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
>      if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
> @@ -1499,7 +1488,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
>          goto exit;
>      }
>  
> -    if((err = snd_pcm_hw_params_get_channels_max(This->hw_params,
> +    if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params,
>                      &max_channels)) < 0){
>          WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_DEVICE_INVALIDATED;
> @@ -1529,7 +1518,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
>  
>      fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
>  
> -    if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max_rate,
> +    if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max_rate,
>                      NULL)) < 0){
>          WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
>          hr = AUDCLNT_E_DEVICE_INVALIDATED;
> @@ -1590,97 +1579,98 @@ static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
>      return S_OK;
>  }
>  
> -static BYTE *remap_channels(ACImpl *This, BYTE *buf, snd_pcm_uframes_t frames)
> +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 = This->fmt->wBitsPerSample / 8;
> +    UINT bytes_per_sample = stream->fmt->wBitsPerSample / 8;
>  
> -    if(!This->need_remapping)
> +    if(!stream->need_remapping)
>          return buf;
>  
> -    if(!This->remapping_buf){
> -        This->remapping_buf = HeapAlloc(GetProcessHeap(), 0,
> -                bytes_per_sample * This->alsa_channels * frames);
> -        This->remapping_buf_frames = frames;
> -    }else if(This->remapping_buf_frames < frames){
> -        This->remapping_buf = HeapReAlloc(GetProcessHeap(), 0, This->remapping_buf,
> -                bytes_per_sample * This->alsa_channels * frames);
> -        This->remapping_buf_frames = frames;
> +    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(This->alsa_format, This->remapping_buf,
> -            frames * This->alsa_channels);
> +    snd_pcm_format_set_silence(stream->alsa_format, stream->remapping_buf,
> +            frames * stream->alsa_channels);
>  
> -    switch(This->fmt->wBitsPerSample){
> +    switch(stream->fmt->wBitsPerSample){
>      case 8: {
>              UINT8 *tgt_buf, *src_buf;
> -            tgt_buf = This->remapping_buf;
> +            tgt_buf = stream->remapping_buf;
>              src_buf = buf;
>              for(i = 0; i < frames; ++i){
> -                for(c = 0; c < This->fmt->nChannels; ++c)
> -                    tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
> -                tgt_buf += This->alsa_channels;
> -                src_buf += This->fmt->nChannels;
> +                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*)This->remapping_buf;
> +            tgt_buf = (UINT16*)stream->remapping_buf;
>              src_buf = (UINT16*)buf;
>              for(i = 0; i < frames; ++i){
> -                for(c = 0; c < This->fmt->nChannels; ++c)
> -                    tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
> -                tgt_buf += This->alsa_channels;
> -                src_buf += This->fmt->nChannels;
> +                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*)This->remapping_buf;
> +            tgt_buf = (UINT32*)stream->remapping_buf;
>              src_buf = (UINT32*)buf;
>              for(i = 0; i < frames; ++i){
> -                for(c = 0; c < This->fmt->nChannels; ++c)
> -                    tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
> -                tgt_buf += This->alsa_channels;
> -                src_buf += This->fmt->nChannels;
> +                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 = This->remapping_buf;
> +            tgt_buf = stream->remapping_buf;
>              src_buf = buf;
>              for(i = 0; i < frames; ++i){
> -                for(c = 0; c < This->fmt->nChannels; ++c)
> -                    memcpy(&tgt_buf[This->alsa_channel_map[c] * bytes_per_sample],
> +                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 += This->alsa_channels * bytes_per_sample;
> -                src_buf += This->fmt->nChannels * bytes_per_sample;
> +                tgt_buf += stream->alsa_channels * bytes_per_sample;
> +                src_buf += stream->fmt->nChannels * bytes_per_sample;
>              }
>          }
>          break;
>      }
>  
> -    return This->remapping_buf;
> +    return stream->remapping_buf;
>  }
>  
>  static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_t frames, BOOL mute)
>  {
> -    float vol[ARRAY_SIZE(This->alsa_channel_map)];
> +    struct alsa_stream *stream = This->stream;
> +    float vol[ARRAY_SIZE(stream->alsa_channel_map)];
>      BOOL adjust = FALSE;
>      UINT32 i, channels;
>      BYTE *end;
>  
> -    if (This->vol_adjusted_frames >= frames)
> +    if (stream->vol_adjusted_frames >= frames)
>          return;
> -    channels = This->fmt->nChannels;
> +    channels = stream->fmt->nChannels;
>  
>      if (mute)
>      {
> -        int err = snd_pcm_format_set_silence(This->alsa_format, buf, frames * 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;
> @@ -1698,10 +1688,10 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
>      if (!adjust) return;
>  
>      /* Skip the frames we've already adjusted before */
> -    end = buf + frames * This->fmt->nBlockAlign;
> -    buf += This->vol_adjusted_frames * This->fmt->nBlockAlign;
> +    end = buf + frames * stream->fmt->nBlockAlign;
> +    buf += stream->vol_adjusted_frames * stream->fmt->nBlockAlign;
>  
> -    switch (This->alsa_format)
> +    switch (stream->alsa_format)
>      {
>  #ifndef WORDS_BIGENDIAN
>  #define PROCESS_BUFFER(type) do         \
> @@ -1735,7 +1725,7 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
>          BYTE *p;
>  
>          /* After we adjust the volume, we need to mask out low bits */
> -        if (This->alsa_format == SND_PCM_FORMAT_S20_3LE)
> +        if (stream->alsa_format == SND_PCM_FORMAT_S20_3LE)
>              mask = ~0x0fff;
>  
>          i = 0;
> @@ -1781,7 +1771,7 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
>          break;
>      }
>      default:
> -        TRACE("Unhandled format %i, not adjusting volume.\n", This->alsa_format);
> +        TRACE("Unhandled format %i, not adjusting volume.\n", stream->alsa_format);
>          break;
>      }
>  }
> @@ -1789,17 +1779,18 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
>  static snd_pcm_sframes_t alsa_write_best_effort(ACImpl *This, BYTE *buf,
>          snd_pcm_uframes_t frames, BOOL mute)
>  {
> +    struct alsa_stream *stream = This->stream;
>      snd_pcm_sframes_t written;
>  
>      adjust_buffer_volume(This, buf, frames, mute);
>  
>      /* Mark the frames we've already adjusted */
> -    if (This->vol_adjusted_frames < frames)
> -        This->vol_adjusted_frames = frames;
> +    if (stream->vol_adjusted_frames < frames)
> +        stream->vol_adjusted_frames = frames;
>  
> -    buf = remap_channels(This, buf, frames);
> +    buf = remap_channels(stream, buf, frames);
>  
> -    written = snd_pcm_writei(This->pcm_handle, buf, frames);
> +    written = snd_pcm_writei(stream->pcm_handle, buf, frames);
>      if(written < 0){
>          int ret;
>  
> @@ -1810,17 +1801,17 @@ static snd_pcm_sframes_t alsa_write_best_effort(ACImpl *This, BYTE *buf,
>          WARN("writei failed, recovering: %ld (%s)\n", written,
>                  snd_strerror(written));
>  
> -        ret = snd_pcm_recover(This->pcm_handle, written, 0);
> +        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(This->pcm_handle, buf, frames);
> +        written = snd_pcm_writei(stream->pcm_handle, buf, frames);
>      }
>  
>      if (written > 0)
> -        This->vol_adjusted_frames -= written;
> +        stream->vol_adjusted_frames -= written;
>      return written;
>  }
>  
> @@ -1828,6 +1819,7 @@ static snd_pcm_sframes_t alsa_write_buffer_wrap(ACImpl *This, BYTE *buf,
>          snd_pcm_uframes_t buflen, snd_pcm_uframes_t offs,
>          snd_pcm_uframes_t to_write)
>  {
> +    struct alsa_stream *stream = This->stream;
>      snd_pcm_sframes_t ret = 0;
>  
>      while(to_write){
> @@ -1839,7 +1831,7 @@ static snd_pcm_sframes_t alsa_write_buffer_wrap(ACImpl *This, BYTE *buf,
>          else
>              chunk = to_write;
>  
> -        tmp = alsa_write_best_effort(This, buf + offs * This->fmt->nBlockAlign, chunk, This->session->mute);
> +        tmp = alsa_write_best_effort(This, buf + offs * stream->fmt->nBlockAlign, chunk, This->session->mute);
>          if(tmp < 0)
>              return ret;
>          if(!tmp)
> @@ -1863,13 +1855,14 @@ static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
>  
>  static UINT data_not_in_alsa(ACImpl *This)
>  {
> +    struct alsa_stream *stream = This->stream;
>      UINT32 diff;
>  
> -    diff = buf_ptr_diff(This->lcl_offs_frames, This->wri_offs_frames, This->bufsize_frames);
> +    diff = buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames, stream->bufsize_frames);
>      if(diff)
>          return diff;
>  
> -    return This->held_frames - This->data_in_alsa_frames;
> +    return stream->held_frames - stream->data_in_alsa_frames;
>  }
>  /* Here's the buffer setup:
>   *
> @@ -1891,25 +1884,26 @@ static UINT data_not_in_alsa(ACImpl *This)
>   */
>  static void alsa_write_data(ACImpl *This)
>  {
> +    struct alsa_stream *stream = This->stream;
>      snd_pcm_sframes_t written;
>      snd_pcm_uframes_t avail, max_copy_frames, data_frames_played;
>      int err;
>  
>      /* this call seems to be required to get an accurate snd_pcm_state() */
> -    avail = snd_pcm_avail_update(This->pcm_handle);
> +    avail = snd_pcm_avail_update(stream->pcm_handle);
>  
> -    if(snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_XRUN){
> +    if(snd_pcm_state(stream->pcm_handle) == SND_PCM_STATE_XRUN){
>          TRACE("XRun state, recovering\n");
>  
> -        avail = This->alsa_bufsize_frames;
> +        avail = stream->alsa_bufsize_frames;
>  
> -        if((err = snd_pcm_recover(This->pcm_handle, -EPIPE, 1)) < 0)
> +        if((err = snd_pcm_recover(stream->pcm_handle, -EPIPE, 1)) < 0)
>              WARN("snd_pcm_recover failed: %d (%s)\n", err, snd_strerror(err));
>  
> -        if((err = snd_pcm_reset(This->pcm_handle)) < 0)
> +        if((err = snd_pcm_reset(stream->pcm_handle)) < 0)
>              WARN("snd_pcm_reset failed: %d (%s)\n", err, snd_strerror(err));
>  
> -        if((err = snd_pcm_prepare(This->pcm_handle)) < 0)
> +        if((err = snd_pcm_prepare(stream->pcm_handle)) < 0)
>              WARN("snd_pcm_prepare failed: %d (%s)\n", err, snd_strerror(err));
>      }
>  
> @@ -1917,61 +1911,63 @@ static void alsa_write_data(ACImpl *This)
>  
>      /* Add a lead-in when starting with too few frames to ensure
>       * continuous rendering.  Additional benefit: Force ALSA to start. */
> -    if(This->data_in_alsa_frames == 0 && This->held_frames < This->alsa_period_frames)
> +    if(stream->data_in_alsa_frames == 0 && stream->held_frames < stream->alsa_period_frames)
>      {
> -        alsa_write_best_effort(This, This->silence_buf, This->alsa_period_frames - This->held_frames, FALSE);
> -        This->vol_adjusted_frames = 0;
> +        alsa_write_best_effort(This, stream->silence_buf,
> +                               stream->alsa_period_frames - stream->held_frames, FALSE);
> +        stream->vol_adjusted_frames = 0;
>      }
>  
> -    if(This->started)
> +    if(stream->started)
>          max_copy_frames = data_not_in_alsa(This);
>      else
>          max_copy_frames = 0;
>  
> -    data_frames_played = min(This->data_in_alsa_frames, avail);
> -    This->data_in_alsa_frames -= data_frames_played;
> +    data_frames_played = min(stream->data_in_alsa_frames, avail);
> +    stream->data_in_alsa_frames -= data_frames_played;
>  
> -    if(This->held_frames > data_frames_played){
> -        if(This->started)
> -            This->held_frames -= data_frames_played;
> +    if(stream->held_frames > data_frames_played){
> +        if(stream->started)
> +            stream->held_frames -= data_frames_played;
>      }else
> -        This->held_frames = 0;
> +        stream->held_frames = 0;
>  
>      while(avail && max_copy_frames){
>          snd_pcm_uframes_t to_write;
>  
>          to_write = min(avail, max_copy_frames);
>  
> -        written = alsa_write_buffer_wrap(This, This->local_buffer,
> -                This->bufsize_frames, This->lcl_offs_frames, to_write);
> +        written = alsa_write_buffer_wrap(This, stream->local_buffer,
> +                stream->bufsize_frames, stream->lcl_offs_frames, to_write);
>          if(written <= 0)
>              break;
>  
>          avail -= written;
> -        This->lcl_offs_frames += written;
> -        This->lcl_offs_frames %= This->bufsize_frames;
> -        This->data_in_alsa_frames += written;
> +        stream->lcl_offs_frames += written;
> +        stream->lcl_offs_frames %= stream->bufsize_frames;
> +        stream->data_in_alsa_frames += written;
>          max_copy_frames -= written;
>      }
>  
> -    if(This->event)
> -        SetEvent(This->event);
> +    if(stream->event)
> +        SetEvent(stream->event);
>  }
>  
>  static void alsa_read_data(ACImpl *This)
>  {
> +    struct alsa_stream *stream = This->stream;
>      snd_pcm_sframes_t nread;
> -    UINT32 pos = This->wri_offs_frames, limit = This->held_frames;
> +    UINT32 pos = stream->wri_offs_frames, limit = stream->held_frames;
>  
> -    if(!This->started)
> +    if(!stream->started)
>          goto exit;
>  
>      /* FIXME: Detect overrun and signal DATA_DISCONTINUITY
>       * How to count overrun frames and report them as position increase? */
> -    limit = This->bufsize_frames - max(limit, pos);
> +    limit = stream->bufsize_frames - max(limit, pos);
>  
> -    nread = snd_pcm_readi(This->pcm_handle,
> -            This->local_buffer + pos * This->fmt->nBlockAlign, limit);
> +    nread = snd_pcm_readi(stream->pcm_handle,
> +            stream->local_buffer + pos * stream->fmt->nBlockAlign, limit);
>      TRACE("read %ld from %u limit %u\n", nread, pos, limit);
>      if(nread < 0){
>          int ret;
> @@ -1981,14 +1977,14 @@ static void alsa_read_data(ACImpl *This)
>  
>          WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
>  
> -        ret = snd_pcm_recover(This->pcm_handle, nread, 0);
> +        ret = snd_pcm_recover(stream->pcm_handle, nread, 0);
>          if(ret < 0){
>              WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
>              return;
>          }
>  
> -        nread = snd_pcm_readi(This->pcm_handle,
> -                This->local_buffer + pos * This->fmt->nBlockAlign, limit);
> +        nread = snd_pcm_readi(stream->pcm_handle,
> +                stream->local_buffer + pos * stream->fmt->nBlockAlign, limit);
>          if(nread < 0){
>              WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
>              return;
> @@ -1997,29 +1993,30 @@ static void alsa_read_data(ACImpl *This)
>  
>      if(This->session->mute){
>          int err;
> -        if((err = snd_pcm_format_set_silence(This->alsa_format,
> -                        This->local_buffer + pos * This->fmt->nBlockAlign,
> +        if((err = snd_pcm_format_set_silence(stream->alsa_format,
> +                        stream->local_buffer + pos * stream->fmt->nBlockAlign,
>                          nread)) < 0)
>              WARN("Setting buffer to silence failed: %d (%s)\n", err,
>                      snd_strerror(err));
>      }
>  
> -    This->wri_offs_frames += nread;
> -    This->wri_offs_frames %= This->bufsize_frames;
> -    This->held_frames += nread;
> +    stream->wri_offs_frames += nread;
> +    stream->wri_offs_frames %= stream->bufsize_frames;
> +    stream->held_frames += nread;
>  
>  exit:
> -    if(This->event)
> -        SetEvent(This->event);
> +    if(stream->event)
> +        SetEvent(stream->event);
>  }
>  
>  static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
>  {
>      ACImpl *This = user;
> +    struct alsa_stream *stream = This->stream;
>  
>      EnterCriticalSection(&This->lock);
>  
> -    QueryPerformanceCounter(&This->last_period_time);
> +    QueryPerformanceCounter(&stream->last_period_time);
>  
>      if(This->dataflow == eRender)
>          alsa_write_data(This);
> @@ -2029,17 +2026,18 @@ static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
>      LeaveCriticalSection(&This->lock);
>  }
>  
> -static snd_pcm_uframes_t interp_elapsed_frames(ACImpl *This)
> +static snd_pcm_uframes_t interp_elapsed_frames(struct alsa_stream *stream)
>  {
>      LARGE_INTEGER time_freq, current_time, time_diff;
>      QueryPerformanceFrequency(&time_freq);
>      QueryPerformanceCounter(&current_time);
> -    time_diff.QuadPart = current_time.QuadPart - This->last_period_time.QuadPart;
> -    return MulDiv(time_diff.QuadPart, This->fmt->nSamplesPerSec, time_freq.QuadPart);
> +    time_diff.QuadPart = current_time.QuadPart - stream->last_period_time.QuadPart;
> +    return MulDiv(time_diff.QuadPart, stream->fmt->nSamplesPerSec, time_freq.QuadPart);
>  }
>  
>  static int alsa_rewind_best_effort(ACImpl *This)
>  {
> +    struct alsa_stream *stream = This->stream;
>      snd_pcm_uframes_t len, leave;
>  
>      /* we can't use snd_pcm_rewindable, some PCM devices crash. so follow
> @@ -2047,25 +2045,25 @@ static int alsa_rewind_best_effort(ACImpl *This)
>       * buffer, minus 1.33ms for safety. */
>  
>      /* amount of data to leave in ALSA buffer */
> -    leave = interp_elapsed_frames(This) + This->safe_rewind_frames;
> +    leave = interp_elapsed_frames(stream) + stream->safe_rewind_frames;
>  
> -    if(This->held_frames < leave)
> -        This->held_frames = 0;
> +    if(stream->held_frames < leave)
> +        stream->held_frames = 0;
>      else
> -        This->held_frames -= leave;
> +        stream->held_frames -= leave;
>  
> -    if(This->data_in_alsa_frames < leave)
> +    if(stream->data_in_alsa_frames < leave)
>          len = 0;
>      else
> -        len = This->data_in_alsa_frames - leave;
> +        len = stream->data_in_alsa_frames - leave;
>  
> -    TRACE("rewinding %lu frames, now held %u\n", len, This->held_frames);
> +    TRACE("rewinding %lu frames, now held %u\n", len, stream->held_frames);
>  
>      if(len)
>          /* snd_pcm_rewind return value is often broken, assume it succeeded */
> -        snd_pcm_rewind(This->pcm_handle, len);
> +        snd_pcm_rewind(stream->pcm_handle, len);
>  
> -    This->data_in_alsa_frames = 0;
> +    stream->data_in_alsa_frames = 0;
>  
>      return len;
>  }
> @@ -2073,6 +2071,7 @@ static int alsa_rewind_best_effort(ACImpl *This)
>  static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)\n", This);
>  
> @@ -2083,55 +2082,55 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
>          return AUDCLNT_E_NOT_INITIALIZED;
>      }
>  
> -    if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
> +    if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_EVENTHANDLE_NOT_SET;
>      }
>  
> -    if(This->started){
> +    if(stream->started){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_NOT_STOPPED;
>      }
>  
>      if(This->dataflow == eCapture){
>          /* dump any data that might be leftover in the ALSA capture buffer */
> -        snd_pcm_readi(This->pcm_handle, This->local_buffer,
> -                This->bufsize_frames);
> +        snd_pcm_readi(stream->pcm_handle, stream->local_buffer,
> +                stream->bufsize_frames);
>      }else{
>          snd_pcm_sframes_t avail, written;
>          snd_pcm_uframes_t offs;
>  
> -        avail = snd_pcm_avail_update(This->pcm_handle);
> -        avail = min(avail, This->held_frames);
> +        avail = snd_pcm_avail_update(stream->pcm_handle);
> +        avail = min(avail, stream->held_frames);
>  
> -        if(This->wri_offs_frames < This->held_frames)
> -            offs = This->bufsize_frames - This->held_frames + This->wri_offs_frames;
> +        if(stream->wri_offs_frames < stream->held_frames)
> +            offs = stream->bufsize_frames - stream->held_frames + stream->wri_offs_frames;
>          else
> -            offs = This->wri_offs_frames - This->held_frames;
> +            offs = stream->wri_offs_frames - stream->held_frames;
>  
>          /* fill it with data */
> -        written = alsa_write_buffer_wrap(This, This->local_buffer,
> -                This->bufsize_frames, offs, avail);
> +        written = alsa_write_buffer_wrap(This, stream->local_buffer,
> +                stream->bufsize_frames, offs, avail);
>  
>          if(written > 0){
> -            This->lcl_offs_frames = (offs + written) % This->bufsize_frames;
> -            This->data_in_alsa_frames = written;
> +            stream->lcl_offs_frames = (offs + written) % stream->bufsize_frames;
> +            stream->data_in_alsa_frames = written;
>          }else{
> -            This->lcl_offs_frames = offs;
> -            This->data_in_alsa_frames = 0;
> +            stream->lcl_offs_frames = offs;
> +            stream->data_in_alsa_frames = 0;
>          }
>      }
>  
>      if(!This->timer){
>          if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
> -                This, 0, This->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
> +                This, 0, stream->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
>              LeaveCriticalSection(&This->lock);
>              WARN("Unable to create timer: %u\n", GetLastError());
>              return E_OUTOFMEMORY;
>          }
>      }
>  
> -    This->started = TRUE;
> +    stream->started = TRUE;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2141,6 +2140,7 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
>  static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)\n", This);
>  
> @@ -2151,7 +2151,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
>          return AUDCLNT_E_NOT_INITIALIZED;
>      }
>  
> -    if(!This->started){
> +    if(!stream->started){
>          LeaveCriticalSection(&This->lock);
>          return S_FALSE;
>      }
> @@ -2159,7 +2159,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
>      if(This->dataflow == eRender)
>          alsa_rewind_best_effort(This);
>  
> -    This->started = FALSE;
> +    stream->started = FALSE;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2169,6 +2169,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
>  static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)\n", This);
>  
> @@ -2179,34 +2180,34 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
>          return AUDCLNT_E_NOT_INITIALIZED;
>      }
>  
> -    if(This->started){
> +    if(stream->started){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_NOT_STOPPED;
>      }
>  
> -    if(This->getbuf_last){
> +    if(stream->getbuf_last){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_BUFFER_OPERATION_PENDING;
>      }
>  
> -    if(snd_pcm_drop(This->pcm_handle) < 0)
> +    if(snd_pcm_drop(stream->pcm_handle) < 0)
>          WARN("snd_pcm_drop failed\n");
>  
> -    if(snd_pcm_reset(This->pcm_handle) < 0)
> +    if(snd_pcm_reset(stream->pcm_handle) < 0)
>          WARN("snd_pcm_reset failed\n");
>  
> -    if(snd_pcm_prepare(This->pcm_handle) < 0)
> +    if(snd_pcm_prepare(stream->pcm_handle) < 0)
>          WARN("snd_pcm_prepare failed\n");
>  
>      if(This->dataflow == eRender){
> -        This->written_frames = 0;
> -        This->last_pos_frames = 0;
> +        stream->written_frames = 0;
> +        stream->last_pos_frames = 0;
>      }else{
> -        This->written_frames += This->held_frames;
> +        stream->written_frames += stream->held_frames;
>      }
> -    This->held_frames = 0;
> -    This->lcl_offs_frames = 0;
> -    This->wri_offs_frames = 0;
> +    stream->held_frames = 0;
> +    stream->lcl_offs_frames = 0;
> +    stream->wri_offs_frames = 0;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2217,6 +2218,7 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
>          HANDLE event)
>  {
>      ACImpl *This = impl_from_IAudioClient3(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p)\n", This, event);
>  
> @@ -2230,18 +2232,18 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
>          return AUDCLNT_E_NOT_INITIALIZED;
>      }
>  
> -    if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
> +    if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
>      }
>  
> -    if (This->event){
> +    if (stream->event){
>          LeaveCriticalSection(&This->lock);
>          FIXME("called twice\n");
>          return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
>      }
>  
> -    This->event = event;
> +    stream->event = event;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2489,6 +2491,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>          UINT32 frames, BYTE **data)
>  {
>      ACImpl *This = impl_from_IAudioRenderClient(iface);
> +    struct alsa_stream *stream = This->stream;
>      UINT32 write_pos;
>  
>      TRACE("(%p)->(%u, %p)\n", This, frames, data);
> @@ -2499,7 +2502,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>  
>      EnterCriticalSection(&This->lock);
>  
> -    if(This->getbuf_last){
> +    if(stream->getbuf_last){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_OUT_OF_ORDER;
>      }
> @@ -2510,50 +2513,50 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>      }
>  
>      /* held_frames == GetCurrentPadding_nolock(); */
> -    if(This->held_frames + frames > This->bufsize_frames){
> +    if(stream->held_frames + frames > stream->bufsize_frames){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_BUFFER_TOO_LARGE;
>      }
>  
> -    write_pos = This->wri_offs_frames;
> -    if(write_pos + frames > This->bufsize_frames){
> -        if(This->tmp_buffer_frames < frames){
> -            HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
> -            This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
> -                    frames * This->fmt->nBlockAlign);
> -            if(!This->tmp_buffer){
> +    write_pos = stream->wri_offs_frames;
> +    if(write_pos + frames > stream->bufsize_frames){
> +        if(stream->tmp_buffer_frames < frames){
> +            HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
> +            stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
> +                    frames * stream->fmt->nBlockAlign);
> +            if(!stream->tmp_buffer){
>                  LeaveCriticalSection(&This->lock);
>                  return E_OUTOFMEMORY;
>              }
> -            This->tmp_buffer_frames = frames;
> +            stream->tmp_buffer_frames = frames;
>          }
> -        *data = This->tmp_buffer;
> -        This->getbuf_last = -frames;
> +        *data = stream->tmp_buffer;
> +        stream->getbuf_last = -frames;
>      }else{
> -        *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
> -        This->getbuf_last = frames;
> +        *data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign;
> +        stream->getbuf_last = frames;
>      }
>  
> -    silence_buffer(This, *data, frames);
> +    silence_buffer(stream, *data, frames);
>  
>      LeaveCriticalSection(&This->lock);
>  
>      return S_OK;
>  }
>  
> -static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
> +static void alsa_wrap_buffer(struct alsa_stream *stream, BYTE *buffer, UINT32 written_frames)
>  {
> -    snd_pcm_uframes_t write_offs_frames = This->wri_offs_frames;
> -    UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
> -    snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
> -    UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
> -    UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
> +    snd_pcm_uframes_t write_offs_frames = stream->wri_offs_frames;
> +    UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign;
> +    snd_pcm_uframes_t chunk_frames = stream->bufsize_frames - write_offs_frames;
> +    UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
> +    UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign;
>  
>      if(written_bytes <= chunk_bytes){
> -        memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
> +        memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes);
>      }else{
> -        memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
> -        memcpy(This->local_buffer, buffer + chunk_bytes,
> +        memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes);
> +        memcpy(stream->local_buffer, buffer + chunk_bytes,
>                  written_bytes - chunk_bytes);
>      }
>  }
> @@ -2562,6 +2565,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
>          IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
>  {
>      ACImpl *This = impl_from_IAudioRenderClient(iface);
> +    struct alsa_stream *stream = This->stream;
>      BYTE *buffer;
>  
>      TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
> @@ -2569,37 +2573,37 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
>      EnterCriticalSection(&This->lock);
>  
>      if(!written_frames){
> -        This->getbuf_last = 0;
> +        stream->getbuf_last = 0;
>          LeaveCriticalSection(&This->lock);
>          return S_OK;
>      }
>  
> -    if(!This->getbuf_last){
> +    if(!stream->getbuf_last){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_OUT_OF_ORDER;
>      }
>  
> -    if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
> +    if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last)){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_INVALID_SIZE;
>      }
>  
> -    if(This->getbuf_last >= 0)
> -        buffer = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
> +    if(stream->getbuf_last >= 0)
> +        buffer = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign;
>      else
> -        buffer = This->tmp_buffer;
> +        buffer = stream->tmp_buffer;
>  
>      if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
> -        silence_buffer(This, buffer, written_frames);
> +        silence_buffer(stream, buffer, written_frames);
>  
> -    if(This->getbuf_last < 0)
> -        alsa_wrap_buffer(This, buffer, written_frames);
> +    if(stream->getbuf_last < 0)
> +        alsa_wrap_buffer(stream, buffer, written_frames);
>  
> -    This->wri_offs_frames += written_frames;
> -    This->wri_offs_frames %= This->bufsize_frames;
> -    This->held_frames += written_frames;
> -    This->written_frames += written_frames;
> -    This->getbuf_last = 0;
> +    stream->wri_offs_frames += written_frames;
> +    stream->wri_offs_frames %= stream->bufsize_frames;
> +    stream->held_frames += written_frames;
> +    stream->written_frames += written_frames;
> +    stream->getbuf_last = 0;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2656,6 +2660,7 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
>          UINT64 *qpcpos)
>  {
>      ACImpl *This = impl_from_IAudioCaptureClient(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
>              devpos, qpcpos);
> @@ -2670,49 +2675,49 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
>  
>      EnterCriticalSection(&This->lock);
>  
> -    if(This->getbuf_last){
> +    if(stream->getbuf_last){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_OUT_OF_ORDER;
>      }
>  
>      /* hr = GetNextPacketSize(iface, frames); */
> -    if(This->held_frames < This->mmdev_period_frames){
> +    if(stream->held_frames < stream->mmdev_period_frames){
>          *frames = 0;
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_S_BUFFER_EMPTY;
>      }
> -    *frames = This->mmdev_period_frames;
> +    *frames = stream->mmdev_period_frames;
>  
> -    if(This->lcl_offs_frames + *frames > This->bufsize_frames){
> +    if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){
>          UINT32 chunk_bytes, offs_bytes, frames_bytes;
> -        if(This->tmp_buffer_frames < *frames){
> -            HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
> -            This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
> -                    *frames * This->fmt->nBlockAlign);
> -            if(!This->tmp_buffer){
> +        if(stream->tmp_buffer_frames < *frames){
> +            HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
> +            stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
> +                    *frames * stream->fmt->nBlockAlign);
> +            if(!stream->tmp_buffer){
>                  LeaveCriticalSection(&This->lock);
>                  return E_OUTOFMEMORY;
>              }
> -            This->tmp_buffer_frames = *frames;
> +            stream->tmp_buffer_frames = *frames;
>          }
>  
> -        *data = This->tmp_buffer;
> -        chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
> -            This->fmt->nBlockAlign;
> -        offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
> -        frames_bytes = *frames * This->fmt->nBlockAlign;
> -        memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
> -        memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
> +        *data = stream->tmp_buffer;
> +        chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) *
> +            stream->fmt->nBlockAlign;
> +        offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
> +        frames_bytes = *frames * stream->fmt->nBlockAlign;
> +        memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes);
> +        memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer,
>                  frames_bytes - chunk_bytes);
>      }else
> -        *data = This->local_buffer +
> -            This->lcl_offs_frames * This->fmt->nBlockAlign;
> +        *data = stream->local_buffer +
> +            stream->lcl_offs_frames * stream->fmt->nBlockAlign;
>  
> -    This->getbuf_last = *frames;
> +    stream->getbuf_last = *frames;
>      *flags = 0;
>  
>      if(devpos)
> -      *devpos = This->written_frames;
> +      *devpos = stream->written_frames;
>      if(qpcpos){ /* fixme: qpc of recording time */
>          LARGE_INTEGER stamp, freq;
>          QueryPerformanceCounter(&stamp);
> @@ -2729,32 +2734,33 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
>          IAudioCaptureClient *iface, UINT32 done)
>  {
>      ACImpl *This = impl_from_IAudioCaptureClient(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%u)\n", This, done);
>  
>      EnterCriticalSection(&This->lock);
>  
>      if(!done){
> -        This->getbuf_last = 0;
> +        stream->getbuf_last = 0;
>          LeaveCriticalSection(&This->lock);
>          return S_OK;
>      }
>  
> -    if(!This->getbuf_last){
> +    if(!stream->getbuf_last){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_OUT_OF_ORDER;
>      }
>  
> -    if(This->getbuf_last != done){
> +    if(stream->getbuf_last != done){
>          LeaveCriticalSection(&This->lock);
>          return AUDCLNT_E_INVALID_SIZE;
>      }
>  
> -    This->written_frames += done;
> -    This->held_frames -= done;
> -    This->lcl_offs_frames += done;
> -    This->lcl_offs_frames %= This->bufsize_frames;
> -    This->getbuf_last = 0;
> +    stream->written_frames += done;
> +    stream->held_frames -= done;
> +    stream->lcl_offs_frames += done;
> +    stream->lcl_offs_frames %= stream->bufsize_frames;
> +    stream->getbuf_last = 0;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2765,6 +2771,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
>          IAudioCaptureClient *iface, UINT32 *frames)
>  {
>      ACImpl *This = impl_from_IAudioCaptureClient(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p)\n", This, frames);
>  
> @@ -2773,7 +2780,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
>  
>      EnterCriticalSection(&This->lock);
>  
> -    *frames = This->held_frames < This->mmdev_period_frames ? 0 : This->mmdev_period_frames;
> +    *frames = stream->held_frames < stream->mmdev_period_frames ? 0 : stream->mmdev_period_frames;
>  
>      LeaveCriticalSection(&This->lock);
>  
> @@ -2829,13 +2836,14 @@ static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
>  static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
>  {
>      ACImpl *This = impl_from_IAudioClock(iface);
> +    struct alsa_stream *stream = This->stream;
>  
>      TRACE("(%p)->(%p)\n", This, freq);
>  
> -    if(This->share == AUDCLNT_SHAREMODE_SHARED)
> -        *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
> +    if(stream->share == AUDCLNT_SHAREMODE_SHARED)
> +        *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
>      else
> -        *freq = This->fmt->nSamplesPerSec;
> +        *freq = stream->fmt->nSamplesPerSec;
>  
>      return S_OK;
>  }
> @@ -2844,6 +2852,7 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
>          UINT64 *qpctime)
>  {
>      ACImpl *This = impl_from_IAudioClock(iface);
> +    struct alsa_stream *stream = This->stream;
>      UINT64 position;
>      snd_pcm_state_t alsa_state;
>  
> @@ -2855,38 +2864,38 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
>      EnterCriticalSection(&This->lock);
>  
>      /* avail_update required to get accurate snd_pcm_state() */
> -    snd_pcm_avail_update(This->pcm_handle);
> -    alsa_state = snd_pcm_state(This->pcm_handle);
> +    snd_pcm_avail_update(stream->pcm_handle);
> +    alsa_state = snd_pcm_state(stream->pcm_handle);
>  
>      if(This->dataflow == eRender){
> -        position = This->written_frames - This->held_frames;
> +        position = stream->written_frames - stream->held_frames;
>  
> -        if(This->started && alsa_state == SND_PCM_STATE_RUNNING && This->held_frames)
> +        if(stream->started && alsa_state == SND_PCM_STATE_RUNNING && stream->held_frames)
>              /* we should be using snd_pcm_delay here, but it is broken
>               * especially during ALSA device underrun. instead, let's just
>               * interpolate between periods with the system timer. */
> -            position += interp_elapsed_frames(This);
> +            position += interp_elapsed_frames(stream);
>  
> -        position = min(position, This->written_frames - This->held_frames + This->mmdev_period_frames);
> +        position = min(position, stream->written_frames - stream->held_frames + stream->mmdev_period_frames);
>  
> -        position = min(position, This->written_frames);
> +        position = min(position, stream->written_frames);
>      }else
> -        position = This->written_frames + This->held_frames;
> +        position = stream->written_frames + stream->held_frames;
>  
>      /* ensure monotic growth */
> -    if(position < This->last_pos_frames)
> -        position = This->last_pos_frames;
> +    if(position < stream->last_pos_frames)
> +        position = stream->last_pos_frames;
>      else
> -        This->last_pos_frames = position;
> +        stream->last_pos_frames = position;
>  
>      TRACE("frames written: %u, held: %u, state: 0x%x, position: %u\n",
> -            (UINT32)(This->written_frames%1000000000), This->held_frames,
> +            (UINT32)(stream->written_frames%1000000000), stream->held_frames,
>              alsa_state, (UINT32)(position%1000000000));
>  
>      LeaveCriticalSection(&This->lock);
>  
> -    if(This->share == AUDCLNT_SHAREMODE_SHARED)
> -        *pos = position * This->fmt->nBlockAlign;
> +    if(stream->share == AUDCLNT_SHAREMODE_SHARED)
> +        *pos = position * stream->fmt->nBlockAlign;
>      else
>          *pos = position;
>  
> @@ -3056,7 +3065,7 @@ static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
>  
>      LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
>          EnterCriticalSection(&client->lock);
> -        if(client->started){
> +        if(client->stream->started){
>              *state = AudioSessionStateActive;
>              LeaveCriticalSection(&client->lock);
>              LeaveCriticalSection(&g_sessions_lock);
> diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
> index f3014d0b448..8a20710b7e5 100644
> --- a/dlls/winealsa.drv/unixlib.h
> +++ b/dlls/winealsa.drv/unixlib.h
> @@ -16,6 +16,41 @@
>   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>   */
>  
> +#include "audioclient.h"
> +
> +struct alsa_stream
> +{
> +    snd_pcm_t *pcm_handle;
> +    snd_pcm_uframes_t alsa_bufsize_frames, alsa_period_frames, safe_rewind_frames;
> +    snd_pcm_hw_params_t *hw_params; /* does not hold state between calls */
> +    snd_pcm_format_t alsa_format;
> +
> +    LARGE_INTEGER last_period_time;
> +
> +    WAVEFORMATEX *fmt;
> +    DWORD flags;
> +    AUDCLNT_SHAREMODE share;
> +    HANDLE event;
> +
> +    BOOL need_remapping;
> +    int alsa_channels;
> +    int alsa_channel_map[32];
> +
> +    BOOL started;
> +    REFERENCE_TIME mmdev_period_rt;
> +    UINT64 written_frames, last_pos_frames;
> +    UINT32 bufsize_frames, held_frames, tmp_buffer_frames, mmdev_period_frames;
> +    snd_pcm_uframes_t remapping_buf_frames;
> +    UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
> +    UINT32 wri_offs_frames; /* where to write fresh data in local_buffer */
> +    UINT32 hidden_frames;   /* ALSA reserve to ensure continuous rendering */
> +    UINT32 vol_adjusted_frames; /* Frames we've already adjusted the volume of but didn't write yet */
> +    UINT32 data_in_alsa_frames;
> +
> +    BYTE *local_buffer, *tmp_buffer, *remapping_buf, *silence_buf;
> +    LONG32 getbuf_last; /* <0 when using tmp_buffer */
> +};
> +
>  struct endpoint
>  {
>      WCHAR *name;
> -- 
> 2.25.1
> 
> 



More information about the wine-devel mailing list