Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Wed, Apr 06, 2022 at 07:55:54AM +0100, Huw Davies wrote:
Signed-off-by: Huw Davies huw@codeweavers.com
dlls/wineoss.drv/mmdevdrv.c | 427 +++++++++++++++++++----------------- dlls/wineoss.drv/unixlib.h | 19 ++ 2 files changed, 242 insertions(+), 204 deletions(-)
diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c index af49c88e6cf..4f8460a3b3b 100644 --- a/dlls/wineoss.drv/mmdevdrv.c +++ b/dlls/wineoss.drv/mmdevdrv.c @@ -108,25 +108,14 @@ struct ACImpl { IMMDevice *parent; IUnknown *pUnkFTMarshal;
- WAVEFORMATEX *fmt;
- EDataFlow dataflow;
- DWORD flags;
- AUDCLNT_SHAREMODE share;
- HANDLE event; float *vols; UINT32 channel_count;
- struct oss_stream *stream;
int fd; oss_audioinfo ai;
BOOL initted, playing;
UINT64 written_frames, last_pos_frames;
UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, in_oss_frames;
UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
BYTE *local_buffer, *tmp_buffer;
LONG32 getbuf_last; /* <0 when using tmp_buffer */
BOOL initted; HANDLE timer;
CRITICAL_SECTION lock;
@@ -443,6 +432,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out) { ACImpl *This;
- struct oss_stream *stream; const OSSDevice *oss_dev; HRESULT hr; int len;
@@ -459,16 +449,26 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, if(!This) return E_OUTOFMEMORY;
- stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
- if(!stream){
HeapFree(GetProcessHeap(), 0, This);
return E_OUTOFMEMORY;
- }
- stream->flow = oss_dev->flow;
- This->stream = stream;
- hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal); if (FAILED(hr)) {
}HeapFree(GetProcessHeap(), 0, stream); HeapFree(GetProcessHeap(), 0, This); return hr;
- This->fd = open_device(oss_dev->devnode, oss_dev->flow);
- if(This->fd < 0){
- stream->fd = open_device(oss_dev->devnode, oss_dev->flow);
- if(stream->fd < 0){ WARN("Unable to open device %s: %d (%s)\n", oss_dev->devnode, errno, strerror(errno));
}HeapFree(GetProcessHeap(), 0, stream); HeapFree(GetProcessHeap(), 0, This); return AUDCLNT_E_DEVICE_INVALIDATED;
@@ -476,10 +476,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, This->dataflow = oss_dev->flow;
This->ai.dev = -1;
- if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
- if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){ WARN("Unable to get audio info for device %s: %d (%s)\n", oss_dev->devnode, errno, strerror(errno));
close(This->fd);
close(stream->fd);
}HeapFree(GetProcessHeap(), 0, stream); HeapFree(GetProcessHeap(), 0, This); return E_FAIL;
@@ -554,6 +555,7 @@ static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface) static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream; ULONG ref;
ref = InterlockedDecrement(&This->ref);
@@ -575,16 +577,17 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) IUnknown_Release(This->pUnkFTMarshal); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock);
close(This->fd);
close(stream->fd); 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->tmp_buffer);
CoTaskMemFree(This->fmt);
HeapFree(GetProcessHeap(), 0, stream->local_buffer);
HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
CoTaskMemFree(stream->fmt);
} return ref;HeapFree(GetProcessHeap(), 0, stream); HeapFree(GetProcessHeap(), 0, This);
@@ -880,6 +883,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, const GUID *sessionguid) { ACImpl *This = impl_from_IAudioClient3(iface);
- struct oss_stream *stream = This->stream; int i; HRESULT hr;
@@ -939,31 +943,31 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, return AUDCLNT_E_ALREADY_INITIALIZED; }
- hr = setup_oss_device(mode, This->fd, fmt, NULL);
- hr = setup_oss_device(mode, stream->fd, fmt, NULL); if(FAILED(hr)){ LeaveCriticalSection(&This->lock); LeaveCriticalSection(&g_sessions_lock); return hr; }
- This->fmt = clone_format(fmt);
- if(!This->fmt){
- stream->fmt = clone_format(fmt);
- if(!stream->fmt){ LeaveCriticalSection(&This->lock); LeaveCriticalSection(&g_sessions_lock); return E_OUTOFMEMORY; }
- This->period_us = period / 10;
- This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
- stream->period_us = period / 10;
- stream->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
- 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->period_frames;
- This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
This->bufsize_frames * fmt->nBlockAlign);
- if(!This->local_buffer){
CoTaskMemFree(This->fmt);
This->fmt = NULL;
stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
- stream->local_buffer = HeapAlloc(GetProcessHeap(), 0,
stream->bufsize_frames * fmt->nBlockAlign);
- if(!stream->local_buffer){
CoTaskMemFree(stream->fmt);
stream->fmt = NULL; LeaveCriticalSection(&This->lock); LeaveCriticalSection(&g_sessions_lock); return E_OUTOFMEMORY;
@@ -972,8 +976,8 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, This->channel_count = fmt->nChannels; This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float)); if(!This->vols){
CoTaskMemFree(This->fmt);
This->fmt = NULL;
CoTaskMemFree(stream->fmt);
stream->fmt = NULL; LeaveCriticalSection(&This->lock); LeaveCriticalSection(&g_sessions_lock); return E_OUTOFMEMORY;
@@ -982,17 +986,17 @@ 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;
- This->oss_bufsize_bytes = 0;
stream->share = mode;
stream->flags = flags;
stream->oss_bufsize_bytes = 0;
hr = get_audio_session(sessionguid, This->parent, This->channel_count, &This->session); if(FAILED(hr)){ HeapFree(GetProcessHeap(), 0, This->vols); This->vols = NULL;
CoTaskMemFree(This->fmt);
This->fmt = NULL;
CoTaskMemFree(stream->fmt);
stream->fmt = NULL; LeaveCriticalSection(&This->lock); LeaveCriticalSection(&g_sessions_lock); return hr;
@@ -1012,6 +1016,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface, UINT32 *frames) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, frames);
@@ -1025,7 +1030,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface, return AUDCLNT_E_NOT_INITIALIZED; }
- *frames = This->bufsize_frames;
*frames = stream->bufsize_frames;
TRACE("buffer size: %u\n", *frames);
@@ -1038,6 +1043,7 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface, REFERENCE_TIME *latency) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, latency);
@@ -1053,7 +1059,7 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
/* pretend we process audio in Period chunks, so max latency includes * the period time. Some native machines add .6666ms in shared mode. */
- *latency = (REFERENCE_TIME)This->period_us * 10 + 6666;
*latency = (REFERENCE_TIME)stream->period_us * 10 + 6666;
LeaveCriticalSection(&This->lock);
@@ -1064,6 +1070,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface, UINT32 *numpad) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, numpad);
@@ -1077,7 +1084,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface, return AUDCLNT_E_NOT_INITIALIZED; }
- *numpad = This->held_frames;
*numpad = stream->held_frames;
TRACE("padding: %u\n", *numpad);
@@ -1239,19 +1246,19 @@ static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, return S_OK; }
-static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames) +static void silence_buffer(struct oss_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)
elsememset(buffer, 128, frames * stream->fmt->nBlockAlign);
memset(buffer, 0, frames * This->fmt->nBlockAlign);
memset(buffer, 0, frames * stream->fmt->nBlockAlign);
}
-static void oss_write_data(ACImpl *This) +static void oss_write_data(struct oss_stream *stream, BOOL mute) { ssize_t written_bytes; UINT32 written_frames, in_oss_frames, write_limit, max_period, write_offs_frames, new_frames; @@ -1259,25 +1266,25 @@ static void oss_write_data(ACImpl *This) audio_buf_info bi; BYTE *buf;
- if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
- if(ioctl(stream->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){ WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno)); return; }
- max_period = max(bi.fragsize / This->fmt->nBlockAlign, This->period_frames);
- max_period = max(bi.fragsize / stream->fmt->nBlockAlign, stream->period_frames);
- if(bi.bytes > This->oss_bufsize_bytes){
- if(bi.bytes > stream->oss_bufsize_bytes){ TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
bi.bytes, This->oss_bufsize_bytes);
This->oss_bufsize_bytes = bi.bytes;
bi.bytes, stream->oss_bufsize_bytes);
}elsestream->oss_bufsize_bytes = bi.bytes; in_oss_frames = 0;
in_oss_frames = (This->oss_bufsize_bytes - bi.bytes) / This->fmt->nBlockAlign;
in_oss_frames = (stream->oss_bufsize_bytes - bi.bytes) / stream->fmt->nBlockAlign;
- if(in_oss_frames > This->in_oss_frames){
- if(in_oss_frames > stream->in_oss_frames){ TRACE("Capping reported frames from %u to %u\n",
in_oss_frames, This->in_oss_frames);
in_oss_frames = This->in_oss_frames;
in_oss_frames, stream->in_oss_frames);
in_oss_frames = stream->in_oss_frames;
}
write_limit = 0;
@@ -1292,48 +1299,48 @@ static void oss_write_data(ACImpl *This) * ^^^^^^^^^^ - held_frames * ^ - lcl_offs_frames */
- advanced = This->in_oss_frames - in_oss_frames;
- if(advanced > This->held_frames)
advanced = This->held_frames;
- This->lcl_offs_frames += advanced;
- This->lcl_offs_frames %= This->bufsize_frames;
- This->held_frames -= advanced;
- This->in_oss_frames = in_oss_frames;
- advanced = stream->in_oss_frames - in_oss_frames;
- if(advanced > stream->held_frames)
advanced = stream->held_frames;
- stream->lcl_offs_frames += advanced;
- stream->lcl_offs_frames %= stream->bufsize_frames;
- stream->held_frames -= advanced;
- stream->in_oss_frames = in_oss_frames; TRACE("advanced by %lu, lcl_offs: %u, held: %u, in_oss: %u\n",
advanced, This->lcl_offs_frames, This->held_frames, This->in_oss_frames);
advanced, stream->lcl_offs_frames, stream->held_frames, stream->in_oss_frames);
- if(This->held_frames == This->in_oss_frames)
- if(stream->held_frames == stream->in_oss_frames) return;
- write_offs_frames = (This->lcl_offs_frames + This->in_oss_frames) % This->bufsize_frames;
- new_frames = This->held_frames - This->in_oss_frames;
- write_offs_frames = (stream->lcl_offs_frames + stream->in_oss_frames) % stream->bufsize_frames;
- new_frames = stream->held_frames - stream->in_oss_frames;
- if(write_offs_frames + new_frames > This->bufsize_frames)
to_write_frames = This->bufsize_frames - write_offs_frames;
if(write_offs_frames + new_frames > stream->bufsize_frames)
to_write_frames = stream->bufsize_frames - write_offs_frames;
else to_write_frames = new_frames;
to_write_frames = min(to_write_frames, write_limit);
- to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
- to_write_bytes = to_write_frames * stream->fmt->nBlockAlign; TRACE("going to write %lu frames from %u (%lu of %u)\n", to_write_frames, write_offs_frames, to_write_frames + write_offs_frames,
This->bufsize_frames);
stream->bufsize_frames);
- buf = This->local_buffer + write_offs_frames * This->fmt->nBlockAlign;
- buf = stream->local_buffer + write_offs_frames * stream->fmt->nBlockAlign;
- if(This->session->mute)
silence_buffer(This, buf, to_write_frames);
- if(mute)
silence_buffer(stream, buf, to_write_frames);
- written_bytes = write(This->fd, buf, to_write_bytes);
- written_bytes = write(stream->fd, buf, to_write_bytes); if(written_bytes < 0){ /* EAGAIN is OSS buffer full, log that too */ WARN("write failed: %d (%s)\n", errno, strerror(errno)); return; }
- written_frames = written_bytes / This->fmt->nBlockAlign;
- written_frames = written_bytes / stream->fmt->nBlockAlign;
- This->in_oss_frames += written_frames;
stream->in_oss_frames += written_frames;
if(written_frames < to_write_frames){ /* OSS buffer probably full */
@@ -1344,70 +1351,72 @@ static void oss_write_data(ACImpl *This) /* wrapped and have some data back at the start to write */
to_write_frames = min(write_limit - written_frames, new_frames - written_frames);
to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
if(This->session->mute)
silence_buffer(This, This->local_buffer, to_write_frames);
if(mute)
silence_buffer(stream, stream->local_buffer, to_write_frames); TRACE("wrapping to write %lu frames from beginning\n", to_write_frames);
written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
written_bytes = write(stream->fd, stream->local_buffer, to_write_bytes); if(written_bytes < 0){ WARN("write failed: %d (%s)\n", errno, strerror(errno)); return; }
written_frames = written_bytes / This->fmt->nBlockAlign;
This->in_oss_frames += written_frames;
written_frames = written_bytes / stream->fmt->nBlockAlign;
}stream->in_oss_frames += written_frames;
}
-static void oss_read_data(ACImpl *This) +static void oss_read_data(struct oss_stream *stream) { UINT64 pos, readable; ssize_t nread;
- pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
- readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
- pos = (stream->held_frames + stream->lcl_offs_frames) % stream->bufsize_frames;
- readable = (stream->bufsize_frames - pos) * stream->fmt->nBlockAlign;
- nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
- nread = read(stream->fd, stream->local_buffer + pos * stream->fmt->nBlockAlign, readable); if(nread < 0){ WARN("read failed: %d (%s)\n", errno, strerror(errno)); return; }
- This->held_frames += nread / This->fmt->nBlockAlign;
- stream->held_frames += nread / stream->fmt->nBlockAlign;
- if(This->held_frames > This->bufsize_frames){
- if(stream->held_frames > stream->bufsize_frames){ WARN("Overflow of unread data\n");
This->lcl_offs_frames += This->held_frames;
This->lcl_offs_frames %= This->bufsize_frames;
This->held_frames = This->bufsize_frames;
stream->lcl_offs_frames += stream->held_frames;
stream->lcl_offs_frames %= stream->bufsize_frames;
}stream->held_frames = stream->bufsize_frames;
}
static void CALLBACK oss_period_callback(void *user, BOOLEAN timer) { ACImpl *This = user;
struct oss_stream *stream = This->stream;
EnterCriticalSection(&This->lock);
- if(This->playing){
if(This->dataflow == eRender && This->held_frames)
oss_write_data(This);
else if(This->dataflow == eCapture)
oss_read_data(This);
if(stream->playing){
if(stream->flow == eRender && stream->held_frames)
oss_write_data(stream, This->session->mute);
else if(stream->flow == eCapture)
oss_read_data(stream);
}
LeaveCriticalSection(&This->lock);
- if(This->event)
SetEvent(This->event);
- if(stream->event)
SetEvent(stream->event);
}
static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)\n", This);
@@ -1418,24 +1427,24 @@ 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->playing){
if(stream->playing){ LeaveCriticalSection(&This->lock); return AUDCLNT_E_NOT_STOPPED; }
if(!This->timer){ if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
oss_period_callback, This, 0, This->period_us / 1000,
}oss_period_callback, This, 0, stream->period_us / 1000, WT_EXECUTEINTIMERTHREAD)) ERR("Unable to create period timer: %u\n", GetLastError());
- This->playing = TRUE;
stream->playing = TRUE;
LeaveCriticalSection(&This->lock);
@@ -1445,6 +1454,7 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)\n", This);
@@ -1455,13 +1465,13 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) return AUDCLNT_E_NOT_INITIALIZED; }
- if(!This->playing){
- if(!stream->playing){ LeaveCriticalSection(&This->lock); return S_FALSE; }
- This->playing = FALSE;
- This->in_oss_frames = 0;
stream->playing = FALSE;
stream->in_oss_frames = 0;
LeaveCriticalSection(&This->lock);
@@ -1471,6 +1481,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)\n", This);
@@ -1481,25 +1492,25 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) return AUDCLNT_E_NOT_INITIALIZED; }
- if(This->playing){
- if(stream->playing){ 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(This->dataflow == eRender){
This->written_frames = 0;
This->last_pos_frames = 0;
- if(stream->flow == eRender){
stream->written_frames = 0;
}else{stream->last_pos_frames = 0;
This->written_frames += This->held_frames;
}stream->written_frames += stream->held_frames;
- This->held_frames = 0;
- This->lcl_offs_frames = 0;
- This->in_oss_frames = 0;
stream->held_frames = 0;
stream->lcl_offs_frames = 0;
stream->in_oss_frames = 0;
LeaveCriticalSection(&This->lock);
@@ -1510,6 +1521,7 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, HANDLE event) { ACImpl *This = impl_from_IAudioClient3(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, event);
@@ -1523,18 +1535,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);
@@ -1781,6 +1793,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, UINT32 frames, BYTE **data) { ACImpl *This = impl_from_IAudioRenderClient(iface);
struct oss_stream *stream = This->stream; UINT32 write_pos;
TRACE("(%p)->(%u, %p)\n", This, frames, data);
@@ -1792,7 +1805,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; }
@@ -1802,52 +1815,52 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, return S_OK; }
- 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->lcl_offs_frames + This->held_frames) % This->bufsize_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){
(stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_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;
}else{stream->getbuf_last = -frames;
*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 oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames) +static void oss_wrap_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 written_frames) { UINT32 write_offs_frames =
(This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
- UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
- UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
- UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
- UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
(stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign;
UINT32 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);
}else{memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes);
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);
} @@ -1856,6 +1869,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer( IAudioRenderClient *iface, UINT32 written_frames, DWORD flags) { ACImpl *This = impl_from_IAudioRenderClient(iface);
struct oss_stream *stream = This->stream; BYTE *buffer;
TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
@@ -1863,36 +1877,36 @@ 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->fmt->nBlockAlign *
((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
- if(stream->getbuf_last >= 0)
buffer = stream->local_buffer + stream->fmt->nBlockAlign *
else((stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames);
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)
oss_wrap_buffer(This, buffer, written_frames);
- if(stream->getbuf_last < 0)
oss_wrap_buffer(stream, buffer, written_frames);
- This->held_frames += written_frames;
- This->written_frames += written_frames;
- This->getbuf_last = 0;
stream->held_frames += written_frames;
stream->written_frames += written_frames;
stream->getbuf_last = 0;
LeaveCriticalSection(&This->lock);
@@ -1948,6 +1962,7 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface, UINT64 *qpcpos) { ACImpl *This = impl_from_IAudioCaptureClient(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags, devpos, qpcpos);
@@ -1962,12 +1977,12 @@ 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; }
- if(This->held_frames < This->period_frames){
- if(stream->held_frames < stream->period_frames){ *frames = 0; LeaveCriticalSection(&This->lock); return AUDCLNT_S_BUFFER_EMPTY;
@@ -1975,37 +1990,37 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
*flags = 0;
- *frames = This->period_frames;
- *frames = stream->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);
}elsememcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer, frames_bytes - chunk_bytes);
*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;
if(devpos)
*devpos = This->written_frames;
if(qpcpos){ LARGE_INTEGER stamp, freq; QueryPerformanceCounter(&stamp);*devpos = stream->written_frames;
@@ -2022,32 +2037,33 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer( IAudioCaptureClient *iface, UINT32 done) { ACImpl *This = impl_from_IAudioCaptureClient(iface);
struct oss_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);
@@ -2058,6 +2074,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize( IAudioCaptureClient *iface, UINT32 *frames) { ACImpl *This = impl_from_IAudioCaptureClient(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, frames);
@@ -2066,7 +2083,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
EnterCriticalSection(&This->lock);
- *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
*frames = stream->held_frames < stream->period_frames ? 0 : stream->period_frames;
LeaveCriticalSection(&This->lock);
@@ -2122,13 +2139,14 @@ static ULONG WINAPI AudioClock_Release(IAudioClock *iface) static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq) { ACImpl *This = impl_from_IAudioClock(iface);
struct oss_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)
else*freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
*freq = This->fmt->nSamplesPerSec;
*freq = stream->fmt->nSamplesPerSec;
return S_OK;
} @@ -2137,6 +2155,7 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos, UINT64 *qpctime) { ACImpl *This = impl_from_IAudioClock(iface);
struct oss_stream *stream = This->stream;
TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
@@ -2145,32 +2164,32 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
EnterCriticalSection(&This->lock);
- if(This->dataflow == eRender){
*pos = This->written_frames - This->held_frames;
if(*pos < This->last_pos_frames)
*pos = This->last_pos_frames;
- }else if(This->dataflow == eCapture){
- if(stream->flow == eRender){
*pos = stream->written_frames - stream->held_frames;
if(*pos < stream->last_pos_frames)
*pos = stream->last_pos_frames;
- }else if(stream->flow == eCapture){ audio_buf_info bi; UINT32 held;
if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
if(ioctl(stream->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){ TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno)); held = 0; }else{ if(bi.bytes <= bi.fragsize) held = 0; else
held = bi.bytes / This->fmt->nBlockAlign;
held = bi.bytes / stream->fmt->nBlockAlign; }
*pos = This->written_frames + held;
}*pos = stream->written_frames + held;
- This->last_pos_frames = *pos;
stream->last_pos_frames = *pos;
TRACE("returning: %s\n", wine_dbgstr_longlong(*pos));
- if(This->share == AUDCLNT_SHAREMODE_SHARED)
*pos *= This->fmt->nBlockAlign;
if(stream->share == AUDCLNT_SHAREMODE_SHARED)
*pos *= stream->fmt->nBlockAlign;
LeaveCriticalSection(&This->lock);
@@ -2340,7 +2359,7 @@ static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){ EnterCriticalSection(&client->lock);
if(client->playing){
if(client->stream->playing){ *state = AudioSessionStateActive; LeaveCriticalSection(&client->lock); LeaveCriticalSection(&g_sessions_lock);
diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h index 1a80794f150..f498609898a 100644 --- a/dlls/wineoss.drv/unixlib.h +++ b/dlls/wineoss.drv/unixlib.h @@ -18,6 +18,25 @@
#include "mmdeviceapi.h"
+struct oss_stream +{
- WAVEFORMATEX *fmt;
- EDataFlow flow;
- UINT flags;
- AUDCLNT_SHAREMODE share;
- HANDLE event;
- int fd;
- BOOL playing;
- UINT64 written_frames, last_pos_frames;
- UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, in_oss_frames;
- UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
- BYTE *local_buffer, *tmp_buffer;
- INT32 getbuf_last; /* <0 when using tmp_buffer */
+};
/* From <dlls/mmdevapi/mmdevapi.h> */ enum DriverPriority { -- 2.25.1