summaryrefslogtreecommitdiffstats
path: root/audio/audio_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/audio_hw.c')
-rw-r--r--audio/audio_hw.c142
1 files changed, 130 insertions, 12 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index c9d5018..e267d4c 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -106,7 +106,7 @@ struct pcm_config pcm_config_mm = {
struct pcm_config pcm_config_vx = {
.channels = 1,
.rate = 8000,
- .period_size = 256,
+ .period_size = 160,
.period_count = 2,
.format = PCM_FORMAT_S16_LE,
};
@@ -301,7 +301,7 @@ struct route_setting headset_vx[] = {
},
};
-struct route_setting modem[] = {
+struct route_setting amic_vx[] = {
{
.ctl_name = MIXER_MUX_VX0,
.strval = MIXER_AMIC0,
@@ -350,7 +350,16 @@ struct tuna_stream_out {
struct tuna_stream_in {
struct audio_stream_in stream;
+ pthread_mutex_t lock;
+ struct pcm_config config;
struct pcm *pcm;
+ SpeexResamplerState *speex;
+ char *buffer;
+ unsigned int requested_rate;
+ int port;
+ int standby;
+
+ struct tuna_audio_device *dev;
};
/* The enable flag when 0 makes the assumption that enums are disabled by
@@ -439,7 +448,7 @@ static void select_mode(struct tuna_audio_device *adev)
{
if (adev->mode == AUDIO_MODE_IN_CALL) {
if (!adev->in_call) {
- set_route_by_array(adev->mixer, modem, 1);
+ set_route_by_array(adev->mixer, amic_vx, 1);
/* force headset voice route otherwise microphone
does not function */
set_route_by_array(adev->mixer, headset_vx, 1);
@@ -450,7 +459,7 @@ static void select_mode(struct tuna_audio_device *adev)
if (adev->in_call) {
adev->in_call = 0;
end_call(adev);
- set_route_by_array(adev->mixer, modem, 0);
+ set_route_by_array(adev->mixer, amic_vx, 0);
}
}
}
@@ -630,9 +639,46 @@ static int out_get_render_position(const struct audio_stream_out *stream,
}
/** audio_stream_in implementation **/
+static int start_input_stream(struct tuna_stream_in *in)
+{
+ int ret = 0;
+ struct tuna_audio_device *adev = in->dev;
+
+ set_route_by_array(adev->mixer, amic_vx, 1);
+ /* force headset voice route otherwise microphone
+ does not function */
+ set_route_by_array(adev->mixer, headset_vx, 1);
+
+ /* this assumes routing is done previously */
+ in->pcm = pcm_open(0, in->port, PCM_IN, &in->config);
+ if (!pcm_is_ready(in->pcm)) {
+ LOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ return -ENOMEM;
+ }
+
+ /* if no supported sample rate is available, use the resampler */
+ if (in->requested_rate != in->config.rate) {
+ in->speex = speex_resampler_init(in->config.channels, in->config.rate,
+ in->requested_rate,
+ SPEEX_RESAMPLER_QUALITY_DEFAULT,
+ &ret);
+ speex_resampler_reset_mem(in->speex);
+ /* todo: allow for reallocing */
+ in->buffer = malloc(RESAMPLER_BUFFER_SIZE);
+ if(!in->buffer) {
+ pcm_close(in->pcm);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
static uint32_t in_get_sample_rate(const struct audio_stream *stream)
{
- return 8000;
+ struct tuna_stream_in *in = (struct tuna_stream_in *)stream;
+
+ return in->requested_rate;
}
static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
@@ -642,7 +688,20 @@ static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
static size_t in_get_buffer_size(const struct audio_stream *stream)
{
- return 320;
+ struct tuna_stream_in *in = (struct tuna_stream_in *)stream;
+ size_t size;
+
+ /* return the number of bytes per period */
+ pthread_mutex_lock(&in->lock);
+ if (in->pcm)
+ size = (size_t)pcm_get_buffer_size(in->pcm) *
+ audio_stream_frame_size((struct audio_stream*)stream) /
+ in->config.period_count;
+ else
+ size = 0;
+ pthread_mutex_unlock(&in->lock);
+
+ return size;
}
static uint32_t in_get_channels(const struct audio_stream *stream)
@@ -662,6 +721,19 @@ static int in_set_format(struct audio_stream *stream, int format)
static int in_standby(struct audio_stream *stream)
{
+ struct tuna_stream_in *in = (struct tuna_stream_in *)stream;
+
+ pthread_mutex_lock(&in->lock);
+ if (!in->standby) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ if (in->buffer)
+ free(in->buffer);
+ if (in->speex)
+ speex_resampler_destroy(in->speex);
+ in->standby = 1;
+ }
+ pthread_mutex_unlock(&in->lock);
return 0;
}
@@ -689,9 +761,27 @@ static int in_set_gain(struct audio_stream_in *stream, float gain)
static ssize_t 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) /
- in_get_sample_rate(&stream->common));
+ int ret = 0;
+ struct tuna_stream_in *in = (struct tuna_stream_in *)stream;
+ struct tuna_audio_device *adev = in->dev;
+
+ pthread_mutex_lock(&in->lock);
+ if (in->standby) {
+ ret = start_input_stream(in);
+ if (ret == 0)
+ in->standby = 0;
+ }
+
+ if (ret == 0)
+ ret = pcm_read(in->pcm, buffer, bytes);
+
+ /* TODO: enable resample */
+
+ if (ret < 0)
+ usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
+ in_get_sample_rate(&stream->common));
+
+ pthread_mutex_unlock(&in->lock);
return bytes;
}
@@ -836,7 +926,7 @@ static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
}
static int adev_open_input_stream(struct audio_hw_device *dev, uint32_t devices,
- int *format, uint32_t *channels,
+ int *format, uint32_t *channel_mask,
uint32_t *sample_rate,
audio_in_acoustics_t acoustics,
struct audio_stream_in **stream_in)
@@ -863,18 +953,46 @@ static int adev_open_input_stream(struct audio_hw_device *dev, uint32_t devices,
in->stream.read = in_read;
in->stream.get_input_frames_lost = in_get_input_frames_lost;
+ in->requested_rate = *sample_rate;
+ in->config.channels = popcount(*channel_mask);
+ if ((in->config.channels) > 2 || (in->requested_rate == 0)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (in->requested_rate <= 8000) {
+ in->port = PORT_VX;
+ memcpy(&in->config, &pcm_config_vx, sizeof(pcm_config_vx));
+ in->config.rate = 8000;
+ } else if (in->requested_rate <= 16000) {
+ in->port = PORT_VX; /* use voice uplink */
+ memcpy(&in->config, &pcm_config_vx, sizeof(pcm_config_vx));
+ in->config.rate = 16000;
+ } else {
+ in->port = PORT_MM; /* use multimedia uplink */
+ memcpy(&in->config, &pcm_config_mm, sizeof(pcm_config_mm));
+ in->config.rate = 48000;
+ }
+
+ in->dev = ladev;
+ in->standby = !!start_input_stream(in);
+
*stream_in = &in->stream;
return 0;
-err_open:
+err:
free(in);
*stream_in = NULL;
return ret;
}
static void adev_close_input_stream(struct audio_hw_device *dev,
- struct audio_stream_in *in)
+ struct audio_stream_in *stream)
{
+ struct tuna_stream_in *in = (struct tuna_stream_in *)stream;
+
+ in_standby(&stream->common);
+ free(stream);
return;
}