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