14765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev/* ALSAMixer.cpp
24765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
34765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Copyright 2008-2010 Wind River Systems
44765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
54765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Licensed under the Apache License, Version 2.0 (the "License");
64765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** you may not use this file except in compliance with the License.
74765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** You may obtain a copy of the License at
84765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
94765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **     http://www.apache.org/licenses/LICENSE-2.0
104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Unless required by applicable law or agreed to in writing, software
124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** distributed under the License is distributed on an "AS IS" BASIS,
134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** See the License for the specific language governing permissions and
154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** limitations under the License.
164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev */
174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <errno.h>
194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdarg.h>
204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <sys/stat.h>
214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <fcntl.h>
224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdlib.h>
234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <unistd.h>
244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <dlfcn.h>
254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define LOG_TAG "AudioHardwareALSA"
274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <utils/Log.h>
284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <utils/String8.h>
294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <cutils/properties.h>
314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <media/AudioRecord.h>
324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <hardware_legacy/power.h>
334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include "AudioHardwareALSA.h"
354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define SND_MIXER_VOL_RANGE_MIN  (0)
374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define SND_MIXER_VOL_RANGE_MAX  (100)
384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_NAME_MAX 128
404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_STRCAT(x,y) \
424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (strlen(x) + strlen(y) < ALSA_NAME_MAX) \
434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        strcat(x, y);
444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevnamespace android
464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev// ----------------------------------------------------------------------------
494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct mixer_info_t;
514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct alsa_properties_t
534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    const AudioSystem::audio_devices device;
554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    const char         *propName;
564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    const char         *propDefault;
574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t       *mInfo;
584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_PROP(dev, name, out, in) \
614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {\
624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        {dev, "alsa.mixer.playback." name, out, NULL},\
634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        {dev, "alsa.mixer.capture." name, in, NULL}\
644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic alsa_properties_t
674765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevmixerMasterProp[SND_PCM_STREAM_LAST+1] =
684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        ALSA_PROP(AudioSystem::DEVICE_OUT_ALL, "master", "PCM", "Capture");
694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic alsa_properties_t
714765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevmixerProp[][SND_PCM_STREAM_LAST+1] = {
724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_EARPIECE, "earpiece", "Earpiece", "Capture"),
734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_SPEAKER, "speaker", "Speaker",  ""),
744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_WIRED_HEADSET, "headset", "Headphone", "Capture"),
754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "bluetooth.sco", "Bluetooth", "Bluetooth Capture"),
764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "bluetooth.a2dp", "Bluetooth A2DP", "Bluetooth A2DP Capture"),
774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(static_cast<AudioSystem::audio_devices>(0), "", NULL, NULL)
784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct mixer_info_t
814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t() :
834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        elem(0),
844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        min(SND_MIXER_VOL_RANGE_MIN),
854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        max(SND_MIXER_VOL_RANGE_MAX),
864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mute(false)
874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {
884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_elem_t *elem;
914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long              min;
924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long              max;
934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long              volume;
944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    bool              mute;
954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    char              name[ALSA_NAME_MAX];
964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int initMixer (snd_mixer_t **mixer, const char *name)
994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
1004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int err;
1014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_open(mixer, 0)) < 0) {
1034113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGE("Unable to open mixer: %s", snd_strerror(err));
1044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return err;
1054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_attach(*mixer, name)) < 0) {
1084113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGW("Unable to attach mixer to device %s: %s",
1094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            name, snd_strerror(err));
1104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if ((err = snd_mixer_attach(*mixer, "hw:00")) < 0) {
1124113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev            ALOGE("Unable to attach mixer to device default: %s",
1134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                snd_strerror(err));
1144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_close (*mixer);
1164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            *mixer = NULL;
1174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return err;
1184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
1194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0) {
1224113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGE("Unable to register mixer elements: %s", snd_strerror(err));
1234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        snd_mixer_close (*mixer);
1244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        *mixer = NULL;
1254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return err;
1264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Get the mixer controls from the kernel
1294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_load(*mixer)) < 0) {
1304113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGE("Unable to load mixer elements: %s", snd_strerror(err));
1314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        snd_mixer_close (*mixer);
1324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        *mixer = NULL;
1334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return err;
1344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return 0;
1374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
1384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevtypedef int (*hasVolume_t)(snd_mixer_elem_t*);
1404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const hasVolume_t hasVolume[] = {
1424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_has_playback_volume,
1434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_has_capture_volume
1444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
1454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevtypedef int (*getVolumeRange_t)(snd_mixer_elem_t*, long int*, long int*);
1474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const getVolumeRange_t getVolumeRange[] = {
1494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_get_playback_volume_range,
1504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_get_capture_volume_range
1514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
1524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevtypedef int (*setVolume_t)(snd_mixer_elem_t*, long int);
1544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const setVolume_t setVol[] = {
1564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_playback_volume_all,
1574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_capture_volume_all
1584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
1594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1604765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevALSAMixer::ALSAMixer()
1614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
1624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int err;
1634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidOut");
1654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidIn");
1664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_id_t *sid;
1684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_id_alloca(&sid);
1694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
1714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (!mMixer[i]) continue;
1734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;
1754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        property_get (mixerMasterProp[i].propName,
1774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      info->name,
1784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      mixerMasterProp[i].propDefault);
1794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
1814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             elem;
1824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             elem = snd_mixer_elem_next(elem)) {
1834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!snd_mixer_selem_is_active(elem))
1854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                continue;
1864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_selem_get_id(elem, sid);
1884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            // Find PCM playback volume control element.
1904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            const char *elementName = snd_mixer_selem_id_get_name(sid);
1914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (info->elem == NULL &&
1934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                strcmp(elementName, info->name) == 0 &&
1944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                hasVolume[i] (elem)) {
1954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                info->elem = elem;
1974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                getVolumeRange[i] (elem, &info->min, &info->max);
1984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                info->volume = info->max;
1994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                setVol[i] (elem, info->volume);
2004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (i == SND_PCM_STREAM_PLAYBACK &&
2014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    snd_mixer_selem_has_playback_switch (elem))
2024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    snd_mixer_selem_set_playback_switch_all (elem, 1);
2034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                break;
2044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2074113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");
2084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for (int j = 0; mixerProp[j][i].device; j++) {
2104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;
2124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            property_get (mixerProp[j][i].propName,
2144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                          info->name,
2154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                          mixerProp[j][i].propDefault);
2164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
2184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 elem;
2194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 elem = snd_mixer_elem_next(elem)) {
2204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (!snd_mixer_selem_is_active(elem))
2224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    continue;
2234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                snd_mixer_selem_get_id(elem, sid);
2254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                // Find PCM playback volume control element.
2274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                const char *elementName = snd_mixer_selem_id_get_name(sid);
2284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               if (info->elem == NULL &&
2304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    strcmp(elementName, info->name) == 0 &&
2314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    hasVolume[i] (elem)) {
2324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    info->elem = elem;
2344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    getVolumeRange[i] (elem, &info->min, &info->max);
2354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    info->volume = info->max;
2364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    setVol[i] (elem, info->volume);
2374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    if (i == SND_PCM_STREAM_PLAYBACK &&
2384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        snd_mixer_selem_has_playback_switch (elem))
2394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        snd_mixer_selem_set_playback_switch_all (elem, 1);
2404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    break;
2414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
2424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2434113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev            ALOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
2444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2464113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev    ALOGV("mixer initialized.");
2474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2494765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevALSAMixer::~ALSAMixer()
2504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
2524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mMixer[i]) snd_mixer_close (mMixer[i]);
2534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerMasterProp[i].mInfo) {
2544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            delete mixerMasterProp[i].mInfo;
2554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixerMasterProp[i].mInfo = NULL;
2564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for (int j = 0; mixerProp[j][i].device; j++) {
2584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (mixerProp[j][i].mInfo) {
2594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                delete mixerProp[j][i].mInfo;
2604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                mixerProp[j][i].mInfo = NULL;
2614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2644113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev    ALOGV("mixer destroyed.");
2654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setMasterVolume(float volume)
2684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo;
2704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!info || !info->elem) return INVALID_OPERATION;
2714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long minVol = info->min;
2734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long maxVol = info->max;
2744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Make sure volume is between bounds.
2764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long vol = minVol + volume * (maxVol - minVol);
2774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol > maxVol) vol = maxVol;
2784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol < minVol) vol = minVol;
2794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    info->volume = vol;
2814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_playback_volume_all (info->elem, vol);
2824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
2844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setMasterGain(float gain)
2874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_CAPTURE].mInfo;
2894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!info || !info->elem) return INVALID_OPERATION;
2904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long minVol = info->min;
2924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long maxVol = info->max;
2934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Make sure volume is between bounds.
2954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long vol = minVol + gain * (maxVol - minVol);
2964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol > maxVol) vol = maxVol;
2974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol < minVol) vol = minVol;
2984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    info->volume = vol;
3004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_capture_volume_all (info->elem, vol);
3014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setVolume(uint32_t device, float left, float right)
3064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
3084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
3094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
3114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long minVol = info->min;
3144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long maxVol = info->max;
3154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            // Make sure volume is between bounds.
3174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long vol = minVol + left * (maxVol - minVol);
3184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol > maxVol) vol = maxVol;
3194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol < minVol) vol = minVol;
3204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->volume = vol;
3224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_selem_set_playback_volume_all (info->elem, vol);
3234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setGain(uint32_t device, float gain)
3294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++)
3314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) {
3324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
3344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long minVol = info->min;
3374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long maxVol = info->max;
3384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            // Make sure volume is between bounds.
3404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long vol = minVol + gain * (maxVol - minVol);
3414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol > maxVol) vol = maxVol;
3424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol < minVol) vol = minVol;
3434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->volume = vol;
3454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_selem_set_capture_volume_all (info->elem, vol);
3464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setCaptureMuteState(uint32_t device, bool state)
3524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++)
3544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) {
3554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
3574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (snd_mixer_selem_has_capture_switch (info->elem)) {
3604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                int err = snd_mixer_selem_set_capture_switch_all (info->elem, static_cast<int>(!state));
3624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (err < 0) {
3634113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev                    ALOGE("Unable to %s capture mixer switch %s",
3644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        state ? "enable" : "disable", info->name);
3654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    return INVALID_OPERATION;
3664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
3684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->mute = state;
3704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::getCaptureMuteState(uint32_t device, bool *state)
3764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!state) return BAD_VALUE;
3784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++)
3804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) {
3814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
3834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            *state = info->mute;
3864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return NO_ERROR;
3874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return BAD_VALUE;
3904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setPlaybackMuteState(uint32_t device, bool state)
3934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
3954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
3964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
3984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (snd_mixer_selem_has_playback_switch (info->elem)) {
4014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                int err = snd_mixer_selem_set_playback_switch_all (info->elem, static_cast<int>(!state));
4034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (err < 0) {
4044113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev                    ALOGE("Unable to %s playback mixer switch %s",
4054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        state ? "enable" : "disable", info->name);
4064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    return INVALID_OPERATION;
4074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
4084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
4094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->mute = state;
4114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
4124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
4144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
4154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::getPlaybackMuteState(uint32_t device, bool *state)
4174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
4184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!state) return BAD_VALUE;
4194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
4214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
4224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
4244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
4254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            *state = info->mute;
4274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return NO_ERROR;
4284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
4294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return BAD_VALUE;
4314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
4324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};        // namespace android
434