diff options
author | Chris Robinson <[email protected]> | 2012-03-05 07:11:09 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2012-03-05 07:11:09 -0800 |
commit | fe6e532c876bf3ec6776f76f9542038ac9c94d68 (patch) | |
tree | 31d29eb21462dbc02287030d8e3b6174dcab92cc /Alc/backends/alsa.c | |
parent | 5cdeeb47f3b4dedefd1ceb2b32c2f7754abc058d (diff) |
Use a separate backend callback to start playback of the device
This allows us to properly update the ALCdevice and its resources with the new
parameters before starting playback, instead of expecting the mixer to block
and wait after it has begun.
This also lets us avoid holding the device lock while resetting and starting
the device, which helps prevent lock inversion on some backends (ie, one thread
locking A then B, and another thread locking B then A), ultimately allowing
certain backends to asynchronously update the ALCdevice without risk of lockup.
Capture still has issues here, however.
Diffstat (limited to 'Alc/backends/alsa.c')
-rw-r--r-- | Alc/backends/alsa.c | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index a9f34491..fa5ef1a6 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -44,6 +44,7 @@ MAKE_FUNC(snd_pcm_bytes_to_frames); MAKE_FUNC(snd_pcm_hw_params_malloc); MAKE_FUNC(snd_pcm_hw_params_free); MAKE_FUNC(snd_pcm_hw_params_any); +MAKE_FUNC(snd_pcm_hw_params_current); MAKE_FUNC(snd_pcm_hw_params_set_access); MAKE_FUNC(snd_pcm_hw_params_set_format); MAKE_FUNC(snd_pcm_hw_params_set_channels); @@ -111,6 +112,7 @@ MAKE_FUNC(snd_card_next); #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc #define snd_pcm_hw_params_free psnd_pcm_hw_params_free #define snd_pcm_hw_params_any psnd_pcm_hw_params_any +#define snd_pcm_hw_params_current psnd_pcm_hw_params_current #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels @@ -196,6 +198,7 @@ static ALCboolean alsa_load(void) LOAD_FUNC(snd_pcm_hw_params_malloc); LOAD_FUNC(snd_pcm_hw_params_free); LOAD_FUNC(snd_pcm_hw_params_any); + LOAD_FUNC(snd_pcm_hw_params_current); LOAD_FUNC(snd_pcm_hw_params_set_access); LOAD_FUNC(snd_pcm_hw_params_set_format); LOAD_FUNC(snd_pcm_hw_params_set_channels); @@ -647,7 +650,6 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) int allowmmap; int err; - format = -1; switch(device->FmtType) { @@ -770,23 +772,52 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) snd_pcm_sw_params_free(sp); sp = NULL; + /* Increase periods by one, since the temp buffer counts as an extra + * period */ + if(access == SND_PCM_ACCESS_RW_INTERLEAVED) + device->NumUpdates = periods+1; + else + device->NumUpdates = periods; + device->UpdateSize = periodSizeInFrames; device->Frequency = rate; + SetDefaultChannelOrder(device); - data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + if(sp) snd_pcm_sw_params_free(sp); + return ALC_FALSE; +} + +static ALCboolean alsa_start_playback(ALCdevice *device) +{ + alsa_data *data = (alsa_data*)device->ExtraData; + snd_pcm_hw_params_t *hp = NULL; + snd_pcm_access_t access; + const char *funcerr; + int err; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = NULL; + + data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - /* Increase periods by one, since the temp buffer counts as an extra - * period */ - periods++; data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); return ALC_FALSE; } - device->UpdateSize = periodSizeInFrames; - device->NumUpdates = periods; data->thread = StartThread(ALSANoMMapProc, device); } else @@ -797,8 +828,6 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } - device->UpdateSize = periodSizeInFrames; - device->NumUpdates = periods; data->thread = StartThread(ALSAProc, device); } if(data->thread == NULL) @@ -814,7 +843,6 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); - if(sp) snd_pcm_sw_params_free(sp); return ALC_FALSE; } @@ -1186,6 +1214,7 @@ static const BackendFuncs alsa_funcs = { alsa_open_playback, alsa_close_playback, alsa_reset_playback, + alsa_start_playback, alsa_stop_playback, alsa_open_capture, alsa_close_capture, |