ALSA driver improvements:
* alsa hotplug thread is low priority * give a chance for other threads to catch up when audio playback is not progressing * use nonblocking for alsa audio capture There is a bug with SDL hanging when an audio capture USB device is removed, because poll never returns
parent
c4d54504fa
commit
6814f5dbc0
|
@ -364,6 +364,13 @@ ALSA_PlayDevice(_THIS)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (status == 0) {
|
||||||
|
/* No frames were written (no available space in pcm device).
|
||||||
|
Allow other threads to catch up. */
|
||||||
|
Uint32 delay = (frames_left / 2 * 1000) / this->spec.freq;
|
||||||
|
SDL_Delay(delay);
|
||||||
|
}
|
||||||
|
|
||||||
sample_buf += status * frame_size;
|
sample_buf += status * frame_size;
|
||||||
frames_left -= status;
|
frames_left -= status;
|
||||||
}
|
}
|
||||||
|
@ -383,23 +390,22 @@ ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
this->spec.channels;
|
this->spec.channels;
|
||||||
const int total_frames = buflen / frame_size;
|
const int total_frames = buflen / frame_size;
|
||||||
snd_pcm_uframes_t frames_left = total_frames;
|
snd_pcm_uframes_t frames_left = total_frames;
|
||||||
|
snd_pcm_uframes_t wait_time = frame_size / 2;
|
||||||
|
|
||||||
SDL_assert((buflen % frame_size) == 0);
|
SDL_assert((buflen % frame_size) == 0);
|
||||||
|
|
||||||
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
|
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
|
||||||
/* !!! FIXME: This works, but needs more testing before going live */
|
int status;
|
||||||
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
|
|
||||||
int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
|
status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
|
||||||
sample_buf, frames_left);
|
sample_buf, frames_left);
|
||||||
|
|
||||||
if (status < 0) {
|
|
||||||
/*printf("ALSA: capture error %d\n", status);*/
|
|
||||||
if (status == -EAGAIN) {
|
if (status == -EAGAIN) {
|
||||||
/* Apparently snd_pcm_recover() doesn't handle this case -
|
ALSA_snd_pcm_wait(this->hidden->pcm_handle, wait_time);
|
||||||
does it assume snd_pcm_wait() above? */
|
status = 0;
|
||||||
SDL_Delay(1);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else if (status < 0) {
|
||||||
|
/*printf("ALSA: capture error %d\n", status);*/
|
||||||
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
|
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
/* Hmm, not much we can do - abort */
|
/* Hmm, not much we can do - abort */
|
||||||
|
@ -745,8 +751,9 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Switch to blocking mode for playback */
|
if (!iscapture) {
|
||||||
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* We're ready to rock and roll. :-) */
|
/* We're ready to rock and roll. :-) */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -763,16 +770,26 @@ static void
|
||||||
add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
|
add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
|
||||||
{
|
{
|
||||||
ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
|
ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
|
||||||
char *desc = ALSA_snd_device_name_get_hint(hint, "DESC");
|
char *desc;
|
||||||
char *handle = NULL;
|
char *handle = NULL;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not all alsa devices are enumerable via snd_device_name_get_hint
|
||||||
|
(i.e. bluetooth devices). Therefore if hint is passed in to this
|
||||||
|
function as NULL, assume name contains desc.
|
||||||
|
Make sure not to free the storage associated with desc in this case */
|
||||||
|
if (hint) {
|
||||||
|
desc = ALSA_snd_device_name_get_hint(hint, "DESC");
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
SDL_free(dev);
|
SDL_free(dev);
|
||||||
return;
|
return;
|
||||||
} else if (!dev) {
|
}
|
||||||
free(desc);
|
} else {
|
||||||
return;
|
desc = (char *) name;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(name != NULL);
|
SDL_assert(name != NULL);
|
||||||
|
@ -788,14 +805,16 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
|
||||||
|
|
||||||
handle = SDL_strdup(name);
|
handle = SDL_strdup(name);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
|
if (hint) {
|
||||||
free(desc);
|
free(desc);
|
||||||
|
}
|
||||||
SDL_free(dev);
|
SDL_free(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AddAudioDevice(iscapture, desc, handle);
|
SDL_AddAudioDevice(iscapture, desc, handle);
|
||||||
|
if (hint)
|
||||||
free(desc);
|
free(desc);
|
||||||
|
|
||||||
dev->name = handle;
|
dev->name = handle;
|
||||||
dev->iscapture = iscapture;
|
dev->iscapture = iscapture;
|
||||||
dev->next = *pSeen;
|
dev->next = *pSeen;
|
||||||
|
@ -815,12 +834,15 @@ ALSA_HotplugThread(void *arg)
|
||||||
ALSA_Device *dev;
|
ALSA_Device *dev;
|
||||||
Uint32 ticks;
|
Uint32 ticks;
|
||||||
|
|
||||||
|
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
|
||||||
|
|
||||||
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
|
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
|
||||||
void **hints = NULL;
|
void **hints = NULL;
|
||||||
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) {
|
ALSA_Device *unseen;
|
||||||
ALSA_Device *unseen = devices;
|
ALSA_Device *seen;
|
||||||
ALSA_Device *seen = NULL;
|
|
||||||
ALSA_Device *prev;
|
ALSA_Device *prev;
|
||||||
|
|
||||||
|
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) {
|
||||||
int i, j;
|
int i, j;
|
||||||
const char *match = NULL;
|
const char *match = NULL;
|
||||||
int bestmatch = 0xFFFF;
|
int bestmatch = 0xFFFF;
|
||||||
|
@ -830,6 +852,8 @@ ALSA_HotplugThread(void *arg)
|
||||||
"hw:", "sysdefault:", "default:", NULL
|
"hw:", "sysdefault:", "default:", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unseen = devices;
|
||||||
|
seen = NULL;
|
||||||
/* Apparently there are several different ways that ALSA lists
|
/* Apparently there are several different ways that ALSA lists
|
||||||
actual hardware. It could be prefixed with "hw:" or "default:"
|
actual hardware. It could be prefixed with "hw:" or "default:"
|
||||||
or "sysdefault:" and maybe others. Go through the list and see
|
or "sysdefault:" and maybe others. Go through the list and see
|
||||||
|
@ -924,7 +948,7 @@ ALSA_HotplugThread(void *arg)
|
||||||
|
|
||||||
/* report anything still in unseen as removed. */
|
/* report anything still in unseen as removed. */
|
||||||
for (dev = unseen; dev; dev = next) {
|
for (dev = unseen; dev; dev = next) {
|
||||||
/*printf("ALSA: removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
|
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
|
||||||
next = dev->next;
|
next = dev->next;
|
||||||
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
|
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
|
||||||
SDL_free(dev->name);
|
SDL_free(dev->name);
|
||||||
|
|
Loading…
Reference in New Issue