From e61d5db12e477a2de085894f4bb9e5c4514d6ee8 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Sat, 20 Oct 2012 19:06:23 +0200 Subject: Input: Implement routing and read Signed-off-by: Paul Kocialkowski --- audio_in.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 276 insertions(+), 11 deletions(-) diff --git a/audio_in.c b/audio_in.c index fd3c836..8e83478 100644 --- a/audio_in.c +++ b/audio_in.c @@ -20,11 +20,13 @@ #define LOG_TAG "TinyALSA-Audio Input" +#include #include #include #include #include +#include #include #define EFFECT_UUID_NULL EFFECT_UUID_NULL_IN @@ -36,44 +38,202 @@ * Functions */ +int audio_in_pcm_open(struct tinyalsa_audio_stream_in *stream_in) +{ + struct pcm *pcm = NULL; + struct pcm_config pcm_config; + + if(stream_in == NULL) + return -1; + + memset(&pcm_config, 0, sizeof(pcm_config)); + pcm_config.channels = popcount(stream_in->mixer_props->channels); + pcm_config.rate = stream_in->mixer_props->rate; + switch(stream_in->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_in->mixer_props->format); + return -1; + } + pcm_config.period_size = stream_in->mixer_props->period_size; + pcm_config.period_count = stream_in->mixer_props->period_count; + + pcm = pcm_open(stream_in->mixer_props->card, + stream_in->mixer_props->device, PCM_IN, &pcm_config); + + if(pcm == NULL || !pcm_is_ready(pcm)) { + LOGE("Unable to open pcm device: %s", pcm_get_error(pcm)); + return -1; + } + + stream_in->pcm = pcm; + + return 0; +} + +void audio_in_pcm_close(struct tinyalsa_audio_stream_in *stream_in) +{ + if(stream_in->pcm == NULL) + return; + + pcm_close(stream_in->pcm); + stream_in->pcm = NULL; +} + +int audio_in_set_route(struct tinyalsa_audio_stream_in *stream_in, + audio_devices_t device) +{ + int rc; + + if(stream_in == NULL) + return -1; + + stream_in->device_current = device; + + if(device == 0) { + tinyalsa_mixer_set_route(stream_in->device->mixer, + AUDIO_DEVICE_IN_DEFAULT, stream_in->device->mode); + + rc = yamaha_mc1n2_audio_input_stop(stream_in->device->mc1n2_pdata); + if(rc < 0) { + LOGE("Failed to set Yamaha-MC1N2-Audio route"); + } + + stream_in->standby = 1; + + return 0; + } + + tinyalsa_mixer_set_route(stream_in->device->mixer, + stream_in->device_current, stream_in->device->mode); + +#ifdef YAMAHA_MC1N2_AUDIO + yamaha_mc1n2_audio_set_route(stream_in->device->mc1n2_pdata, device, + stream_in->device->mode); +#endif + + return 0; +} + static uint32_t audio_in_get_sample_rate(const struct audio_stream *stream) { - return 8000; + struct tinyalsa_audio_stream_in *stream_in; + + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + return stream_in->rate; } static int audio_in_set_sample_rate(struct audio_stream *stream, uint32_t rate) { + struct tinyalsa_audio_stream_in *stream_in; + LOGD("%s(%p, %d)", __func__, stream, rate); + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + // FIXME: If rate is different, change resampler + stream_in->rate = rate; + return 0; } static size_t audio_in_get_buffer_size(const struct audio_stream *stream) { - return 320; + struct tinyalsa_audio_stream_in *stream_in; + size_t size; + + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + size = (stream_in->mixer_props->period_size * stream_in->rate) / + stream_in->rate; + size = ((size + 15) / 16) * 16; + size = size * audio_stream_frame_size((struct audio_stream *) stream); + + return size; } static uint32_t audio_in_get_channels(const struct audio_stream *stream) { - return AUDIO_CHANNEL_IN_MONO; + struct tinyalsa_audio_stream_in *stream_in; + + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + return stream_in->channels; } static int audio_in_get_format(const struct audio_stream *stream) { - return AUDIO_FORMAT_PCM_16_BIT; + struct tinyalsa_audio_stream_in *stream_in; + + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + return stream_in->format; } static int audio_in_set_format(struct audio_stream *stream, int format) { + struct tinyalsa_audio_stream_in *stream_in; + LOGD("%s(%p, %d)", __func__, stream, format); + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + // FIXME: If format is different, change resampler + stream_in->format = format; + return 0; } static int audio_in_standby(struct audio_stream *stream) { + struct tinyalsa_audio_stream_in *stream_in; + int rc; + LOGD("%s(%p)", __func__, stream); + if(stream == NULL) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + if(stream_in->pcm != NULL) + audio_in_pcm_close(stream_in); + +#ifdef YAMAHA_MC1N2_AUDIO + if(!stream_in->standby) { + rc = yamaha_mc1n2_audio_input_stop(stream_in->device->mc1n2_pdata); + if(rc < 0) { + LOGE("Failed to set Yamaha-MC1N2-Audio route"); + } + } +#endif + + stream_in->standby = 1; + return 0; } @@ -86,9 +246,43 @@ static int audio_in_dump(const struct audio_stream *stream, int fd) static int audio_in_set_parameters(struct audio_stream *stream, const char *kvpairs) { + struct tinyalsa_audio_stream_in *stream_in; + 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_in = (struct tinyalsa_audio_stream_in *) stream; + + if(stream_in->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_in->device_current != (audio_devices_t) value) + audio_in_set_route(stream_in, (audio_devices_t) value); + + str_parms_destroy(parms); + return 0; + +error_params: + str_parms_destroy(parms); + + return -1; } static char *audio_in_get_parameters(const struct audio_stream *stream, @@ -113,9 +307,8 @@ static int audio_in_set_gain(struct audio_stream_in *stream, float gain) if(stream_in->device == NULL || stream_in->device->mixer == NULL) return -1; - // FIXME: Select the device tinyalsa_mixer_set_input_gain(stream_in->device->mixer, - AUDIO_DEVICE_IN_DEFAULT, stream_in->device->mode, gain); + stream_in->device_current, stream_in->device->mode, gain); return 0; } @@ -123,16 +316,50 @@ static int audio_in_set_gain(struct audio_stream_in *stream, float gain) static ssize_t audio_in_read(struct audio_stream_in *stream, void *buffer, size_t bytes) { - /* XXX: fake timing for audio input */ - usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / - audio_in_get_sample_rate(&stream->common)); + struct tinyalsa_audio_stream_in *stream_in; + int rc; + + if(stream == NULL || buffer == NULL || bytes <= 0) + return -1; + + stream_in = (struct tinyalsa_audio_stream_in *) stream; + + if(stream_in->standby) { +#ifdef YAMAHA_MC1N2_AUDIO + rc = yamaha_mc1n2_audio_input_start(stream_in->device->mc1n2_pdata); + if(rc < 0) { + LOGE("Failed to set Yamaha-MC1N2-Audio route"); + } +#endif + + rc = audio_in_pcm_open(stream_in); + if(rc < 0) { + LOGE("Unable to open pcm device"); + return -1; + } + + stream_in->standby = 0; + } + + if(stream_in->pcm == NULL || !pcm_is_ready(stream_in->pcm)) { + LOGE("pcm device is not ready"); + return -1; + } + + rc = pcm_read(stream_in->pcm, (void *) buffer, (int) bytes); + if(rc != 0) { + LOGE("pcm read failed!"); + return -1; + } + + if(stream_in->device != NULL && stream_in->device->mic_mute) + memset(buffer, 0, bytes); + return bytes; } static uint32_t audio_in_get_input_frames_lost(struct audio_stream_in *stream) { - LOGD("%s(%p)", __func__, stream); - return 0; } @@ -179,6 +406,7 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev, struct tinyalsa_audio_device *tinyalsa_audio_device; struct tinyalsa_audio_stream_in *tinyalsa_audio_stream_in; struct audio_stream_in *stream; + int rc; LOGD("%s(%p, %d, %p, %p, %p, %d, %p)", __func__, dev, devices, format, channels, sample_rate, acoustics, stream_in); @@ -211,7 +439,44 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev, stream->read = audio_in_read; stream->get_input_frames_lost = audio_in_get_input_frames_lost; + if(tinyalsa_audio_device->mixer == NULL) + goto error_stream; + + tinyalsa_audio_stream_in->mixer_props = + tinyalsa_mixer_get_input_props(tinyalsa_audio_device->mixer); + + if(tinyalsa_audio_stream_in->mixer_props == NULL) + goto error_stream; + + tinyalsa_audio_stream_in->rate = + tinyalsa_audio_stream_in->mixer_props->rate; + tinyalsa_audio_stream_in->channels = + tinyalsa_audio_stream_in->mixer_props->channels; + tinyalsa_audio_stream_in->format = + tinyalsa_audio_stream_in->mixer_props->format; + + *sample_rate = (uint32_t) tinyalsa_audio_stream_in->rate; + *channels = (uint32_t) tinyalsa_audio_stream_in->channels; + *format = (uint32_t) tinyalsa_audio_stream_in->format; + + audio_in_set_route(tinyalsa_audio_stream_in, devices); + + rc = audio_in_pcm_open(tinyalsa_audio_stream_in); + if(rc < 0) { + LOGE("Unable to open pcm device"); + goto error_stream; + } + + audio_in_pcm_close(tinyalsa_audio_stream_in); + + tinyalsa_audio_stream_in->standby = 1; + *stream_in = stream; return 0; + +error_stream: + *stream_in = NULL; + + return -1; } -- cgit v1.1