From 3df839e5300e148d1fd4f6c4fc93012071b9380b Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Sat, 13 Oct 2012 14:47:43 +0200 Subject: Output: Implement routing and write Signed-off-by: Paul Kocialkowski --- audio_hw.h | 10 ++++ audio_out.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 154 insertions(+), 6 deletions(-) diff --git a/audio_hw.h b/audio_hw.h index cc7f963..555ee0b 100644 --- a/audio_hw.h +++ b/audio_hw.h @@ -31,6 +31,11 @@ struct tinyalsa_audio_stream_out { int rate; audio_channels_t channels; audio_format_t format; + + audio_devices_t device_current; + + struct pcm *pcm; + int standby; }; struct tinyalsa_audio_stream_in { @@ -42,6 +47,11 @@ struct tinyalsa_audio_stream_in { int rate; audio_channels_t channels; audio_format_t format; + + audio_devices_t device_current; + + struct pcm *pcm; + int standby; }; struct tinyalsa_audio_device { diff --git a/audio_out.c b/audio_out.c index e55190a..c5621ba 100644 --- a/audio_out.c +++ b/audio_out.c @@ -25,6 +25,7 @@ #include #include +#include #include #define EFFECT_UUID_NULL EFFECT_UUID_NULL_OUT @@ -36,6 +37,49 @@ * Functions */ +int audio_out_pcm_open(struct tinyalsa_audio_stream_out *stream_out) +{ + struct pcm *pcm = NULL; + struct pcm_config pcm_config; + + memset(&pcm_config, 0, sizeof(pcm_config)); + pcm_config.channels = popcount(stream_out->mixer_props->channels); + pcm_config.rate = stream_out->mixer_props->rate; + switch(stream_out->mixer_props->format) { + case AUDIO_FORMAT_PCM_16_BIT: + pcm_config.format = PCM_FORMAT_S16_LE; + break; + case AUDIO_FORMAT_PCM_32_BIT: + pcm_config.format = PCM_FORMAT_S32_LE; + break; + default: + LOGE("Invalid format: 0x%x", stream_out->mixer_props->format); + return -1; + } + pcm_config.period_size = stream_out->mixer_props->period_size; + pcm_config.period_count = stream_out->mixer_props->period_count; + + pcm = pcm_open(stream_out->mixer_props->card, + stream_out->mixer_props->device, PCM_OUT, &pcm_config); + + if(!pcm || !pcm_is_ready(pcm)) { + LOGE("Unable to open pcm device: %s", pcm_get_error(pcm)); + return -1; + } + + stream_out->pcm = pcm; + + return 0; +} + +void audio_out_pcm_close(struct tinyalsa_audio_stream_out *stream_out) +{ + if(stream_out->pcm != NULL) { + pcm_close(stream_out->pcm); + stream_out->pcm = NULL; + } +} + static uint32_t audio_out_get_sample_rate(const struct audio_stream *stream) { struct tinyalsa_audio_stream_out *stream_out; @@ -126,8 +170,20 @@ static int audio_out_set_format(struct audio_stream *stream, int format) static int audio_out_standby(struct audio_stream *stream) { + struct tinyalsa_audio_stream_out *stream_out; + LOGD("%s(%p)", __func__, stream); + if(stream == NULL) + return -1; + + stream_out = (struct tinyalsa_audio_stream_out *) stream; + + if(stream_out->pcm != NULL) + audio_out_pcm_close(stream_out); + + stream_out->standby = 1; + return 0; } @@ -140,12 +196,49 @@ static int audio_out_dump(const struct audio_stream *stream, int fd) static int audio_out_set_parameters(struct audio_stream *stream, const char *kvpairs) { + struct tinyalsa_audio_stream_out *stream_out; + struct str_parms *parms; + char value_string[32] = { 0 }; + int value; + int rc; + LOGD("%s(%p, %s)", __func__, stream, kvpairs); + if(stream == NULL || kvpairs == NULL) + return -1; + + stream_out = (struct tinyalsa_audio_stream_out *) stream; + + if(stream_out->device->mixer == NULL) + return -1; + + parms = str_parms_create_str(kvpairs); + if(parms == NULL) + return -1; + + rc = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value_string, sizeof(value_string)); + if(rc < 0) + goto error_params; + + value = atoi(value_string); + + if(stream_out->device_current != (audio_devices_t) value) { + stream_out->device_current = (audio_devices_t) value; + tinyalsa_mixer_set_route(stream_out->device->mixer, + stream_out->device_current, stream_out->device->mode); + } + + str_parms_destroy(parms); + return 0; + +error_params: + str_parms_destroy(parms); + + return -1; } -static char * audio_out_get_parameters(const struct audio_stream *stream, const char *keys) +static char *audio_out_get_parameters(const struct audio_stream *stream, const char *keys) { LOGD("%s(%p, %s)", __func__, stream, keys); @@ -177,9 +270,8 @@ static int audio_out_set_volume(struct audio_stream_out *stream, float left, volume = (left + right) / 2; - // FIXME: Select the device tinyalsa_mixer_set_output_volume(stream_out->device->mixer, - AUDIO_DEVICE_IN_DEFAULT, stream_out->device->mode, volume); + stream_out->device_current, stream_out->device->mode, volume); return 0; } @@ -187,9 +279,35 @@ static int audio_out_set_volume(struct audio_stream_out *stream, float left, static ssize_t audio_out_write(struct audio_stream_out *stream, const void *buffer, size_t bytes) { - /* XXX: fake timing for audio output */ - usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / - audio_out_get_sample_rate(&stream->common)); + struct tinyalsa_audio_stream_out *stream_out; + int rc; + + if(stream == NULL || buffer == NULL || bytes <= 0) + return -1; + + stream_out = (struct tinyalsa_audio_stream_out *) stream; + + if(stream_out->standby) { + rc = audio_out_pcm_open(stream_out); + if(rc < 0) { + LOGE("Unable to open pcm device"); + return -1; + } + + stream_out->standby = 0; + } + + if(stream_out->pcm == NULL || pcm_is_ready(stream_out->pcm)) { + LOGE("pcm device is not ready"); + return -1; + } + + rc = pcm_write(stream_out->pcm, (void *) buffer, (int) bytes); + if(rc != 0) { + LOGE("pcm write failed!"); + return -1; + } + return bytes; } @@ -235,6 +353,7 @@ int audio_hw_open_output_stream(struct audio_hw_device *dev, struct tinyalsa_audio_device *tinyalsa_audio_device; struct tinyalsa_audio_stream_out *tinyalsa_audio_stream_out; struct audio_stream_out *stream; + int rc; LOGD("%s(%p, %d, %p, %p, %p, %p)", __func__, dev, devices, format, channels, sample_rate, stream_out); @@ -284,6 +403,25 @@ int audio_hw_open_output_stream(struct audio_hw_device *dev, tinyalsa_audio_stream_out->format = tinyalsa_audio_stream_out->mixer_props->format; + *sample_rate = (uint32_t) tinyalsa_audio_stream_out->rate; + *channels = (uint32_t) tinyalsa_audio_stream_out->channels; + *format = (uint32_t) tinyalsa_audio_stream_out->format; + + tinyalsa_audio_stream_out->device_current = devices; + tinyalsa_mixer_set_route(tinyalsa_audio_stream_out->device->mixer, + tinyalsa_audio_stream_out->device_current, + tinyalsa_audio_stream_out->device->mode); + + rc = audio_out_pcm_open(tinyalsa_audio_stream_out); + if(rc < 0) { + LOGE("Unable to open pcm device"); + goto error_stream; + } + + audio_out_pcm_close(tinyalsa_audio_stream_out); + + tinyalsa_audio_stream_out->standby = 1; + *stream_out = stream; return 0; -- cgit v1.1