ALSAMixer.cpp revision 4113f34dfbaa8d82a5e1ef0265e916317161984d
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>
284113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev
294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <utils/String8.h>
304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <cutils/properties.h>
324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <media/AudioRecord.h>
334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <hardware_legacy/power.h>
344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include "AudioHardwareALSA.h"
364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define SND_MIXER_VOL_RANGE_MIN  (0)
384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define SND_MIXER_VOL_RANGE_MAX  (100)
394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_NAME_MAX 128
414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_STRCAT(x,y) \
434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (strlen(x) + strlen(y) < ALSA_NAME_MAX) \
444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        strcat(x, y);
454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevnamespace android
474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev// ----------------------------------------------------------------------------
504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct mixer_info_t;
524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct alsa_properties_t
544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    const AudioSystem::audio_devices device;
564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    const char         *propName;
574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    const char         *propDefault;
584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t       *mInfo;
594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_PROP(dev, name, out, in) \
624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {\
634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        {dev, "alsa.mixer.playback." name, out, NULL},\
644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        {dev, "alsa.mixer.capture." name, in, NULL}\
654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic alsa_properties_t
684765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevmixerMasterProp[SND_PCM_STREAM_LAST+1] =
694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        ALSA_PROP(AudioSystem::DEVICE_OUT_ALL, "master", "PCM", "Capture");
704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic alsa_properties_t
724765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevmixerProp[][SND_PCM_STREAM_LAST+1] = {
734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_EARPIECE, "earpiece", "Earpiece", "Capture"),
744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_SPEAKER, "speaker", "Speaker",  ""),
754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_WIRED_HEADSET, "headset", "Headphone", "Capture"),
764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "bluetooth.sco", "Bluetooth", "Bluetooth Capture"),
774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "bluetooth.a2dp", "Bluetooth A2DP", "Bluetooth A2DP Capture"),
784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSA_PROP(static_cast<AudioSystem::audio_devices>(0), "", NULL, NULL)
794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct mixer_info_t
824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t() :
844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        elem(0),
854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        min(SND_MIXER_VOL_RANGE_MIN),
864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        max(SND_MIXER_VOL_RANGE_MAX),
874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mute(false)
884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {
894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_elem_t *elem;
924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long              min;
934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long              max;
944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long              volume;
954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    bool              mute;
964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    char              name[ALSA_NAME_MAX];
974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int initMixer (snd_mixer_t **mixer, const char *name)
1004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
1014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int err;
1024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_open(mixer, 0)) < 0) {
1044113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGE("Unable to open mixer: %s", snd_strerror(err));
1054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return err;
1064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_attach(*mixer, name)) < 0) {
1094113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGW("Unable to attach mixer to device %s: %s",
1104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            name, snd_strerror(err));
1114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if ((err = snd_mixer_attach(*mixer, "hw:00")) < 0) {
1134113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev            ALOGE("Unable to attach mixer to device default: %s",
1144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                snd_strerror(err));
1154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_close (*mixer);
1174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            *mixer = NULL;
1184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return err;
1194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
1204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0) {
1234113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGE("Unable to register mixer elements: %s", snd_strerror(err));
1244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        snd_mixer_close (*mixer);
1254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        *mixer = NULL;
1264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return err;
1274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Get the mixer controls from the kernel
1304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if ((err = snd_mixer_load(*mixer)) < 0) {
1314113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGE("Unable to load mixer elements: %s", snd_strerror(err));
1324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        snd_mixer_close (*mixer);
1334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        *mixer = NULL;
1344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return err;
1354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return 0;
1384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
1394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevtypedef int (*hasVolume_t)(snd_mixer_elem_t*);
1414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const hasVolume_t hasVolume[] = {
1434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_has_playback_volume,
1444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_has_capture_volume
1454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
1464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevtypedef int (*getVolumeRange_t)(snd_mixer_elem_t*, long int*, long int*);
1484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const getVolumeRange_t getVolumeRange[] = {
1504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_get_playback_volume_range,
1514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_get_capture_volume_range
1524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
1534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevtypedef int (*setVolume_t)(snd_mixer_elem_t*, long int);
1554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const setVolume_t setVol[] = {
1574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_playback_volume_all,
1584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_capture_volume_all
1594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
1604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1614765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevALSAMixer::ALSAMixer()
1624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
1634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int err;
1644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidOut");
1664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidIn");
1674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_id_t *sid;
1694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_id_alloca(&sid);
1704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
1724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (!mMixer[i]) continue;
1744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;
1764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        property_get (mixerMasterProp[i].propName,
1784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      info->name,
1794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      mixerMasterProp[i].propDefault);
1804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
1824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             elem;
1834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             elem = snd_mixer_elem_next(elem)) {
1844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!snd_mixer_selem_is_active(elem))
1864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                continue;
1874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_selem_get_id(elem, sid);
1894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            // Find PCM playback volume control element.
1914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            const char *elementName = snd_mixer_selem_id_get_name(sid);
1924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (info->elem == NULL &&
1944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                strcmp(elementName, info->name) == 0 &&
1954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                hasVolume[i] (elem)) {
1964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                info->elem = elem;
1984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                getVolumeRange[i] (elem, &info->min, &info->max);
1994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                info->volume = info->max;
2004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                setVol[i] (elem, info->volume);
2014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (i == SND_PCM_STREAM_PLAYBACK &&
2024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    snd_mixer_selem_has_playback_switch (elem))
2034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    snd_mixer_selem_set_playback_switch_all (elem, 1);
2044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                break;
2054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2084113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");
2094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for (int j = 0; mixerProp[j][i].device; j++) {
2114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;
2134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            property_get (mixerProp[j][i].propName,
2154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                          info->name,
2164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                          mixerProp[j][i].propDefault);
2174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
2194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 elem;
2204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 elem = snd_mixer_elem_next(elem)) {
2214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (!snd_mixer_selem_is_active(elem))
2234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    continue;
2244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                snd_mixer_selem_get_id(elem, sid);
2264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                // Find PCM playback volume control element.
2284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                const char *elementName = snd_mixer_selem_id_get_name(sid);
2294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               if (info->elem == NULL &&
2314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    strcmp(elementName, info->name) == 0 &&
2324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    hasVolume[i] (elem)) {
2334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    info->elem = elem;
2354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    getVolumeRange[i] (elem, &info->min, &info->max);
2364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    info->volume = info->max;
2374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    setVol[i] (elem, info->volume);
2384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    if (i == SND_PCM_STREAM_PLAYBACK &&
2394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        snd_mixer_selem_has_playback_switch (elem))
2404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        snd_mixer_selem_set_playback_switch_all (elem, 1);
2414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    break;
2424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
2434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2444113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev            ALOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
2454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2474113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev    ALOGV("mixer initialized.");
2484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2504765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevALSAMixer::~ALSAMixer()
2514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
2534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mMixer[i]) snd_mixer_close (mMixer[i]);
2544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerMasterProp[i].mInfo) {
2554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            delete mixerMasterProp[i].mInfo;
2564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixerMasterProp[i].mInfo = NULL;
2574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for (int j = 0; mixerProp[j][i].device; j++) {
2594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (mixerProp[j][i].mInfo) {
2604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                delete mixerProp[j][i].mInfo;
2614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                mixerProp[j][i].mInfo = NULL;
2624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2654113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev    ALOGV("mixer destroyed.");
2664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setMasterVolume(float volume)
2694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo;
2714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!info || !info->elem) return INVALID_OPERATION;
2724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long minVol = info->min;
2744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long maxVol = info->max;
2754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Make sure volume is between bounds.
2774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long vol = minVol + volume * (maxVol - minVol);
2784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol > maxVol) vol = maxVol;
2794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol < minVol) vol = minVol;
2804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    info->volume = vol;
2824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_playback_volume_all (info->elem, vol);
2834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
2854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setMasterGain(float gain)
2884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_CAPTURE].mInfo;
2904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!info || !info->elem) return INVALID_OPERATION;
2914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long minVol = info->min;
2934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long maxVol = info->max;
2944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Make sure volume is between bounds.
2964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long vol = minVol + gain * (maxVol - minVol);
2974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol > maxVol) vol = maxVol;
2984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (vol < minVol) vol = minVol;
2994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    info->volume = vol;
3014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_mixer_selem_set_capture_volume_all (info->elem, vol);
3024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setVolume(uint32_t device, float left, float right)
3074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
3094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
3104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
3124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long minVol = info->min;
3154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long maxVol = info->max;
3164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            // Make sure volume is between bounds.
3184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long vol = minVol + left * (maxVol - minVol);
3194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol > maxVol) vol = maxVol;
3204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol < minVol) vol = minVol;
3214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->volume = vol;
3234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_selem_set_playback_volume_all (info->elem, vol);
3244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setGain(uint32_t device, float gain)
3304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++)
3324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) {
3334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
3354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long minVol = info->min;
3384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long maxVol = info->max;
3394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            // Make sure volume is between bounds.
3414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            long vol = minVol + gain * (maxVol - minVol);
3424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol > maxVol) vol = maxVol;
3434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (vol < minVol) vol = minVol;
3444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->volume = vol;
3464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            snd_mixer_selem_set_capture_volume_all (info->elem, vol);
3474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setCaptureMuteState(uint32_t device, bool state)
3534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++)
3554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) {
3564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
3584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (snd_mixer_selem_has_capture_switch (info->elem)) {
3614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                int err = snd_mixer_selem_set_capture_switch_all (info->elem, static_cast<int>(!state));
3634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (err < 0) {
3644113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev                    ALOGE("Unable to %s capture mixer switch %s",
3654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        state ? "enable" : "disable", info->name);
3664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    return INVALID_OPERATION;
3674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
3694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->mute = state;
3714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::getCaptureMuteState(uint32_t device, bool *state)
3774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!state) return BAD_VALUE;
3794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++)
3814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) {
3824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
3844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
3854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            *state = info->mute;
3874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return NO_ERROR;
3884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
3894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return BAD_VALUE;
3914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::setPlaybackMuteState(uint32_t device, bool state)
3944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
3964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
3974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
3994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
4004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (snd_mixer_selem_has_playback_switch (info->elem)) {
4024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                int err = snd_mixer_selem_set_playback_switch_all (info->elem, static_cast<int>(!state));
4044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (err < 0) {
4054113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev                    ALOGE("Unable to %s playback mixer switch %s",
4064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        state ? "enable" : "disable", info->name);
4074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    return INVALID_OPERATION;
4084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
4094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
4104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            info->mute = state;
4124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
4134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
4154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
4164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t ALSAMixer::getPlaybackMuteState(uint32_t device, bool *state)
4184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
4194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!state) return BAD_VALUE;
4204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
4224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
4234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
4254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!info || !info->elem) return INVALID_OPERATION;
4264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            *state = info->mute;
4284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return NO_ERROR;
4294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
4304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return BAD_VALUE;
4324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
4334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};        // namespace android
435