[PATCH 5/7] winepulse: Introduce pulse_stream struct.

Andrew Eikum aeikum at codeweavers.com
Wed May 12 11:37:23 CDT 2021


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

On Tue, May 11, 2021 at 06:31:24PM +0200, Jacek Caban wrote:
> Signed-off-by: Jacek Caban <jacek at codeweavers.com>
> ---
> It's in unixlib.h for now, but the plan is for it to be accessible only from
> pulse.c.
> 
>  dlls/winepulse.drv/mmdevdrv.c | 586 +++++++++++++++++-----------------
>  dlls/winepulse.drv/pulse.c    |   1 +
>  dlls/winepulse.drv/unixlib.h  |  30 ++
>  3 files changed, 319 insertions(+), 298 deletions(-)
> 
> 

> diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
> index 0c5e08c54e6..1531a2c0075 100644
> --- a/dlls/winepulse.drv/mmdevdrv.c
> +++ b/dlls/winepulse.drv/mmdevdrv.c
> @@ -149,30 +149,12 @@ struct ACImpl {
>      LONG ref;
>      EDataFlow dataflow;
>      UINT32 channel_count;
> -    DWORD flags;
> -    AUDCLNT_SHAREMODE share;
> -    HANDLE event, timer;
> -
> -    INT32 locked;
> -    UINT32 bufsize_frames, real_bufsize_bytes, period_bytes;
> -    UINT32 started, peek_ofs, read_offs_bytes, lcl_offs_bytes, pa_offs_bytes;
> -    UINT32 tmp_buffer_bytes, held_bytes, peek_len, peek_buffer_len, pa_held_bytes;
> -    BYTE *local_buffer, *tmp_buffer, *peek_buffer;
> -    void *locked_ptr;
> -    BOOL please_quit, just_started, just_underran;
> -    pa_usec_t last_time, mmdev_period_usec;
> -
> -    pa_stream *stream;
> -    pa_sample_spec ss;
> -    pa_channel_map map;
> -    pa_buffer_attr attr;
> +    HANDLE timer;
>  
> -    INT64 clock_lastpos, clock_written;
> +    struct pulse_stream *pulse_stream;
>  
>      AudioSession *session;
>      AudioSessionWrapper *session_wrapper;
> -    struct list packet_free_head;
> -    struct list packet_filled_head;
>  };
>  
>  static const WCHAR defaultW[] = {'P','u','l','s','e','a','u','d','i','o',0};
> @@ -287,9 +269,9 @@ static char *get_application_name(void)
>  }
>  
>  static HRESULT pulse_stream_valid(ACImpl *This) {
> -    if (!This->stream)
> +    if (!This->pulse_stream)
>          return AUDCLNT_E_NOT_INITIALIZED;
> -    if (pa_stream_get_state(This->stream) != PA_STREAM_READY)
> +    if (pa_stream_get_state(This->pulse_stream->stream) != PA_STREAM_READY)
>          return AUDCLNT_E_DEVICE_INVALIDATED;
>      return S_OK;
>  }
> @@ -309,12 +291,12 @@ static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes)
>      if (!bytes) return 0;
>      if (This->session->mute)
>      {
> -        silence_buffer(This->ss.format, buffer, bytes);
> +        silence_buffer(This->pulse_stream->ss.format, buffer, bytes);
>          goto write;
>      }
>  
>      /* Adjust the buffer based on the volume for each channel */
> -    channels = This->ss.channels;
> +    channels = This->pulse_stream->ss.channels;
>      for (i = 0; i < channels; i++)
>      {
>          vol[i] = This->vol[i] * This->session->master_vol * This->session->channel_vols[i];
> @@ -323,7 +305,7 @@ static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes)
>      if (!adjust) goto write;
>  
>      end = buffer + bytes;
> -    switch (This->ss.format)
> +    switch (This->pulse_stream->ss.format)
>      {
>  #ifndef WORDS_BIGENDIAN
>  #define PROCESS_BUFFER(type) do         \
> @@ -429,12 +411,12 @@ static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes)
>          break;
>      }
>      default:
> -        TRACE("Unhandled format %i, not adjusting volume.\n", This->ss.format);
> +        TRACE("Unhandled format %i, not adjusting volume.\n", This->pulse_stream->ss.format);
>          break;
>      }
>  
>  write:
> -    return pa_stream_write(This->stream, buffer, bytes, NULL, 0, PA_SEEK_RELATIVE);
> +    return pa_stream_write(This->pulse_stream->stream, buffer, bytes, NULL, 0, PA_SEEK_RELATIVE);
>  }
>  
>  static void dump_attr(const pa_buffer_attr *attr) {
> @@ -461,54 +443,54 @@ static void pulse_write(ACImpl *This)
>  {
>      /* write as much data to PA as we can */
>      UINT32 to_write;
> -    BYTE *buf = This->local_buffer + This->pa_offs_bytes;
> -    UINT32 bytes = pa_stream_writable_size(This->stream);
> +    BYTE *buf = This->pulse_stream->local_buffer + This->pulse_stream->pa_offs_bytes;
> +    UINT32 bytes = pa_stream_writable_size(This->pulse_stream->stream);
>  
> -    if(This->just_underran){
> +    if(This->pulse_stream->just_underran){
>          /* prebuffer with silence if needed */
> -        if(This->pa_held_bytes < bytes){
> -            to_write = bytes - This->pa_held_bytes;
> +        if(This->pulse_stream->pa_held_bytes < bytes){
> +            to_write = bytes - This->pulse_stream->pa_held_bytes;
>              TRACE("prebuffering %u frames of silence\n",
> -                    (int)(to_write / pa_frame_size(&This->ss)));
> +                    (int)(to_write / pa_frame_size(&This->pulse_stream->ss)));
>              buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, to_write);
> -            pa_stream_write(This->stream, buf, to_write, NULL, 0, PA_SEEK_RELATIVE);
> +            pa_stream_write(This->pulse_stream->stream, buf, to_write, NULL, 0, PA_SEEK_RELATIVE);
>              HeapFree(GetProcessHeap(), 0, buf);
>          }
>  
> -        This->just_underran = FALSE;
> +        This->pulse_stream->just_underran = FALSE;
>      }
>  
> -    buf = This->local_buffer + This->pa_offs_bytes;
> +    buf = This->pulse_stream->local_buffer + This->pulse_stream->pa_offs_bytes;
>      TRACE("held: %u, avail: %u\n",
> -            This->pa_held_bytes, bytes);
> -    bytes = min(This->pa_held_bytes, bytes);
> +            This->pulse_stream->pa_held_bytes, bytes);
> +    bytes = min(This->pulse_stream->pa_held_bytes, bytes);
>  
> -    if(This->pa_offs_bytes + bytes > This->real_bufsize_bytes){
> -        to_write = This->real_bufsize_bytes - This->pa_offs_bytes;
> +    if(This->pulse_stream->pa_offs_bytes + bytes > This->pulse_stream->real_bufsize_bytes){
> +        to_write = This->pulse_stream->real_bufsize_bytes - This->pulse_stream->pa_offs_bytes;
>          TRACE("writing small chunk of %u bytes\n", to_write);
>          write_buffer(This, buf, to_write);
> -        This->pa_held_bytes -= to_write;
> +        This->pulse_stream->pa_held_bytes -= to_write;
>          to_write = bytes - to_write;
> -        This->pa_offs_bytes = 0;
> -        buf = This->local_buffer;
> +        This->pulse_stream->pa_offs_bytes = 0;
> +        buf = This->pulse_stream->local_buffer;
>      }else
>          to_write = bytes;
>  
>      TRACE("writing main chunk of %u bytes\n", to_write);
>      write_buffer(This, buf, to_write);
> -    This->pa_offs_bytes += to_write;
> -    This->pa_offs_bytes %= This->real_bufsize_bytes;
> -    This->pa_held_bytes -= to_write;
> +    This->pulse_stream->pa_offs_bytes += to_write;
> +    This->pulse_stream->pa_offs_bytes %= This->pulse_stream->real_bufsize_bytes;
> +    This->pulse_stream->pa_held_bytes -= to_write;
>  }
>  
>  static void pulse_underflow_callback(pa_stream *s, void *userdata)
>  {
>      ACImpl *This = userdata;
>      WARN("%p: Underflow\n", userdata);
> -    This->just_underran = TRUE;
> +    This->pulse_stream->just_underran = TRUE;
>      /* re-sync */
> -    This->pa_offs_bytes = This->lcl_offs_bytes;
> -    This->pa_held_bytes = This->held_bytes;
> +    This->pulse_stream->pa_offs_bytes = This->pulse_stream->lcl_offs_bytes;
> +    This->pulse_stream->pa_held_bytes = This->pulse_stream->held_bytes;
>  }
>  
>  static void pulse_started_callback(pa_stream *s, void *userdata)
> @@ -518,56 +500,56 @@ static void pulse_started_callback(pa_stream *s, void *userdata)
>  
>  static void pulse_read(ACImpl *This)
>  {
> -    size_t bytes = pa_stream_readable_size(This->stream);
> +    size_t bytes = pa_stream_readable_size(This->pulse_stream->stream);
>  
> -    TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(This->stream)->fragsize);
> +    TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(This->pulse_stream->stream)->fragsize);
>  
> -    bytes += This->peek_len - This->peek_ofs;
> +    bytes += This->pulse_stream->peek_len - This->pulse_stream->peek_ofs;
>  
> -    while (bytes >= This->period_bytes) {
> +    while (bytes >= This->pulse_stream->period_bytes) {
>          BYTE *dst = NULL, *src;
> -        size_t src_len, copy, rem = This->period_bytes;
> +        size_t src_len, copy, rem = This->pulse_stream->period_bytes;
>  
> -        if (This->started) {
> +        if (This->pulse_stream->started) {
>              LARGE_INTEGER stamp, freq;
>              ACPacket *p, *next;
>  
> -            if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
> -                p = (ACPacket*)list_head(&This->packet_filled_head);
> +            if (!(p = (ACPacket*)list_head(&This->pulse_stream->packet_free_head))) {
> +                p = (ACPacket*)list_head(&This->pulse_stream->packet_filled_head);
>                  if (!p) return;
>                  if (!p->discont) {
>                      next = (ACPacket*)p->entry.next;
>                      next->discont = 1;
>                  } else
> -                    p = (ACPacket*)list_tail(&This->packet_filled_head);
> +                    p = (ACPacket*)list_tail(&This->pulse_stream->packet_filled_head);
>              } else {
> -                This->held_bytes += This->period_bytes;
> +                This->pulse_stream->held_bytes += This->pulse_stream->period_bytes;
>              }
>              QueryPerformanceCounter(&stamp);
>              QueryPerformanceFrequency(&freq);
>              p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
>              p->discont = 0;
>              list_remove(&p->entry);
> -            list_add_tail(&This->packet_filled_head, &p->entry);
> +            list_add_tail(&This->pulse_stream->packet_filled_head, &p->entry);
>  
>              dst = p->data;
>          }
>  
>          while (rem) {
> -            if (This->peek_len) {
> -                copy = min(rem, This->peek_len - This->peek_ofs);
> +            if (This->pulse_stream->peek_len) {
> +                copy = min(rem, This->pulse_stream->peek_len - This->pulse_stream->peek_ofs);
>  
>                  if (dst) {
> -                    memcpy(dst, This->peek_buffer + This->peek_ofs, copy);
> +                    memcpy(dst, This->pulse_stream->peek_buffer + This->pulse_stream->peek_ofs, copy);
>                      dst += copy;
>                  }
>  
>                  rem -= copy;
> -                This->peek_ofs += copy;
> -                if(This->peek_len == This->peek_ofs)
> -                    This->peek_len = This->peek_ofs = 0;
> +                This->pulse_stream->peek_ofs += copy;
> +                if(This->pulse_stream->peek_len == This->pulse_stream->peek_ofs)
> +                    This->pulse_stream->peek_len = This->pulse_stream->peek_ofs = 0;
>  
> -            } else if (pa_stream_peek(This->stream, (const void**)&src, &src_len) == 0 && src_len) {
> +            } else if (pa_stream_peek(This->pulse_stream->stream, (const void**)&src, &src_len) == 0 && src_len) {
>  
>                  copy = min(rem, src_len);
>  
> @@ -575,7 +557,7 @@ static void pulse_read(ACImpl *This)
>                      if(src)
>                          memcpy(dst, src, copy);
>                      else
> -                        silence_buffer(This->ss.format, dst, copy);
> +                        silence_buffer(This->pulse_stream->ss.format, dst, copy);
>  
>                      dst += copy;
>                  }
> @@ -583,26 +565,26 @@ static void pulse_read(ACImpl *This)
>                  rem -= copy;
>  
>                  if (copy < src_len) {
> -                    if (src_len > This->peek_buffer_len) {
> -                        HeapFree(GetProcessHeap(), 0, This->peek_buffer);
> -                        This->peek_buffer = HeapAlloc(GetProcessHeap(), 0, src_len);
> -                        This->peek_buffer_len = src_len;
> +                    if (src_len > This->pulse_stream->peek_buffer_len) {
> +                        HeapFree(GetProcessHeap(), 0, This->pulse_stream->peek_buffer);
> +                        This->pulse_stream->peek_buffer = HeapAlloc(GetProcessHeap(), 0, src_len);
> +                        This->pulse_stream->peek_buffer_len = src_len;
>                      }
>  
>                      if(src)
> -                        memcpy(This->peek_buffer, src + copy, src_len - copy);
> +                        memcpy(This->pulse_stream->peek_buffer, src + copy, src_len - copy);
>                      else
> -                        silence_buffer(This->ss.format, This->peek_buffer, src_len - copy);
> +                        silence_buffer(This->pulse_stream->ss.format, This->pulse_stream->peek_buffer, src_len - copy);
>  
> -                    This->peek_len = src_len - copy;
> -                    This->peek_ofs = 0;
> +                    This->pulse_stream->peek_len = src_len - copy;
> +                    This->pulse_stream->peek_ofs = 0;
>                  }
>  
> -                pa_stream_drop(This->stream);
> +                pa_stream_drop(This->pulse_stream->stream);
>              }
>          }
>  
> -        bytes -= This->period_bytes;
> +        bytes -= This->pulse_stream->period_bytes;
>      }
>  }
>  
> @@ -615,11 +597,11 @@ static DWORD WINAPI pulse_timer_cb(void *user)
>      pa_operation *o;
>  
>      pulse->lock();
> -    delay.QuadPart = -This->mmdev_period_usec * 10;
> -    pa_stream_get_time(This->stream, &This->last_time);
> +    delay.QuadPart = -This->pulse_stream->mmdev_period_usec * 10;
> +    pa_stream_get_time(This->pulse_stream->stream, &This->pulse_stream->last_time);
>      pulse->unlock();
>  
> -    while(!This->please_quit){
> +    while(!This->pulse_stream->please_quit){
>          pa_usec_t now, adv_usec = 0;
>          int err;
>  
> @@ -627,70 +609,70 @@ static DWORD WINAPI pulse_timer_cb(void *user)
>  
>          pulse->lock();
>  
> -        delay.QuadPart = -This->mmdev_period_usec * 10;
> +        delay.QuadPart = -This->pulse_stream->mmdev_period_usec * 10;
>  
> -        o = pa_stream_update_timing_info(This->stream, pulse_op_cb, &success);
> +        o = pa_stream_update_timing_info(This->pulse_stream->stream, pulse_op_cb, &success);
>          if (o)
>          {
>              while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
>                  pulse->cond_wait();
>              pa_operation_unref(o);
>          }
> -        err = pa_stream_get_time(This->stream, &now);
> +        err = pa_stream_get_time(This->pulse_stream->stream, &now);
>          if(err == 0){
> -            TRACE("got now: %s, last time: %s\n", wine_dbgstr_longlong(now), wine_dbgstr_longlong(This->last_time));
> -            if(This->started && (This->dataflow == eCapture || This->held_bytes)){
> -                if(This->just_underran){
> -                    This->last_time = now;
> -                    This->just_started = TRUE;
> +            TRACE("got now: %s, last time: %s\n", wine_dbgstr_longlong(now), wine_dbgstr_longlong(This->pulse_stream->last_time));
> +            if(This->pulse_stream->started && (This->dataflow == eCapture || This->pulse_stream->held_bytes)){
> +                if(This->pulse_stream->just_underran){
> +                    This->pulse_stream->last_time = now;
> +                    This->pulse_stream->just_started = TRUE;
>                  }
>  
> -                if(This->just_started){
> +                if(This->pulse_stream->just_started){
>                      /* let it play out a period to absorb some latency and get accurate timing */
> -                    pa_usec_t diff = now - This->last_time;
> +                    pa_usec_t diff = now - This->pulse_stream->last_time;
>  
> -                    if(diff > This->mmdev_period_usec){
> -                        This->just_started = FALSE;
> -                        This->last_time = now;
> +                    if(diff > This->pulse_stream->mmdev_period_usec){
> +                        This->pulse_stream->just_started = FALSE;
> +                        This->pulse_stream->last_time = now;
>                      }
>                  }else{
> -                    INT32 adjust = This->last_time + This->mmdev_period_usec - now;
> +                    INT32 adjust = This->pulse_stream->last_time + This->pulse_stream->mmdev_period_usec - now;
>  
> -                    adv_usec = now - This->last_time;
> +                    adv_usec = now - This->pulse_stream->last_time;
>  
> -                    if(adjust > ((INT32)(This->mmdev_period_usec / 2)))
> -                        adjust = This->mmdev_period_usec / 2;
> -                    else if(adjust < -((INT32)(This->mmdev_period_usec / 2)))
> -                        adjust = -1 * This->mmdev_period_usec / 2;
> +                    if(adjust > ((INT32)(This->pulse_stream->mmdev_period_usec / 2)))
> +                        adjust = This->pulse_stream->mmdev_period_usec / 2;
> +                    else if(adjust < -((INT32)(This->pulse_stream->mmdev_period_usec / 2)))
> +                        adjust = -1 * This->pulse_stream->mmdev_period_usec / 2;
>  
> -                    delay.QuadPart = -(This->mmdev_period_usec + adjust) * 10;
> +                    delay.QuadPart = -(This->pulse_stream->mmdev_period_usec + adjust) * 10;
>  
> -                    This->last_time += This->mmdev_period_usec;
> +                    This->pulse_stream->last_time += This->pulse_stream->mmdev_period_usec;
>                  }
>  
>                  if(This->dataflow == eRender){
>                      pulse_write(This);
>  
>                      /* regardless of what PA does, advance one period */
> -                    adv_bytes = min(This->period_bytes, This->held_bytes);
> -                    This->lcl_offs_bytes += adv_bytes;
> -                    This->lcl_offs_bytes %= This->real_bufsize_bytes;
> -                    This->held_bytes -= adv_bytes;
> +                    adv_bytes = min(This->pulse_stream->period_bytes, This->pulse_stream->held_bytes);
> +                    This->pulse_stream->lcl_offs_bytes += adv_bytes;
> +                    This->pulse_stream->lcl_offs_bytes %= This->pulse_stream->real_bufsize_bytes;
> +                    This->pulse_stream->held_bytes -= adv_bytes;
>                  }else if(This->dataflow == eCapture){
>                      pulse_read(This);
>                  }
>              }else{
> -                This->last_time = now;
> -                delay.QuadPart = -This->mmdev_period_usec * 10;
> +                This->pulse_stream->last_time = now;
> +                delay.QuadPart = -This->pulse_stream->mmdev_period_usec * 10;
>              }
>          }
>  
> -        if (This->event)
> -            SetEvent(This->event);
> +        if (This->pulse_stream->event)
> +            SetEvent(This->pulse_stream->event);
>  
>          TRACE("%p after update, adv usec: %d, held: %u, delay usec: %u\n",
>                  This, (int)adv_usec,
> -                (int)(This->held_bytes/ pa_frame_size(&This->ss)), (unsigned int)(-delay.QuadPart / 10));
> +                (int)(This->pulse_stream->held_bytes/ pa_frame_size(&This->pulse_stream->ss)), (unsigned int)(-delay.QuadPart / 10));
>  
>          pulse->unlock();
>      }
> @@ -703,49 +685,49 @@ static HRESULT pulse_stream_connect(ACImpl *This, pa_context *pulse_ctx, UINT32
>      char buffer[64];
>      static LONG number;
>      pa_buffer_attr attr;
> -    if (This->stream) {
> -        pa_stream_disconnect(This->stream);
> -        while (pa_stream_get_state(This->stream) == PA_STREAM_READY)
> +    if (This->pulse_stream->stream) {
> +        pa_stream_disconnect(This->pulse_stream->stream);
> +        while (pa_stream_get_state(This->pulse_stream->stream) == PA_STREAM_READY)
>              pulse->cond_wait();
> -        pa_stream_unref(This->stream);
> +        pa_stream_unref(This->pulse_stream->stream);
>      }
>      ret = InterlockedIncrement(&number);
>      sprintf(buffer, "audio stream #%i", ret);
> -    This->stream = pa_stream_new(pulse_ctx, buffer, &This->ss, &This->map);
> +    This->pulse_stream->stream = pa_stream_new(pulse_ctx, buffer, &This->pulse_stream->ss, &This->pulse_stream->map);
>  
> -    if (!This->stream) {
> +    if (!This->pulse_stream->stream) {
>          WARN("pa_stream_new returned error %i\n", pa_context_errno(pulse_ctx));
>          return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>      }
>  
> -    pa_stream_set_state_callback(This->stream, pulse_stream_state, This);
> -    pa_stream_set_buffer_attr_callback(This->stream, pulse_attr_update, This);
> -    pa_stream_set_moved_callback(This->stream, pulse_attr_update, This);
> +    pa_stream_set_state_callback(This->pulse_stream->stream, pulse_stream_state, This);
> +    pa_stream_set_buffer_attr_callback(This->pulse_stream->stream, pulse_attr_update, This);
> +    pa_stream_set_moved_callback(This->pulse_stream->stream, pulse_attr_update, This);
>  
>      /* PulseAudio will fill in correct values */
>      attr.minreq = attr.fragsize = period_bytes;
>      attr.tlength = period_bytes * 3;
> -    attr.maxlength = This->bufsize_frames * pa_frame_size(&This->ss);
> -    attr.prebuf = pa_frame_size(&This->ss);
> +    attr.maxlength = This->pulse_stream->bufsize_frames * pa_frame_size(&This->pulse_stream->ss);
> +    attr.prebuf = pa_frame_size(&This->pulse_stream->ss);
>      dump_attr(&attr);
>      if (This->dataflow == eRender)
> -        ret = pa_stream_connect_playback(This->stream, NULL, &attr,
> +        ret = pa_stream_connect_playback(This->pulse_stream->stream, NULL, &attr,
>          PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY, NULL, NULL);
>      else
> -        ret = pa_stream_connect_record(This->stream, NULL, &attr,
> +        ret = pa_stream_connect_record(This->pulse_stream->stream, NULL, &attr,
>          PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY);
>      if (ret < 0) {
>          WARN("Returns %i\n", ret);
>          return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>      }
> -    while (pa_stream_get_state(This->stream) == PA_STREAM_CREATING)
> +    while (pa_stream_get_state(This->pulse_stream->stream) == PA_STREAM_CREATING)
>          pulse->cond_wait();
> -    if (pa_stream_get_state(This->stream) != PA_STREAM_READY)
> +    if (pa_stream_get_state(This->pulse_stream->stream) != PA_STREAM_READY)
>          return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
>  
>      if (This->dataflow == eRender) {
> -        pa_stream_set_underflow_callback(This->stream, pulse_underflow_callback, This);
> -        pa_stream_set_started_callback(This->stream, pulse_started_callback, This);
> +        pa_stream_set_underflow_callback(This->pulse_stream->stream, pulse_underflow_callback, This);
> +        pa_stream_set_started_callback(This->pulse_stream->stream, pulse_started_callback, This);
>      }
>      return S_OK;
>  }
> @@ -885,28 +867,30 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
>      ref = InterlockedDecrement(&This->ref);
>      TRACE("(%p) Refcount now %u\n", This, ref);
>      if (!ref) {
> -        if (This->stream) {
> -            if(This->timer){
> -                This->please_quit = TRUE;
> +        if (This->pulse_stream) {
> +            if(This->timer) {
> +                This->pulse_stream->please_quit = TRUE;
>                  WaitForSingleObject(This->timer, INFINITE);
>                  CloseHandle(This->timer);
>              }
> +
>              pulse->lock();
> -            if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) {
> -                pa_stream_disconnect(This->stream);
> -                while (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream)))
> +            if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->pulse_stream->stream))) {
> +                pa_stream_disconnect(This->pulse_stream->stream);
> +                while (PA_STREAM_IS_GOOD(pa_stream_get_state(This->pulse_stream->stream)))
>                      pulse->cond_wait();
>              }
> -            pa_stream_unref(This->stream);
> -            This->stream = NULL;
> +            pa_stream_unref(This->pulse_stream->stream);
> +            HeapFree(GetProcessHeap(), 0, This->pulse_stream->tmp_buffer);
> +            HeapFree(GetProcessHeap(), 0, This->pulse_stream->peek_buffer);
> +            HeapFree(GetProcessHeap(), 0, This->pulse_stream->local_buffer);
> +            HeapFree(GetProcessHeap(), 0, This->pulse_stream);
> +            This->pulse_stream = NULL;
>              list_remove(&This->entry);
>              pulse->unlock();
>          }
>          IUnknown_Release(This->marshal);
>          IMMDevice_Release(This->parent);
> -        HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
> -        HeapFree(GetProcessHeap(), 0, This->peek_buffer);
> -        HeapFree(GetProcessHeap(), 0, This->local_buffer);
>          HeapFree(GetProcessHeap(), 0, This);
>      }
>      return ref;
> @@ -1074,27 +1058,27 @@ static HRESULT get_audio_session(const GUID *sessionguid,
>  
>  static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
>  {
> -    pa_channel_map_init(&This->map);
> -    This->ss.rate = fmt->nSamplesPerSec;
> -    This->ss.format = PA_SAMPLE_INVALID;
> +    pa_channel_map_init(&This->pulse_stream->map);
> +    This->pulse_stream->ss.rate = fmt->nSamplesPerSec;
> +    This->pulse_stream->ss.format = PA_SAMPLE_INVALID;
>  
>      switch(fmt->wFormatTag) {
>      case WAVE_FORMAT_IEEE_FLOAT:
>          if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32)
>              break;
> -        This->ss.format = PA_SAMPLE_FLOAT32LE;
> -        pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
> +        This->pulse_stream->ss.format = PA_SAMPLE_FLOAT32LE;
> +        pa_channel_map_init_auto(&This->pulse_stream->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
>          break;
>      case WAVE_FORMAT_PCM:
>          if (!fmt->nChannels || fmt->nChannels > 2)
>              break;
>          if (fmt->wBitsPerSample == 8)
> -            This->ss.format = PA_SAMPLE_U8;
> +            This->pulse_stream->ss.format = PA_SAMPLE_U8;
>          else if (fmt->wBitsPerSample == 16)
> -            This->ss.format = PA_SAMPLE_S16LE;
> +            This->pulse_stream->ss.format = PA_SAMPLE_S16LE;
>          else
>              return AUDCLNT_E_UNSUPPORTED_FORMAT;
> -        pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
> +        pa_channel_map_init_auto(&This->pulse_stream->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
>          break;
>      case WAVE_FORMAT_EXTENSIBLE: {
>          WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)fmt;
> @@ -1105,7 +1089,7 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
>          if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
>              (!wfe->Samples.wValidBitsPerSample || wfe->Samples.wValidBitsPerSample == 32) &&
>              fmt->wBitsPerSample == 32)
> -            This->ss.format = PA_SAMPLE_FLOAT32LE;
> +            This->pulse_stream->ss.format = PA_SAMPLE_FLOAT32LE;
>          else if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
>              DWORD valid = wfe->Samples.wValidBitsPerSample;
>              if (!valid)
> @@ -1115,40 +1099,40 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
>              switch (fmt->wBitsPerSample) {
>                  case 8:
>                      if (valid == 8)
> -                        This->ss.format = PA_SAMPLE_U8;
> +                        This->pulse_stream->ss.format = PA_SAMPLE_U8;
>                      break;
>                  case 16:
>                      if (valid == 16)
> -                        This->ss.format = PA_SAMPLE_S16LE;
> +                        This->pulse_stream->ss.format = PA_SAMPLE_S16LE;
>                      break;
>                  case 24:
>                      if (valid == 24)
> -                        This->ss.format = PA_SAMPLE_S24LE;
> +                        This->pulse_stream->ss.format = PA_SAMPLE_S24LE;
>                      break;
>                  case 32:
>                      if (valid == 24)
> -                        This->ss.format = PA_SAMPLE_S24_32LE;
> +                        This->pulse_stream->ss.format = PA_SAMPLE_S24_32LE;
>                      else if (valid == 32)
> -                        This->ss.format = PA_SAMPLE_S32LE;
> +                        This->pulse_stream->ss.format = PA_SAMPLE_S32LE;
>                      break;
>                  default:
>                      return AUDCLNT_E_UNSUPPORTED_FORMAT;
>              }
>          }
> -        This->map.channels = fmt->nChannels;
> +        This->pulse_stream->map.channels = fmt->nChannels;
>          if (!mask || (mask & (SPEAKER_ALL|SPEAKER_RESERVED)))
>              mask = get_channel_mask(fmt->nChannels);
>          for (j = 0; j < ARRAY_SIZE(pulse_pos_from_wfx) && i < fmt->nChannels; ++j) {
>              if (mask & (1 << j))
> -                This->map.map[i++] = pulse_pos_from_wfx[j];
> +                This->pulse_stream->map.map[i++] = pulse_pos_from_wfx[j];
>          }
>  
>          /* Special case for mono since pulse appears to map it differently */
>          if (mask == SPEAKER_FRONT_CENTER)
> -            This->map.map[0] = PA_CHANNEL_POSITION_MONO;
> +            This->pulse_stream->map.map[0] = PA_CHANNEL_POSITION_MONO;
>  
>          if (i < fmt->nChannels || (mask & SPEAKER_RESERVED)) {
> -            This->map.channels = 0;
> +            This->pulse_stream->map.channels = 0;
>              ERR("Invalid channel mask: %i/%i and %x(%x)\n", i, fmt->nChannels, mask, wfe->dwChannelMask);
>              break;
>          }
> @@ -1164,16 +1148,16 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
>              FIXME("Unsupported channels %u for LAW\n", fmt->nChannels);
>              return AUDCLNT_E_UNSUPPORTED_FORMAT;
>          }
> -        This->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW;
> -        pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
> +        This->pulse_stream->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW;
> +        pa_channel_map_init_auto(&This->pulse_stream->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
>          break;
>      default:
>          WARN("Unhandled tag %x\n", fmt->wFormatTag);
>          return AUDCLNT_E_UNSUPPORTED_FORMAT;
>      }
> -    This->channel_count = This->ss.channels = This->map.channels;
> -    if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) {
> -        ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This->map), This->ss.format);
> +    This->channel_count = This->pulse_stream->ss.channels = This->pulse_stream->map.channels;
> +    if (!pa_channel_map_valid(&This->pulse_stream->map) || This->pulse_stream->ss.format == PA_SAMPLE_INVALID) {
> +        ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This->pulse_stream->map), This->pulse_stream->ss.format);
>          return AUDCLNT_E_UNSUPPORTED_FORMAT;
>      }
>      return S_OK;
> @@ -1217,7 +1201,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>  
>      pulse->lock();
>  
> -    if (This->stream) {
> +    if (This->pulse_stream) {
>          pulse->unlock();
>          return AUDCLNT_E_ALREADY_INITIALIZED;
>      }
> @@ -1242,6 +1226,11 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>          return hr;
>      }
>  
> +    if (!(This->pulse_stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->pulse_stream))))
> +        return E_OUTOFMEMORY;
> +
> +    This->pulse_stream->dataflow = This->dataflow;
> +
>      hr = pulse_spec_from_waveformat(This, fmt);
>      TRACE("Obtaining format returns %08x\n", hr);
>      dump_fmt(fmt);
> @@ -1253,49 +1242,49 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>      if (duration < 3 * period)
>          duration = 3 * period;
>  
> -    This->period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
> +    This->pulse_stream->period_bytes = pa_frame_size(&This->pulse_stream->ss) * MulDiv(period, This->pulse_stream->ss.rate, 10000000);
>  
> -    This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
> -    bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss);
> -    This->mmdev_period_usec = period / 10;
> +    This->pulse_stream->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
> +    bufsize_bytes = This->pulse_stream->bufsize_frames * pa_frame_size(&This->pulse_stream->ss);
> +    This->pulse_stream->mmdev_period_usec = period / 10;
>  
> -    This->share = mode;
> -    This->flags = flags;
> -    hr = pulse_stream_connect(This, pulse_ctx, This->period_bytes);
> +    This->pulse_stream->share = mode;
> +    This->pulse_stream->flags = flags;
> +    hr = pulse_stream_connect(This, pulse_ctx, This->pulse_stream->period_bytes);
>      if (SUCCEEDED(hr)) {
>          UINT32 unalign;
> -        const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream);
> -        This->attr = *attr;
> +        const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->pulse_stream->stream);
> +        This->pulse_stream->attr = *attr;
>          /* Update frames according to new size */
>          dump_attr(attr);
>          if (This->dataflow == eRender) {
> -            This->real_bufsize_bytes = This->bufsize_frames * 2 * pa_frame_size(&This->ss);
> -            This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->real_bufsize_bytes);
> -            if(!This->local_buffer)
> +            This->pulse_stream->real_bufsize_bytes = This->pulse_stream->bufsize_frames * 2 * pa_frame_size(&This->pulse_stream->ss);
> +            This->pulse_stream->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->pulse_stream->real_bufsize_bytes);
> +            if(!This->pulse_stream->local_buffer)
>                  hr = E_OUTOFMEMORY;
>          } else {
>              UINT32 i, capture_packets;
>  
> -            if ((unalign = bufsize_bytes % This->period_bytes))
> -                bufsize_bytes += This->period_bytes - unalign;
> -            This->bufsize_frames = bufsize_bytes / pa_frame_size(&This->ss);
> -            This->real_bufsize_bytes = bufsize_bytes;
> +            if ((unalign = bufsize_bytes % This->pulse_stream->period_bytes))
> +                bufsize_bytes += This->pulse_stream->period_bytes - unalign;
> +            This->pulse_stream->bufsize_frames = bufsize_bytes / pa_frame_size(&This->pulse_stream->ss);
> +            This->pulse_stream->real_bufsize_bytes = bufsize_bytes;
>  
> -            capture_packets = This->real_bufsize_bytes / This->period_bytes;
> +            capture_packets = This->pulse_stream->real_bufsize_bytes / This->pulse_stream->period_bytes;
>  
> -            This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->real_bufsize_bytes + capture_packets * sizeof(ACPacket));
> -            if (!This->local_buffer)
> +            This->pulse_stream->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->pulse_stream->real_bufsize_bytes + capture_packets * sizeof(ACPacket));
> +            if (!This->pulse_stream->local_buffer)
>                  hr = E_OUTOFMEMORY;
>              else {
> -                ACPacket *cur_packet = (ACPacket*)((char*)This->local_buffer + This->real_bufsize_bytes);
> -                BYTE *data = This->local_buffer;
> -                silence_buffer(This->ss.format, This->local_buffer, This->real_bufsize_bytes);
> -                list_init(&This->packet_free_head);
> -                list_init(&This->packet_filled_head);
> +                ACPacket *cur_packet = (ACPacket*)((char*)This->pulse_stream->local_buffer + This->pulse_stream->real_bufsize_bytes);
> +                BYTE *data = This->pulse_stream->local_buffer;
> +                silence_buffer(This->pulse_stream->ss.format, This->pulse_stream->local_buffer, This->pulse_stream->real_bufsize_bytes);
> +                list_init(&This->pulse_stream->packet_free_head);
> +                list_init(&This->pulse_stream->packet_filled_head);
>                  for (i = 0; i < capture_packets; ++i, ++cur_packet) {
> -                    list_add_tail(&This->packet_free_head, &cur_packet->entry);
> +                    list_add_tail(&This->pulse_stream->packet_free_head, &cur_packet->entry);
>                      cur_packet->data = data;
> -                    data += This->period_bytes;
> +                    data += This->pulse_stream->period_bytes;
>                  }
>              }
>          }
> @@ -1307,13 +1296,14 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
>  
>  exit:
>      if (FAILED(hr)) {
> -        HeapFree(GetProcessHeap(), 0, This->local_buffer);
> -        This->local_buffer = NULL;
> -        if (This->stream) {
> -            pa_stream_disconnect(This->stream);
> -            pa_stream_unref(This->stream);
> -            This->stream = NULL;
> +        HeapFree(GetProcessHeap(), 0, This->pulse_stream->local_buffer);
> +        This->pulse_stream->local_buffer = NULL;
> +        if (This->pulse_stream->stream) {
> +            pa_stream_disconnect(This->pulse_stream->stream);
> +            pa_stream_unref(This->pulse_stream->stream);
>          }
> +        HeapFree(GetProcessHeap(), 0, This->pulse_stream);
> +        This->pulse_stream = NULL;
>      }
>      pulse->unlock();
>      return hr;
> @@ -1333,7 +1323,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
>      pulse->lock();
>      hr = pulse_stream_valid(This);
>      if (SUCCEEDED(hr))
> -        *out = This->bufsize_frames;
> +        *out = This->pulse_stream->bufsize_frames;
>      pulse->unlock();
>  
>      return hr;
> @@ -1358,14 +1348,14 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
>          pulse->unlock();
>          return hr;
>      }
> -    attr = pa_stream_get_buffer_attr(This->stream);
> +    attr = pa_stream_get_buffer_attr(This->pulse_stream->stream);
>      if (This->dataflow == eRender){
> -        lat = attr->minreq / pa_frame_size(&This->ss);
> +        lat = attr->minreq / pa_frame_size(&This->pulse_stream->ss);
>      }else
> -        lat = attr->fragsize / pa_frame_size(&This->ss);
> +        lat = attr->fragsize / pa_frame_size(&This->pulse_stream->ss);
>      *latency = 10000000;
>      *latency *= lat;
> -    *latency /= This->ss.rate;
> +    *latency /= This->pulse_stream->ss.rate;
>      *latency += pulse_config.modes[0].def_period;
>      pulse->unlock();
>      TRACE("Latency: %u ms\n", (DWORD)(*latency / 10000));
> @@ -1374,19 +1364,19 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
>  
>  static void ACImpl_GetRenderPad(ACImpl *This, UINT32 *out)
>  {
> -    *out = This->held_bytes / pa_frame_size(&This->ss);
> +    *out = This->pulse_stream->held_bytes / pa_frame_size(&This->pulse_stream->ss);
>  }
>  
>  static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out)
>  {
> -    ACPacket *packet = This->locked_ptr;
> -    if (!packet && !list_empty(&This->packet_filled_head)) {
> -        packet = (ACPacket*)list_head(&This->packet_filled_head);
> -        This->locked_ptr = packet;
> +    ACPacket *packet = This->pulse_stream->locked_ptr;
> +    if (!packet && !list_empty(&This->pulse_stream->packet_filled_head)) {
> +        packet = (ACPacket*)list_head(&This->pulse_stream->packet_filled_head);
> +        This->pulse_stream->locked_ptr = packet;
>          list_remove(&packet->entry);
>      }
>      if (out)
> -        *out = This->held_bytes / pa_frame_size(&This->ss);
> +        *out = This->pulse_stream->held_bytes / pa_frame_size(&This->pulse_stream->ss);
>  }
>  
>  static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
> @@ -1413,7 +1403,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
>          ACImpl_GetCapturePad(This, out);
>      pulse->unlock();
>  
> -    TRACE("%p Pad: %u ms (%u)\n", This, MulDiv(*out, 1000, This->ss.rate), *out);
> +    TRACE("%p Pad: %u ms (%u)\n", This, MulDiv(*out, 1000, This->pulse_stream->ss.rate), *out);
>      return S_OK;
>  }
>  
> @@ -1621,20 +1611,20 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
>          return hr;
>      }
>  
> -    if ((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event) {
> +    if ((This->pulse_stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->pulse_stream->event) {
>          pulse->unlock();
>          return AUDCLNT_E_EVENTHANDLE_NOT_SET;
>      }
>  
> -    if (This->started) {
> +    if (This->pulse_stream->started) {
>          pulse->unlock();
>          return AUDCLNT_E_NOT_STOPPED;
>      }
>  
>      pulse_write(This);
>  
> -    if (pa_stream_is_corked(This->stream)) {
> -        o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success);
> +    if (pa_stream_is_corked(This->pulse_stream->stream)) {
> +        o = pa_stream_cork(This->pulse_stream->stream, 0, pulse_op_cb, &success);
>          if (o) {
>              while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
>                  pulse->cond_wait();
> @@ -1646,8 +1636,8 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
>      }
>  
>      if (SUCCEEDED(hr)) {
> -        This->started = TRUE;
> -        This->just_started = TRUE;
> +        This->pulse_stream->started = TRUE;
> +        This->pulse_stream->just_started = TRUE;
>  
>          if(!This->timer) {
>              This->timer = CreateThread(NULL, 0, pulse_timer_cb, This, 0, NULL);
> @@ -1674,13 +1664,13 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
>          return hr;
>      }
>  
> -    if (!This->started) {
> +    if (!This->pulse_stream->started) {
>          pulse->unlock();
>          return S_FALSE;
>      }
>  
>      if (This->dataflow == eRender) {
> -        o = pa_stream_cork(This->stream, 1, pulse_op_cb, &success);
> +        o = pa_stream_cork(This->pulse_stream->stream, 1, pulse_op_cb, &success);
>          if (o) {
>              while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
>                  pulse->cond_wait();
> @@ -1691,7 +1681,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
>              hr = E_FAIL;
>      }
>      if (SUCCEEDED(hr)) {
> -        This->started = FALSE;
> +        This->pulse_stream->started = FALSE;
>      }
>      pulse->unlock();
>      return hr;
> @@ -1711,12 +1701,12 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
>          return hr;
>      }
>  
> -    if (This->started) {
> +    if (This->pulse_stream->started) {
>          pulse->unlock();
>          return AUDCLNT_E_NOT_STOPPED;
>      }
>  
> -    if (This->locked) {
> +    if (This->pulse_stream->locked) {
>          pulse->unlock();
>          return AUDCLNT_E_BUFFER_OPERATION_PENDING;
>      }
> @@ -1724,28 +1714,28 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
>      if (This->dataflow == eRender) {
>          /* If there is still data in the render buffer it needs to be removed from the server */
>          int success = 0;
> -        if (This->held_bytes) {
> -            pa_operation *o = pa_stream_flush(This->stream, pulse_op_cb, &success);
> +        if (This->pulse_stream->held_bytes) {
> +            pa_operation *o = pa_stream_flush(This->pulse_stream->stream, pulse_op_cb, &success);
>              if (o) {
>                  while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
>                      pulse->cond_wait();
>                  pa_operation_unref(o);
>              }
>          }
> -        if (success || !This->held_bytes){
> -            This->clock_lastpos = This->clock_written = 0;
> -            This->pa_offs_bytes = This->lcl_offs_bytes = This->held_bytes = This->pa_held_bytes = 0;
> +        if (success || !This->pulse_stream->held_bytes){
> +            This->pulse_stream->clock_lastpos = This->pulse_stream->clock_written = 0;
> +            This->pulse_stream->pa_offs_bytes = This->pulse_stream->lcl_offs_bytes = This->pulse_stream->held_bytes = This->pulse_stream->pa_held_bytes = 0;
>          }
>      } else {
>          ACPacket *p;
> -        This->clock_written += This->held_bytes;
> -        This->held_bytes = 0;
> +        This->pulse_stream->clock_written += This->pulse_stream->held_bytes;
> +        This->pulse_stream->held_bytes = 0;
>  
> -        if ((p = This->locked_ptr)) {
> -            This->locked_ptr = NULL;
> -            list_add_tail(&This->packet_free_head, &p->entry);
> +        if ((p = This->pulse_stream->locked_ptr)) {
> +            This->pulse_stream->locked_ptr = NULL;
> +            list_add_tail(&This->pulse_stream->packet_free_head, &p->entry);
>          }
> -        list_move_tail(&This->packet_free_head, &This->packet_filled_head);
> +        list_move_tail(&This->pulse_stream->packet_free_head, &This->pulse_stream->packet_filled_head);
>      }
>      pulse->unlock();
>  
> @@ -1770,12 +1760,12 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
>          return hr;
>      }
>  
> -    if (!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
> +    if (!(This->pulse_stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
>          hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
> -    else if (This->event)
> +    else if (This->pulse_stream->event)
>          hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
>      else
> -        This->event = event;
> +        This->pulse_stream->event = event;
>      pulse->unlock();
>      return hr;
>  }
> @@ -1990,19 +1980,19 @@ static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
>  
>  static void alloc_tmp_buffer(ACImpl *This, UINT32 bytes)
>  {
> -    if(This->tmp_buffer_bytes >= bytes)
> +    if(This->pulse_stream->tmp_buffer_bytes >= bytes)
>          return;
>  
> -    HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
> -    This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, bytes);
> -    This->tmp_buffer_bytes = bytes;
> +    HeapFree(GetProcessHeap(), 0, This->pulse_stream->tmp_buffer);
> +    This->pulse_stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, bytes);
> +    This->pulse_stream->tmp_buffer_bytes = bytes;
>  }
>  
>  static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>          UINT32 frames, BYTE **data)
>  {
>      ACImpl *This = impl_from_IAudioRenderClient(iface);
> -    size_t bytes = frames * pa_frame_size(&This->ss);
> +    size_t bytes = frames * pa_frame_size(&This->pulse_stream->ss);
>      HRESULT hr = S_OK;
>      UINT32 wri_offs_bytes;
>  
> @@ -2014,7 +2004,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>  
>      pulse->lock();
>      hr = pulse_stream_valid(This);
> -    if (FAILED(hr) || This->locked) {
> +    if (FAILED(hr) || This->pulse_stream->locked) {
>          pulse->unlock();
>          return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
>      }
> @@ -2023,22 +2013,22 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>          return S_OK;
>      }
>  
> -    if(This->held_bytes / pa_frame_size(&This->ss) + frames > This->bufsize_frames){
> +    if(This->pulse_stream->held_bytes / pa_frame_size(&This->pulse_stream->ss) + frames > This->pulse_stream->bufsize_frames){
>          pulse->unlock();
>          return AUDCLNT_E_BUFFER_TOO_LARGE;
>      }
>  
> -    wri_offs_bytes = (This->lcl_offs_bytes + This->held_bytes) % This->real_bufsize_bytes;
> -    if(wri_offs_bytes + bytes > This->real_bufsize_bytes){
> +    wri_offs_bytes = (This->pulse_stream->lcl_offs_bytes + This->pulse_stream->held_bytes) % This->pulse_stream->real_bufsize_bytes;
> +    if(wri_offs_bytes + bytes > This->pulse_stream->real_bufsize_bytes){
>          alloc_tmp_buffer(This, bytes);
> -        *data = This->tmp_buffer;
> -        This->locked = -bytes;
> +        *data = This->pulse_stream->tmp_buffer;
> +        This->pulse_stream->locked = -bytes;
>      }else{
> -        *data = This->local_buffer + wri_offs_bytes;
> -        This->locked = bytes;
> +        *data = This->pulse_stream->local_buffer + wri_offs_bytes;
> +        This->pulse_stream->locked = bytes;
>      }
>  
> -    silence_buffer(This->ss.format, *data, bytes);
> +    silence_buffer(This->pulse_stream->ss.format, *data, bytes);
>  
>      pulse->unlock();
>  
> @@ -2047,14 +2037,14 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
>  
>  static void pulse_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
>  {
> -    UINT32 wri_offs_bytes = (This->lcl_offs_bytes + This->held_bytes) % This->real_bufsize_bytes;
> -    UINT32 chunk_bytes = This->real_bufsize_bytes - wri_offs_bytes;
> +    UINT32 wri_offs_bytes = (This->pulse_stream->lcl_offs_bytes + This->pulse_stream->held_bytes) % This->pulse_stream->real_bufsize_bytes;
> +    UINT32 chunk_bytes = This->pulse_stream->real_bufsize_bytes - wri_offs_bytes;
>  
>      if(written_bytes <= chunk_bytes){
> -        memcpy(This->local_buffer + wri_offs_bytes, buffer, written_bytes);
> +        memcpy(This->pulse_stream->local_buffer + wri_offs_bytes, buffer, written_bytes);
>      }else{
> -        memcpy(This->local_buffer + wri_offs_bytes, buffer, chunk_bytes);
> -        memcpy(This->local_buffer, buffer + chunk_bytes,
> +        memcpy(This->pulse_stream->local_buffer + wri_offs_bytes, buffer, chunk_bytes);
> +        memcpy(This->pulse_stream->local_buffer, buffer + chunk_bytes,
>                  written_bytes - chunk_bytes);
>      }
>  }
> @@ -2063,45 +2053,45 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
>          IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
>  {
>      ACImpl *This = impl_from_IAudioRenderClient(iface);
> -    UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
> +    UINT32 written_bytes = written_frames * pa_frame_size(&This->pulse_stream->ss);
>      BYTE *buffer;
>  
>      TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
>  
>      pulse->lock();
> -    if (!This->locked || !written_frames) {
> -        This->locked = 0;
> +    if (!This->pulse_stream->locked || !written_frames) {
> +        This->pulse_stream->locked = 0;
>          pulse->unlock();
>          return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
>      }
>  
> -    if(written_frames * pa_frame_size(&This->ss) > (This->locked >= 0 ? This->locked : -This->locked)){
> +    if(written_frames * pa_frame_size(&This->pulse_stream->ss) > (This->pulse_stream->locked >= 0 ? This->pulse_stream->locked : -This->pulse_stream->locked)){
>          pulse->unlock();
>          return AUDCLNT_E_INVALID_SIZE;
>      }
>  
> -    if(This->locked >= 0)
> -        buffer = This->local_buffer + (This->lcl_offs_bytes + This->held_bytes) % This->real_bufsize_bytes;
> +    if(This->pulse_stream->locked >= 0)
> +        buffer = This->pulse_stream->local_buffer + (This->pulse_stream->lcl_offs_bytes + This->pulse_stream->held_bytes) % This->pulse_stream->real_bufsize_bytes;
>      else
> -        buffer = This->tmp_buffer;
> +        buffer = This->pulse_stream->tmp_buffer;
>  
>      if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
> -        silence_buffer(This->ss.format, buffer, written_bytes);
> +        silence_buffer(This->pulse_stream->ss.format, buffer, written_bytes);
>  
> -    if(This->locked < 0)
> +    if(This->pulse_stream->locked < 0)
>          pulse_wrap_buffer(This, buffer, written_bytes);
>  
> -    This->held_bytes += written_bytes;
> -    This->pa_held_bytes += written_bytes;
> -    if(This->pa_held_bytes > This->real_bufsize_bytes){
> -        This->pa_offs_bytes += This->pa_held_bytes - This->real_bufsize_bytes;
> -        This->pa_offs_bytes %= This->real_bufsize_bytes;
> -        This->pa_held_bytes = This->real_bufsize_bytes;
> +    This->pulse_stream->held_bytes += written_bytes;
> +    This->pulse_stream->pa_held_bytes += written_bytes;
> +    if(This->pulse_stream->pa_held_bytes > This->pulse_stream->real_bufsize_bytes){
> +        This->pulse_stream->pa_offs_bytes += This->pulse_stream->pa_held_bytes - This->pulse_stream->real_bufsize_bytes;
> +        This->pulse_stream->pa_offs_bytes %= This->pulse_stream->real_bufsize_bytes;
> +        This->pulse_stream->pa_held_bytes = This->pulse_stream->real_bufsize_bytes;
>      }
> -    This->clock_written += written_bytes;
> -    This->locked = 0;
> +    This->pulse_stream->clock_written += written_bytes;
> +    This->pulse_stream->locked = 0;
>  
> -    TRACE("Released %u, held %zu\n", written_frames, This->held_bytes / pa_frame_size(&This->ss));
> +    TRACE("Released %u, held %zu\n", written_frames, This->pulse_stream->held_bytes / pa_frame_size(&This->pulse_stream->ss));
>  
>      pulse->unlock();
>  
> @@ -2174,22 +2164,22 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
>  
>      pulse->lock();
>      hr = pulse_stream_valid(This);
> -    if (FAILED(hr) || This->locked) {
> +    if (FAILED(hr) || This->pulse_stream->locked) {
>          pulse->unlock();
>          return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
>      }
>  
>      ACImpl_GetCapturePad(This, NULL);
> -    if ((packet = This->locked_ptr)) {
> -        *frames = This->period_bytes / pa_frame_size(&This->ss);
> +    if ((packet = This->pulse_stream->locked_ptr)) {
> +        *frames = This->pulse_stream->period_bytes / pa_frame_size(&This->pulse_stream->ss);
>          *flags = 0;
>          if (packet->discont)
>              *flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY;
>          if (devpos) {
>              if (packet->discont)
> -                *devpos = (This->clock_written + This->period_bytes) / pa_frame_size(&This->ss);
> +                *devpos = (This->pulse_stream->clock_written + This->pulse_stream->period_bytes) / pa_frame_size(&This->pulse_stream->ss);
>              else
> -                *devpos = This->clock_written / pa_frame_size(&This->ss);
> +                *devpos = This->pulse_stream->clock_written / pa_frame_size(&This->pulse_stream->ss);
>          }
>          if (qpcpos)
>              *qpcpos = packet->qpcpos;
> @@ -2197,7 +2187,7 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
>      }
>      else
>          *frames = 0;
> -    This->locked = *frames;
> +    This->pulse_stream->locked = *frames;
>      pulse->unlock();
>      return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
>  }
> @@ -2210,25 +2200,25 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
>      TRACE("(%p)->(%u)\n", This, done);
>  
>      pulse->lock();
> -    if (!This->locked && done) {
> +    if (!This->pulse_stream->locked && done) {
>          pulse->unlock();
>          return AUDCLNT_E_OUT_OF_ORDER;
>      }
> -    if (done && This->locked != done) {
> +    if (done && This->pulse_stream->locked != done) {
>          pulse->unlock();
>          return AUDCLNT_E_INVALID_SIZE;
>      }
>      if (done) {
> -        ACPacket *packet = This->locked_ptr;
> -        This->locked_ptr = NULL;
> -        This->held_bytes -= This->period_bytes;
> +        ACPacket *packet = This->pulse_stream->locked_ptr;
> +        This->pulse_stream->locked_ptr = NULL;
> +        This->pulse_stream->held_bytes -= This->pulse_stream->period_bytes;
>          if (packet->discont)
> -            This->clock_written += 2 * This->period_bytes;
> +            This->pulse_stream->clock_written += 2 * This->pulse_stream->period_bytes;
>          else
> -            This->clock_written += This->period_bytes;
> -        list_add_tail(&This->packet_free_head, &packet->entry);
> +            This->pulse_stream->clock_written += This->pulse_stream->period_bytes;
> +        list_add_tail(&This->pulse_stream->packet_free_head, &packet->entry);
>      }
> -    This->locked = 0;
> +    This->pulse_stream->locked = 0;
>      pulse->unlock();
>      return S_OK;
>  }
> @@ -2244,8 +2234,8 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
>  
>      pulse->lock();
>      ACImpl_GetCapturePad(This, NULL);
> -    if (This->locked_ptr)
> -        *frames = This->period_bytes / pa_frame_size(&This->ss);
> +    if (This->pulse_stream->locked_ptr)
> +        *frames = This->pulse_stream->period_bytes / pa_frame_size(&This->pulse_stream->ss);
>      else
>          *frames = 0;
>      pulse->unlock();
> @@ -2311,9 +2301,9 @@ static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
>      pulse->lock();
>      hr = pulse_stream_valid(This);
>      if (SUCCEEDED(hr)) {
> -        *freq = This->ss.rate;
> -        if (This->share == AUDCLNT_SHAREMODE_SHARED)
> -            *freq *= pa_frame_size(&This->ss);
> +        *freq = This->pulse_stream->ss.rate;
> +        if (This->pulse_stream->share == AUDCLNT_SHAREMODE_SHARED)
> +            *freq *= pa_frame_size(&This->pulse_stream->ss);
>      }
>      pulse->unlock();
>      return hr;
> @@ -2337,16 +2327,16 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
>          return hr;
>      }
>  
> -    *pos = This->clock_written - This->held_bytes;
> +    *pos = This->pulse_stream->clock_written - This->pulse_stream->held_bytes;
>  
> -    if (This->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
> -        *pos /= pa_frame_size(&This->ss);
> +    if (This->pulse_stream->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
> +        *pos /= pa_frame_size(&This->pulse_stream->ss);
>  
>      /* Make time never go backwards */
> -    if (*pos < This->clock_lastpos)
> -        *pos = This->clock_lastpos;
> +    if (*pos < This->pulse_stream->clock_lastpos)
> +        *pos = This->pulse_stream->clock_lastpos;
>      else
> -        This->clock_lastpos = *pos;
> +        This->pulse_stream->clock_lastpos = *pos;
>      pulse->unlock();
>  
>      TRACE("%p Position: %u\n", This, (unsigned)*pos);
> @@ -2410,8 +2400,8 @@ static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
>  {
>      ACImpl *This = impl_from_IAudioClock2(iface);
>      HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime);
> -    if (SUCCEEDED(hr) && This->share == AUDCLNT_SHAREMODE_SHARED)
> -        *pos /= pa_frame_size(&This->ss);
> +    if (SUCCEEDED(hr) && This->pulse_stream->share == AUDCLNT_SHAREMODE_SHARED)
> +        *pos /= pa_frame_size(&This->pulse_stream->ss);
>      return hr;
>  }
>  
> @@ -2680,7 +2670,7 @@ static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
>          goto out;
>      }
>      LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry) {
> -        if (client->started) {
> +        if (client->pulse_stream->started) {
>              *state = AudioSessionStateActive;
>              goto out;
>          }
> diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c
> index 5369d5d08a5..5f4998e641f 100644
> --- a/dlls/winepulse.drv/pulse.c
> +++ b/dlls/winepulse.drv/pulse.c
> @@ -32,6 +32,7 @@
>  #define WIN32_NO_STATUS
>  #include "winternl.h"
>  
> +#include "mmdeviceapi.h"
>  #include "initguid.h"
>  #include "audioclient.h"
>  
> diff --git a/dlls/winepulse.drv/unixlib.h b/dlls/winepulse.drv/unixlib.h
> index f2bb7c78c82..89d3c05611a 100644
> --- a/dlls/winepulse.drv/unixlib.h
> +++ b/dlls/winepulse.drv/unixlib.h
> @@ -16,6 +16,8 @@
>   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>   */
>  
> +#include "wine/list.h"
> +
>  struct pulse_config
>  {
>      struct
> @@ -27,6 +29,34 @@ struct pulse_config
>      unsigned int speakers_mask;
>  };
>  
> +struct pulse_stream
> +{
> +    EDataFlow dataflow;
> +
> +    pa_stream *stream;
> +    pa_sample_spec ss;
> +    pa_channel_map map;
> +    pa_buffer_attr attr;
> +
> +    DWORD flags;
> +    AUDCLNT_SHAREMODE share;
> +    HANDLE event;
> +
> +    INT32 locked;
> +    UINT32 bufsize_frames, real_bufsize_bytes, period_bytes;
> +    UINT32 started, peek_ofs, read_offs_bytes, lcl_offs_bytes, pa_offs_bytes;
> +    UINT32 tmp_buffer_bytes, held_bytes, peek_len, peek_buffer_len, pa_held_bytes;
> +    BYTE *local_buffer, *tmp_buffer, *peek_buffer;
> +    void *locked_ptr;
> +    BOOL please_quit, just_started, just_underran;
> +    pa_usec_t last_time, mmdev_period_usec;
> +
> +    INT64 clock_lastpos, clock_written;
> +
> +    struct list packet_free_head;
> +    struct list packet_filled_head;
> +};
> +
>  struct unix_funcs
>  {
>      void (WINAPI *lock)(void);
> 




More information about the wine-devel mailing list