blob: 01c9d88957b29cc411da39aa7881f403b2e519f6 [file] [log] [blame]
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001/* AudioSessionOutALSA.cpp
2 **
3 ** Copyright 2008-2009 Wind River Systems
Ravishankar Sarawadi92abe662012-12-28 18:45:52 -08004 ** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Mingming Yinbbd94ad2012-11-29 20:04:36 -08005 **
6 ** Not a Contribution, Apache license notifications and license are
7 ** retained for attribution purposes only.
8 **
9 ** Licensed under the Apache License, Version 2.0 (the "License");
10 ** you may not use this file except in compliance with the License.
11 ** You may obtain a copy of the License at
12 **
13 ** http://www.apache.org/licenses/LICENSE-2.0
14 **
15 ** Unless required by applicable law or agreed to in writing, software
16 ** distributed under the License is distributed on an "AS IS" BASIS,
17 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 ** See the License for the specific language governing permissions and
19 ** limitations under the License.
20 */
21
22#include <errno.h>
23#include <stdarg.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <dlfcn.h>
29#include <math.h>
30
31#define LOG_TAG "AudioSessionOutALSA"
Steve Kondik341c8502013-05-04 01:55:32 -070032//#define LOG_NDEBUG 0
Mingming Yinbbd94ad2012-11-29 20:04:36 -080033#include <utils/Log.h>
34#include <utils/String8.h>
35
36#include <cutils/properties.h>
37#include <media/AudioRecord.h>
38#include <hardware_legacy/power.h>
39
40#include <linux/ioctl.h>
41#include <sys/prctl.h>
42#include <sys/resource.h>
43#include <pthread.h>
44#include <sys/poll.h>
45#include <sys/eventfd.h>
46#include <linux/unistd.h>
47
48#include "AudioHardwareALSA.h"
49
50namespace sys_write {
51 ssize_t lib_write(int fd, const void *buf, size_t count) {
52 return write(fd, buf, count);
53 }
54};
55namespace android_audio_legacy
56{
57#define LPA_MODE 0
58#define TUNNEL_MODE 1
59#define NUM_FDS 2
60#define KILL_EVENT_THREAD 1
61#define BUFFER_COUNT 4
Arne Coucheron04c080a2013-09-04 04:46:52 +020062#ifndef LPA_DEFAULT_BUFFER_SIZE
63#define LPA_DEFAULT_BUFFER_SIZE 256
64#endif
65#define LPA_BUFFER_SIZE LPA_DEFAULT_BUFFER_SIZE*1024
Haynes Mathew George3184a322013-02-01 16:29:54 -080066#define TUNNEL_BUFFER_SIZE 240*1024
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -080067#define TUNNEL_METADATA_SIZE 64
Mingming Yinbbd94ad2012-11-29 20:04:36 -080068#define MONO_CHANNEL_MODE 1
69// ----------------------------------------------------------------------------
70
71AudioSessionOutALSA::AudioSessionOutALSA(AudioHardwareALSA *parent,
72 uint32_t devices,
73 int format,
74 uint32_t channels,
75 uint32_t samplingRate,
76 int type,
77 status_t *status)
78{
79
80 alsa_handle_t alsa_handle;
81 char *use_case;
82 bool bIsUseCaseSet = false;
83
84 Mutex::Autolock autoLock(mLock);
85 // Default initilization
86 mParent = parent;
87 mAlsaDevice = mParent->mALSADevice;
88 mUcMgr = mParent->mUcMgr;
89 mFormat = format;
90 mSampleRate = samplingRate;
91 mChannels = channels;
92
93
94 mBufferSize = 0;
95 *status = BAD_VALUE;
96
97 mPaused = false;
98 mSeeking = false;
99 mReachedEOS = false;
100 mSkipWrite = false;
101
102 mAlsaHandle = NULL;
103 mUseCase = AudioHardwareALSA::USECASE_NONE;
104
105 mInputBufferSize = type ? TUNNEL_BUFFER_SIZE : LPA_BUFFER_SIZE;
106 mInputBufferCount = BUFFER_COUNT;
107 mEfd = -1;
108 mEosEventReceived = false;
109 mEventThread = NULL;
110 mEventThreadAlive = false;
111 mKillEventThread = false;
112 mObserver = NULL;
113 mOutputMetadataLength = 0;
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800114 mSkipEOS = false;
Haynes Mathew George9e5c3ef2013-02-13 11:54:56 -0800115 mTunnelMode = false;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800116
117 if(devices == 0) {
118 ALOGE("No output device specified");
119 return;
120 }
121 if((format == AUDIO_FORMAT_PCM_16_BIT) && (channels == 0 || channels > 6)) {
122 ALOGE("Invalid number of channels %d", channels);
123 return;
124 }
125
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800126 if(mParent->isExtOutDevice(devices)) {
127 ALOGE("Set Capture from proxy true");
128 mParent->mRouteAudioToExtOut = true;
Subhash Chandra Bose Naripeddy1ec163f2012-12-21 18:12:05 -0800129 if(mParent->mExtOutStream == NULL) {
130 mParent->switchExtOut(devices);
131 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800132 }
133
134 //open device based on the type (LPA or Tunnel) and devices
135 //TODO: Check format type for linear vs non-linear to determine LPA/Tunnel
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800136 *status = openAudioSessionDevice(type, devices);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800137
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800138 if (*status != NO_ERROR) {
139 ALOGE("Failed to open LPA/Tunnel Session");
140 return;
141 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800142 //Creates the event thread to poll events from LPA/Compress Driver
143 createEventThread();
144
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800145 mUseCase = mParent->useCaseStringToEnum(mAlsaHandle->useCase);
146 ALOGV("mParent->mRouteAudioToExtOut = %d", mParent->mRouteAudioToExtOut);
147 if (mParent->mRouteAudioToExtOut) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800148 status_t err = NO_ERROR;
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800149 err = mParent->startPlaybackOnExtOut_l(mUseCase);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800150 *status = err;
151 }
152
153 *status = NO_ERROR;
154}
155
156AudioSessionOutALSA::~AudioSessionOutALSA()
157{
158 ALOGD("~AudioSessionOutALSA");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800159 mSkipWrite = true;
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800160
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800161 mWriteCv.signal();
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800162 // trying to acquire mDecoderLock, make sure that, the waiting decoder thread
163 // receives the signal before the conditional variable "mWriteCv" is
164 // destroyed in ~AudioSessionOut(). Decoder thread acquires this lock
165 // before it waits for the signal.
166 Mutex::Autolock autoDecoderLock(mDecoderLock);
167 //TODO: This might need to be Locked using Parent lock
168 reset();
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800169 if (mParent->mRouteAudioToExtOut) {
170 status_t err = mParent->stopPlaybackOnExtOut_l(mUseCase);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800171 if(err){
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800172 ALOGE("stopPlaybackOnExtOut_l return err %d", err);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800173 }
174 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800175}
176
177status_t AudioSessionOutALSA::setVolume(float left, float right)
178{
179 Mutex::Autolock autoLock(mLock);
180 float volume;
181 status_t status = NO_ERROR;
182
183 volume = (left + right) / 2;
184 if (volume < 0.0) {
185 ALOGW("AudioSessionOutALSA::setVolume(%f) under 0.0, assuming 0.0\n", volume);
186 volume = 0.0;
187 } else if (volume > 1.0) {
188 ALOGW("AudioSessionOutALSA::setVolume(%f) over 1.0, assuming 1.0\n", volume);
189 volume = 1.0;
190 }
Subhash Chandra Bose Naripeddy0ab86af2013-02-19 23:15:17 -0800191 mStreamVol = (lrint((left * 0x2000)+0.5)) << 16 | (lrint((right * 0x2000)+0.5));
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800192
193 ALOGV("Setting stream volume to %d (available range is 0 to 0x2000)\n", mStreamVol);
194 if(mAlsaHandle) {
195 if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) ||
196 !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) {
197 ALOGD("setLpaVolume(%u)\n", mStreamVol);
198 ALOGD("Setting LPA volume to %d (available range is 0 to 100)\n", mStreamVol);
199 mAlsaHandle->module->setLpaVolume(mStreamVol);
200 return status;
201 }
202 else if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) ||
203 !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) {
204 ALOGD("setCompressedVolume(%u)\n", mStreamVol);
205 ALOGD("Setting Compressed volume to %d (available range is 0 to 100)\n", mStreamVol);
206 mAlsaHandle->module->setCompressedVolume(mStreamVol);
207 return status;
208 }
209 }
210 return INVALID_OPERATION;
211}
212
213
214status_t AudioSessionOutALSA::openAudioSessionDevice(int type, int devices)
215{
216 char* use_case;
217 status_t status = NO_ERROR;
218 //1.) Based on the current device and session type (LPA/Tunnel), open a device
219 // with verb or modifier
220 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
221 if (type == LPA_MODE) {
222 if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
223 strlen(SND_USE_CASE_VERB_INACTIVE)))) {
224 status = openDevice(SND_USE_CASE_VERB_HIFI_LOW_POWER, true, devices);
225 } else {
226 status = openDevice(SND_USE_CASE_MOD_PLAY_LPA, false, devices);
227 }
228 } else if (type == TUNNEL_MODE) {
229 if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
230 strlen(SND_USE_CASE_VERB_INACTIVE)))) {
231 status = openDevice(SND_USE_CASE_VERB_HIFI_TUNNEL, true, devices);
232 } else {
233 status = openDevice(SND_USE_CASE_MOD_PLAY_TUNNEL, false, devices);
234 }
Haynes Mathew George9e5c3ef2013-02-13 11:54:56 -0800235 mTunnelMode = true;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800236 }
Krishnankutty Kolathappilly338813c2013-02-11 18:24:24 -0800237
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700238 mOutputMetadataLength = sizeof(output_metadata_handle_t);
239 ALOGD("openAudioSessionDevice - mOutputMetadataLength = %d", mOutputMetadataLength);
240
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800241 if(use_case) {
242 free(use_case);
243 use_case = NULL;
244 }
245 if(status != NO_ERROR) {
246 return status;
247 }
248
249 //2.) Get the device handle
250 ALSAHandleList::iterator it = mParent->mDeviceList.end();
251 it--;
252
253 mAlsaHandle = &(*it);
254 ALOGV("mAlsaHandle %p, mAlsaHandle->useCase %s",mAlsaHandle, mAlsaHandle->useCase);
255
256 //3.) mmap the buffers for playback
257 status_t err = mmap_buffer(mAlsaHandle->handle);
258 if(err) {
259 ALOGE("MMAP buffer failed - playback err = %d", err);
260 return err;
261 }
262 ALOGV("buffer pointer %p ", mAlsaHandle->handle->addr);
263
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700264 //Set Meta data mode
265 if (type == LPA_MODE) {
266 status = setMetaDataMode();
267 if(status != NO_ERROR) {
268 return status;
269 }
270 }
271
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800272 //4.) prepare the driver for playback and allocate the buffers
273 status = pcm_prepare(mAlsaHandle->handle);
274 if (status) {
275 ALOGE("PCM Prepare failed - playback err = %d", err);
276 return status;
277 }
278 bufferAlloc(mAlsaHandle);
279 mBufferSize = mAlsaHandle->periodSize;
280 return NO_ERROR;
281}
282
283ssize_t AudioSessionOutALSA::write(const void *buffer, size_t bytes)
284{
285 Mutex::Autolock autoLock(mLock);
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700286 int err = 0;
Haynes Mathew George9e244fc2013-02-07 20:30:04 -0800287
288 ALOGV("write Empty Queue size() = %d, Filled Queue size() = %d "
289 "mReached EOS %d, mEosEventReceived %d bytes %d",
290 mEmptyQueue.size(),mFilledQueue.size(), mReachedEOS, mEosEventReceived, bytes);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800291
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800292 mEosEventReceived = false;
293 mReachedEOS = false;
294
295 if (!bytes) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800296 mReachedEOS = true;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800297 }
298
299 //1.) Dequeue the buffer from empty buffer queue. Copy the data to be
300 // written into the buffer. Then Enqueue the buffer to the filled
301 // buffer queue
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800302
Haynes Mathew George9e244fc2013-02-07 20:30:04 -0800303 if (mSkipWrite) {
304 LOG_ALWAYS_FATAL_IF((mEmptyQueue.size() != BUFFER_COUNT),
305 "::write, mSkipwrite is true but empty queue isnt full");
306 ALOGD("reset mSkipWrite in write");
307 mSkipWrite = false;
308 ALOGD("mSkipWrite is false now write bytes %d", bytes);
309 ALOGD("skipping buffer in write");
Srikanth Katta7c6f5092013-07-09 20:31:18 +0530310
311 /* returning the bytes itself as we are skipping write.
312 * This is considered as successfull write.
313 * Skipping write could be because of a flush.
314 */
315 return bytes;
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800316 }
317
Haynes Mathew George9e244fc2013-02-07 20:30:04 -0800318 ALOGV("not skipping buffer in write since mSkipWrite = %d, "
319 "mEmptyQueuesize %d ", mSkipWrite, mEmptyQueue.size());
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800320
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800321 List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
322 BuffersAllocated buf = *it;
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800323
324 mEmptyQueue.erase(it);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800325
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700326 updateMetaData(bytes);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800327
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700328 memcpy(buf.memBuf, &mOutputMetadataTunnel, mOutputMetadataLength);
Steve Kondik4027a1e2013-06-01 20:34:23 -0700329 ALOGV("buf.memBuf =%x , Copy Metadata = %d, bytes = %d", buf.memBuf,mOutputMetadataLength, bytes);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800330
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700331 if (bytes == 0) {
332 buf.bytesToWrite = 0;
333 err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size);
Haynes Mathew George6db504e2013-01-28 18:04:45 -0800334
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700335 //bad part is !err does not guarantee pcm_write succeeded!
336 if (!err) { //mReachedEOS is already set
337 /*
338 * This workaround is needed to ensure EOS from the event thread
339 * is posted when the first (only) buffer given to the driver
340 * is a zero length buffer. Note that the compressed driver
341 * does not interrupt the timer fd if the EOS buffer was queued
342 * after a buffer with valid data (full or partial). So we
343 * only need to do this in this special case.
344 */
345 if (mFilledQueue.empty()) {
346 mFilledQueue.push_back(buf);
Haynes Mathew George6db504e2013-01-28 18:04:45 -0800347 }
Srikanth Katta7c6f5092013-07-09 20:31:18 +0530348 return bytes;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800349 }
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700350
351 return err;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800352 }
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800353 ALOGV("PCM write before memcpy start");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800354 memcpy((buf.memBuf + mOutputMetadataLength), buffer, bytes);
Haynes Mathew George9e5c3ef2013-02-13 11:54:56 -0800355
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800356 buf.bytesToWrite = bytes;
357
358 //2.) Write the buffer to the Driver
359 ALOGV("PCM write start");
360 err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size);
361 ALOGV("PCM write complete");
362 if (bytes < (mAlsaHandle->handle->period_size - mOutputMetadataLength)) {
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800363 ALOGV("Last buffer case %d", mAlsaHandle->handle->start);
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800364 if(!mAlsaHandle->handle->start) {
365 if ( ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START) < 0 ) {
366 ALOGE("Audio Start failed");
367 } else {
368 mAlsaHandle->handle->start = 1;
369 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800370 }
Haynes Mathew George9e5c3ef2013-02-13 11:54:56 -0800371
372 if (!mTunnelMode) mReachedEOS = true;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800373 }
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700374 int32_t * Buf = (int32_t *) buf.memBuf;
Steve Kondik4027a1e2013-06-01 20:34:23 -0700375 ALOGV(" buf.memBuf [0] = %x , buf.memBuf [1] = %x", Buf[0], Buf[1]);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800376 mFilledQueue.push_back(buf);
Srikanth Katta7c6f5092013-07-09 20:31:18 +0530377 if(!err) {
378 //return the bytes written to HAL if write is successful.
379 return bytes;
380 } else {
381 //else condition return err value returned
382 return err;
383 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800384}
385
386void AudioSessionOutALSA::bufferAlloc(alsa_handle_t *handle) {
387 void *mem_buf = NULL;
388 int i = 0;
389
390 int32_t nSize = mAlsaHandle->handle->period_size;
391 ALOGV("number of input buffers = %d", mInputBufferCount);
392 ALOGV("memBufferAlloc calling with required size %d", nSize);
393 for (i = 0; i < mInputBufferCount; i++) {
394 mem_buf = (int32_t *)mAlsaHandle->handle->addr + (nSize * i/sizeof(int));
395 ALOGV("Buffer pointer %p ", mem_buf);
396 BuffersAllocated buf(mem_buf, nSize);
397 memset(buf.memBuf, 0x0, nSize);
398 mEmptyQueue.push_back(buf);
399 mBufPool.push_back(buf);
400 ALOGV("The MEM that is allocated - buffer is %x",\
401 (unsigned int)mem_buf);
402 }
403}
404
405void AudioSessionOutALSA::bufferDeAlloc() {
406 while (!mBufPool.empty()) {
407 List<BuffersAllocated>::iterator it = mBufPool.begin();
408 ALOGV("Removing input buffer from Buffer Pool ");
409 mBufPool.erase(it);
410 }
411}
412
413void AudioSessionOutALSA::requestAndWaitForEventThreadExit() {
414 if (!mEventThreadAlive)
415 return;
416 mKillEventThread = true;
417 if(mEfd != -1) {
418 ALOGE("Writing to mEfd %d",mEfd);
419 uint64_t writeValue = KILL_EVENT_THREAD;
420 sys_write::lib_write(mEfd, &writeValue, sizeof(uint64_t));
421 }
422 pthread_join(mEventThread,NULL);
423 ALOGV("event thread killed");
424}
425
426void * AudioSessionOutALSA::eventThreadWrapper(void *me) {
427 static_cast<AudioSessionOutALSA *>(me)->eventThreadEntry();
428 return NULL;
429}
430
431void AudioSessionOutALSA::eventThreadEntry() {
432 //1.) Initialize the variables required for polling events
433 int rc = 0;
434 int err_poll = 0;
435 int avail = 0;
436 int i = 0;
437 struct pollfd pfd[NUM_FDS];
438 int timeout = -1;
439
440 //2.) Set the priority for the event thread
441 pid_t tid = gettid();
442 androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
443 prctl(PR_SET_NAME, (unsigned long)"HAL Audio EventThread", 0, 0, 0);
444
445 //3.) Allocate two FDs for polling.
446 // 1st FD: Polling on the Driver's timer_fd. This is used for getting write done
447 // events from the driver
448 // 2nd FD: Polling on a local fd so we can interrup the event thread locally
449 // when playback is stopped from Apps
450 // The event thread will when a write is performed on one of these FDs
451 ALOGV("Allocating poll fd");
452 if(!mKillEventThread) {
453 pfd[0].fd = mAlsaHandle->handle->timer_fd;
454 pfd[0].events = (POLLIN | POLLERR | POLLNVAL);
455 mEfd = eventfd(0,0);
456 pfd[1].fd = mEfd;
457 pfd[1].events = (POLLIN | POLLERR | POLLNVAL);
458 }
459
460 //4.) Start a poll for write done events from driver.
461 while(!mKillEventThread && ((err_poll = poll(pfd, NUM_FDS, timeout)) >=0)) {
462 ALOGV("pfd[0].revents =%d ", pfd[0].revents);
463 ALOGV("pfd[1].revents =%d ", pfd[1].revents);
464 // Handle Poll errors
465 if (err_poll == EINTR)
466 ALOGE("Timer is intrrupted");
467 if ((pfd[1].revents & POLLERR) || (pfd[1].revents & POLLNVAL)) {
468 pfd[1].revents = 0;
469 ALOGE("POLLERR or INVALID POLL");
470 }
471
472 //POLLIN event on 2nd FD. Kill from event thread
473 if (pfd[1].revents & POLLIN) {
474 uint64_t u;
475 read(mEfd, &u, sizeof(uint64_t));
476 ALOGV("POLLIN event occured on the event fd, value written to %llu",
477 (unsigned long long)u);
478 pfd[1].revents = 0;
479 if (u == KILL_EVENT_THREAD) {
480 continue;
481 }
482 }
483
484 //Poll error on Driver's timer fd
485 if((pfd[0].revents & POLLERR) || (pfd[0].revents & POLLNVAL)) {
486 pfd[0].revents = 0;
487 continue;
488 }
489
490 //Pollin event on Driver's timer fd
491 if (pfd[0].revents & POLLIN && !mKillEventThread) {
492 struct snd_timer_tread rbuf[4];
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800493 ALOGV("mAlsaHandle->handle = %p", mAlsaHandle->handle);
494 if( !mAlsaHandle->handle ) {
495 ALOGD(" mAlsaHandle->handle is NULL, breaking from while loop in eventthread");
496 pfd[0].revents = 0;
497 break;
498 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800499 read(mAlsaHandle->handle->timer_fd, rbuf, sizeof(struct snd_timer_tread) * 4 );
500 pfd[0].revents = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800501 ALOGV("After an event occurs");
502
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800503 {
504 Mutex::Autolock _l(mLock);
505 if (mFilledQueue.empty()) {
506 ALOGV("Filled queue is empty"); //only time this would be valid is after a flush?
507 continue;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800508 }
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800509 // Transfer a buffer that was consumed by the driver from filled queue
510 // to empty queue
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800511
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800512 BuffersAllocated buf = *(mFilledQueue.begin());
513 mFilledQueue.erase(mFilledQueue.begin());
514 ALOGV("mFilledQueue %d", mFilledQueue.size());
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800515
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800516 mEmptyQueue.push_back(buf);
517 mWriteCv.signal();
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800518 ALOGV("Reset mSkipwrite in eventthread entry");
519 mSkipWrite = false;
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800520
521 //Post EOS in case the filled queue is empty and EOS is reached.
522 if (mFilledQueue.empty() && mReachedEOS) {
523 drainAndPostEOS_l();
524 }
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800525 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800526 }
527 }
528
529 //5.) Close mEfd that was created
530 mEventThreadAlive = false;
531 if (mEfd != -1) {
532 close(mEfd);
533 mEfd = -1;
534 }
535 ALOGV("Event Thread is dying.");
536 return;
537
538}
539
540void AudioSessionOutALSA::createEventThread() {
541 ALOGV("Creating Event Thread");
542 mKillEventThread = false;
543 mEventThreadAlive = true;
544 pthread_attr_t attr;
545 pthread_attr_init(&attr);
546 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
547 pthread_create(&mEventThread, &attr, eventThreadWrapper, this);
548 ALOGV("Event Thread created");
549}
550
551status_t AudioSessionOutALSA::start()
552{
553 Mutex::Autolock autoLock(mLock);
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800554 ALOGV("AudioSessionOutALSA start()");
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800555 //we should not reset EOS here, since EOS could have been
556 //marked in write, the only place to clear EOS should
557 //be flush
558 //mEosEventReceived = false;
559 //mReachedEOS = false;
560 //mSkipEOS = false;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800561 if (mPaused) {
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800562 ALOGV("AudioSessionOutALSA ::start mPaused true");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800563 status_t err = NO_ERROR;
564 if (mSeeking) {
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800565 ALOGV("AudioSessionOutALSA ::start before drain");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800566 drain();
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800567 ALOGV("AudioSessionOutALSA ::start after drain");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800568 mSeeking = false;
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800569 } else {
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800570 ALOGV("AudioSessionOutALSA ::start before resume");
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800571 if (resume_l() == UNKNOWN_ERROR) {
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800572 ALOGV("AudioSessionOutALSA ::start after resume error");
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800573 return UNKNOWN_ERROR;
574 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800575 }
576 mPaused = false;
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800577 } else if (!mAlsaHandle->handle->start) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800578 //Signal the driver to start rendering data
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800579 ALOGV("AudioSessionOutALSA ::start calling _ioctl_start");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800580 if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START)) {
581 ALOGE("start:SNDRV_PCM_IOCTL_START failed\n");
582 return UNKNOWN_ERROR;
583 }
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800584 mAlsaHandle->handle->start = 1;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800585 }
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800586 ALOGV("AudioSessionOutALSA ::start done");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800587 return NO_ERROR;
588}
589
590status_t AudioSessionOutALSA::pause()
591{
592 Mutex::Autolock autoLock(mLock);
593 status_t err = NO_ERROR;
594 ALOGD("Pausing the driver");
595 //Signal the driver to pause rendering data
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800596 if (pause_l() == UNKNOWN_ERROR) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800597 return UNKNOWN_ERROR;
598 }
599 mPaused = true;
600
601 if(err) {
602 ALOGE("pause returned error");
603 return err;
604 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800605 return err;
606
607}
608
609status_t AudioSessionOutALSA::pause_l()
610{
611 if (!mPaused) {
612 if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1) < 0) {
613 ALOGE("PAUSE failed on use case %s", mAlsaHandle->useCase);
614 return UNKNOWN_ERROR;
615 }
616 }
617 return NO_ERROR;
618}
619
620status_t AudioSessionOutALSA::resume_l()
621{
622 status_t err = NO_ERROR;
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800623 if (mPaused) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800624 if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,0) < 0) {
625 ALOGE("Resume failed on use case %s", mAlsaHandle->useCase);
626 return UNKNOWN_ERROR;
627 }
628 }
629 return NO_ERROR;
630}
631
632status_t AudioSessionOutALSA::drain()
633{
634 mAlsaHandle->handle->start = 0;
635 int err = pcm_prepare(mAlsaHandle->handle);
636 if(err != OK) {
637 ALOGE("pcm_prepare -seek = %d",err);
638 //Posting EOS
639 if (mObserver)
640 mObserver->postEOS(0);
641 return UNKNOWN_ERROR;
642 }
643
644 ALOGV("drain Empty Queue size() = %d, Filled Queue size() = %d ",
645 mEmptyQueue.size(), mFilledQueue.size());
646
647 mAlsaHandle->handle->sync_ptr->flags =
648 SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
649 sync_ptr(mAlsaHandle->handle);
650 ALOGV("appl_ptr=%d",(int)mAlsaHandle->handle->sync_ptr->c.control.appl_ptr);
651 return NO_ERROR;
652}
653
654status_t AudioSessionOutALSA::flush()
655{
656 Mutex::Autolock autoLock(mLock);
657 ALOGV("AudioSessionOutALSA flush");
658 int err;
659 {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800660 // 1.) Clear the Empty and Filled buffer queue
661 mEmptyQueue.clear();
662 mFilledQueue.clear();
663
664 // 2.) Add all the available buffers to Request Queue (Maintain order)
665 List<BuffersAllocated>::iterator it = mBufPool.begin();
666 for (; it!=mBufPool.end(); ++it) {
667 memset(it->memBuf, 0x0, (*it).memBufsize);
668 mEmptyQueue.push_back(*it);
669 }
670 }
671
672 ALOGV("Transferred all the buffers from Filled queue to "
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800673 "Empty queue to handle seek paused %d, skipwrite %d", mPaused, mSkipWrite);
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800674 ALOGV("Set mReachedEOS to false and mEosEventReceived to false");
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800675 mReachedEOS = false;
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800676 mEosEventReceived = false;
677 mSkipEOS = false;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800678 // 3.) If its in start state,
679 // Pause and flush the driver and Resume it again
680 // If its in paused state,
681 // Set the seek flag, Resume will take care of flushing the
682 // driver
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800683 if (!mPaused) {
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800684 ALOGV("AudioSessionOutALSA flush going to call Pause");
685 if ((err = ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1)) < 0) {
686 ALOGE("Audio Pause failed - continuing");
687 //return UNKNOWN_ERROR;
688 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800689 } else {
690 mSeeking = true;
691 }
692
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800693 //drain has to be called every time irrespective of whether its paused or not
694 if ((err = drain()) != OK) {
695 ALOGE("pcm_prepare failed - continuing");
696 //return err;
697 }
698
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800699 //4.) Skip the current write from the decoder and signal to the Write get
700 // the next set of data from the decoder
701 mSkipWrite = true;
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800702 ALOGV("signalling from flush mSkipWrite %d", mSkipWrite);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800703 mWriteCv.signal();
704
705 ALOGV("AudioSessionOutALSA::flush completed");
706 return NO_ERROR;
707}
708
709
710
711status_t AudioSessionOutALSA::stop()
712{
713 Mutex::Autolock autoLock(mLock);
714 ALOGV("AudioSessionOutALSA- stop");
715 // close all the existing PCM devices
716 mSkipWrite = true;
717 mWriteCv.signal();
718
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800719 if (mParent->mRouteAudioToExtOut) {
720 status_t err = mParent->suspendPlaybackOnExtOut(mUseCase);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800721 if(err) {
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800722 ALOGE("stop-suspendPlaybackOnExtOut- return err = %d", err);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800723 return err;
724 }
725 }
726
727 ALOGV("stop -");
728
729 return NO_ERROR;
730}
731
732status_t AudioSessionOutALSA::standby()
733{
Subhash Chandra Bose Naripeddyebd7ad82012-12-18 21:50:46 -0800734 // At this point, all the buffers with the driver should be
735 // flushed.
Haynes Mathew Georgea5a6a802013-01-02 21:20:16 -0800736 status_t err = NO_ERROR;
Krishnankutty Kolathappillyed775c12013-03-26 20:39:53 -0700737 flush();
Amit Shekharcd26b132013-07-31 16:03:11 -0700738 Mutex::Autolock autoLock(mParent->mLock);
739
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800740 mAlsaHandle->module->standby(mAlsaHandle);
741 if (mParent->mRouteAudioToExtOut) {
742 ALOGD("Standby - stopPlaybackOnExtOut_l - mUseCase = %d",mUseCase);
743 err = mParent->stopPlaybackOnExtOut_l(mUseCase);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800744 if(err){
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800745 ALOGE("stopPlaybackOnExtOut_l return err %d", err);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800746 }
747 }
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800748 mPaused = false;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800749 return err;
750}
751
752#define USEC_TO_MSEC(x) ((x + 999) / 1000)
753
754uint32_t AudioSessionOutALSA::latency() const
755{
756 // Android wants latency in milliseconds.
Steve Kondikd97aa372013-09-25 17:19:52 -0700757 return USEC_TO_MSEC (mAlsaHandle->latency);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800758}
759
760status_t AudioSessionOutALSA::setObserver(void *observer)
761{
762 ALOGV("Registering the callback \n");
763 mObserver = reinterpret_cast<AudioEventObserver *>(observer);
764 return NO_ERROR;
765}
766
767status_t AudioSessionOutALSA::dump(int fd, const Vector<String16>& args)
768{
769 return NO_ERROR;
770}
771
772status_t AudioSessionOutALSA::getNextWriteTimestamp(int64_t *timestamp)
773{
774 struct snd_compr_tstamp tstamp;
775 tstamp.timestamp = -1;
776 if (ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_TSTAMP, &tstamp)){
777 ALOGE("Failed SNDRV_COMPRESS_TSTAMP\n");
778 return UNKNOWN_ERROR;
779 } else {
780 ALOGV("Timestamp returned = %lld\n", tstamp.timestamp);
781 *timestamp = tstamp.timestamp;
782 return NO_ERROR;
783 }
784 return NO_ERROR;
785}
786
787// return the number of audio frames written by the audio dsp to DAC since
788// the output has exited standby
789status_t AudioSessionOutALSA::getRenderPosition(uint32_t *dspFrames)
790{
791 Mutex::Autolock autoLock(mLock);
792 *dspFrames = mFrameCount;
793 return NO_ERROR;
794}
795
796status_t AudioSessionOutALSA::getBufferInfo(buf_info **buf) {
797 if (!mAlsaHandle) {
798 return NO_ERROR;
799 }
800 buf_info *tempbuf = (buf_info *)malloc(sizeof(buf_info) + mInputBufferCount*sizeof(int *));
801 ALOGV("Get buffer info");
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700802 tempbuf->bufsize = (mAlsaHandle->handle->period_size - mOutputMetadataLength);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800803 tempbuf->nBufs = mInputBufferCount;
804 tempbuf->buffers = (int **)((char*)tempbuf + sizeof(buf_info));
805 List<BuffersAllocated>::iterator it = mBufPool.begin();
806 for (int i = 0; i < mInputBufferCount; i++) {
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -0700807 tempbuf->buffers[i] = (int *)(((char *)it->memBuf) + mOutputMetadataLength);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800808 it++;
809 }
810 *buf = tempbuf;
811 return NO_ERROR;
812}
813
814status_t AudioSessionOutALSA::isBufferAvailable(int *isAvail) {
815
816 Mutex::Autolock autoLock(mLock);
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800817 // this lock is required to synchronize between decoder thread and control thread.
818 // if this thread is waiting for a signal on the conditional ariable "mWriteCv"
819 // and the ~AudioSessionOut() signals but the mWriteCv is destroyed, before the
820 // signal reaches the waiting thread, it can lead to an indefinite wait resulting
821 // in deadlock.
822 ALOGV("acquiring mDecoderLock in isBufferAvailable()");
823 Mutex::Autolock autoDecoderLock(mDecoderLock);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800824 ALOGV("isBufferAvailable Empty Queue size() = %d, Filled Queue size() = %d ",
825 mEmptyQueue.size(),mFilledQueue.size());
826 *isAvail = false;
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800827
Haynes Mathew George9e244fc2013-02-07 20:30:04 -0800828 /*
829 * Only time the below condition is true is when isBufferAvailable is called
830 * immediately after a flush
831 */
832 if (mSkipWrite) {
833 LOG_ALWAYS_FATAL_IF((mEmptyQueue.size() != BUFFER_COUNT),
834 "::isBufferAvailable, mSkipwrite is true but empty queue isnt full");
Subhash Chandra Bose Naripeddy908253a2012-12-07 11:57:25 -0800835 mSkipWrite = false;
836 }
837 // 1.) Wait till a empty buffer is available in the Empty buffer queue
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800838 while (mEmptyQueue.empty()) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800839 ALOGV("Write: waiting on mWriteCv");
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -0800840 mWriteCv.wait(mLock);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800841 if (mSkipWrite) {
842 ALOGV("Write: Flushing the previous write buffer");
843 mSkipWrite = false;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800844 return NO_ERROR;
845 }
846 ALOGV("isBufferAvailable: received a signal to wake up");
847 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800848
849 *isAvail = true;
850 return NO_ERROR;
851}
852
853status_t AudioSessionOutALSA::openDevice(char *useCase, bool bIsUseCase, int devices)
854{
855 alsa_handle_t alsa_handle;
856 status_t status = NO_ERROR;
857 ALOGV("openDevice: E usecase %s", useCase);
858 alsa_handle.module = mAlsaDevice;
859 alsa_handle.bufferSize = mInputBufferSize;
860 alsa_handle.devices = devices;
861 alsa_handle.handle = 0;
862 alsa_handle.format = (mFormat == AUDIO_FORMAT_PCM_16_BIT ? SNDRV_PCM_FORMAT_S16_LE : mFormat);
863 //ToDo: Add conversion from channel Mask to channel count.
864 if (mChannels == AUDIO_CHANNEL_OUT_MONO)
865 alsa_handle.channels = MONO_CHANNEL_MODE;
866 else
867 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
Subhash Chandra Bose Naripeddy27c90302012-12-19 20:14:54 -0800868 alsa_handle.channels = AudioSystem::popCount(mChannels);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800869 alsa_handle.sampleRate = mSampleRate;
870 alsa_handle.latency = PLAYBACK_LATENCY;
871 alsa_handle.rxHandle = 0;
872 alsa_handle.ucMgr = mUcMgr;
873 alsa_handle.session = this;
874 strlcpy(alsa_handle.useCase, useCase, sizeof(alsa_handle.useCase));
875
876 mAlsaDevice->route(&alsa_handle, devices, mParent->mode());
877 if (bIsUseCase) {
878 snd_use_case_set(mUcMgr, "_verb", useCase);
879 } else {
880 snd_use_case_set(mUcMgr, "_enamod", useCase);
881 }
882
Krishnankutty Kolathappilly338813c2013-02-11 18:24:24 -0800883 //Set Tunnel or LPA bit if the playback over usb is tunnel or Lpa
884 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
885 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
886 if((!strcmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
887 (!strcmp(useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
888 ALOGV("doRouting: LPA device switch to proxy");
889 mParent->startUsbPlaybackIfNotStarted();
890 mParent->musbPlaybackState |= USBPLAYBACKBIT_LPA;
891 } else if((!strcmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
892 (!strcmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
893 ALOGD("doRouting: Tunnel Player device switch to proxy");
894 mParent->startUsbPlaybackIfNotStarted();
895 mParent->musbPlaybackState |= USBPLAYBACKBIT_TUNNEL;
896 }
897 }
898
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800899 status = mAlsaDevice->open(&alsa_handle);
900 if(status != NO_ERROR) {
901 ALOGE("Could not open the ALSA device for use case %s", alsa_handle.useCase);
902 mAlsaDevice->close(&alsa_handle);
903 } else{
904 mParent->mDeviceList.push_back(alsa_handle);
905 }
906 return status;
907}
908
909status_t AudioSessionOutALSA::closeDevice(alsa_handle_t *pHandle)
910{
911 status_t status = NO_ERROR;
912 ALOGV("closeDevice: useCase %s", pHandle->useCase);
913 //TODO: remove from mDeviceList
914 if(pHandle) {
915 status = mAlsaDevice->close(pHandle);
916 }
917 return status;
918}
919
920status_t AudioSessionOutALSA::setParameters(const String8& keyValuePairs)
921{
922 Mutex::Autolock autoLock(mLock);
923 AudioParameter param = AudioParameter(keyValuePairs);
924 String8 key = String8(AudioParameter::keyRouting);
Ravishankar Sarawadi92abe662012-12-28 18:45:52 -0800925 String8 value;
926
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800927 int device;
928 if (param.getInt(key, device) == NO_ERROR) {
929 // Ignore routing if device is 0.
930 if(device) {
931 ALOGV("setParameters(): keyRouting with device %#x", device);
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800932 if (mParent->isExtOutDevice(device)) {
933 mParent->mRouteAudioToExtOut = true;
934 ALOGD("setParameters(): device %#x", device);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800935 }
936 mParent->doRouting(device);
937 }
938 param.remove(key);
Ravishankar Sarawadi92abe662012-12-28 18:45:52 -0800939 }
Steve Kondikfb50ff22013-07-25 23:07:48 -0700940 key = String8(AUDIO_PARAMETER_KEY_ADSP_STATUS);
Ravishankar Sarawadi92abe662012-12-28 18:45:52 -0800941 if (param.get(key, value) == NO_ERROR) {
942 if (value == "ONLINE"){
943 mReachedEOS = true;
944 mSkipWrite = true;
945 mWriteCv.signal();
946 mObserver->postEOS(1);
947 }
948 else if (value == "OFFLINE") {
949 mParent->mLock.lock();
950 requestAndWaitForEventThreadExit();
951 mParent->mLock.unlock();
952 }
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800953 } else {
954 mParent->setParameters(keyValuePairs);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800955 }
Mingming Yin4d33ffd2012-12-10 00:11:29 -0800956
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800957 return NO_ERROR;
958}
959
960String8 AudioSessionOutALSA::getParameters(const String8& keys)
961{
962 Mutex::Autolock autoLock(mLock);
963 AudioParameter param = AudioParameter(keys);
964 String8 value;
965 String8 key = String8(AudioParameter::keyRouting);
966
967 if (param.get(key, value) == NO_ERROR) {
968 param.addInt(key, (int)mAlsaHandle->devices);
969 }
970
971 ALOGV("getParameters() %s", param.toString().string());
972 return param.toString();
973}
974
975void AudioSessionOutALSA::reset() {
976 mParent->mLock.lock();
977 requestAndWaitForEventThreadExit();
978
Vidyakumar Athota9acf3d92012-12-07 11:05:01 -0800979#ifdef QCOM_USBAUDIO_ENABLED
980 if (mParent->musbPlaybackState) {
981 if((!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
982 (!strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
983 ALOGV("Deregistering LPA bit: musbPlaybackState =%d",mParent->musbPlaybackState);
984 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
985 } else if((!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
986 (!strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
987 ALOGV("Deregistering Tunnel Player bit: musbPlaybackState =%d",mParent->musbPlaybackState);
988 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_TUNNEL;
989 }
990 }
991#endif
992
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800993 if(mAlsaHandle) {
994 ALOGV("closeDevice mAlsaHandle");
995 closeDevice(mAlsaHandle);
996 mAlsaHandle = NULL;
997 }
Vidyakumar Athota9acf3d92012-12-07 11:05:01 -0800998#ifdef QCOM_USBAUDIO_ENABLED
999 mParent->closeUsbPlaybackIfNothingActive();
1000#endif
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001001 ALOGV("Erase device list");
1002 for(ALSAHandleList::iterator it = mParent->mDeviceList.begin();
1003 it != mParent->mDeviceList.end(); ++it) {
1004 if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
1005 strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
1006 (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
1007 strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
1008 (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
1009 strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
1010 (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
1011 strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
1012 mParent->mDeviceList.erase(it);
1013 break;
1014 }
1015 }
1016 mParent->mLock.unlock();
1017}
1018void AudioSessionOutALSA::updateMetaData(size_t bytes) {
1019 mOutputMetadataTunnel.metadataLength = sizeof(mOutputMetadataTunnel);
1020 mOutputMetadataTunnel.timestamp = 0;
1021 mOutputMetadataTunnel.bufferLength = bytes;
Steve Kondik4027a1e2013-06-01 20:34:23 -07001022 ALOGV("bytes = %d , mAlsaHandle->handle->period_size = %d, metadata = %d ",
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -07001023 mOutputMetadataTunnel.bufferLength, mAlsaHandle->handle->period_size, mOutputMetadataTunnel.metadataLength);
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001024}
1025
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -08001026status_t AudioSessionOutALSA::drainAndPostEOS_l()
1027{
1028 if (!mFilledQueue.empty()) {
1029 ALOGD("drainAndPostEOS called without empty mFilledQueue");
1030 return INVALID_OPERATION;
1031 }
1032
1033 if (!mReachedEOS) {
1034 ALOGD("drainAndPostEOS called without mReachedEOS set");
1035 return INVALID_OPERATION;
1036 }
1037
1038 if (mEosEventReceived) {
1039 ALOGD("drainAndPostEOS called after mEosEventReceived");
1040 return INVALID_OPERATION;
1041 }
1042
1043 mSkipEOS = false;
1044 if ((!strncmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
1045 strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
1046 (!strncmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
1047 strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
1048 ALOGD("Audio Drain DONE ++");
1049 mLock.unlock(); //to allow flush()
1050 int ret = ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_DRAIN);
1051 mLock.lock();
1052
Haynes Mathew George6b526072013-02-08 15:08:24 -08001053 if (ret < 0) {
1054 ret = -errno;
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -08001055 ALOGE("Audio Drain failed with errno %s", strerror(errno));
1056 switch (ret) {
1057 case -EINTR: //interrupted by flush
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -08001058 mSkipEOS = true;
1059 break;
Haynes Mathew George722337a2013-02-27 16:13:26 -08001060 case -EWOULDBLOCK: //no writes given, drain would block indefintely
1061 //mReachedEOS might have been cleared in the meantime
1062 //by a flush. Do not send a false EOS in that case
1063 mSkipEOS = mReachedEOS ? false : true;
1064 break;
Haynes Mathew George3b3ffdc2013-01-13 23:21:21 -08001065 default:
1066 mSkipEOS = false;
1067 break;
1068 }
1069 }
1070 ALOGD("Audio Drain DONE --");
1071 }
1072
1073 if (mSkipEOS == false) {
1074 ALOGV("Posting the EOS to the observer player %p depending on mReachedEOS %d", \
1075 mObserver, mReachedEOS);
1076 mEosEventReceived = true;
1077 if (mObserver != NULL) {
1078 ALOGV("mObserver: posting EOS from eventcallback");
1079 mLock.unlock();
1080 mObserver->postEOS(0);
1081 mLock.lock();
1082 };
1083 } else {
1084 ALOGD("Ignored EOS posting since mSkipEOS is false");
1085 }
1086 return OK;
1087}
1088
Krishnankutty Kolathappilly376e2ab2013-03-14 09:57:57 -07001089status_t AudioSessionOutALSA::setMetaDataMode() {
1090
1091 status_t err = NO_ERROR;
1092 //Call IOCTL
1093 if(mAlsaHandle->handle && !mAlsaHandle->handle->start) {
1094 err = ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_METADATA_MODE);
1095 if(err < 0) {
1096 ALOGE("ioctl Set metadata mode failed = %d", err);
1097 }
1098 }
1099 else {
1100 ALOGE("ALSA pcm handle invalid / pcm driver already started");
1101 err = INVALID_OPERATION;
1102 }
1103 return err;
1104}
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001105} // namespace android_audio_legacy