summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2012-10-20 19:06:23 +0200
committerPaul Kocialkowski <contact@paulk.fr>2012-10-20 19:06:23 +0200
commite61d5db12e477a2de085894f4bb9e5c4514d6ee8 (patch)
tree7a8715a7e04d3b5ded386f5c4c4321628be40fc1
parentbcc4da353afc37a6b9b4d65e43ff1876fd10bb3e (diff)
downloadhardware_tinyalsa-audio-e61d5db12e477a2de085894f4bb9e5c4514d6ee8.tar.gz
hardware_tinyalsa-audio-e61d5db12e477a2de085894f4bb9e5c4514d6ee8.tar.bz2
hardware_tinyalsa-audio-e61d5db12e477a2de085894f4bb9e5c4514d6ee8.zip
Input: Implement routing and read
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
-rw-r--r--audio_in.c287
1 files 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 <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <sys/time.h>
+#include <cutils/str_parms.h>
#include <cutils/log.h>
#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;
}