blob: 72e399b8e9f2d6a25622523616ac60102e98e3c9 [file] [log] [blame]
Iliyan Malchev4765c432012-06-11 14:36:16 -07001/* AudioStreamInALSA.cpp
2 **
3 ** Copyright 2008-2009 Wind River Systems
4 ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
5 **
6 ** Licensed under the Apache License, Version 2.0 (the "License");
7 ** you may not use this file except in compliance with the License.
8 ** You may obtain a copy of the License at
9 **
10 ** http://www.apache.org/licenses/LICENSE-2.0
11 **
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 */
18
19#include <errno.h>
20#include <stdarg.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <dlfcn.h>
26
Ajay Dudani9746c472012-06-18 16:01:16 -070027#define LOG_TAG "AudioStreamInALSA"
Iliyan Malchev4765c432012-06-11 14:36:16 -070028//#define LOG_NDEBUG 0
Ajay Dudani9746c472012-06-18 16:01:16 -070029#define LOG_NDDEBUG 0
Iliyan Malchev4765c432012-06-11 14:36:16 -070030#include <utils/Log.h>
31#include <utils/String8.h>
32
33#include <cutils/properties.h>
34#include <media/AudioRecord.h>
35#include <hardware_legacy/power.h>
36
37#include "AudioHardwareALSA.h"
38
39extern "C" {
Ajay Dudani9746c472012-06-18 16:01:16 -070040#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070041#include "csd_client.h"
42#endif
Ajay Dudani9746c472012-06-18 16:01:16 -070043#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070044#include "surround_filters_interface.h"
45#endif
46}
47
48namespace android_audio_legacy
49{
Ajay Dudani9746c472012-06-18 16:01:16 -070050#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070051#define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm"
52#define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm"
53#define SURROUND_FILE_3R "/system/etc/surround_sound/filter3r.pcm"
54#define SURROUND_FILE_4R "/system/etc/surround_sound/filter4r.pcm"
55
56#define SURROUND_FILE_1I "/system/etc/surround_sound/filter1i.pcm"
57#define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm"
58#define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm"
59#define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm"
60
61// Use AAC/DTS channel mapping as default channel mapping: C,FL,FR,Ls,Rs,LFE
62const int chanMap[] = { 1, 2, 4, 3, 0, 5 };
63#endif
64
65AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent,
66 alsa_handle_t *handle,
67 AudioSystem::audio_in_acoustics audio_acoustics) :
68 ALSAStreamOps(parent, handle),
69 mFramesLost(0),
70 mParent(parent),
71 mAcoustics(audio_acoustics)
Ajay Dudani9746c472012-06-18 16:01:16 -070072#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070073 , mFp_4ch(NULL),
74 mFp_6ch(NULL),
75 mRealCoeffs(NULL),
76 mImagCoeffs(NULL),
77 mSurroundObj(NULL),
78 mSurroundOutputBuffer(NULL),
79 mSurroundInputBuffer(NULL),
80 mSurroundOutputBufferIdx(0),
81 mSurroundInputBufferIdx(0)
82#endif
83{
Ajay Dudani9746c472012-06-18 16:01:16 -070084#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070085 char c_multi_ch_dump[128] = {0};
86 status_t err = NO_ERROR;
87
88 // Call surround sound library init if device is Surround Sound
89 if ( handle->channels == 6) {
90 if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
91 || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
92
93 err = initSurroundSoundLibrary(handle->bufferSize);
94 if ( NO_ERROR != err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -070095 ALOGE("initSurroundSoundLibrary failed: %d handle->bufferSize:%d", err,handle->bufferSize);
Iliyan Malchev4765c432012-06-11 14:36:16 -070096 }
97
98 property_get("ssr.pcmdump",c_multi_ch_dump,"0");
99 if (0 == strncmp("true",c_multi_ch_dump, sizeof("ssr.dump-pcm"))) {
100 //Remember to change file system permission of data(e.g. chmod 777 data/),
101 //otherwise, fopen may fail.
102 if ( !mFp_4ch)
103 mFp_4ch = fopen("/data/4ch_ssr.pcm", "wb");
104 if ( !mFp_6ch)
105 mFp_6ch = fopen("/data/6ch_ssr.pcm", "wb");
106 if ((!mFp_4ch) || (!mFp_6ch))
Iliyan Malchev4113f342012-06-11 14:39:47 -0700107 ALOGE("mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",mFp_4ch,mFp_6ch);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700108 }
109 }
110 }
111#endif
112}
113
114AudioStreamInALSA::~AudioStreamInALSA()
115{
116 close();
117}
118
119status_t AudioStreamInALSA::setGain(float gain)
120{
121 return 0; //mixer() ? mixer()->setMasterGain(gain) : (status_t)NO_INIT;
122}
123
124ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes)
125{
126 int period_size;
127
Iliyan Malchev4113f342012-06-11 14:39:47 -0700128 ALOGV("read:: buffer %p, bytes %d", buffer, bytes);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700129
130 int n;
131 status_t err;
132 size_t read = 0;
133 char *use_case;
134 int newMode = mParent->mode();
135
136 if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) &&
137 (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) &&
138 (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
139 mParent->mLock.lock();
140 snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
141 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
142 if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
143 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700144 ALOGD("read:: mParent->mIncallMode=%d", mParent->mIncallMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700145 if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
146 (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700147#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700148 if (mParent->mFusion3Platform) {
149 mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO);
150 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
151 sizeof(mHandle->useCase));
152 csd_client_start_record(INCALL_REC_STEREO);
153 } else
154#endif
155 {
156 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
157 sizeof(mHandle->useCase));
158 }
159 } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700160#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700161 if (mParent->mFusion3Platform) {
162 mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO);
163 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
164 sizeof(mHandle->useCase));
165 csd_client_start_record(INCALL_REC_MONO);
166 } else
167#endif
168 {
169 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
170 sizeof(mHandle->useCase));
171 }
172 }
Ajay Dudani92919432012-06-28 14:23:11 -0700173#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700174 } else if(mHandle->devices == AudioSystem::DEVICE_IN_FM_RX) {
175 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(mHandle->useCase));
176 } else if (mHandle->devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
177 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(mHandle->useCase));
178#endif
179 } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
180 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase));
181 }else {
182 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase));
183 }
184 } else {
185 if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
186 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700187 ALOGD("read:: ---- mParent->mIncallMode=%d", mParent->mIncallMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700188 if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
189 (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700190#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700191 if (mParent->mFusion3Platform) {
192 mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO);
193 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC,
194 sizeof(mHandle->useCase));
195 csd_client_start_record(INCALL_REC_STEREO);
196 } else
197#endif
198 {
199 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC,
200 sizeof(mHandle->useCase));
201 }
202 } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700203#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700204 if (mParent->mFusion3Platform) {
205 mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO);
206 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC,
207 sizeof(mHandle->useCase));
208 csd_client_start_record(INCALL_REC_MONO);
209 } else
210#endif
211 {
212 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC,
213 sizeof(mHandle->useCase));
214 }
215 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700216#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700217 } else if(mHandle->devices == AudioSystem::DEVICE_IN_FM_RX) {
218 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_FM_REC, sizeof(mHandle->useCase));
219 } else if (mHandle->devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
220 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(mHandle->useCase));
221#endif
222 } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
223 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(mHandle->useCase));
224 } else {
225 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase));
226 }
227 }
228 free(use_case);
229 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
230 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700231#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700232 if((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
233 (mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) {
234 mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AudioSystem::MODE_IN_COMMUNICATION);
235 }else
236#endif
237 {
238 mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION);
239 }
240 } else {
Ajay Dudani9746c472012-06-18 16:01:16 -0700241#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700242 if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
243 (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
244 mHandle->module->route(mHandle, AudioSystem::DEVICE_IN_PROXY , mParent->mode());
245 } else
246#endif
247 {
248
249 mHandle->module->route(mHandle, mDevices , mParent->mode());
250 }
251 }
252 if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
253 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_REC) ||
254 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
255 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
256 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
257 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_DL_REC) ||
258 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
259 snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
260 } else {
261 snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase);
262 }
263 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
264 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
265 err = mHandle->module->startVoipCall(mHandle);
266 }
267 else
268 mHandle->module->open(mHandle);
269 if(mHandle->handle == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700270 ALOGE("read:: PCM device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700271 mParent->mLock.unlock();
272
273 return 0;
274 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700275#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700276 if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
277 (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
278 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
279 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
280 mParent->musbRecordingState |= USBRECBIT_VOIPCALL;
281 } else {
282 mParent->startUsbRecordingIfNotStarted();
283 mParent->musbRecordingState |= USBRECBIT_REC;
284 }
285 }
286#endif
287 mParent->mLock.unlock();
288 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700289#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700290 if(((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
291 (mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) &&
292 (!mParent->musbRecordingState)) {
293 mParent->mLock.lock();
Iliyan Malchev4113f342012-06-11 14:39:47 -0700294 ALOGD("Starting UsbRecording thread");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700295 mParent->startUsbRecordingIfNotStarted();
296 if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
297 !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700298 ALOGD("Enabling voip recording bit");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700299 mParent->musbRecordingState |= USBRECBIT_VOIPCALL;
300 }else{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700301 ALOGD("Enabling HiFi Recording bit");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700302 mParent->musbRecordingState |= USBRECBIT_REC;
303 }
304 mParent->mLock.unlock();
305 }
306#endif
307 period_size = mHandle->periodSize;
308 int read_pending = bytes;
309
Ajay Dudani9746c472012-06-18 16:01:16 -0700310#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700311 if (mSurroundObj) {
312 int processed = 0;
313 int processed_pending;
314 int samples = bytes >> 1;
315 void *buffer_start = buffer;
316 int period_bytes = mHandle->handle->period_size;
317 int period_samples = period_bytes >> 1;
318
319 do {
320 if (mSurroundOutputBufferIdx > 0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700321 ALOGV("AudioStreamInALSA::read() - copy processed output "
Iliyan Malchev4765c432012-06-11 14:36:16 -0700322 "to buffer, mSurroundOutputBufferIdx = %d",
323 mSurroundOutputBufferIdx);
324 // Copy processed output to buffer
325 processed_pending = mSurroundOutputBufferIdx;
326 if (processed_pending > (samples - processed)) {
327 processed_pending = (samples - processed);
328 }
329 memcpy(buffer, mSurroundOutputBuffer, processed_pending * sizeof(Word16));
330 buffer += processed_pending * sizeof(Word16);
331 processed += processed_pending;
332 if (mSurroundOutputBufferIdx > processed_pending) {
333 // Shift leftover samples to beginning of the buffer
334 memcpy(&mSurroundOutputBuffer[0],
335 &mSurroundOutputBuffer[processed_pending],
336 (mSurroundOutputBufferIdx - processed_pending) * sizeof(Word16));
337 }
338 mSurroundOutputBufferIdx -= processed_pending;
339 }
340
341 if (processed >= samples) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700342 ALOGV("AudioStreamInALSA::read() - done processing buffer, "
Iliyan Malchev4765c432012-06-11 14:36:16 -0700343 "processed = %d", processed);
344 // Done processing this buffer
345 break;
346 }
347
348 // Fill input buffer until there is enough to process
349 read_pending = SSR_INPUT_FRAME_SIZE - mSurroundInputBufferIdx;
350 read = mSurroundInputBufferIdx;
351 while (mHandle->handle && read_pending > 0) {
352 n = pcm_read(mHandle->handle, &mSurroundInputBuffer[read],
353 period_bytes);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700354 ALOGV("pcm_read() returned n = %d buffer:%p size:%d", n, &mSurroundInputBuffer[read], period_bytes);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700355 if (n && n != -EAGAIN) {
356 //Recovery part of pcm_read. TODO:split recovery.
357 return static_cast<ssize_t>(n);
358 }
359 else if (n < 0) {
360 // Recovery is part of pcm_write. TODO split is later.
361 return static_cast<ssize_t>(n);
362 }
363 else {
364 read_pending -= period_samples;
365 read += period_samples;
366 }
367 }
368
369
370 if (mFp_4ch) {
371 fwrite( mSurroundInputBuffer, 1,
372 SSR_INPUT_FRAME_SIZE * sizeof(Word16), mFp_4ch);
373 }
374
375 //apply ssr libs to conver 4ch to 6ch
376 surround_filters_intl_process(mSurroundObj,
377 &mSurroundOutputBuffer[mSurroundOutputBufferIdx],
378 (Word16 *)mSurroundInputBuffer);
379
380 // Shift leftover samples to beginning of input buffer
381 if (read_pending < 0) {
382 memcpy(&mSurroundInputBuffer[0],
383 &mSurroundInputBuffer[SSR_INPUT_FRAME_SIZE],
384 (-read_pending) * sizeof(Word16));
385 }
386 mSurroundInputBufferIdx = -read_pending;
387
388 if (mFp_6ch) {
389 fwrite( &mSurroundOutputBuffer[mSurroundOutputBufferIdx],
390 1, SSR_OUTPUT_FRAME_SIZE * sizeof(Word16), mFp_6ch);
391 }
392
393 mSurroundOutputBufferIdx += SSR_OUTPUT_FRAME_SIZE;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700394 ALOGV("do_while loop: processed=%d, samples=%d\n", processed, samples);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700395 } while (mHandle->handle && processed < samples);
396 read = processed * sizeof(Word16);
397 buffer = buffer_start;
398 } else
Ajay Dudani9746c472012-06-18 16:01:16 -0700399#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700400 {
401
402 do {
403 if (read_pending < period_size) {
404 read_pending = period_size;
405 }
406
407 n = pcm_read(mHandle->handle, buffer,
408 period_size);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700409 ALOGV("pcm_read() returned n = %d", n);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700410 if (n && (n == -EIO || n == -EAGAIN || n == -EPIPE || n == -EBADFD)) {
411 mParent->mLock.lock();
Iliyan Malchev4113f342012-06-11 14:39:47 -0700412 ALOGW("pcm_read() returned error n %d, Recovering from error\n", n);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700413 pcm_close(mHandle->handle);
414 mHandle->handle = NULL;
415 if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
416 (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
417 pcm_close(mHandle->rxHandle);
418 mHandle->rxHandle = NULL;
419 mHandle->module->startVoipCall(mHandle);
420 }
421 else
422 mHandle->module->open(mHandle);
423 mParent->mLock.unlock();
424 continue;
425 }
426 else if (n < 0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700427 ALOGD("pcm_read() returned n < 0");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700428 return static_cast<ssize_t>(n);
429 }
430 else {
431 read += static_cast<ssize_t>((period_size));
432 read_pending -= period_size;
433 buffer += period_size;
434 }
435
436 } while (mHandle->handle && read < bytes);
437 }
438
439 return read;
440}
441
442status_t AudioStreamInALSA::dump(int fd, const Vector<String16>& args)
443{
444 return NO_ERROR;
445}
446
447status_t AudioStreamInALSA::open(int mode)
448{
449 Mutex::Autolock autoLock(mParent->mLock);
450
451 status_t status = ALSAStreamOps::open(mode);
452
453 return status;
454}
455
456status_t AudioStreamInALSA::close()
457{
458 Mutex::Autolock autoLock(mParent->mLock);
459
Iliyan Malchev4113f342012-06-11 14:39:47 -0700460 ALOGD("close");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700461 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
462 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
463 if((mParent->mVoipStreamCount)) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700464#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4113f342012-06-11 14:39:47 -0700465 ALOGD("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700466 mParent->mVoipStreamCount );
467 if(mParent->mVoipStreamCount == 1) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700468 ALOGE("Deregistering VOIP Call bit, musbPlaybackState:%d,"
Iliyan Malchev4765c432012-06-11 14:36:16 -0700469 "musbRecordingState:%d", mParent->musbPlaybackState, mParent->musbRecordingState);
470 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL;
471 mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL;
472 mParent->closeUsbRecordingIfNothingActive();
473 mParent->closeUsbPlaybackIfNothingActive();
474 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700475#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700476 return NO_ERROR;
477 }
478 mParent->mVoipStreamCount = 0;
479 mParent->mVoipMicMute = 0;
Ajay Dudani9746c472012-06-18 16:01:16 -0700480#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700481 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700482 ALOGD("Deregistering REC bit, musbRecordingState:%d", mParent->musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700483 mParent->musbRecordingState &= ~USBRECBIT_REC;
Ajay Dudani9746c472012-06-18 16:01:16 -0700484#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700485 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700486#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700487 if (mParent->mFusion3Platform) {
488 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) ||
489 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE))) {
490 csd_client_stop_record();
491 }
492 }
493#endif
Iliyan Malchev4113f342012-06-11 14:39:47 -0700494 ALOGD("close");
Ajay Dudani9746c472012-06-18 16:01:16 -0700495#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700496 mParent->closeUsbRecordingIfNothingActive();
Ajay Dudani9746c472012-06-18 16:01:16 -0700497#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700498
499 ALSAStreamOps::close();
500
Ajay Dudani9746c472012-06-18 16:01:16 -0700501#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700502 if (mSurroundObj) {
503 surround_filters_release(mSurroundObj);
504 if (mSurroundObj)
505 free(mSurroundObj);
506 mSurroundObj = NULL;
507 if (mRealCoeffs){
508 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) {
509 if (mRealCoeffs[i]) {
510 free(mRealCoeffs[i]);
511 mRealCoeffs[i] = NULL;
512 }
513 }
514 free(mRealCoeffs);
515 mRealCoeffs = NULL;
516 }
517 if (mImagCoeffs){
518 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) {
519 if (mImagCoeffs[i]) {
520 free(mImagCoeffs[i]);
521 mImagCoeffs[i] = NULL;
522 }
523 }
524 free(mImagCoeffs);
525 mImagCoeffs = NULL;
526 }
527 if (mSurroundOutputBuffer){
528 free(mSurroundOutputBuffer);
529 mSurroundOutputBuffer = NULL;
530 }
531 if (mSurroundInputBuffer) {
532 free(mSurroundInputBuffer);
533 mSurroundInputBuffer = NULL;
534 }
535
536 if ( mFp_4ch ) fclose(mFp_4ch);
537 if ( mFp_6ch ) fclose(mFp_6ch);
538
539 }
540#endif
541
542 return NO_ERROR;
543}
544
545status_t AudioStreamInALSA::standby()
546{
547 Mutex::Autolock autoLock(mParent->mLock);
548
Iliyan Malchev4113f342012-06-11 14:39:47 -0700549 ALOGD("standby");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700550
551 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
552 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
553 return NO_ERROR;
554 }
555
Ajay Dudani9746c472012-06-18 16:01:16 -0700556#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4113f342012-06-11 14:39:47 -0700557 ALOGD("standby");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700558 if (mParent->mFusion3Platform) {
559 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) ||
560 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700561 ALOGD(" into standby, stop record");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700562 csd_client_stop_record();
563 }
564 }
565#endif
566 mHandle->module->standby(mHandle);
567
Ajay Dudani9746c472012-06-18 16:01:16 -0700568#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4113f342012-06-11 14:39:47 -0700569 ALOGD("Checking for musbRecordingState %d", mParent->musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700570 mParent->musbRecordingState &= ~USBRECBIT_REC;
571 mParent->closeUsbRecordingIfNothingActive();
Ajay Dudani9746c472012-06-18 16:01:16 -0700572#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700573
574 return NO_ERROR;
575}
576
577void AudioStreamInALSA::resetFramesLost()
578{
579 mFramesLost = 0;
580}
581
582unsigned int AudioStreamInALSA::getInputFramesLost() const
583{
584 unsigned int count = mFramesLost;
585 // Stupid interface wants us to have a side effect of clearing the count
586 // but is defined as a const to prevent such a thing.
587 ((AudioStreamInALSA *)this)->resetFramesLost();
588 return count;
589}
590
591status_t AudioStreamInALSA::setAcousticParams(void *params)
592{
593 Mutex::Autolock autoLock(mParent->mLock);
594
595 return (status_t)NO_ERROR;
596}
597
Ajay Dudani9746c472012-06-18 16:01:16 -0700598#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700599status_t AudioStreamInALSA::initSurroundSoundLibrary(unsigned long buffersize)
600{
601 int subwoofer = 0; // subwoofer channel assignment: default as first microphone input channel
602 int low_freq = 4; // frequency upper bound for subwoofer: frequency=(low_freq-1)/FFT_SIZE*samplingRate, default as 4
603 int high_freq = 100; // frequency upper bound for spatial processing: frequency=(high_freq-1)/FFT_SIZE*samplingRate, default as 100
604 int ret = 0;
605
606 mSurroundInputBufferIdx = 0;
607 mSurroundOutputBufferIdx = 0;
608
609 if ( mSurroundObj ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700610 ALOGE("ola filter library is already initialized");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700611 return ALREADY_EXISTS;
612 }
613
614 // Allocate memory for input buffer
615 mSurroundInputBuffer = (Word16 *) calloc(2 * SSR_INPUT_FRAME_SIZE,
616 sizeof(Word16));
617 if ( !mSurroundInputBuffer ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700618 ALOGE("Memory allocation failure. Not able to allocate memory for surroundInputBuffer");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700619 goto init_fail;
620 }
621
622 // Allocate memory for output buffer
623 mSurroundOutputBuffer = (Word16 *) calloc(2 * SSR_OUTPUT_FRAME_SIZE,
624 sizeof(Word16));
625 if ( !mSurroundOutputBuffer ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700626 ALOGE("Memory allocation failure. Not able to allocate memory for surroundOutputBuffer");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700627 goto init_fail;
628 }
629
630 // Allocate memory for real and imag coeffs array
631 mRealCoeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
632 if ( !mRealCoeffs ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700633 ALOGE("Memory allocation failure during real Coefficient array");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700634 goto init_fail;
635 }
636
637 mImagCoeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
638 if ( !mImagCoeffs ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700639 ALOGE("Memory allocation failure during imaginary Coefficient array");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700640 goto init_fail;
641 }
642
643 if( readCoeffsFromFile() != NO_ERROR) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700644 ALOGE("Error while loading coeffs from file");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700645 goto init_fail;
646 }
647
648 //calculate the size of data to allocate for mSurroundObj
649 ret = surround_filters_init(NULL,
650 6, // Num output channel
651 4, // Num input channel
652 mRealCoeffs, // Coeffs hardcoded in header
653 mImagCoeffs, // Coeffs hardcoded in header
654 subwoofer,
655 low_freq,
656 high_freq,
657 NULL);
658
659 if ( ret > 0 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700660 ALOGV("Allocating surroundObj size is %d", ret);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700661 mSurroundObj = (void *)malloc(ret);
662 memset(mSurroundObj,0,ret);
663 if (NULL != mSurroundObj) {
664 //initialize after allocating the memory for mSurroundObj
665 ret = surround_filters_init(mSurroundObj,
666 6,
667 4,
668 mRealCoeffs,
669 mImagCoeffs,
670 subwoofer,
671 low_freq,
672 high_freq,
673 NULL);
674 if (0 != ret) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700675 ALOGE("surround_filters_init failed with ret:%d",ret);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700676 surround_filters_release(mSurroundObj);
677 goto init_fail;
678 }
679 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700680 ALOGE("Allocationg mSurroundObj failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700681 goto init_fail;
682 }
683 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700684 ALOGE("surround_filters_init(mSurroundObj=Null) failed with ret: %d",ret);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700685 goto init_fail;
686 }
687
688 (void) surround_filters_set_channel_map(mSurroundObj, chanMap);
689
690 return NO_ERROR;
691
692init_fail:
693 if (mSurroundObj) {
694 free(mSurroundObj);
695 mSurroundObj = NULL;
696 }
697 if (mSurroundOutputBuffer) {
698 free(mSurroundOutputBuffer);
699 mSurroundOutputBuffer = NULL;
700 }
701 if (mSurroundInputBuffer) {
702 free(mSurroundInputBuffer);
703 mSurroundInputBuffer = NULL;
704 }
705 if (mRealCoeffs){
706 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) {
707 if (mRealCoeffs[i]) {
708 free(mRealCoeffs[i]);
709 mRealCoeffs[i] = NULL;
710 }
711 }
712 free(mRealCoeffs);
713 mRealCoeffs = NULL;
714 }
715 if (mImagCoeffs){
716 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) {
717 if (mImagCoeffs[i]) {
718 free(mImagCoeffs[i]);
719 mImagCoeffs[i] = NULL;
720 }
721 }
722 free(mImagCoeffs);
723 mImagCoeffs = NULL;
724 }
725
726 return NO_MEMORY;
727
728}
729
730
731// Helper function to read coeffs from File and updates real and imaginary
732// coeff array member variable
733status_t AudioStreamInALSA::readCoeffsFromFile()
734{
735 FILE *flt1r;
736 FILE *flt2r;
737 FILE *flt3r;
738 FILE *flt4r;
739 FILE *flt1i;
740 FILE *flt2i;
741 FILE *flt3i;
742 FILE *flt4i;
743
744 if ( (flt1r = fopen(SURROUND_FILE_1R, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700745 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_1R);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700746 return NAME_NOT_FOUND;
747 }
748
749 if ( (flt2r = fopen(SURROUND_FILE_2R, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700750 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_2R);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700751 return NAME_NOT_FOUND;
752 }
753
754 if ( (flt3r = fopen(SURROUND_FILE_3R, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700755 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_3R);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700756 return NAME_NOT_FOUND;
757 }
758
759 if ( (flt4r = fopen(SURROUND_FILE_4R, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700760 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_4R);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700761 return NAME_NOT_FOUND;
762 }
763
764 if ( (flt1i = fopen(SURROUND_FILE_1I, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700765 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_1I);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700766 return NAME_NOT_FOUND;
767 }
768
769 if ( (flt2i = fopen(SURROUND_FILE_2I, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700770 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_2I);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700771 return NAME_NOT_FOUND;
772 }
773
774 if ( (flt3i = fopen(SURROUND_FILE_3I, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700775 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_3I);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700776 return NAME_NOT_FOUND;
777 }
778
779 if ( (flt4i = fopen(SURROUND_FILE_4I, "rb")) == NULL ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700780 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_4I);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700781 return NAME_NOT_FOUND;
782 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700783 ALOGV("readCoeffsFromFile all filter files opened");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700784
785 for (int i=0; i<COEFF_ARRAY_SIZE; i++) {
786 mRealCoeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16));
787 }
788 for (int i=0; i<COEFF_ARRAY_SIZE; i++) {
789 mImagCoeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16));
790 }
791
792 // Read real co-efficients
793 if (NULL != mRealCoeffs[0]) {
794 fread(mRealCoeffs[0], sizeof(int16), FILT_SIZE, flt1r);
795 }
796 if (NULL != mRealCoeffs[0]) {
797 fread(mRealCoeffs[1], sizeof(int16), FILT_SIZE, flt2r);
798 }
799 if (NULL != mRealCoeffs[0]) {
800 fread(mRealCoeffs[2], sizeof(int16), FILT_SIZE, flt3r);
801 }
802 if (NULL != mRealCoeffs[0]) {
803 fread(mRealCoeffs[3], sizeof(int16), FILT_SIZE, flt4r);
804 }
805
806 // read imaginary co-efficients
807 if (NULL != mImagCoeffs[0]) {
808 fread(mImagCoeffs[0], sizeof(int16), FILT_SIZE, flt1i);
809 }
810 if (NULL != mImagCoeffs[0]) {
811 fread(mImagCoeffs[1], sizeof(int16), FILT_SIZE, flt2i);
812 }
813 if (NULL != mImagCoeffs[0]) {
814 fread(mImagCoeffs[2], sizeof(int16), FILT_SIZE, flt3i);
815 }
816 if (NULL != mImagCoeffs[0]) {
817 fread(mImagCoeffs[3], sizeof(int16), FILT_SIZE, flt4i);
818 }
819
820 fclose(flt1r);
821 fclose(flt2r);
822 fclose(flt3r);
823 fclose(flt4r);
824 fclose(flt1i);
825 fclose(flt2i);
826 fclose(flt3i);
827 fclose(flt4i);
828
829 return NO_ERROR;
830}
831#endif
832
833} // namespace android_audio_legacy