14765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev/* AudioStreamOutALSA.cpp
24765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
34765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Copyright 2008-2009 Wind River Systems
44765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Copyright (c) 2011, Code Aurora Forum. All rights reserved.
54765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
64765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Licensed under the Apache License, Version 2.0 (the "License");
74765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** you may not use this file except in compliance with the License.
84765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** You may obtain a copy of the License at
94765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **     http://www.apache.org/licenses/LICENSE-2.0
114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev **
124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** Unless required by applicable law or agreed to in writing, software
134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** distributed under the License is distributed on an "AS IS" BASIS,
144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** See the License for the specific language governing permissions and
164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev ** limitations under the License.
174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev */
184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <errno.h>
204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdarg.h>
214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <sys/stat.h>
224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <fcntl.h>
234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdlib.h>
244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <unistd.h>
254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <dlfcn.h>
264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <math.h>
274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
289746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#define LOG_TAG "AudioStreamOutALSA"
294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev//#define LOG_NDEBUG 0
309746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#define LOG_NDDEBUG 0
314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <utils/Log.h>
324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <utils/String8.h>
334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <cutils/properties.h>
354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <media/AudioRecord.h>
364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <hardware_legacy/power.h>
374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include "AudioHardwareALSA.h"
394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#ifndef ALSA_DEFAULT_SAMPLE_RATE
414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#endif
434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevnamespace android_audio_legacy
454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev// ----------------------------------------------------------------------------
484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE;
504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev// ----------------------------------------------------------------------------
524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
534765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevAudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent, alsa_handle_t *handle) :
544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSAStreamOps(parent, handle),
554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mParent(parent),
564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mFrameCount(0)
574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
604765c439491ddda3de658e62cc4a64d10e726b34Iliyan MalchevAudioStreamOutALSA::~AudioStreamOutALSA()
614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    close();
634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevuint32_t AudioStreamOutALSA::channels() const
664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int c = ALSAStreamOps::channels();
684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return c;
694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t AudioStreamOutALSA::setVolume(float left, float right)
724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int vol;
744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    float volume;
754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    status_t status = NO_ERROR;
764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    volume = (left + right) / 2;
784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (volume < 0.0) {
794113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGW("AudioSessionOutALSA::setVolume(%f) under 0.0, assuming 0.0\n", volume);
804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        volume = 0.0;
814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else if (volume > 1.0) {
824113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGW("AudioSessionOutALSA::setVolume(%f) over 1.0, assuming 1.0\n", volume);
834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        volume = 1.0;
844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    vol = lrint((volume * 0x2000)+0.5);
864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) ||
884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) {
898a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("setLpaVolume(%f)\n", volume);
908a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("Setting LPA volume to %d (available range is 0 to 100)\n", vol);
914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mHandle->module->setLpaVolume(vol);
924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return status;
934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) ||
954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) {
968a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("setCompressedVolume(%f)\n", volume);
978a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("Setting Compressed volume to %d (available range is 0 to 100)\n", vol);
984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mHandle->module->setCompressedVolume(vol);
994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return status;
1004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    else if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
1024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            sizeof(mHandle->useCase)) || !strncmp(mHandle->useCase,
1034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase))) {
1044113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev        ALOGV("Avoid Software volume by returning success\n");
1054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return status;
1064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return INVALID_OPERATION;
1084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
1094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
1114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
1124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int period_size;
1134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    char *use_case;
1144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1154113f34dfbaa8d82a5e1ef0265e916317161984dIliyan Malchev    ALOGV("write:: buffer %p, bytes %d", buffer, bytes);
1164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    snd_pcm_sframes_t n = 0;
1184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    size_t            sent = 0;
1194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    status_t          err;
1204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int write_pending = bytes;
1224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) &&
1244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) &&
1254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
1264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->mLock.lock();
127e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani
128bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani        ALOGD("mHandle->useCase: %s", mHandle->useCase);
129e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
130e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
131bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)){
132bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
133bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_VERB_IP_VOICECALL));
134bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) {
135bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2,
136bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
137bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)){
138bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI,
139bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
140bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) {
141bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
142bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
1434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
144e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        } else {
145bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
146bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,
147bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_VOIP));
148bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) {
149bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
150bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
151bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)){
152bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
153bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
154bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
155bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
156bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani                        sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
157e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            }
158e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        }
159e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        free(use_case);
160e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
161e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani           (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
1629746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
163e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
164e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                  (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
165e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                  (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
1664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                mDevices |= AudioSystem::DEVICE_OUT_PROXY;
1674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                mHandle->module->route(mHandle, mDevices , mParent->mode());
168e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            }else
1694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#endif
170e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            {
171e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani              mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION);
1724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
1739746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
174e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
175e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                  (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
176e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                  (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
177e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            mDevices |= AudioSystem::DEVICE_OUT_PROXY;
178e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            mHandle->module->route(mHandle, mDevices , mParent->mode());
1794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#endif
180e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        } else {
181d4f2d069126d564b2ef504e0cb59369d8e1e9f32ty.lee            mHandle->module->route(mHandle, mDevices , mParent->mode());
182e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        }
183e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) ||
184bf1c87481d62736cab8832e9085c121fbafdbb6bSathishKumar Mani            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) ||
185e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) ||
186e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
187e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
188e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        } else {
189e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase);
190e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        }
191e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
192e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani          (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
193e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani             err = mHandle->module->startVoipCall(mHandle);
194e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        }
195e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        else
196e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani             mHandle->module->open(mHandle);
197e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        if(mHandle->handle == NULL) {
198e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            ALOGE("write:: device open failed");
199e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            mParent->mLock.unlock();
2005f24fd93afdcc66bfd9246a0e0000c0fd7283b7fSathishKumar Mani            return bytes;
201e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        }
202e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani#ifdef QCOM_USBAUDIO_ENABLED
203e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani        if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
204e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani               (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
205e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
206e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani               (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
207e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
208e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            } else {
209e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                mParent->startUsbPlaybackIfNotStarted();
210e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC;
211e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            }
2124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
213e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani#endif
214e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani
2154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->mLock.unlock();
2164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2189746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
2194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if(((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
2204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) &&
2214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        (!mParent->musbPlaybackState)) {
2224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->mLock.lock();
2234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->startUsbPlaybackIfNotStarted();
2248a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("Starting playback on USB");
2254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
2264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev           !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
2270a019914794cc27f5dacddf4e5dbc019dbe21788SathishKumar Mani            ALOGD("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState);
2284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
2294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }else{
2308a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani            ALOGV("enabling music, musbPlaybackState: %d ", mParent->musbPlaybackState);
2314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC;
2324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->mLock.unlock();
2344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2359746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#endif
2364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    period_size = mHandle->periodSize;
2384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    do {
2394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (write_pending < period_size) {
2404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            write_pending = period_size;
2414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if((mParent->mVoipStreamCount) && (mHandle->rxHandle != 0)) {
2434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            n = pcm_write(mHandle->rxHandle,
2444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     (char *)buffer + sent,
2454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      period_size);
2464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        } else if (mHandle->handle != 0){
2474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            n = pcm_write(mHandle->handle,
2484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     (char *)buffer + sent,
2494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      period_size);
2504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (n < 0) {
2529746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani            mParent->mLock.lock();
253e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani            if (mHandle->handle != NULL) {
254e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                ALOGE("pcm_write returned error %d, trying to recover\n", n);
255e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                pcm_close(mHandle->handle);
256e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                mHandle->handle = NULL;
257e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
258e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                  (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
259e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                     pcm_close(mHandle->rxHandle);
260e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                     mHandle->rxHandle = NULL;
261e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                     mHandle->module->startVoipCall(mHandle);
262e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                }
26389c224e298fd280a3f2a69da8cc930ff6d036e18SathishKumar Mani                else
264e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                    mHandle->module->open(mHandle);
26589c224e298fd280a3f2a69da8cc930ff6d036e18SathishKumar Mani                if(mHandle->handle == NULL) {
26689c224e298fd280a3f2a69da8cc930ff6d036e18SathishKumar Mani                   ALOGE("write:: device re-open failed");
26789c224e298fd280a3f2a69da8cc930ff6d036e18SathishKumar Mani                   mParent->mLock.unlock();
26889c224e298fd280a3f2a69da8cc930ff6d036e18SathishKumar Mani                   return bytes;
269e42406e02e32dbb398a2fa0c452e52526b763c8dSathishKumar Mani                }
2704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
2714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mParent->mLock.unlock();
2724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            continue;
2734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        else {
2754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            mFrameCount += n;
2764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            sent += static_cast<ssize_t>((period_size));
2774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            write_pending -= period_size;
2784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } while ((mHandle->handle||(mHandle->rxHandle && mParent->mVoipStreamCount)) && sent < bytes);
2814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return sent;
2834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t AudioStreamOutALSA::dump(int fd, const Vector<String16>& args)
2864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
2884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t AudioStreamOutALSA::open(int mode)
2914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    Mutex::Autolock autoLock(mParent->mLock);
2934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return ALSAStreamOps::open(mode);
2954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
2964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t AudioStreamOutALSA::close()
2984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
2994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    Mutex::Autolock autoLock(mParent->mLock);
3004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3018a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani    ALOGV("close");
3024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
3034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
3044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         if((mParent->mVoipStreamCount)) {
3059746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
3064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             if(mParent->mVoipStreamCount == 1) {
3078a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani                 ALOGV("Deregistering VOIP Call bit, musbPlaybackState:%d, musbRecordingState: %d",
3084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                       mParent->musbPlaybackState, mParent->musbRecordingState);
3094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL;
3104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL;
3114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 mParent->closeUsbPlaybackIfNothingActive();
3124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                 mParent->closeUsbRecordingIfNothingActive();
3134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             }
3149746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#endif
3154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                return NO_ERROR;
3164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         }
3174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         mParent->mVoipStreamCount = 0;
3189746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani    }
3199746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
3209746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani      else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
3214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev              (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
3224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
3234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
3244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC;
3254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
3264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mParent->closeUsbPlaybackIfNothingActive();
3289746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#endif
3294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    ALSAStreamOps::close();
3314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t AudioStreamOutALSA::standby()
3364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    Mutex::Autolock autoLock(mParent->mLock);
3384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3398a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani    ALOGV("standby");
3404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
3424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev      (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
3434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return NO_ERROR;
3444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
3454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3469746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
3474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
3484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
3498a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("Deregistering LPA bit");
3504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
3514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
3528a9785b5e6a199a6c64ac671afc2e8036c7ec13fAjay Dudani        ALOGV("Deregistering MUSIC bit, musbPlaybackState: %d", mParent->musbPlaybackState);
3534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC;
3544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
3559746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#endif
3564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mHandle->module->standby(mHandle);
3584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3599746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#ifdef QCOM_USBAUDIO_ENABLED
3604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mParent->closeUsbPlaybackIfNothingActive();
3619746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudani#endif
3624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    mFrameCount = 0;
3644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define USEC_TO_MSEC(x) ((x + 999) / 1000)
3694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevuint32_t AudioStreamOutALSA::latency() const
3714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    // Android wants latency in milliseconds.
3734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return USEC_TO_MSEC (mHandle->latency);
3744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev// return the number of audio frames written by the audio dsp to DAC since
3774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev// the output has exited standby
3784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatus_t AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames)
3794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    *dspFrames = mFrameCount;
3814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return NO_ERROR;
3824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}       // namespace android_audio_legacy
385