[PATCH] winealsa.drv: Add support for indirect read/write in directsound support
Maarten Lankhorst
m.b.lankhorst at gmail.com
Sun Jul 12 13:11:55 CDT 2009
---
dlls/winealsa.drv/dsoutput.c | 159 ++++++++++++++++++++++++++++++++----------
1 files changed, 123 insertions(+), 36 deletions(-)
diff --git a/dlls/winealsa.drv/dsoutput.c b/dlls/winealsa.drv/dsoutput.c
index 15cff5f..9c6d7fd 100644
--- a/dlls/winealsa.drv/dsoutput.c
+++ b/dlls/winealsa.drv/dsoutput.c
@@ -83,8 +83,9 @@ struct IDsDriverBufferImpl
IDsDriverImpl* drv;
CRITICAL_SECTION pcm_crst;
- LPVOID mmap_buffer;
+ BYTE *mmap_buffer;
DWORD mmap_buflen_bytes;
+ BOOL mmap;
snd_pcm_t *pcm;
snd_pcm_hw_params_t *hw_params;
@@ -102,25 +103,44 @@ struct IDsDriverBufferImpl
static snd_pcm_uframes_t CommitAll(IDsDriverBufferImpl *This)
{
const snd_pcm_channel_area_t *areas;
- snd_pcm_uframes_t used;
+ snd_pcm_sframes_t used;
const snd_pcm_uframes_t commitahead = This->mmap_commitahead;
used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm);
- TRACE("%p needs to commit to %lu, used: %lu\n", This, commitahead, used);
+ if (used < 0) used = 0;
+ TRACE("%p needs to commit to %lu, used: %ld\n", This, commitahead, used);
if (used < commitahead)
{
snd_pcm_uframes_t done, putin = commitahead - used;
- snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
- done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
+ if (This->mmap)
+ {
+ snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
+ done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
+ }
+ else
+ {
+ if (putin + This->mmap_pos > This->mmap_buflen_frames)
+ putin = This->mmap_buflen_frames - This->mmap_pos;
+ done = putin;
+ snd_pcm_writei(This->pcm, This->mmap_buffer + snd_pcm_frames_to_bytes(This->pcm, This->mmap_pos), putin);
+ }
This->mmap_pos += done;
used += done;
putin = commitahead - used;
if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0)
{
- snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
- done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
- This->mmap_pos += done;
+ if (This->mmap)
+ {
+ snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
+ done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
+ This->mmap_pos += done;
+ }
+ else
+ {
+ snd_pcm_writei(This->pcm, This->mmap_buffer, putin);
+ This->mmap_pos = done = putin;
+ }
used += done;
}
}
@@ -176,6 +196,7 @@ static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi)
const snd_pcm_channel_area_t *areas;
snd_pcm_hw_params_t *hw_params = pdbi->hw_params;
snd_pcm_sw_params_t *sw_params = pdbi->sw_params;
+ void *buf;
mmap_mode = snd_pcm_type(pcm);
@@ -218,15 +239,27 @@ static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi)
ERR("No buffer is available: %s.\n", snd_strerror(avail));
return DSERR_GENERIC;
}
- err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
- if ( err < 0 )
+
+ if (!pdbi->mmap)
{
- ERR("Can't map sound device for direct access: %s\n", snd_strerror(err));
- return DSERR_GENERIC;
+ buf = pdbi->mmap_buffer = HeapAlloc(GetProcessHeap(), 0, pdbi->mmap_buflen_bytes);
+ if (!buf)
+ return DSERR_OUTOFMEMORY;
+
+ snd_pcm_format_set_silence(format, buf, pdbi->mmap_buflen_frames);
+ }
+ else
+ {
+ err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
+ if ( err < 0 )
+ {
+ ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err);
+ return DSERR_GENERIC;
+ }
+ snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
+ pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
+ pdbi->mmap_buffer = areas->addr;
}
- snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
- pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
- pdbi->mmap_buffer = areas->addr;
TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);
@@ -274,6 +307,8 @@ static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
This->pcm = NULL;
HeapFree(GetProcessHeap(), 0, This->sw_params);
HeapFree(GetProcessHeap(), 0, This->hw_params);
+ if (!This->mmap)
+ HeapFree(GetProcessHeap(), 0, This->mmap_buffer);
HeapFree(GetProcessHeap(), 0, This);
return 0;
}
@@ -305,7 +340,7 @@ static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
if (ppvAudio2) *ppvAudio2 = NULL;
if (pdwLen2) *pdwLen2 = 0;
- *ppvAudio1 = (LPBYTE)This->mmap_buffer + dwWritePosition;
+ *ppvAudio1 = This->mmap_buffer + dwWritePosition;
*pdwLen1 = dwWriteLen;
if (dwWritePosition+dwWriteLen > This->mmap_buflen_bytes)
@@ -327,7 +362,8 @@ static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t writelen = snd_pcm_bytes_to_frames(This->pcm, dwWriteLen), putin = writelen;
TRACE("Hit mmap_pos, locking data!\n");
- snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
+ if (This->mmap)
+ snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
}
else
WARN("mmap_pos (%lu) != writepos (%lu) not locking data!\n", This->mmap_pos, writepos);
@@ -356,14 +392,40 @@ static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t writelen = snd_pcm_bytes_to_frames(This->pcm, dwLen1);
TRACE("Committing data\n");
- This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
+ if (This->mmap)
+ This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
+ else
+ {
+ int ret;
+ ret = snd_pcm_writei(This->pcm, pvAudio1, writelen);
+ if (ret == -EPIPE)
+ {
+ WARN("Underrun occured\n");
+ snd_pcm_prepare(This->pcm);
+ ret = snd_pcm_writei(This->pcm, pvAudio1, writelen);
+ snd_pcm_start(This->pcm);
+ }
+ if (ret < 0)
+ WARN("Committing data: %d / %s (%p %ld)\n", ret, snd_strerror(ret), pvAudio1, writelen);
+ This->mmap_pos += writelen;
+ }
+
if (This->mmap_pos == This->mmap_buflen_frames)
This->mmap_pos = 0;
if (!This->mmap_pos && dwLen2)
{
writelen = snd_pcm_bytes_to_frames(This->pcm, dwLen2);
- snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &writelen);
- This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
+ if (This->mmap)
+ {
+ snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &writelen);
+ This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
+ }
+ else
+ {
+ int ret;
+ ret = snd_pcm_writei(This->pcm, pvAudio2, writelen);
+ This->mmap_pos = writelen;
+ }
assert(This->mmap_pos < This->mmap_buflen_frames);
}
}
@@ -442,13 +504,30 @@ static HRESULT SetFormat(IDsDriverBufferImpl *This, LPWAVEFORMATEX pwfx)
snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, NULL);
buffer_time = 10000;
snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &buffer_time, NULL);
+
+ err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
+ buffer_time = 16;
+ snd_pcm_hw_params_set_periods_near(pcm, hw_params, &buffer_time, NULL);
+
+ if (!This->mmap)
+ {
+ HeapFree(GetProcessHeap(), 0, This->mmap_buffer);
+ This->mmap_buffer = NULL;
+ }
+
+ err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (err >= 0)
+ This->mmap = 1;
+ else
+ {
+ This->mmap = 0;
+ err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ }
+
err = snd_pcm_hw_params(pcm, hw_params);
err = snd_pcm_sw_params(pcm, This->sw_params);
snd_pcm_prepare(pcm);
- err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
- TRACE("Period size is: %lu\n", psize);
-
/* ALSA needs at least 3 buffers to work successfully */
This->mmap_commitahead = 3 * psize;
while (This->mmap_commitahead <= 512)
@@ -553,9 +632,13 @@ static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
if (used < 0)
{
- This->mmap_pos += -used;
- snd_pcm_forward(This->pcm, -used);
- This->mmap_pos %= This->mmap_buflen_frames;
+ WARN("Underrun: %ld / %ld\n", used, snd_pcm_avail_update(This->pcm));
+ if (This->mmap)
+ {
+ snd_pcm_forward(This->pcm, -used);
+ This->mmap_pos += -used;
+ This->mmap_pos %= This->mmap_buflen_frames;
+ }
used = 0;
}
@@ -609,10 +692,19 @@ static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
snd_pcm_drop(This->pcm);
snd_pcm_prepare(This->pcm);
avail = snd_pcm_avail_update(This->pcm);
- snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &avail);
snd_pcm_hw_params_get_format(This->hw_params, &format);
- snd_pcm_format_set_silence(format, areas->addr, This->mmap_buflen_frames);
- snd_pcm_mmap_commit(This->pcm, This->mmap_pos, 0);
+ if (This->mmap)
+ {
+ snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &avail);
+ snd_pcm_format_set_silence(format, areas->addr, This->mmap_buflen_frames);
+ snd_pcm_mmap_commit(This->pcm, This->mmap_pos, 0);
+ }
+ else
+ {
+ snd_pcm_format_set_silence(format, This->mmap_buffer, This->mmap_buflen_frames);
+ snd_pcm_writei(This->pcm, This->mmap_buffer, This->mmap_buflen_frames);
+ This->mmap_pos = 0;
+ }
/* **** */
LeaveCriticalSection(&This->pcm_crst);
@@ -710,6 +802,8 @@ static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
err = snd_pcm_hw_params_any(pcm, hw_params);
if (err < 0) goto err;
err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (err < 0)
+ err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) goto err;
TRACE("Success\n");
@@ -833,13 +927,6 @@ DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
TRACE("driver created\n");
- /* the HAL isn't much better than the HEL if we can't do mmap() */
- if (!(WOutDev[wDevID].outcaps.dwSupport & WAVECAPS_DIRECTSOUND))
- {
- WARN("MMAP not supported for this device, falling back to waveout, should be harmless\n");
- return MMSYSERR_NOTSUPPORTED;
- }
-
*idrv = HeapAlloc(GetProcessHeap(),0,sizeof(IDsDriverImpl));
if (!*idrv)
return MMSYSERR_NOMEM;
--
1.6.3.3
--------------070807070102080100000409--
More information about the wine-patches
mailing list