ALSA: better pause/unpause behavior

This commit is contained in:
Andrew Kelley 2015-09-01 14:43:50 -07:00
parent afdb8b7feb
commit fe4a04d93c
6 changed files with 51 additions and 12 deletions

View file

@ -229,8 +229,24 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
for (;;) for (;;) {
soundio_wait_events(soundio); soundio_flush_events(soundio);
int c = getc(stdin);
if (c == 'p') {
fprintf(stderr, "pausing result: %s\n",
soundio_strerror(soundio_outstream_pause(outstream, true)));
} else if (c == 'u') {
fprintf(stderr, "unpausing result: %s\n",
soundio_strerror(soundio_outstream_pause(outstream, false)));
} else if (c == 'c') {
fprintf(stderr, "clear buffer result: %s\n",
soundio_strerror(soundio_outstream_clear_buffer(outstream)));
} else if (c == '\r' || c == '\n') {
// ignore
} else {
fprintf(stderr, "Unrecognized command: %c\n", c);
}
}
soundio_outstream_destroy(outstream); soundio_outstream_destroy(outstream);
soundio_device_unref(device); soundio_device_unref(device);

View file

@ -972,23 +972,30 @@ SOUNDIO_EXPORT int soundio_outstream_begin_write(struct SoundIoOutStream *outstr
SOUNDIO_EXPORT int soundio_outstream_end_write(struct SoundIoOutStream *outstream); SOUNDIO_EXPORT int soundio_outstream_end_write(struct SoundIoOutStream *outstream);
/// Clears the output stream buffer. /// Clears the output stream buffer.
/// You must call this function only from the SoundIoOutStream::write_callback thread context. /// This function can be called from any thread.
/// Some backends do not support clearing the buffer. On these backends this
/// function will return SoundIoErrorIncompatibleBackend.
/// Possible errors: /// Possible errors:
/// ///
/// * #SoundIoErrorStreaming /// * #SoundIoErrorStreaming
/// * #SoundIoErrorIncompatibleBackend
SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream); SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
/// If the underyling device supports pausing, this pauses the stream and /// If the underlying device supports pausing, this pauses the stream.
/// prevents SoundIoOutStream::write_callback from being called. Otherwise this returns /// SoundIoOutStream::write_callback may be called a few more times if the
/// #SoundIoErrorIncompatibleDevice. /// buffer is not full.
/// You must call this function only from the SoundIoOutStream::write_callback thread context. /// Pausing might put the hardware into a low power state which is ideal if your
/// software is silent for some time.
/// This function may be called any thread.
/// Pausing when already paused or unpausing when already unpaused has no /// Pausing when already paused or unpausing when already unpaused has no
/// effect and always returns SoundIoErrorNone. /// effect and always returns SoundIoErrorNone.
/// ///
/// Possible errors: /// Possible errors:
/// * #SoundIoErrorBackendDisconnected /// * #SoundIoErrorBackendDisconnected
/// * #SoundIoErrorStreaming /// * #SoundIoErrorStreaming
/// * #SoundIoErrorIncompatibleDevice - device does not support pausing/unpausing /// * #SoundIoErrorIncompatibleDevice - device does not support
/// pausing/unpausing. This error code might not be returned even if the
/// device does not support pausing/unpausing.
SOUNDIO_EXPORT int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause); SOUNDIO_EXPORT int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause);

View file

@ -1054,6 +1054,7 @@ void outstream_thread_run(void *arg) {
continue; continue;
} }
case SND_PCM_STATE_RUNNING: case SND_PCM_STATE_RUNNING:
case SND_PCM_STATE_PAUSED:
{ {
if ((err = outstream_wait_for_poll(os)) < 0) { if ((err = outstream_wait_for_poll(os)) < 0) {
if (!osa->thread_exit_flag.test_and_set()) if (!osa->thread_exit_flag.test_and_set())
@ -1090,7 +1091,6 @@ void outstream_thread_run(void *arg) {
continue; continue;
case SND_PCM_STATE_OPEN: case SND_PCM_STATE_OPEN:
case SND_PCM_STATE_DRAINING: case SND_PCM_STATE_DRAINING:
case SND_PCM_STATE_PAUSED:
case SND_PCM_STATE_DISCONNECTED: case SND_PCM_STATE_DISCONNECTED:
outstream->error_callback(outstream, SoundIoErrorStreaming); outstream->error_callback(outstream, SoundIoErrorStreaming);
return; return;
@ -1437,9 +1437,17 @@ static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) { static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
if (osa->is_paused == pause)
return 0;
int err; int err;
if ((err = snd_pcm_pause(osa->handle, pause)) < 0) if ((err = snd_pcm_pause(osa->handle, pause)) < 0) {
fprintf(stderr, "alsa pause result: %s\n", snd_strerror(err));
return SoundIoErrorIncompatibleDevice; return SoundIoErrorIncompatibleDevice;
}
osa->is_paused = pause;
return 0; return 0;
} }
@ -1701,9 +1709,15 @@ static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) { static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa; SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (isa->is_paused == pause)
return 0;
int err; int err;
if ((err = snd_pcm_pause(isa->handle, pause)) < 0) if ((err = snd_pcm_pause(isa->handle, pause)) < 0)
return SoundIoErrorIncompatibleDevice; return SoundIoErrorIncompatibleDevice;
isa->is_paused = pause;
return 0; return 0;
} }

View file

@ -58,6 +58,7 @@ struct SoundIoOutStreamAlsa {
atomic_flag thread_exit_flag; atomic_flag thread_exit_flag;
int period_size; int period_size;
int write_frame_count; int write_frame_count;
bool is_paused;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };
@ -75,6 +76,7 @@ struct SoundIoInStreamAlsa {
atomic_flag thread_exit_flag; atomic_flag thread_exit_flag;
int period_size; int period_size;
int read_frame_count; int read_frame_count;
bool is_paused;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };

View file

@ -1049,7 +1049,7 @@ static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutSt
} }
static int outstream_clear_buffer_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_clear_buffer_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
return 0; return SoundIoErrorIncompatibleBackend;
} }

View file

@ -561,7 +561,7 @@ static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOut
} }
static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
return 0; return SoundIoErrorIncompatibleBackend;
} }