summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2012-10-31 12:57:33 +0100
committerPaul Kocialkowski <contact@paulk.fr>2012-10-31 12:57:33 +0100
commitb484b2aa3ae9b8512eedac1f70a0d0a20c2ce672 (patch)
tree1976d42dbb0f77eb30d699f82208e84db5391001
parent62bffb6008aad930652d21e9a14b3a790514c5d0 (diff)
downloadhardware_tinyalsa-audio-b484b2aa3ae9b8512eedac1f70a0d0a20c2ce672.tar.gz
hardware_tinyalsa-audio-b484b2aa3ae9b8512eedac1f70a0d0a20c2ce672.tar.bz2
hardware_tinyalsa-audio-b484b2aa3ae9b8512eedac1f70a0d0a20c2ce672.zip
Output/Input: Use resampler when required
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
-rw-r--r--audio_hw.h10
-rw-r--r--audio_in.c317
-rw-r--r--audio_out.c229
3 files changed, 511 insertions, 45 deletions
diff --git a/audio_hw.h b/audio_hw.h
index c7e6d05..a06ef9b 100644
--- a/audio_hw.h
+++ b/audio_hw.h
@@ -22,6 +22,8 @@
#include <hardware/audio.h>
#include <system/audio.h>
+#include <audio_utils/resampler.h>
+
#ifdef YAMAHA_MC1N2_AUDIO
#include <yamaha-mc1n2-audio.h>
#endif
@@ -41,6 +43,8 @@ struct tinyalsa_audio_stream_out {
audio_devices_t device_current;
+ struct resampler_itfe *resampler;
+
struct pcm *pcm;
int standby;
};
@@ -50,13 +54,17 @@ struct tinyalsa_audio_stream_in {
struct tinyalsa_audio_device *device;
struct tinyalsa_mixer_io_props *mixer_props;
-
int rate;
audio_channels_t channels;
audio_format_t format;
audio_devices_t device_current;
+ struct resampler_itfe *resampler;
+ struct resampler_buffer_provider buffer_provider;
+ void *buffer;
+ int frames_left;
+
struct pcm *pcm;
int standby;
};
diff --git a/audio_in.c b/audio_in.c
index 560aa25..3933bbf 100644
--- a/audio_in.c
+++ b/audio_in.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
- *
+ *
* This is based on Galaxy Nexus audio.primary.tuna implementation:
* Copyright 2011, The Android Open-Source Project
*
@@ -31,6 +31,7 @@
#define EFFECT_UUID_NULL EFFECT_UUID_NULL_IN
#define EFFECT_UUID_NULL_STR EFFECT_UUID_NULL_STR_IN
+#include <audio_utils/resampler.h>
#include "audio_hw.h"
#include "mixer.h"
@@ -73,6 +74,9 @@ int audio_in_pcm_open(struct tinyalsa_audio_stream_in *stream_in)
stream_in->pcm = pcm;
+ if(stream_in->resampler != NULL)
+ stream_in->resampler->reset(stream_in->resampler);
+
return 0;
}
@@ -108,12 +112,239 @@ int audio_in_set_route(struct tinyalsa_audio_stream_in *stream_in,
return 0;
}
+int audio_in_resampler_open(struct tinyalsa_audio_stream_in *stream_in)
+{
+ int rc;
+
+ if(stream_in == NULL)
+ return -1;
+
+ rc = create_resampler(stream_in->mixer_props->rate,
+ stream_in->rate,
+ popcount(stream_in->mixer_props->channels),
+ RESAMPLER_QUALITY_DEFAULT,
+ &stream_in->buffer_provider,
+ &stream_in->resampler);
+ if(rc < 0 || stream_in->resampler == NULL) {
+ LOGE("Failed to create resampler");
+ return -1;
+ }
+
+ stream_in->buffer = malloc(stream_in->mixer_props->period_size *
+ popcount(stream_in->mixer_props->channels) *
+ audio_bytes_per_sample(stream_in->mixer_props->format));
+
+ return 0;
+}
+
+void audio_in_resampler_close(struct tinyalsa_audio_stream_in *stream_in)
+{
+ if(stream_in == NULL)
+ return;
+
+ if(stream_in->resampler != NULL) {
+ release_resampler(stream_in->resampler);
+ stream_in->resampler = NULL;
+ }
+
+ if(stream_in->buffer != NULL) {
+ free(stream_in->buffer);
+ stream_in->buffer = NULL;
+ }
+}
+
+int audio_in_get_next_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer *buffer)
+{
+ struct tinyalsa_audio_stream_in *stream_in;
+ int rc;
+
+ if(buffer_provider == NULL || buffer == NULL)
+ return -1;
+
+ stream_in = (struct tinyalsa_audio_stream_in *) ((void *) buffer_provider -
+ offsetof(struct tinyalsa_audio_stream_in, buffer_provider));
+
+ if(stream_in->frames_left == 0) {
+ if(stream_in->pcm == NULL || !pcm_is_ready(stream_in->pcm)) {
+ LOGE("pcm device is not ready");
+ goto error_pcm;
+ }
+
+ rc = pcm_read(stream_in->pcm, stream_in->buffer,
+ stream_in->mixer_props->period_size *
+ popcount(stream_in->mixer_props->channels) *
+ audio_bytes_per_sample(stream_in->mixer_props->format));
+ if(rc != 0) {
+ LOGE("pcm read failed!");
+ goto error_pcm;
+ }
+
+ stream_in->frames_left = stream_in->mixer_props->period_size;
+ }
+
+ buffer->frame_count = (buffer->frame_count > stream_in->frames_left) ?
+ stream_in->frames_left : buffer->frame_count;
+
+ buffer->raw = stream_in->buffer +
+ (stream_in->mixer_props->period_size - stream_in->frames_left) *
+ popcount(stream_in->mixer_props->channels) *
+ audio_bytes_per_sample(stream_in->mixer_props->format);
+
+ return 0;
+
+error_pcm:
+ buffer->raw = NULL;
+ buffer->frame_count = 0;
+ return -1;
+}
+
+void audio_in_release_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer *buffer)
+{
+ struct tinyalsa_audio_stream_in *stream_in;
+
+ if(buffer_provider == NULL || buffer == NULL)
+ return;
+
+ stream_in = (struct tinyalsa_audio_stream_in *) ((void *) buffer_provider -
+ offsetof(struct tinyalsa_audio_stream_in, buffer_provider));
+
+ stream_in->frames_left -= buffer->frame_count;
+}
+
+int audio_in_read_process(struct tinyalsa_audio_stream_in *stream_in, void *buffer, int size)
+{
+ size_t frames_out;
+
+ size_t frames_in;
+ int size_in;
+ void *buffer_in = NULL;
+
+ int frames_out_resampler;
+ int size_out_resampler;
+ void *buffer_out_resampler = NULL;
+
+ int frames_out_read;
+ int size_out_read;
+ void *buffer_out_read = NULL;
+
+ int frames_out_channels;
+ int size_out_channels;
+ void *buffer_out_channels = NULL;
+
+ int i, j;
+ int rc;
+
+ if(stream_in == NULL || buffer == NULL || size <= 0)
+ return -1;
+
+ frames_in = size / audio_stream_frame_size((struct audio_stream *) stream_in);
+
+ if(stream_in->resampler != NULL) {
+ frames_out_resampler = frames_in;
+ size_out_resampler = frames_out_resampler * popcount(stream_in->mixer_props->channels) * audio_bytes_per_sample(stream_in->mixer_props->format);
+ buffer_out_resampler = calloc(1, size_out_resampler);
+
+ frames_out = 0;
+ while(frames_out < frames_out_resampler) {
+ frames_in = frames_out_resampler - frames_out;
+ stream_in->resampler->resample_from_provider(stream_in->resampler,
+ buffer_out_resampler + (size_out_resampler / frames_out_resampler) * frames_out,
+ &frames_in);
+
+ frames_out += frames_in;
+ }
+
+ frames_in = frames_out_resampler;
+ size_in = size_out_resampler;
+ buffer_in = buffer_out_resampler;
+ } else {
+ frames_out_read = frames_in;
+ size_out_read = frames_out_read * popcount(stream_in->mixer_props->channels) * audio_bytes_per_sample(stream_in->mixer_props->format);
+ buffer_out_read = calloc(1, size_out_read);
+
+ if(stream_in->pcm == NULL || !pcm_is_ready(stream_in->pcm)) {
+ LOGE("pcm device is not ready");
+ goto error;
+ }
+
+ rc = pcm_read(stream_in->pcm, buffer_out_read, size_out_read);
+ if(rc != 0) {
+ LOGE("pcm read failed!");
+ goto error;
+ }
+
+ frames_in = frames_out_read;
+ size_in = size_out_read;
+ buffer_in = buffer_out_read;
+ }
+
+ if(buffer_in == NULL)
+ goto error;
+
+ //FIXME: This is only for PCM 16
+ if(popcount(stream_in->channels) < popcount(stream_in->mixer_props->channels)) {
+ frames_out_channels = frames_in;
+ size_out_channels = frames_out_channels * audio_stream_frame_size((struct audio_stream *) stream_in);
+ buffer_out_channels = calloc(1, size_out_channels);
+
+ int channels_count_in = popcount(stream_in->mixer_props->channels);
+ int channels_count_out = popcount(stream_in->channels);
+ int ratio = channels_count_in / channels_count_out;
+
+ int16_t *byte_in = (int16_t *) buffer_in;
+ int16_t *byte_out = (int16_t *) buffer_out_channels;
+ int16_t byte;
+
+ for(i=0 ; i < frames_out_channels * channels_count_out; i++) {
+ byte = 0;
+ for(j=0 ; j < ratio ; j++) {
+ byte += *byte_in / ratio;
+ byte_in++;
+ }
+
+ *byte_out = byte;
+ byte_out++;
+ }
+
+ frames_in = frames_out_channels;
+ size_in = size_out_channels;
+ buffer_in = buffer_out_channels;
+ } else if(popcount(stream_in->channels) != popcount(stream_in->mixer_props->channels)) {
+ LOGE("Asked for more channels than hardware can provide!");
+ goto error;
+ }
+
+ if(buffer_in != NULL)
+ memcpy(buffer, buffer_in, size);
+
+ if(buffer_out_resampler != NULL)
+ free(buffer_out_resampler);
+ if(buffer_out_read != NULL)
+ free(buffer_out_read);
+ if(buffer_out_channels != NULL)
+ free(buffer_out_channels);
+
+ return 0;
+
+error:
+ if(buffer_out_resampler != NULL)
+ free(buffer_out_resampler);
+ if(buffer_out_read != NULL)
+ free(buffer_out_read);
+ if(buffer_out_channels != NULL)
+ free(buffer_out_channels);
+
+ return -1;
+}
+
static uint32_t audio_in_get_sample_rate(const struct audio_stream *stream)
{
struct tinyalsa_audio_stream_in *stream_in;
if(stream == NULL)
- return -1;
+ return 0;
stream_in = (struct tinyalsa_audio_stream_in *) stream;
@@ -131,8 +362,16 @@ static int audio_in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
stream_in = (struct tinyalsa_audio_stream_in *) stream;
- // FIXME: If rate is different, change resampler
- stream_in->rate = rate;
+ if(stream_in->rate != (int) rate) {
+ stream_in->rate = rate;
+
+ if(stream_in->rate != stream_in->mixer_props->rate) {
+ audio_in_resampler_close(stream_in);
+ audio_in_resampler_open(stream_in);
+
+ stream_in->standby = 1;
+ }
+ }
return 0;
}
@@ -148,7 +387,7 @@ static size_t audio_in_get_buffer_size(const struct audio_stream *stream)
stream_in = (struct tinyalsa_audio_stream_in *) stream;
size = (stream_in->mixer_props->period_size * stream_in->rate) /
- stream_in->rate;
+ stream_in->mixer_props->rate;
size = ((size + 15) / 16) * 16;
size = size * audio_stream_frame_size((struct audio_stream *) stream);
@@ -190,8 +429,12 @@ static int audio_in_set_format(struct audio_stream *stream, int format)
stream_in = (struct tinyalsa_audio_stream_in *) stream;
- // FIXME: If format is different, change resampler
- stream_in->format = format;
+ if(stream_in->format != (audio_format_t) format) {
+ stream_in->format = format;
+
+ if(stream_in->format != stream_in->mixer_props->format)
+ stream_in->standby = 1;
+ }
return 0;
}
@@ -329,14 +572,9 @@ static ssize_t audio_in_read(struct audio_stream_in *stream,
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!");
+ rc = audio_in_read_process(stream_in, buffer, (int) bytes);
+ if(rc < 0) {
+ LOGE("Read and process failed!");
return -1;
}
@@ -379,6 +617,9 @@ void audio_hw_close_input_stream(struct audio_hw_device *dev,
stream_in = (struct tinyalsa_audio_stream_in *) stream;
+ if(stream_in != NULL && stream_in->resampler != NULL)
+ audio_in_resampler_close(stream_in);
+
#ifdef YAMAHA_MC1N2_AUDIO
if(stream_in != NULL && !stream_in->standby)
yamaha_mc1n2_audio_input_stop(stream_in->device->mc1n2_pdata);
@@ -409,7 +650,7 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev,
LOGD("%s(%p, %d, %p, %p, %p, %d, %p)",
__func__, dev, devices, format, channels, sample_rate, acoustics, stream_in);
- if(dev == NULL || stream_in == NULL)
+ if(dev == NULL || format == NULL || channels == NULL || sample_rate == NULL || stream_in == NULL)
return -EINVAL;
tinyalsa_audio_device = (struct tinyalsa_audio_device *) dev;
@@ -447,12 +688,42 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev,
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;
+ // Default values
+ if(tinyalsa_audio_stream_in->mixer_props->rate == 0)
+ tinyalsa_audio_stream_in->mixer_props->rate = 44100;
+ if(tinyalsa_audio_stream_in->mixer_props->channels == 0)
+ tinyalsa_audio_stream_in->mixer_props->channels = AUDIO_CHANNEL_IN_STEREO;
+ if(tinyalsa_audio_stream_in->mixer_props->format == 0)
+ tinyalsa_audio_stream_in->mixer_props->format = AUDIO_FORMAT_PCM_16_BIT;
+
+ if(*sample_rate == 0)
+ tinyalsa_audio_stream_in->rate =
+ tinyalsa_audio_stream_in->mixer_props->rate;
+ else
+ tinyalsa_audio_stream_in->rate = *sample_rate;
+ if(*channels == 0)
+ tinyalsa_audio_stream_in->channels =
+ tinyalsa_audio_stream_in->mixer_props->channels;
+ else
+ tinyalsa_audio_stream_in->channels = *channels;
+ if(*format == 0)
+ tinyalsa_audio_stream_in->format =
+ tinyalsa_audio_stream_in->mixer_props->format;
+ else
+ tinyalsa_audio_stream_in->format = *format;
+
+ tinyalsa_audio_stream_in->buffer_provider.get_next_buffer =
+ audio_in_get_next_buffer;
+ tinyalsa_audio_stream_in->buffer_provider.release_buffer =
+ audio_in_release_buffer;
+
+ if(tinyalsa_audio_stream_in->rate != tinyalsa_audio_stream_in->mixer_props->rate) {
+ rc = audio_in_resampler_open(tinyalsa_audio_stream_in);
+ if(rc < 0) {
+ LOGE("Unable to open resampler!");
+ goto error_stream;
+ }
+ }
*sample_rate = (uint32_t) tinyalsa_audio_stream_in->rate;
*channels = (uint32_t) tinyalsa_audio_stream_in->channels;
@@ -482,6 +753,8 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev,
error_stream:
*stream_in = NULL;
+ if(tinyalsa_audio_stream_in->resampler != NULL)
+ audio_in_resampler_close(tinyalsa_audio_stream_in);
free(tinyalsa_audio_stream_in);
tinyalsa_audio_device->stream_in = NULL;
diff --git a/audio_out.c b/audio_out.c
index 9b814a6..3438f53 100644
--- a/audio_out.c
+++ b/audio_out.c
@@ -35,6 +35,7 @@
#define EFFECT_UUID_NULL EFFECT_UUID_NULL_OUT
#define EFFECT_UUID_NULL_STR EFFECT_UUID_NULL_STR_OUT
+#include <audio_utils/resampler.h>
#include "audio_hw.h"
#include "mixer.h"
@@ -77,6 +78,9 @@ int audio_out_pcm_open(struct tinyalsa_audio_stream_out *stream_out)
stream_out->pcm = pcm;
+ if(stream_out->resampler != NULL)
+ stream_out->resampler->reset(stream_out->resampler);
+
return 0;
}
@@ -111,12 +115,151 @@ int audio_out_set_route(struct tinyalsa_audio_stream_out *stream_out,
return 0;
}
+int audio_out_resampler_open(struct tinyalsa_audio_stream_out *stream_out)
+{
+ int rc;
+
+ if(stream_out == NULL)
+ return -1;
+
+ rc = create_resampler(stream_out->rate,
+ stream_out->mixer_props->rate,
+ popcount(stream_out->channels),
+ RESAMPLER_QUALITY_DEFAULT,
+ NULL,
+ &stream_out->resampler);
+ if(rc < 0 || stream_out->resampler == NULL) {
+ LOGE("Failed to create resampler");
+ return -1;
+ }
+
+ return 0;
+}
+
+void audio_out_resampler_close(struct tinyalsa_audio_stream_out *stream_out)
+{
+ if(stream_out == NULL)
+ return;
+
+ if(stream_out->resampler != NULL) {
+ release_resampler(stream_out->resampler);
+ stream_out->resampler = NULL;
+ }
+}
+
+int audio_out_write_process(struct tinyalsa_audio_stream_out *stream_out, void *buffer, int size)
+{
+ size_t frames_out;
+
+ size_t frames_in;
+ int size_in;
+ void *buffer_in = NULL;
+
+ int frames_out_resampler;
+ int size_out_resampler;
+ void *buffer_out_resampler = NULL;
+
+ int frames_out_channels;
+ int size_out_channels;
+ void *buffer_out_channels = NULL;
+
+ int i, j;
+ int rc;
+
+ if(stream_out == NULL || buffer == NULL || size <= 0)
+ return -1;
+
+ frames_in = size / audio_stream_frame_size((struct audio_stream *) stream_out);
+ size_in = size;
+ buffer_in = buffer;
+
+ if(stream_out->resampler != NULL) {
+ frames_out_resampler = (frames_in * stream_out->mixer_props->rate) /
+ stream_out->rate;
+ frames_out_resampler = ((frames_out_resampler + 15) / 16) * 16;
+ size_out_resampler = frames_out_resampler * audio_stream_frame_size((struct audio_stream *) stream_out);
+ buffer_out_resampler = calloc(1, size_out_resampler);
+
+ frames_out = frames_out_resampler;
+ stream_out->resampler->resample_from_input(stream_out->resampler,
+ buffer_in, &frames_in, buffer_out_resampler, &frames_out);
+
+ frames_in = frames_out;
+ size_in = frames_out * audio_stream_frame_size((struct audio_stream *) stream_out);
+ buffer_in = buffer_out_resampler;
+ }
+
+ if(buffer_in == NULL)
+ goto error;
+
+ //FIXME: This is only for PCM 16
+ if(popcount(stream_out->mixer_props->channels) < popcount(stream_out->channels)) {
+ frames_out_channels = frames_in;
+ size_out_channels = frames_out_channels * popcount(stream_out->mixer_props->channels) * audio_bytes_per_sample(stream_out->mixer_props->format);
+ buffer_out_channels = calloc(1, size_out_channels);
+
+ int channels_count_in = popcount(stream_out->channels);
+ int channels_count_out = popcount(stream_out->mixer_props->channels);
+ int ratio = channels_count_in / channels_count_out;
+
+ int16_t *byte_in = (int16_t *) buffer_in;
+ int16_t *byte_out = (int16_t *) buffer_out_channels;
+ int16_t byte;
+
+ for(i=0 ; i < frames_out_channels * channels_count_out; i++) {
+ byte = 0;
+ for(j=0 ; j < ratio ; j++) {
+ byte += *byte_in / ratio;
+ byte_in++;
+ }
+
+ *byte_out = byte;
+ byte_out++;
+ }
+
+ frames_in = frames_out_channels;
+ size_in = size_out_channels;
+ buffer_in = buffer_out_channels;
+ } else if(popcount(stream_out->channels) != popcount(stream_out->mixer_props->channels)) {
+ LOGE("Asked for more channels than software can provide!");
+ goto error;
+ }
+
+ if(buffer_in != NULL) {
+ if(stream_out->pcm == NULL || !pcm_is_ready(stream_out->pcm)) {
+ LOGE("pcm device is not ready");
+ goto error;
+ }
+
+ rc = pcm_write(stream_out->pcm, buffer_in, size_in);
+ if(rc != 0) {
+ LOGE("pcm write failed!");
+ goto error;
+ }
+ }
+
+ if(buffer_out_resampler != NULL)
+ free(buffer_out_resampler);
+ if(buffer_out_channels != NULL)
+ free(buffer_out_channels);
+
+ return 0;
+
+error:
+ if(buffer_out_resampler != NULL)
+ free(buffer_out_resampler);
+ if(buffer_out_channels != NULL)
+ free(buffer_out_channels);
+
+ return -1;
+}
+
static uint32_t audio_out_get_sample_rate(const struct audio_stream *stream)
{
struct tinyalsa_audio_stream_out *stream_out;
if(stream == NULL)
- return -1;
+ return 0;
stream_out = (struct tinyalsa_audio_stream_out *) stream;
@@ -134,8 +277,16 @@ static int audio_out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
stream_out = (struct tinyalsa_audio_stream_out *) stream;
- // FIXME: If rate is different, change resampler
- stream_out->rate = rate;
+ if(stream_out->rate != (int) rate) {
+ stream_out->rate = rate;
+
+ if(stream_out->rate != stream_out->mixer_props->rate) {
+ audio_out_resampler_close(stream_out);
+ audio_out_resampler_open(stream_out);
+
+ stream_out->standby = 1;
+ }
+ }
return 0;
}
@@ -151,7 +302,7 @@ static size_t audio_out_get_buffer_size(const struct audio_stream *stream)
stream_out = (struct tinyalsa_audio_stream_out *) stream;
size = (stream_out->mixer_props->period_size * stream_out->rate) /
- stream_out->rate;
+ stream_out->mixer_props->rate;
size = ((size + 15) / 16) * 16;
size = size * audio_stream_frame_size((struct audio_stream *) stream);
@@ -193,8 +344,12 @@ static int audio_out_set_format(struct audio_stream *stream, int format)
stream_out = (struct tinyalsa_audio_stream_out *) stream;
- // FIXME: If format is different, change resampler
- stream_out->format = format;
+ if(stream_out->format != (audio_format_t) format) {
+ stream_out->format = format;
+
+ if(stream_out->format != stream_out->mixer_props->format)
+ stream_out->standby = 1;
+ }
return 0;
}
@@ -287,9 +442,21 @@ static char *audio_out_get_parameters(const struct audio_stream *stream, const c
static uint32_t audio_out_get_latency(const struct audio_stream_out *stream)
{
+ struct tinyalsa_audio_stream_out *stream_out;
+ uint32_t latency;
+
LOGD("%s(%p)", __func__, stream);
- return 0;
+ if(stream == NULL)
+ return -1;
+
+ stream_out = (struct tinyalsa_audio_stream_out *) stream;
+
+ latency = (stream_out->mixer_props->period_size *
+ stream_out->mixer_props->period_count * 1000) /
+ stream_out->mixer_props->rate;
+
+ return latency;
}
static int audio_out_set_volume(struct audio_stream_out *stream, float left,
@@ -344,14 +511,9 @@ static ssize_t audio_out_write(struct audio_stream_out *stream,
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!");
+ rc = audio_out_write_process(stream_out, (void *) buffer, (int) bytes);
+ if(rc < 0) {
+ LOGE("Process and write failed!");
return -1;
}
@@ -424,7 +586,7 @@ int audio_hw_open_output_stream(struct audio_hw_device *dev,
LOGD("%s(%p, %d, %p, %p, %p, %p)",
__func__, dev, devices, format, channels, sample_rate, stream_out);
- if(dev == NULL || stream_out == NULL)
+ if(dev == NULL || format == NULL || channels == NULL || sample_rate == NULL || stream_out == NULL)
return -EINVAL;
tinyalsa_audio_device = (struct tinyalsa_audio_device *) dev;
@@ -463,12 +625,35 @@ int audio_hw_open_output_stream(struct audio_hw_device *dev,
if(tinyalsa_audio_stream_out->mixer_props == NULL)
goto error_stream;
- tinyalsa_audio_stream_out->rate =
- tinyalsa_audio_stream_out->mixer_props->rate;
- tinyalsa_audio_stream_out->channels =
- tinyalsa_audio_stream_out->mixer_props->channels;
- tinyalsa_audio_stream_out->format =
- tinyalsa_audio_stream_out->mixer_props->format;
+ // Default values
+ if(tinyalsa_audio_stream_out->mixer_props->rate == 0)
+ tinyalsa_audio_stream_out->mixer_props->rate = 44100;
+ if(tinyalsa_audio_stream_out->mixer_props->channels == 0)
+ tinyalsa_audio_stream_out->mixer_props->channels = AUDIO_CHANNEL_OUT_STEREO;
+ if(tinyalsa_audio_stream_out->mixer_props->format == 0)
+ tinyalsa_audio_stream_out->mixer_props->format = AUDIO_FORMAT_PCM_16_BIT;
+
+ //Default incoming data will always be 44100Hz, stereo, PCM 16
+ if(*sample_rate == 0)
+ tinyalsa_audio_stream_out->rate = 44100;
+ else
+ tinyalsa_audio_stream_out->rate = *sample_rate;
+ if(*channels == 0)
+ tinyalsa_audio_stream_out->channels = AUDIO_CHANNEL_OUT_STEREO;
+ else
+ tinyalsa_audio_stream_out->channels = *channels;
+ if(*format == 0)
+ tinyalsa_audio_stream_out->format = AUDIO_FORMAT_PCM_16_BIT;
+ else
+ tinyalsa_audio_stream_out->format = *format;
+
+ if(tinyalsa_audio_stream_out->rate != tinyalsa_audio_stream_out->mixer_props->rate) {
+ rc = audio_out_resampler_open(tinyalsa_audio_stream_out);
+ if(rc < 0) {
+ LOGE("Unable to open resampler!");
+ goto error_stream;
+ }
+ }
*sample_rate = (uint32_t) tinyalsa_audio_stream_out->rate;
*channels = (uint32_t) tinyalsa_audio_stream_out->channels;