Mixer: Add input controls handling
authorPaul Kocialkowski <contact@paulk.fr>
Sun, 15 Jul 2012 21:03:47 +0000 (23:03 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Sun, 15 Jul 2012 21:03:47 +0000 (23:03 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
AudioStreamIn.cpp
AudioStreamIn.h
AudioStreamOut.cpp
Mixer.cpp
Mixer.h

index 75b1c5e..b22e962 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 #include <poll.h>
-/*
- * Missing:
- * - Mixer support
- * - Downsampler to record at the rate we want with out stream opened
- */
 
 namespace android {
 
 TinyALSAAudioStreamIn::TinyALSAAudioStreamIn() :
        mAudioHardware(NULL),
        mAudioResampler(NULL),
+       mMixer(NULL),
        mPcm(NULL),
        mDevice(0)
 {
        LOGD("TinyALSAAudioStreamIn()");
+
+       memset(&mPcmConfig, 0, sizeof(struct pcm_config));
+
+       mMixer = new TinyALSAMixer();
 }
 
 TinyALSAAudioStreamIn::~TinyALSAAudioStreamIn()
@@ -59,6 +59,8 @@ TinyALSAAudioStreamIn::~TinyALSAAudioStreamIn()
                pcm_close(mPcm);
        if(mAudioResampler)
                delete mAudioResampler;
+
+       delete mMixer;
 }
 
 status_t TinyALSAAudioStreamIn::set(AudioHardware *hw, uint32_t devices,
@@ -113,7 +115,7 @@ status_t TinyALSAAudioStreamIn::set(AudioHardware *hw, uint32_t devices,
 
        // Do the routing
        mDevice = devices;
-       //mMixer->route(mDevice);
+       mMixer->route(mDevice);
 
        // Copy the PCM infos
        mPcm = Pcm;
@@ -191,8 +193,11 @@ status_t TinyALSAAudioStreamIn::setParameters(const String8& keyValuePairs)
                keyValuePairs.string());
 
        if(param.getInt(key, device) == NO_ERROR) {
-               // TODO: change routing
-               mDevice = device;
+               if(device != mDevice) {
+                       mDevice = device;
+                       mMixer->route(mDevice);
+               }
+
                param.remove(key);
        }
 
index fc41aa5..5b4a8aa 100644 (file)
@@ -61,6 +61,7 @@ private:
        Mutex mLock;
        AudioHardware *mAudioHardware;
        TinyALSAAudioResampler *mAudioResampler;
+       TinyALSAMixer *mMixer;
 
        struct pcm *mPcm;
        struct pcm_config mPcmConfig;
index 0a87f6b..6a2c349 100644 (file)
@@ -83,7 +83,7 @@ status_t TinyALSAAudioStreamOut::set(AudioHardware *hw, uint32_t devices,
 
                LOGD("TinyALSAAudioStreamOut::set(): trying fixed params");
 
-               // TODO: Get known-to-work values from Mixer config
+               // Fixed good known-to-work values
                PcmConfig.channels = 2;
                PcmConfig.rate = 44100;
 
@@ -194,8 +194,10 @@ status_t TinyALSAAudioStreamOut::setParameters(const String8& keyValuePairs)
                keyValuePairs.string());
 
        if(param.getInt(key, device) == NO_ERROR) {
-               mDevice = device;
-               mMixer->route(mDevice);
+               if(device != mDevice) {
+                       mDevice = device;
+                       mMixer->route(mDevice);
+               }
 
                param.remove(key);
        }
index d0c0805..c21d7a0 100644 (file)
--- a/Mixer.cpp
+++ b/Mixer.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
- * 
+ *
  * This is based on TinyHardware:
  * Copyright 2011 Wolfson Microelectronics plc
  *
@@ -28,9 +28,8 @@
 
 #include "Mixer.h"
 
-/* 
+/*
  * Missing:
- * - Input handling (parsing/allocating/names/routing)
  * - "write" element handling (as well as ctl), for type MIXER_DATA_TYPE_WRITE
  */
 
@@ -51,10 +50,27 @@ struct tinyalsa_mixer_device_name mixer_output_devices_names[] = {
        { AudioSystem::DEVICE_OUT_HDMI, "hdmi" }
 };
 
+struct tinyalsa_mixer_device_name mixer_input_devices_names[] = {
+       { AudioSystem::DEVICE_IN_COMMUNICATION, "communication" },
+       { AudioSystem::DEVICE_IN_AMBIENT, "ambient" },
+       { AudioSystem::DEVICE_IN_BUILTIN_MIC, "builtin-mic" },
+       { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bluetooth-sco-headset" },
+       { AudioSystem::DEVICE_IN_WIRED_HEADSET, "headset" },
+       { AudioSystem::DEVICE_IN_AUX_DIGITAL, "aux-digital" },
+       { AudioSystem::DEVICE_IN_VOICE_CALL, "voice-call" },
+       { AudioSystem::DEVICE_IN_BACK_MIC, "back-mic" }
+};
+
 struct tinyalsa_mixer_device mixer_init_device;
+
 struct tinyalsa_mixer_device *mixer_output_devices = NULL;
 struct tinyalsa_mixer_device *mixer_current_output_device = NULL;
 
+struct tinyalsa_mixer_device *mixer_input_devices = NULL;
+struct tinyalsa_mixer_device *mixer_current_input_device = NULL;
+
+int tinyalsa_mixer_started = 0;
+
 status_t tinyalsa_mixer_devices_alloc(void)
 {
        int i, c;
@@ -77,18 +93,40 @@ status_t tinyalsa_mixer_devices_alloc(void)
                        mixer_output_devices_names[i].type;
        }
 
+       if(mixer_input_devices != NULL) {
+               LOGE("Error: mixer_input_devices are already allocated");
+               return BAD_VALUE;
+       }
+
+       c = sizeof(mixer_input_devices_names) /
+               sizeof(mixer_input_devices_names[0]);
+       mixer_input_devices = (struct tinyalsa_mixer_device *)
+               calloc(c, sizeof(*mixer_input_devices));
+
+       LOGD("Alloc %d elements (%d bytes) to mixer_input_devices", c,
+               (sizeof(*mixer_input_devices) * c));
+
+       for(i=0 ; i < c ; i++) {
+               mixer_input_devices[i].type =
+                       mixer_input_devices_names[i].type;
+       }
+
        memset(&mixer_init_device, 0, sizeof(mixer_init_device));
        mixer_current_output_device = NULL;
+       mixer_current_input_device = NULL;
 
        return NO_ERROR;
 }
 
 void tinyalsa_mixer_devices_free(void)
 {
-       if(mixer_output_devices != NULL) 
+       if(mixer_output_devices != NULL)
                free(mixer_output_devices);
+       if(mixer_input_devices != NULL)
+               free(mixer_input_devices);
 
        mixer_current_output_device = NULL;
+       mixer_current_input_device = NULL;
 }
 
 void list_head_dump(struct list_head *list_p)
@@ -166,8 +204,8 @@ void tinyalsa_mixer_device_free(struct tinyalsa_mixer_device *device)
 }
 
 struct tinyalsa_mixer_device *tinyalsa_mixer_device_get(
-       struct tinyalsa_mixer_device_name *devices_names, 
-       struct tinyalsa_mixer_device *devices, int devices_count, 
+       struct tinyalsa_mixer_device_name *devices_names,
+       struct tinyalsa_mixer_device *devices, int devices_count,
        char *device_name, int device_type)
 {
        int type = 0;
@@ -185,7 +223,7 @@ struct tinyalsa_mixer_device *tinyalsa_mixer_device_get(
 
        for(i=0 ; i < devices_count ; i++) {
                if(strcmp(devices_names[i].name, device_name) == 0) {
-                       type = mixer_output_devices_names[i].type;
+                       type = devices_names[i].type;
                        break;
                }
        }
@@ -209,9 +247,15 @@ struct tinyalsa_mixer_device *tinyalsa_mixer_device_get_with_type(
                c = sizeof(mixer_output_devices_names) /
                        sizeof(mixer_output_devices_names[0]);
 
-               return tinyalsa_mixer_device_get(mixer_output_devices_names, 
+               return tinyalsa_mixer_device_get(mixer_output_devices_names,
                        mixer_output_devices, c, device_name, 0);
-       } else { //TODO: input
+       } else if(strcmp(device_type, "input") == 0) {
+               c = sizeof(mixer_input_devices_names) /
+                       sizeof(mixer_input_devices_names[0]);
+
+               return tinyalsa_mixer_device_get(mixer_input_devices_names,
+                       mixer_input_devices, c, device_name, 0);
+       } else {
                LOGE("Unknown device type: %s", device_type);
                return NULL;
        }
@@ -229,10 +273,8 @@ status_t tinyalsa_mixer_route_set(struct mixer *mixer, struct list_head *list)
 
        while(list) {
                mixer_data = (struct tinyalsa_mixer_data *) list->data;
-//--- split to another function based on switch on type with MIXER_DATA_TYPE_CTL
 
                ctl = mixer_get_ctl_by_name(mixer, mixer_data->name);
-
                type = mixer_ctl_get_type(ctl);
 
                switch(type) {
@@ -303,7 +345,7 @@ status_t tinyalsa_mixer_route(struct mixer *mixer, int type) {
                        goto error_device;
 
                if(mixer_current_output_device != NULL) {
-                       status = tinyalsa_mixer_route_set(mixer, 
+                       status = tinyalsa_mixer_route_set(mixer,
                                mixer_current_output_device->disable);
                        mixer_current_output_device = NULL;
                        if(status != NO_ERROR) {
@@ -319,7 +361,31 @@ status_t tinyalsa_mixer_route(struct mixer *mixer, int type) {
                }
                mixer_current_output_device = device;
        } else if(AudioSystem::isInputDevice((AudioSystem::audio_devices) type)) {
-               //TODO: input
+               c = sizeof(mixer_input_devices_names) /
+                       sizeof(mixer_input_devices_names[0]);
+
+               device = tinyalsa_mixer_device_get(mixer_input_devices_names,
+                       mixer_input_devices, c, NULL, type);
+
+               if(!device)
+                       goto error_device;
+
+               if(mixer_current_input_device != NULL) {
+                       status = tinyalsa_mixer_route_set(mixer,
+                               mixer_current_input_device->disable);
+                       mixer_current_input_device = NULL;
+                       if(status != NO_ERROR) {
+                               LOGE("Failed to set disable route for current device!");
+                               goto error;
+                       }
+               }
+
+               status = tinyalsa_mixer_route_set(mixer, device->enable);
+               if(status != NO_ERROR) {
+                       LOGE("Failed to set enable route for device type: %d!", type);
+                       goto error;
+               }
+               mixer_current_input_device = device;
        } else {
                goto error_device;
        }
@@ -334,21 +400,27 @@ error:
 
 void tinyalsa_mixer_config_free(void)
 {
-       int output_devices_count;
+       int c;
        int i;
 
        // free init device
        tinyalsa_mixer_device_free(&mixer_init_device);
 
        // free output devices
-       output_devices_count = sizeof(mixer_output_devices_names) /
+       c = sizeof(mixer_output_devices_names) /
                sizeof(mixer_output_devices_names[0]);
 
-       for(i=0 ; i < output_devices_count ; i++) {
+       for(i=0 ; i < c ; i++) {
                tinyalsa_mixer_device_free(&mixer_output_devices[i]);
        }
 
-       //TODO: input
+       // free input devices
+       c = sizeof(mixer_input_devices_names) /
+               sizeof(mixer_input_devices_names[0]);
+
+       for(i=0 ; i < c ; i++) {
+               tinyalsa_mixer_device_free(&mixer_input_devices[i]);
+       }
 }
 
 void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
@@ -388,7 +460,7 @@ void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
                if(strcmp(device_type, "init") == 0) {
                        config_data->device = &mixer_init_device;
                } else if(device_name != NULL) {
-                       config_data->device = 
+                       config_data->device =
                                tinyalsa_mixer_device_get_with_type((char *) device_name, (char *) device_type);
                } else {
                        LOGE("Missing device name!");
@@ -433,7 +505,7 @@ void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
 
                        mixer_data->name = strdup((char *) data_name);
                        mixer_data->value = strdup((char *) data_value);
-                       mixer_data->type = MIXER_DATA_TYPE_CTL; 
+                       mixer_data->type = MIXER_DATA_TYPE_CTL;
 
                        config_data->list = list;
                }
@@ -494,7 +566,7 @@ status_t tinyalsa_mixer_config_parse(void)
                eof = feof(f);
 
                if(XML_Parse(p, buf, len, eof) == XML_STATUS_ERROR) {
-                       LOGE("Failed to parse line %d: %s", 
+                       LOGE("Failed to parse line %d: %s",
                                XML_GetCurrentLineNumber(p),
                                XML_ErrorString(XML_GetErrorCode(p)));
                        goto error_xml_parser;
@@ -512,25 +584,47 @@ error_file:
        return BAD_VALUE;
 }
 
+int tinyalsa_mixer_is_started(void)
+{
+       return tinyalsa_mixer_started;
+}
+
+void tinyalsa_mixer_start(void)
+{
+       tinyalsa_mixer_started = 1;
+}
+
+void tinyalsa_mixer_stop(void)
+{
+       tinyalsa_mixer_started = 0;
+}
+
 TinyALSAMixer::TinyALSAMixer() :
-       mMixer(NULL)
+       mMixer(NULL), mMainInstance(0)
 {
        LOGD("Mixer()");
 
-       tinyalsa_mixer_devices_alloc();
-       tinyalsa_mixer_config_parse();
-
        mMixer = mixer_open(0);
 
-       tinyalsa_mixer_route_init(mMixer);
+       if(!tinyalsa_mixer_is_started()) {
+               tinyalsa_mixer_start();
+               mMainInstance = 1;
+
+               tinyalsa_mixer_devices_alloc();
+               tinyalsa_mixer_config_parse();
+
+               tinyalsa_mixer_route_init(mMixer);
+       }
 }
 
 TinyALSAMixer::~TinyALSAMixer()
 {
        LOGD("~Mixer()");
 
-       tinyalsa_mixer_config_free();
-       tinyalsa_mixer_devices_free();
+       if(mMainInstance) {
+               tinyalsa_mixer_config_free();
+               tinyalsa_mixer_devices_free();
+       }
 
        if(mMixer)
                mixer_close(mMixer);
diff --git a/Mixer.h b/Mixer.h
index fa4c768..cbfd75b 100644 (file)
--- a/Mixer.h
+++ b/Mixer.h
@@ -79,6 +79,7 @@ public:
 
 private:
        struct mixer *mMixer;
+       int mMainInstance;
 
 };