summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2012-10-13 14:47:43 +0200
committerPaul Kocialkowski <contact@paulk.fr>2012-10-13 14:47:43 +0200
commit3df839e5300e148d1fd4f6c4fc93012071b9380b (patch)
tree7f9517921d108430442050597974857b1339bea6
parenteae512666c652d8c9efbb5986a43f2f3ae82b687 (diff)
downloadhardware_tinyalsa-audio-3df839e5300e148d1fd4f6c4fc93012071b9380b.zip
hardware_tinyalsa-audio-3df839e5300e148d1fd4f6c4fc93012071b9380b.tar.gz
hardware_tinyalsa-audio-3df839e5300e148d1fd4f6c4fc93012071b9380b.tar.bz2
Output: Implement routing and write
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
-rw-r--r--audio_hw.h10
-rw-r--r--audio_out.c150
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 <stdint.h>
#include <sys/time.h>
+#include <cutils/str_parms.h>
#include <cutils/log.h>
#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;