Mixer: Added mode support and various other small changes
authorPaul Kocialkowski <contact@paulk.fr>
Tue, 28 Aug 2012 22:05:32 +0000 (00:05 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Tue, 28 Aug 2012 22:21:18 +0000 (00:21 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
AudioHardware.cpp
AudioHardware.h
AudioStreamIn.cpp
AudioStreamOut.cpp
Mixer.cpp
Mixer.h

index 14248e7..a9bb430 100644 (file)
@@ -38,6 +38,7 @@ AudioHardware::AudioHardware() :
        mRILInterface(NULL),
        mInDevices(0),
        mOutDevices(0),
+       mMode(AudioSystem::MODE_NORMAL),
        mMicMute(false)
 {
        LOGD("AudioHardware()");
@@ -83,12 +84,24 @@ status_t AudioHardware::setMode(int mode)
 {
        LOGD("setMode(%d)", mode);
 
+       mMode = mode;
+
        if(mRILInterface)
                mRILInterface->setMode(mode);
 
        return NO_ERROR;
 }
 
+status_t AudioHardware::getMode(int *mode)
+{
+       LOGD("getMode()");
+
+       if(mode != NULL)
+               *mode = mMode;
+
+       return NO_ERROR;
+}
+
 status_t AudioHardware::setMicMute(bool state)
 {
        LOGD("setMicMute(%d)", state);
@@ -101,11 +114,12 @@ status_t AudioHardware::setMicMute(bool state)
        return NO_ERROR;
 }
 
-status_t AudioHardware::getMicMute(boolstate)
+status_t AudioHardware::getMicMute(bool *state)
 {
        LOGD("getMicMute()");
 
-       *state = mMicMute;
+       if(state != NULL)
+               *state = mMicMute;
 
        return NO_ERROR;
 }
index 309c352..f780007 100644 (file)
@@ -43,9 +43,10 @@ public:
        virtual status_t setMasterVolume(float volume);
 
        virtual status_t setMode(int mode);
+       virtual status_t getMode(int *mode);
 
        virtual status_t setMicMute(bool state);
-       virtual status_t getMicMute(boolstate);
+       virtual status_t getMicMute(bool *state);
 
        virtual status_t setParameters(const String8& keyValuePairs);
        virtual String8 getParameters(const String8& keys);
@@ -77,6 +78,7 @@ private:
        bool mInit;
        unsigned int mOutDevices;
        unsigned int mInDevices;
+       int mMode;
        bool mMicMute;
 };
 
index b22e962..3192419 100644 (file)
@@ -193,10 +193,8 @@ status_t TinyALSAAudioStreamIn::setParameters(const String8& keyValuePairs)
                keyValuePairs.string());
 
        if(param.getInt(key, device) == NO_ERROR) {
-               if(device != mDevice) {
-                       mDevice = device;
-                       mMixer->route(mDevice);
-               }
+               mDevice = device;
+               mMixer->route(mDevice);
 
                param.remove(key);
        }
index 74b2048..48ac7a4 100644 (file)
@@ -58,6 +58,7 @@ status_t TinyALSAAudioStreamOut::set(AudioHardware *hw, uint32_t devices,
 {
        struct pcm *Pcm = NULL;
        struct pcm_config PcmConfig;
+       int mode = AudioSystem::MODE_NORMAL;
 
        LOGD("TinyALSAAudioStreamOut::set()");
 
@@ -99,7 +100,8 @@ status_t TinyALSAAudioStreamOut::set(AudioHardware *hw, uint32_t devices,
 
        // Do the routing
        mDevice = devices;
-       mMixer->route(mDevice);
+       mAudioHardware->getMode(&mode);
+       mMixer->route(mDevice, mode);
 
        // Copy the PCM infos
        mPcm = Pcm;
@@ -189,15 +191,16 @@ status_t TinyALSAAudioStreamOut::setParameters(const String8& keyValuePairs)
        AudioParameter param = AudioParameter(keyValuePairs);
        String8 key = String8(AudioParameter::keyRouting);
        int device;
+       int mode = AudioSystem::MODE_NORMAL;
 
        LOGD("TinyALSAAudioStreamOut::setParameters(%s)",
                keyValuePairs.string());
 
        if(param.getInt(key, device) == NO_ERROR) {
-               if(device != mDevice) {
-                       mDevice = device;
-                       mMixer->route(mDevice);
-               }
+               mDevice = device;
+               mAudioHardware->getMode(&mode);
+
+               mMixer->route(mDevice, mode);
 
                if(mAudioHardware->mRILInterface)
                        mAudioHardware->mRILInterface->setRouting(device);
index c21d7a0..ce6912b 100644 (file)
--- a/Mixer.cpp
+++ b/Mixer.cpp
@@ -61,6 +61,13 @@ struct tinyalsa_mixer_device_name mixer_input_devices_names[] = {
        { AudioSystem::DEVICE_IN_BACK_MIC, "back-mic" }
 };
 
+struct tinyalsa_mixer_mode_name mixer_modes_names[] = {
+       { AudioSystem::MODE_NORMAL, "normal" },
+       { AudioSystem::MODE_RINGTONE, "ringtone" },
+       { AudioSystem::MODE_IN_CALL, "in-call" },
+       { AudioSystem::MODE_IN_COMMUNICATION, "in-communication" }
+};
+
 struct tinyalsa_mixer_device mixer_init_device;
 
 struct tinyalsa_mixer_device *mixer_output_devices = NULL;
@@ -73,24 +80,36 @@ int tinyalsa_mixer_started = 0;
 
 status_t tinyalsa_mixer_devices_alloc(void)
 {
-       int i, c;
+       int devices_names_count, modes_names_count;
+       int i, j, c;
+
+       modes_names_count = sizeof(mixer_modes_names) /
+               sizeof(mixer_modes_names[0]);
 
        if(mixer_output_devices != NULL) {
                LOGE("Error: mixer_output_devices are already allocated");
                return BAD_VALUE;
        }
 
-       c = sizeof(mixer_output_devices_names) /
+       devices_names_count = sizeof(mixer_output_devices_names) /
                sizeof(mixer_output_devices_names[0]);
+       c = devices_names_count * modes_names_count;
+
        mixer_output_devices = (struct tinyalsa_mixer_device *)
                calloc(c, sizeof(*mixer_output_devices));
 
        LOGD("Alloc %d elements (%d bytes) to mixer_output_devices", c,
                (sizeof(*mixer_output_devices) * c));
 
-       for(i=0 ; i < c ; i++) {
-               mixer_output_devices[i].type =
-                       mixer_output_devices_names[i].type;
+       for(i=0 ; i < devices_names_count ; i++) {
+               for(j=0 ; j < modes_names_count ; j++) {
+                       c = i * modes_names_count + j;
+                       mixer_output_devices[c].type =
+                               mixer_output_devices_names[i].type;
+                       mixer_output_devices[c].mode =
+                               mixer_modes_names[j].mode;
+                       mixer_output_devices[c].enabled = 0;
+               }
        }
 
        if(mixer_input_devices != NULL) {
@@ -100,6 +119,7 @@ status_t tinyalsa_mixer_devices_alloc(void)
 
        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));
 
@@ -109,6 +129,7 @@ status_t tinyalsa_mixer_devices_alloc(void)
        for(i=0 ; i < c ; i++) {
                mixer_input_devices[i].type =
                        mixer_input_devices_names[i].type;
+               mixer_input_devices[i].mode = AudioSystem::MODE_NORMAL;
        }
 
        memset(&mixer_init_device, 0, sizeof(mixer_init_device));
@@ -203,67 +224,118 @@ void tinyalsa_mixer_device_free(struct tinyalsa_mixer_device *device)
                tinyalsa_mixer_device_list_free(device->disable);
 }
 
-struct tinyalsa_mixer_device *tinyalsa_mixer_device_get(
-       struct tinyalsa_mixer_device_name *devices_names,
-       struct tinyalsa_mixer_device *devices, int devices_count,
-       char *device_name, int device_type)
+struct tinyalsa_mixer_device *tinyalsa_mixer_device_get(int type, int mode,
+       int enabled, struct tinyalsa_mixer_device *devices, int devices_count)
 {
-       int type = 0;
        int i;
 
-       if(device_type != 0) {
-               type = device_type;
-               goto seek_type;
-       }
-
-       if(device_name == NULL) {
-               LOGE("Unable to retrieve device: no data given!");
+       if(type < 0 || mode < 0 || devices == NULL || devices_count <= 0) {
                return NULL;
        }
 
        for(i=0 ; i < devices_count ; i++) {
+               if(devices[i].type == type && devices[i].mode == mode) {
+                       if(enabled && devices[i].enabled)
+                               return &devices[i];
+                       else if(!enabled)
+                               return &devices[i];
+               }
+       }
+
+       return NULL;
+}
+
+int tinyalsa_mixer_type_get_from_string(char *device_name,
+       struct tinyalsa_mixer_device_name *devices_names, int devices_names_count)
+{
+       int i;
+
+       if(device_name == NULL || devices_names == NULL || devices_names_count <= 0) {
+               return -1;
+       }
+
+       for(i=0 ; i < devices_names_count ; i++) {
                if(strcmp(devices_names[i].name, device_name) == 0) {
-                       type = devices_names[i].type;
-                       break;
+                       return devices_names[i].type;
                }
        }
 
-seek_type:
-       for(i=0 ; i < devices_count ; i++) {
-               if(devices[i].type == type) {
-                       return &devices[i];
+       return -1;
+}
+
+int tinyalsa_mixer_mode_get_from_string(char *device_mode)
+{
+       int modes_names_count;
+       int i;
+
+       // Fallback
+       if(device_mode == NULL)
+               return AudioSystem::MODE_NORMAL;
+
+       modes_names_count = sizeof(mixer_modes_names) /
+               sizeof(mixer_modes_names[0]);
+
+       for(i=0 ; i < modes_names_count ; i++) {
+               if(strcmp(mixer_modes_names[i].name, device_mode) == 0) {
+                       return mixer_modes_names[i].mode;
                }
        }
 
-       return NULL;
+       // Fallback
+       return AudioSystem::MODE_NORMAL;
 }
 
-struct tinyalsa_mixer_device *tinyalsa_mixer_device_get_with_type(
-       char *device_name, char *device_type)
+struct tinyalsa_mixer_device *tinyalsa_mixer_device_get_from_strings(
+       char *device_name, char *device_type, char *device_mode)
 {
+       int devices_names_count, modes_names_count;
+       int mode, type;
        int c;
 
+       if(device_name == NULL || device_type == NULL)
+               return NULL;
+
        if(strcmp(device_type, "output") == 0) {
-               c = sizeof(mixer_output_devices_names) /
+               modes_names_count = sizeof(mixer_modes_names) /
+                       sizeof(mixer_modes_names[0]);
+
+               mode = tinyalsa_mixer_mode_get_from_string(device_mode);
+
+               devices_names_count = sizeof(mixer_output_devices_names) /
                        sizeof(mixer_output_devices_names[0]);
 
-               return tinyalsa_mixer_device_get(mixer_output_devices_names,
-                       mixer_output_devices, c, device_name, 0);
+               type = tinyalsa_mixer_type_get_from_string(device_name,
+                       mixer_output_devices_names, devices_names_count);
+
+               c = devices_names_count * modes_names_count;
+
+               return tinyalsa_mixer_device_get(type, mode, 0,
+                       mixer_output_devices, c);
        } else if(strcmp(device_type, "input") == 0) {
-               c = sizeof(mixer_input_devices_names) /
+               modes_names_count = sizeof(mixer_modes_names) /
+                       sizeof(mixer_modes_names[0]);
+
+               mode = tinyalsa_mixer_mode_get_from_string(device_mode);
+
+               devices_names_count = 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);
+               type = tinyalsa_mixer_type_get_from_string(device_name,
+                       mixer_input_devices_names, devices_names_count);
+
+               c = devices_names_count * modes_names_count;
+
+               return tinyalsa_mixer_device_get(type, mode, 0,
+                       mixer_input_devices, c);
        } else {
                LOGE("Unknown device type: %s", device_type);
                return NULL;
        }
 }
 
-status_t tinyalsa_mixer_route_set(struct mixer *mixer, struct list_head *list)
+status_t tinyalsa_mixer_route_set(struct mixer *mixer,
+       struct tinyalsa_mixer_data *mixer_data)
 {
-       struct tinyalsa_mixer_data *mixer_data;
        struct mixer_ctl *ctl;
        status_t status = BAD_VALUE;
        int value;
@@ -271,40 +343,50 @@ status_t tinyalsa_mixer_route_set(struct mixer *mixer, struct list_head *list)
        int rc;
        int i;
 
-       while(list) {
-               mixer_data = (struct tinyalsa_mixer_data *) list->data;
+       ctl = mixer_get_ctl_by_name(mixer, mixer_data->name);
+       type = mixer_ctl_get_type(ctl);
+
+       switch(type) {
+               case MIXER_CTL_TYPE_BOOL:
+                       value = strcmp(mixer_data->value, "on") == 0 ?
+                               1 : 0;
+                       break;
+               case MIXER_CTL_TYPE_INT:
+                       value = atoi(mixer_data->value);
+                       break;
+               case MIXER_CTL_TYPE_BYTE:
+                       value = atoi(mixer_data->value) & 0xff;
+                       break;
+               case MIXER_CTL_TYPE_ENUM:
+               case MIXER_CTL_TYPE_UNKNOWN:
+                       rc = mixer_ctl_set_enum_by_string(ctl, mixer_data->value);
+                       if(!rc)
+                               status = NO_ERROR;
+       }
 
-               ctl = mixer_get_ctl_by_name(mixer, mixer_data->name);
-               type = mixer_ctl_get_type(ctl);
-
-               switch(type) {
-                       case MIXER_CTL_TYPE_BOOL:
-                               value = strcmp(mixer_data->value, "on") == 0 ?
-                                       1 : 0;
-                               break;
-                       case MIXER_CTL_TYPE_INT:
-                               value = atoi(mixer_data->value);
-                               break;
-                       case MIXER_CTL_TYPE_BYTE:
-                               value = atoi(mixer_data->value) & 0xff;
-                               break;
-                       case MIXER_CTL_TYPE_ENUM:
-                       case MIXER_CTL_TYPE_UNKNOWN:
-                               rc = mixer_ctl_set_enum_by_string(ctl, mixer_data->value);
+       if(type == MIXER_CTL_TYPE_BOOL || type == MIXER_CTL_TYPE_INT ||
+               type == MIXER_CTL_TYPE_BYTE) {
+                       for(i=0 ; i < mixer_ctl_get_num_values(ctl) ; i++) {
+                               rc = mixer_ctl_set_value(ctl, i, value);
                                if(!rc)
                                        status = NO_ERROR;
-               }
+                       }
+       }
 
-               if(type == MIXER_CTL_TYPE_BOOL || type == MIXER_CTL_TYPE_INT ||
-                       type == MIXER_CTL_TYPE_BYTE) {
-                               for(i=0 ; i < mixer_ctl_get_num_values(ctl) ; i++) {
-                                       rc = mixer_ctl_set_value(ctl, i, value);
-                                       if(!rc)
-                                               status = NO_ERROR;
-                               }
-               }
+       LOGD("Setting %s to %s", mixer_data->name, mixer_data->value);
 
-               LOGD("Setting %s to %s", mixer_data->name, mixer_data->value);
+       return status;
+}
+
+status_t tinyalsa_mixer_route_set_list(struct mixer *mixer, struct list_head *list)
+{
+       struct tinyalsa_mixer_data *mixer_data = NULL;
+       status_t status;
+
+       while(list) {
+               mixer_data = (struct tinyalsa_mixer_data *) list->data;
+
+               status = tinyalsa_mixer_route_set(mixer, mixer_data);
 
                if(list->next != NULL)
                        list = list->next;
@@ -319,7 +401,7 @@ status_t tinyalsa_mixer_route_init(struct mixer *mixer)
 {
        status_t status;
 
-       status = tinyalsa_mixer_route_set(mixer, mixer_init_device.enable);
+       status = tinyalsa_mixer_route_set_list(mixer, mixer_init_device.enable);
        if(status != NO_ERROR) {
                LOGE("Failed to set init route!");
                goto error;
@@ -329,23 +411,36 @@ error:
        return BAD_VALUE;
 }
 
-status_t tinyalsa_mixer_route(struct mixer *mixer, int type) {
+status_t tinyalsa_mixer_route(struct mixer *mixer, int type, int mode) {
+       int devices_names_count, modes_names_count;
        struct tinyalsa_mixer_device *device;
        status_t status;
        int c;
 
        if(AudioSystem::isOutputDevice((AudioSystem::audio_devices) type)) {
-               c = sizeof(mixer_output_devices_names) /
+               modes_names_count = sizeof(mixer_modes_names) /
+                       sizeof(mixer_modes_names[0]);
+
+               devices_names_count = sizeof(mixer_output_devices_names) /
                        sizeof(mixer_output_devices_names[0]);
 
-               device = tinyalsa_mixer_device_get(mixer_output_devices_names,
-                       mixer_output_devices, c, NULL, type);
+               c = devices_names_count * modes_names_count;
 
-               if(!device)
-                       goto error_device;
+               device = tinyalsa_mixer_device_get(type, mode, 1,
+                       mixer_output_devices, c);
+
+               // Try normal mode
+               if(!device) {
+                       LOGE("Fallback to normal mode");
+                       device = tinyalsa_mixer_device_get(type, AudioSystem::MODE_NORMAL, 1,
+                       mixer_output_devices, c);
+
+                       if(!device)
+                               goto error_device;
+               }
 
                if(mixer_current_output_device != NULL) {
-                       status = tinyalsa_mixer_route_set(mixer,
+                       status = tinyalsa_mixer_route_set_list(mixer,
                                mixer_current_output_device->disable);
                        mixer_current_output_device = NULL;
                        if(status != NO_ERROR) {
@@ -354,24 +449,26 @@ status_t tinyalsa_mixer_route(struct mixer *mixer, int type) {
                        }
                }
 
-               status = tinyalsa_mixer_route_set(mixer, device->enable);
+               status = tinyalsa_mixer_route_set_list(mixer, device->enable);
                if(status != NO_ERROR) {
-                       LOGE("Failed to set enable route for device type: %d!", type);
+                       LOGE("Failed to set enable route for device: %d/%d!", type, mode);
                        goto error;
                }
+
                mixer_current_output_device = device;
        } else if(AudioSystem::isInputDevice((AudioSystem::audio_devices) type)) {
                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);
+               // There are no modes for input
+               device = tinyalsa_mixer_device_get(type, AudioSystem::MODE_NORMAL, 1,
+                       mixer_input_devices, c);
 
                if(!device)
                        goto error_device;
 
                if(mixer_current_input_device != NULL) {
-                       status = tinyalsa_mixer_route_set(mixer,
+                       status = tinyalsa_mixer_route_set_list(mixer,
                                mixer_current_input_device->disable);
                        mixer_current_input_device = NULL;
                        if(status != NO_ERROR) {
@@ -380,11 +477,12 @@ status_t tinyalsa_mixer_route(struct mixer *mixer, int type) {
                        }
                }
 
-               status = tinyalsa_mixer_route_set(mixer, device->enable);
+               status = tinyalsa_mixer_route_set_list(mixer, device->enable);
                if(status != NO_ERROR) {
-                       LOGE("Failed to set enable route for device type: %d!", type);
+                       LOGE("Failed to set enable route for device: %d!", type);
                        goto error;
                }
+
                mixer_current_input_device = device;
        } else {
                goto error_device;
@@ -400,24 +498,32 @@ error:
 
 void tinyalsa_mixer_config_free(void)
 {
+       int devices_names_count, modes_names_count;
        int c;
        int i;
 
+       modes_names_count = sizeof(mixer_modes_names) /
+               sizeof(mixer_modes_names[0]);
+
        // free init device
        tinyalsa_mixer_device_free(&mixer_init_device);
 
-       // free output devices
-       c = sizeof(mixer_output_devices_names) /
+       devices_names_count = sizeof(mixer_output_devices_names) /
                sizeof(mixer_output_devices_names[0]);
 
+       // free output devices
+       c = devices_names_count * modes_names_count;
+
        for(i=0 ; i < c ; i++) {
                tinyalsa_mixer_device_free(&mixer_output_devices[i]);
        }
 
-       // free input devices
-       c = sizeof(mixer_input_devices_names) /
+       devices_names_count = sizeof(mixer_input_devices_names) /
                sizeof(mixer_input_devices_names[0]);
 
+       // free input devices
+       c = devices_names_count;
+
        for(i=0 ; i < c ; i++) {
                tinyalsa_mixer_device_free(&mixer_input_devices[i]);
        }
@@ -433,6 +539,7 @@ void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
 
        const XML_Char *device_name = NULL;
        const XML_Char *device_type = NULL;
+       const XML_Char *device_mode = NULL;
        const XML_Char *data_name = NULL;
        const XML_Char *data_value = NULL;
        int i;
@@ -451,21 +558,32 @@ void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
                        if(strcmp(attr[i], "type") == 0) {
                                i++;
                                device_type = attr[i];
+                       } else if(strcmp(attr[i], "mode") == 0) {
+                               i++;
+                               device_mode = attr[i];
                        } else if(strcmp(attr[i], "name") == 0) {
                                i++;
                                device_name = attr[i];
                        }
                }
 
+               if(device_type == NULL) {
+                       LOGE("Missing device type!");
+                       return;
+               }
+
                if(strcmp(device_type, "init") == 0) {
                        config_data->device = &mixer_init_device;
                } else if(device_name != NULL) {
                        config_data->device =
-                               tinyalsa_mixer_device_get_with_type((char *) device_name, (char *) device_type);
+                               tinyalsa_mixer_device_get_from_strings((char *) device_name, (char *) device_type, (char *) device_mode);
+                       if(config_data->device != NULL)
+                               config_data->device->enabled = 1;
                } else {
                        LOGE("Missing device name!");
+                       return;
                }
-       } else if(strcmp(elem, "path") == 0) {
+       } else if(strcmp(elem, "path") == 0 && config_data->device != NULL) {
                for(i=0 ; attr[i] && attr[i+1] ; i++) {
                        if(strcmp(attr[i], "name") == 0) {
                                i++;
@@ -478,7 +596,7 @@ void tinyalsa_mixer_config_start(void *data, const XML_Char *elem,
                                }
                        }
                }
-       } else if(strcmp(elem, "ctl") == 0) {
+       } else if(strcmp(elem, "ctl") == 0 && config_data->device != NULL) {
                for(i=0 ; attr[i] && attr[i+1] ; i++) {
                        if(strcmp(attr[i], "name") == 0) {
                                i++;
@@ -632,7 +750,12 @@ TinyALSAMixer::~TinyALSAMixer()
 
 status_t TinyALSAMixer::route(int type)
 {
-       return tinyalsa_mixer_route(mMixer, type);
+       return tinyalsa_mixer_route(mMixer, type, AudioSystem::MODE_NORMAL);
+}
+
+status_t TinyALSAMixer::route(int type, int mode)
+{
+       return tinyalsa_mixer_route(mMixer, type, mode);
 }
 
 }; // namespace android
diff --git a/Mixer.h b/Mixer.h
index cbfd75b..9d5d9c8 100644 (file)
--- a/Mixer.h
+++ b/Mixer.h
@@ -57,9 +57,16 @@ struct tinyalsa_mixer_device_name {
        char *name;
 };
 
+struct tinyalsa_mixer_mode_name {
+       int mode;
+       char *name;
+};
+
 struct tinyalsa_mixer_device {
        int type;
+       int mode;
 
+       int enabled;
        struct list_head *enable;
        struct list_head *disable;
 };
@@ -75,7 +82,8 @@ class TinyALSAMixer
 public:
        TinyALSAMixer();
        virtual ~TinyALSAMixer();
-       status_t route(int type);
+       virtual status_t route(int type);
+       virtual status_t route(int type, int mode);
 
 private:
        struct mixer *mMixer;