blob: 3316e3e267a9761ac5cc9d0124c389694ffca8c7 [file] [log] [blame]
Iliyan Malchev4765c432012-06-11 14:36:16 -07001/* AudioUsbALSA.cpp
2Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
28
Ajay Dudani9746c472012-06-18 16:01:16 -070029#define LOG_TAG "AudioUsbALSA"
30#define LOG_NDEBUG 0
31#define LOG_NDDEBUG 0
Iliyan Malchev4765c432012-06-11 14:36:16 -070032#include <utils/Log.h>
33#include <utils/String8.h>
34
35#include <cutils/properties.h>
36#include <media/AudioRecord.h>
37#include <hardware_legacy/power.h>
38#include <sys/poll.h>
39#include <sys/ioctl.h>
40#include <fcntl.h>
41#include <string.h>
42#include <sys/stat.h>
43#include <errno.h>
44#include <jni.h>
45#include <stdio.h>
46#include <sys/eventfd.h>
47
48
49#include "AudioUsbALSA.h"
50struct pollfd pfdProxyPlayback[2];
51struct pollfd pfdUsbPlayback[2];
52struct pollfd pfdProxyRecording[1];
53struct pollfd pfdUsbRecording[1];
54
Ajay Dudani9746c472012-06-18 16:01:16 -070055#define USB_PERIOD_SIZE 2048
56#define PROXY_PERIOD_SIZE 3072
57
Iliyan Malchev4765c432012-06-11 14:36:16 -070058namespace android_audio_legacy
59{
60AudioUsbALSA::AudioUsbALSA()
61{
62 mproxypfdPlayback = -1;
63 musbpfdPlayback = -1;
64 mkillPlayBackThread = false;
65 mkillRecordingThread = false;
66}
67
68AudioUsbALSA::~AudioUsbALSA()
69{
70 mkillPlayBackThread = true;
71 mkillRecordingThread = true;
72}
73
74
75int AudioUsbALSA::getnumOfRates(char *ratesStr){
76 int i, size = 0;
77 char *nextSRString, *temp_ptr;
78 nextSRString = strtok_r(ratesStr, " ,", &temp_ptr);
79 if (nextSRString == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -070080 ALOGE("ERROR: getnumOfRates: could not find rates string");
Iliyan Malchev4765c432012-06-11 14:36:16 -070081 return NULL;
82 }
83 for (i = 1; nextSRString != NULL; i++) {
84 size ++;
85 nextSRString = strtok_r(NULL, " ,.-", &temp_ptr);
86 }
87 return size;
88}
89
Ajay Dudani9746c472012-06-18 16:01:16 -070090
91status_t AudioUsbALSA::getCap(char * type, int &channels, int &sampleRate)
Iliyan Malchev4765c432012-06-11 14:36:16 -070092{
Ajay Dudani9746c472012-06-18 16:01:16 -070093 ALOGD("getCap for %s",type);
Iliyan Malchev4765c432012-06-11 14:36:16 -070094 long unsigned fileSize;
95 FILE *fp;
96 char *buffer;
97 int err = 1;
98 int size = 0;
99 int fd, i, lchannelsPlayback;
Ajay Dudani9746c472012-06-18 16:01:16 -0700100 char *read_buf, *str_start, *channel_start, *ratesStr, *ratesStrForVal,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700101 *ratesStrStart, *chString, *nextSRStr, *test, *nextSRString, *temp_ptr;
102 struct stat st;
103 memset(&st, 0x0, sizeof(struct stat));
Ajay Dudani9746c472012-06-18 16:01:16 -0700104 sampleRate = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700105 fd = open(PATH, O_RDONLY);
106 if (fd <0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700107 ALOGE("ERROR: failed to open config file %s error: %d\n", PATH, errno);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700108 close(fd);
109 return UNKNOWN_ERROR;
110 }
111
112 if (fstat(fd, &st) < 0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700113 ALOGE("ERROR: failed to stat %s error %d\n", PATH, errno);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700114 close(fd);
115 return UNKNOWN_ERROR;
116 }
117
118 fileSize = st.st_size;
119
120 read_buf = (char *)malloc(BUFFSIZE);
121 memset(read_buf, 0x0, BUFFSIZE);
122 err = read(fd, read_buf, BUFFSIZE);
Ajay Dudani9746c472012-06-18 16:01:16 -0700123 str_start = strstr(read_buf, type);
124 if (str_start == NULL) {
125 ALOGE("ERROR:%s section not found in usb config file", type);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700126 close(fd);
127 free(read_buf);
128 return UNKNOWN_ERROR;
129 }
130
Ajay Dudani9746c472012-06-18 16:01:16 -0700131 channel_start = strstr(str_start, "Channels:");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700132 if (channel_start == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700133 ALOGE("ERROR: Could not find Channels information");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700134 close(fd);
135 free(read_buf);
136 return UNKNOWN_ERROR;
137 }
138 channel_start = strstr(channel_start, " ");
139 if (channel_start == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700140 ALOGE("ERROR: Channel section not found in usb config file");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700141 close(fd);
142 free(read_buf);
143 return UNKNOWN_ERROR;
144 }
145
146 lchannelsPlayback = atoi(channel_start);
147 if (lchannelsPlayback == 1) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700148 channels = 1;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700149 } else {
Ajay Dudani9746c472012-06-18 16:01:16 -0700150 channels = 2;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700151 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700152 ALOGD("channels supported by device: %d", lchannelsPlayback);
Ajay Dudani9746c472012-06-18 16:01:16 -0700153 ratesStrStart = strstr(str_start, "Rates:");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700154 if (ratesStrStart == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700155 ALOGE("ERROR: Cant find rates information");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700156 close(fd);
157 free(read_buf);
158 return UNKNOWN_ERROR;
159 }
160
161 ratesStrStart = strstr(ratesStrStart, " ");
162 if (ratesStrStart == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700163 ALOGE("ERROR: Channel section not found in usb config file");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700164 close(fd);
165 free(read_buf);
166 return UNKNOWN_ERROR;
167 }
168
169 //copy to ratesStr, current line.
170 char *target = strchr(ratesStrStart, '\n');
171 if (target == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700172 ALOGE("ERROR: end of line not found");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700173 close(fd);
174 free(read_buf);
175 return UNKNOWN_ERROR;
176 }
177 size = target - ratesStrStart;
178 ratesStr = (char *)malloc(size + 1) ;
179 ratesStrForVal = (char *)malloc(size + 1) ;
180 memcpy(ratesStr, ratesStrStart, size);
181 memcpy(ratesStrForVal, ratesStrStart, size);
182 ratesStr[size] = '\0';
183 ratesStrForVal[size] = '\0';
184
185 size = getnumOfRates(ratesStr);
186 if (!size) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700187 ALOGE("ERROR: Could not get rate size, returning");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700188 close(fd);
189 free(ratesStrForVal);
190 free(ratesStr);
191 free(read_buf);
192 return UNKNOWN_ERROR;
193 }
194
195 //populate playback rates array
196 int ratesSupported[size];
197 nextSRString = strtok_r(ratesStrForVal, " ,", &temp_ptr);
198 if (nextSRString == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700199 ALOGE("ERROR: Could not get first rate val");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700200 close(fd);
201 free(ratesStrForVal);
202 free(ratesStr);
203 free(read_buf);
204 return UNKNOWN_ERROR;
205 }
206
207 ratesSupported[0] = atoi(nextSRString);
208 for (i = 1; i<size; i++) {
209 nextSRString = strtok_r(NULL, " ,.-", &temp_ptr);
210 ratesSupported[i] = atoi(nextSRString);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700211 ALOGV("ratesSupported[%d] for playback: %d",i, ratesSupported[i]);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700212 }
213
214 for (i = 0; i<=size; i++) {
215 if (ratesSupported[i] <= 48000) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700216 sampleRate = ratesSupported[i];
Iliyan Malchev4765c432012-06-11 14:36:16 -0700217 break;
218 }
219 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700220 ALOGD("sampleRate: %d", sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700221
222 close(fd);
223 free(ratesStrForVal);
224 free(ratesStr);
225 free(read_buf);
226 ratesStrForVal = NULL;
227 ratesStr = NULL;
228 read_buf = NULL;
229 return NO_ERROR;
230}
231
Iliyan Malchev4765c432012-06-11 14:36:16 -0700232void AudioUsbALSA::exitPlaybackThread(uint64_t writeVal)
233{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700234 ALOGD("exitPlaybackThread, mproxypfdPlayback: %d", mproxypfdPlayback);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700235 if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700236 int err;
237
238 err = closeDevice(mproxyPlaybackHandle);
239 if (err) {
240 ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle);
241 }
242 err = closeDevice(musbPlaybackHandle);
243 if (err) {
244 ALOGE("Info: Could not close USB device %p", musbPlaybackHandle);
245 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700246 }
247 if ((mproxypfdPlayback != -1) && (musbpfdPlayback != -1)) {
248 write(mproxypfdPlayback, &writeVal, sizeof(uint64_t));
249 write(musbpfdPlayback, &writeVal, sizeof(uint64_t));
250 mkillPlayBackThread = true;
251 pthread_join(mPlaybackUsb,NULL);
252 }
253}
254
255void AudioUsbALSA::exitRecordingThread(uint64_t writeVal)
256{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700257 ALOGD("exitRecordingThread");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700258 if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700259 int err;
260
261 err = closeDevice(mproxyRecordingHandle);
262 if (err) {
263 ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle);
264 }
265 err = closeDevice(musbRecordingHandle);
266 if (err) {
267 ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle);
268 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700269 }
270 mkillRecordingThread = true;
271}
272
Iliyan Malchev4765c432012-06-11 14:36:16 -0700273void AudioUsbALSA::setkillUsbRecordingThread(bool val){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700274 ALOGD("setkillUsbRecordingThread");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700275 mkillRecordingThread = val;
276}
277
Ajay Dudani9746c472012-06-18 16:01:16 -0700278status_t AudioUsbALSA::setHardwareParams(pcm *txHandle, uint32_t sampleRate, uint32_t channels, int periodBytes)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700279{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700280 ALOGD("setHardwareParams");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700281 struct snd_pcm_hw_params *params;
282 unsigned long bufferSize, reqBuffSize;
283 unsigned int periodTime, bufferTime;
284 unsigned int requestedRate = sampleRate;
285 int status = 0;
286
287 params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
288 if (!params) {
289 return NO_INIT;
290 }
291
292 param_init(params);
293 param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
294 SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
295 param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
296 SNDRV_PCM_FORMAT_S16_LE);
297 param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
298 SNDRV_PCM_SUBFORMAT_STD);
Ajay Dudani9746c472012-06-18 16:01:16 -0700299 ALOGV("Setting period size:%d samplerate:%d, channels: %d",periodBytes,sampleRate, channels);
300 param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, periodBytes);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700301 param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
302 param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
303 channels - 1 ? 32 : 16);
304 param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
305 channels);
306 param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, sampleRate);
307 param_set_hw_refine(txHandle, params);
308
309 if (param_set_hw_params(txHandle, params)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700310 ALOGE("ERROR: cannot set hw params");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700311 return NO_INIT;
312 }
313
314 param_dump(params);
315
316 txHandle->period_size = pcm_period_size(params);
317 txHandle->buffer_size = pcm_buffer_size(params);
318 txHandle->period_cnt = txHandle->buffer_size/txHandle->period_size;
319
Iliyan Malchev4113f342012-06-11 14:39:47 -0700320 ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700321 txHandle->buffer_size, txHandle->period_size,
322 txHandle->period_cnt);
323
324 return NO_ERROR;
325}
326
Ajay Dudani9746c472012-06-18 16:01:16 -0700327status_t AudioUsbALSA::setSoftwareParams(pcm *pcm, bool playback)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700328{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700329 ALOGD("setSoftwareParams");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700330 struct snd_pcm_sw_params* params;
331
Iliyan Malchev4765c432012-06-11 14:36:16 -0700332 params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
333 if (!params) {
334 LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
335 return NO_INIT;
336 }
337
338 params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
339 params->period_step = 1;
340
341 params->avail_min = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
342
Ajay Dudani9746c472012-06-18 16:01:16 -0700343 if (playback) {
344 params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size*8 : pcm->period_size*4;
345 params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size*8 : pcm->period_size*4;
346 } else {
347 params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
348 params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
349 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700350 params->stop_threshold = pcm->buffer_size;
Ajay Dudani9746c472012-06-18 16:01:16 -0700351
Iliyan Malchev4765c432012-06-11 14:36:16 -0700352 params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
353 params->silence_size = 0;
354 params->silence_threshold = 0;
355
356 if (param_set_sw_params(pcm, params)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700357 ALOGE("ERROR: cannot set sw params");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700358 return NO_INIT;
359 }
360
361 return NO_ERROR;
362}
363
364status_t AudioUsbALSA::closeDevice(pcm *handle)
365{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700366 ALOGD("closeDevice handle %p", handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700367 status_t err = NO_ERROR;
368 if (handle) {
369 err = pcm_close(handle);
370 if (err != NO_ERROR) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700371 ALOGE("INFO: closeDevice: pcm_close failed with err %d", err);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700372 }
373 }
374 handle = NULL;
375 return err;
376}
377
378void AudioUsbALSA::RecordingThreadEntry() {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700379 ALOGD("Inside RecordingThreadEntry");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700380 int nfds = 1;
381 mtimeOutRecording = TIMEOUT_INFINITE;
382 int fd;
383 long frames;
384 static int start = 0;
385 struct snd_xferi x;
386 int filed;
387 unsigned avail, bufsize;
388 int bytes_written;
389 uint32_t sampleRate;
390 uint32_t channels;
391 u_int8_t *srcUsb_addr = NULL;
392 u_int8_t *dstProxy_addr = NULL;
393 int err;
394 const char *fn = "/data/RecordPcm.pcm";
395 filed = open(fn, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0664);
396
Ajay Dudani9746c472012-06-18 16:01:16 -0700397 err = getCap((char *)"Capture:", mchannelsCapture, msampleRateCapture);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700398 if (err) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700399 ALOGE("ERROR: Could not get capture capabilities from usb device");
400 return;
401 }
402 int channelFlag = PCM_MONO;
403 if (mchannelsCapture >= 2) {
404 channelFlag = PCM_STEREO;
405 }
406
407 musbRecordingHandle = configureDevice(PCM_IN|channelFlag|PCM_MMAP, (char *)"hw:1,0",
408 msampleRateCapture, mchannelsCapture,768,false);
409 if (!musbRecordingHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700410 ALOGE("ERROR: Could not configure USB device for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700411 return;
412 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700413 ALOGD("USB device Configured for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700414 }
415
416 pfdUsbRecording[0].fd = musbRecordingHandle->fd; //DEBUG
417 pfdUsbRecording[0].events = POLLIN;
418
Ajay Dudani9746c472012-06-18 16:01:16 -0700419 mproxyRecordingHandle = configureDevice(PCM_OUT|channelFlag|PCM_MMAP, (char *)"hw:0,7",
420 msampleRateCapture, mchannelsCapture,768,false);
421 if (!mproxyRecordingHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700422 ALOGE("ERROR: Could not configure Proxy for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700423 closeDevice(musbRecordingHandle);
424 return;
425 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700426 ALOGD("Proxy Configured for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700427 }
428
429 bufsize = musbRecordingHandle->period_size;
430 pfdProxyRecording[0].fd = mproxyRecordingHandle->fd;
431 pfdProxyRecording[0].events = POLLOUT;
432 frames = (musbRecordingHandle->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
433 x.frames = (musbRecordingHandle->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
434
435 /***********************keep reading from usb and writing to proxy******************************************/
436 while (mkillRecordingThread != true) {
437 if (!musbRecordingHandle->running) {
438 if (pcm_prepare(musbRecordingHandle)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700439 ALOGE("ERROR: pcm_prepare failed for usb device for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700440 mkillRecordingThread = true;
441 break;;
442 }
443 }
444 if (!mproxyRecordingHandle->running) {
445 if (pcm_prepare(mproxyRecordingHandle)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700446 ALOGE("ERROR: pcm_prepare failed for proxy device for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700447 mkillRecordingThread = true;
448 break;;
449 }
450 }
451
452 /********** USB syncing before write **************/
453 if (!musbRecordingHandle->start && !mkillRecordingThread) {
454 err = startDevice(musbRecordingHandle, &mkillRecordingThread);
455 if (err == EPIPE) {
456 continue;
457 } else if (err != NO_ERROR) {
458 mkillRecordingThread = true;
459 break;
460 }
461 }
462 for (;;) {
463 if (!musbRecordingHandle->running) {
464 if (pcm_prepare(musbRecordingHandle)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700465 ALOGE("ERROR: pcm_prepare failed for proxy device for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700466 mkillRecordingThread = true;
467 break;
468 }
469 }
470 /* Sync the current Application pointer from the kernel */
471 musbRecordingHandle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL |
472 SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
473
474 err = syncPtr(musbRecordingHandle, &mkillRecordingThread);
475 if (err == EPIPE) {
476 continue;
477 } else if (err != NO_ERROR) {
478 break;
479 }
480
481 avail = pcm_avail(musbRecordingHandle);
482 if (avail < musbRecordingHandle->sw_p->avail_min) {
483 poll(pfdUsbRecording, nfds, TIMEOUT_INFINITE);
484 continue;
485 } else {
486 break;
487 }
488 }
489 if (mkillRecordingThread) {
490 break;
491 }
492 if (x.frames > avail)
493 frames = avail;
494
495 srcUsb_addr = dst_address(musbRecordingHandle);
496 /**********End USB syncing before write**************/
497
498 /*************Proxy syncing before write ******************/
499
500 for (;;) {
501 if (!mproxyRecordingHandle->running) {
502 if (pcm_prepare(mproxyRecordingHandle)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700503 ALOGE("ERROR: pcm_prepare failed for proxy device for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700504 mkillRecordingThread = true;
505 break;
506 }
507 }
508 mproxyRecordingHandle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL |
509 SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
510
511 err = syncPtr(mproxyRecordingHandle, &mkillRecordingThread);
512 if (err == EPIPE) {
513 continue;
514 } else if (err != NO_ERROR) {
515 break;
516 }
517 avail = pcm_avail(mproxyRecordingHandle);
518 if (avail < mproxyRecordingHandle->sw_p->avail_min) {
519 poll(pfdProxyRecording, nfds, TIMEOUT_INFINITE);
520 continue;
521 } else {
522 break;
523 }
524 }
525 if (mkillRecordingThread) {
526 break;
527 }
528
529 dstProxy_addr = dst_address(mproxyRecordingHandle);
530 memset(dstProxy_addr, 0x0, bufsize);
531
532 /**************End Proxy syncing before write *************/
533
534 memcpy(dstProxy_addr, srcUsb_addr, bufsize );
535
536 /************* sync up after write -- USB *********************/
537 musbRecordingHandle->sync_ptr->c.control.appl_ptr += frames;
538 musbRecordingHandle->sync_ptr->flags = 0;
539 err = syncPtr(musbRecordingHandle, &mkillRecordingThread);
540 if (err == EPIPE) {
541 continue;
542 } else if (err != NO_ERROR) {
543 break;
544 }
545
546 /************* end sync up after write -- USB *********************/
547
548 /**************** sync up after write -- Proxy ************************/
549 mproxyRecordingHandle->sync_ptr->c.control.appl_ptr += frames;
550 mproxyRecordingHandle->sync_ptr->flags = 0;
551
552 err = syncPtr(mproxyRecordingHandle, &mkillRecordingThread);
553 if (err == EPIPE) {
554 continue;
555 } else if (err != NO_ERROR) {
556 break;
557 }
558
559 bytes_written = mproxyRecordingHandle->sync_ptr->c.control.appl_ptr - mproxyRecordingHandle->sync_ptr->s.status.hw_ptr;
560 if ((bytes_written >= mproxyRecordingHandle->sw_p->start_threshold) && (!mproxyRecordingHandle->start)) {
561 if (!mkillPlayBackThread) {
562 err = startDevice(mproxyRecordingHandle, &mkillRecordingThread);
563 if (err == EPIPE) {
564 continue;
565 } else if (err != NO_ERROR) {
566 mkillRecordingThread = true;
567 break;
568 }
569 }
570 }
571 }
572 /*************** End sync up after write -- Proxy *********************/
573 if (mkillRecordingThread) {
574 closeDevice(mproxyRecordingHandle);
575 closeDevice(musbRecordingHandle);
576 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700577 ALOGD("Exiting USB Recording thread");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700578}
579
580void *AudioUsbALSA::PlaybackThreadWrapper(void *me) {
581 static_cast<AudioUsbALSA *>(me)->PlaybackThreadEntry();
582 return NULL;
583}
584
585void *AudioUsbALSA::RecordingThreadWrapper(void *me) {
586 static_cast<AudioUsbALSA *>(me)->RecordingThreadEntry();
587 return NULL;
588}
589
Ajay Dudani9746c472012-06-18 16:01:16 -0700590struct pcm * AudioUsbALSA::configureDevice(unsigned flags, char* hw, int sampleRate, int channelCount, int periodSize, bool playback){
Iliyan Malchev4765c432012-06-11 14:36:16 -0700591 int err = NO_ERROR;
Ajay Dudani9746c472012-06-18 16:01:16 -0700592 struct pcm * handle = NULL;
593 handle = pcm_open(flags, hw);
594 if (!handle || handle->fd < 0) {
595 ALOGE("ERROR: pcm_open failed");
596 return NULL;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700597 }
598
Ajay Dudani9746c472012-06-18 16:01:16 -0700599 if (!pcm_ready(handle)) {
600 ALOGE("ERROR: pcm_ready failed");
601 closeDevice(handle);
602 return NULL;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700603 }
604
Ajay Dudani9746c472012-06-18 16:01:16 -0700605 ALOGD("Setting hardware params: sampleRate:%d, channels: %d",sampleRate, channelCount);
606 err = setHardwareParams(handle, sampleRate, channelCount,periodSize);
607 if (err != NO_ERROR) {
608 ALOGE("ERROR: setHardwareParams failed");
609 closeDevice(handle);
610 return NULL;
611 }
612
613 err = setSoftwareParams(handle, playback);
614 if (err != NO_ERROR) {
615 ALOGE("ERROR: setSoftwareParams failed");
616 closeDevice(handle);
617 return NULL;
618 }
619
620 err = mmap_buffer(handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700621 if (err) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700622 ALOGE("ERROR: mmap_buffer failed");
623 closeDevice(handle);
624 return NULL;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700625 }
626
Ajay Dudani9746c472012-06-18 16:01:16 -0700627 err = pcm_prepare(handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700628 if (err) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700629 ALOGE("ERROR: pcm_prepare failed");
630 closeDevice(handle);
631 return NULL;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700632 }
633
Ajay Dudani9746c472012-06-18 16:01:16 -0700634 return handle;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700635}
636
637status_t AudioUsbALSA::startDevice(pcm *handle, bool *killThread) {
638 int err = NO_ERROR;;
639 if (ioctl(handle->fd, SNDRV_PCM_IOCTL_START)) {
640 err = -errno;
641 if (errno == EPIPE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700642 ALOGE("ERROR: SNDRV_PCM_IOCTL_START returned EPIPE for usb recording case");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700643 handle->underruns++;
644 handle->running = 0;
645 handle->start = 0;
646 return errno;
647 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700648 ALOGE("ERROR: SNDRV_PCM_IOCTL_START failed for usb recording case errno:%d", errno);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700649 *killThread = true;
650 return errno;
651 }
652 }
653 handle->start = 1;
654 if (handle == musbRecordingHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700655 ALOGD("Usb Driver started for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700656 } else if (handle == mproxyRecordingHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700657 ALOGD("Proxy Driver started for recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700658 } else if (handle == musbPlaybackHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700659 ALOGD("Usb Driver started for playback");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700660 } else if (handle == mproxyPlaybackHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700661 ALOGD("proxy Driver started for playback");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700662 }
663 return NO_ERROR;
664}
665
666status_t AudioUsbALSA::syncPtr(struct pcm *handle, bool *killThread) {
667 int err;
668 err = sync_ptr(handle);
669 if (err == EPIPE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700670 ALOGE("ERROR: Failed in sync_ptr \n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700671 handle->running = 0;
672 handle->underruns++;
673 handle->start = 0;
674 } else if (err == ENODEV) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700675 ALOGE("Info: Device not available");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700676 } else if (err != NO_ERROR) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700677 ALOGE("ERROR: Sync ptr returned %d", err);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700678 *killThread = true;
679 }
680 return err;
681}
682
683void AudioUsbALSA::pollForProxyData(){
684 int err_poll = poll(pfdProxyPlayback, mnfdsPlayback, mtimeOut);
685 if (err_poll == 0 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700686 ALOGD("POLL timedout");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700687 mkillPlayBackThread = true;
688 pfdProxyPlayback[0].revents = 0;
689 pfdProxyPlayback[1].revents = 0;
690 return;
691 }
692
693 if (pfdProxyPlayback[1].revents & POLLIN) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700694 ALOGD("Signalled from HAL about timeout");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700695 uint64_t u;
696 read(mproxypfdPlayback, &u, sizeof(uint64_t));
697 pfdProxyPlayback[1].revents = 0;
698 if (u == SIGNAL_EVENT_KILLTHREAD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700699 ALOGD("kill thread event");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700700 mkillPlayBackThread = true;
701 pfdProxyPlayback[0].revents = 0;
702 pfdProxyPlayback[1].revents = 0;
703 return;
704 } else if (u == SIGNAL_EVENT_TIMEOUT) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700705 ALOGD("Setting timeout for 3 sec");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700706 mtimeOut = POLL_TIMEOUT;
707 }
708 } else if (pfdProxyPlayback[1].revents & POLLERR || pfdProxyPlayback[1].revents & POLLHUP ||
709 pfdProxyPlayback[1].revents & POLLNVAL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700710 ALOGE("Info: proxy throwing error from location 1");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700711 mkillPlayBackThread = true;
712 pfdProxyPlayback[0].revents = 0;
713 pfdProxyPlayback[1].revents = 0;
714 return;
715 }
716
717 if (pfdProxyPlayback[0].revents & POLLERR || pfdProxyPlayback[0].revents & POLLHUP ||
718 pfdProxyPlayback[0].revents & POLLNVAL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700719 ALOGE("Info: proxy throwing error");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700720 mkillPlayBackThread = true;
721 pfdProxyPlayback[0].revents = 0;
722 pfdProxyPlayback[1].revents = 0;
723 }
724}
725
726void AudioUsbALSA::pollForUsbData(){
727 int err_poll = poll(pfdUsbPlayback, mnfdsPlayback, mtimeOut);
728 if (err_poll == 0 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700729 ALOGD("POLL timedout");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700730 mkillPlayBackThread = true;
731 pfdUsbPlayback[0].revents = 0;
732 pfdUsbPlayback[1].revents = 0;
733 return;
734 }
735
736 if (pfdUsbPlayback[1].revents & POLLIN) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700737 ALOGD("Info: Signalled from HAL about an event");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700738 uint64_t u;
739 read(musbpfdPlayback, &u, sizeof(uint64_t));
740 pfdUsbPlayback[0].revents = 0;
741 pfdUsbPlayback[1].revents = 0;
742 if (u == SIGNAL_EVENT_KILLTHREAD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700743 ALOGD("kill thread");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700744 mkillPlayBackThread = true;
745 return;
746 } else if (u == SIGNAL_EVENT_TIMEOUT) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700747 ALOGD("Setting timeout for 3 sec");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700748 mtimeOut = POLL_TIMEOUT;
749 }
750 } else if (pfdUsbPlayback[1].revents & POLLERR || pfdUsbPlayback[1].revents & POLLHUP ||
751 pfdUsbPlayback[1].revents & POLLNVAL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700752 ALOGE("Info: usb throwing error from location 1");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700753 mkillPlayBackThread = true;
754 pfdUsbPlayback[0].revents = 0;
755 pfdUsbPlayback[1].revents = 0;
756 return;
757 }
758
759 if (pfdUsbPlayback[0].revents & POLLERR || pfdProxyPlayback[0].revents & POLLHUP ||
760 pfdUsbPlayback[0].revents & POLLNVAL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700761 ALOGE("Info: usb throwing error");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700762 mkillPlayBackThread = true;
763 pfdUsbPlayback[0].revents = 0;
764 return;
765 }
766}
767
768void AudioUsbALSA::PlaybackThreadEntry() {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700769 ALOGD("PlaybackThreadEntry");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700770 mnfdsPlayback = 2;
771 mtimeOut = TIMEOUT_INFINITE;
772 long frames;
773 static int fd;
774 struct snd_xferi x;
775 int bytes_written;
776 unsigned avail, xfer, bufsize;
Ajay Dudani9746c472012-06-18 16:01:16 -0700777 unsigned proxyPeriod, usbPeriod;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700778 uint32_t sampleRate;
779 uint32_t channels;
780 unsigned int tmp;
781 int numOfBytesWritten;
782 int err;
783 int filed;
784 const char *fn = "/data/test.pcm";
785 mdstUsb_addr = NULL;
786 msrcProxy_addr = NULL;
787
Ajay Dudani9746c472012-06-18 16:01:16 -0700788 int proxySizeRemaining = 0;
789 int usbSizeFilled = 0;
790
791 pid_t tid = gettid();
792 androidSetThreadPriority(tid, ANDROID_PRIORITY_URGENT_AUDIO);
793
794 err = getCap((char *)"Playback:", mchannelsPlayback, msampleRatePlayback);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700795 if (err) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700796 ALOGE("ERROR: Could not get playback capabilities from usb device");
797 return;
798 }
799
800 musbPlaybackHandle = configureDevice(PCM_OUT|PCM_STEREO|PCM_MMAP, (char *)"hw:1,0",
801 msampleRatePlayback, mchannelsPlayback, USB_PERIOD_SIZE, true);
802 if (!musbPlaybackHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700803 ALOGE("ERROR: configureUsbDevice failed, returning");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700804 closeDevice(musbPlaybackHandle);
805 return;
806 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700807 ALOGD("USB Configured for playback");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700808 }
809
810 if (!mkillPlayBackThread) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700811 pfdUsbPlayback[0].fd = musbPlaybackHandle->timer_fd;
812 pfdUsbPlayback[0].events = POLLIN;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700813 musbpfdPlayback = eventfd(0,0);
814 pfdUsbPlayback[1].fd = musbpfdPlayback;
815 pfdUsbPlayback[1].events = (POLLIN | POLLOUT | POLLERR | POLLNVAL | POLLHUP);
816 }
817
Ajay Dudani9746c472012-06-18 16:01:16 -0700818 mproxyPlaybackHandle = configureDevice(PCM_IN|PCM_STEREO|PCM_MMAP, (char *)"hw:0,8",
819 msampleRatePlayback, mchannelsPlayback, PROXY_PERIOD_SIZE, false);
820 if (!mproxyPlaybackHandle) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700821 ALOGE("ERROR: Could not configure Proxy, returning");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700822 closeDevice(musbPlaybackHandle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700823 return;
824 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700825 ALOGD("Proxy Configured for playback");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700826 }
827
Ajay Dudani9746c472012-06-18 16:01:16 -0700828 proxyPeriod = mproxyPlaybackHandle->period_size;
829 usbPeriod = musbPlaybackHandle->period_size;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700830
831 if (!mkillPlayBackThread) {
832 pfdProxyPlayback[0].fd = mproxyPlaybackHandle->fd;
833 pfdProxyPlayback[0].events = (POLLIN); // | POLLERR | POLLNVAL);
834 mproxypfdPlayback = eventfd(0,0);
835 pfdProxyPlayback[1].fd = mproxypfdPlayback;
836 pfdProxyPlayback[1].events = (POLLIN | POLLOUT| POLLERR | POLLNVAL);
837 }
838
Ajay Dudani9746c472012-06-18 16:01:16 -0700839 frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4);
840 x.frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4);
841 int usbframes = (musbPlaybackHandle->flags & PCM_MONO) ? (usbPeriod / 2) : (usbPeriod / 4);
842
843 u_int8_t *proxybuf = ( u_int8_t *) malloc(PROXY_PERIOD_SIZE);
844 u_int8_t *usbbuf = ( u_int8_t *) malloc(USB_PERIOD_SIZE);
845 memset(proxybuf, 0x0, PROXY_PERIOD_SIZE);
846 memset(usbbuf, 0x0, USB_PERIOD_SIZE);
847
Iliyan Malchev4765c432012-06-11 14:36:16 -0700848
849 /***********************keep reading from proxy and writing to USB******************************************/
850 while (mkillPlayBackThread != true) {
851 if (!mproxyPlaybackHandle->running) {
852 if (pcm_prepare(mproxyPlaybackHandle)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700853 ALOGE("ERROR: pcm_prepare failed for proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700854 mkillPlayBackThread = true;
855 break;
856 }
857 }
858 if (!musbPlaybackHandle->running) {
859 if (pcm_prepare(musbPlaybackHandle)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700860 ALOGE("ERROR: pcm_prepare failed for usb");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700861 mkillPlayBackThread = true;
862 break;
863 }
864 }
865
866 /********** Proxy syncing before write **************/
867 if (!mkillPlayBackThread && (!mproxyPlaybackHandle->start)) {
868 err = startDevice(mproxyPlaybackHandle, &mkillPlayBackThread);
869 if (err == EPIPE) {
870 continue;
871 } else if (err != NO_ERROR) {
872 mkillPlayBackThread = true;
873 break;
874 }
875 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700876 if (proxySizeRemaining == 0) {
877 for (;;) {
878 if (!mproxyPlaybackHandle->running) {
879 if (pcm_prepare(mproxyPlaybackHandle)) {
880 ALOGE("ERROR: pcm_prepare failed for proxy");
881 mkillPlayBackThread = true;
882 break;
883 }
884 }
885 /* Sync the current Application pointer from the kernel */
886 mproxyPlaybackHandle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL |
887 SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700888
Ajay Dudani9746c472012-06-18 16:01:16 -0700889 if (mtimeOut == TIMEOUT_INFINITE && !mkillPlayBackThread) {
890 err = syncPtr(mproxyPlaybackHandle, &mkillPlayBackThread);
891 if (err == EPIPE) {
892 continue;
893 } else if (err != NO_ERROR) {
894 break;
895 }
896 avail = pcm_avail(mproxyPlaybackHandle);
897 }
898 if (avail < mproxyPlaybackHandle->sw_p->avail_min && !mkillPlayBackThread) {
899 pollForProxyData();
900 //if polling returned some error
901 if (!mkillPlayBackThread) {
902 continue;
903 } else {
904 break;
905 }
906 } else { //Got some data or mkillPlayBackThread is true
Iliyan Malchev4765c432012-06-11 14:36:16 -0700907 break;
908 }
909 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700910 if (mkillPlayBackThread) {
911 break;
912 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700913
Ajay Dudani9746c472012-06-18 16:01:16 -0700914 if (x.frames > avail)
915 frames = avail;
916
917 if (!mkillPlayBackThread) {
918 msrcProxy_addr = dst_address(mproxyPlaybackHandle);
919 memcpy(proxybuf, msrcProxy_addr, proxyPeriod );
920
921 x.frames -= frames;
922 mproxyPlaybackHandle->sync_ptr->c.control.appl_ptr += frames;
923 mproxyPlaybackHandle->sync_ptr->flags = 0;
924 proxySizeRemaining = proxyPeriod;
925 }
926
927 if (!mkillPlayBackThread) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700928 err = syncPtr(mproxyPlaybackHandle, &mkillPlayBackThread);
929 if (err == EPIPE) {
930 continue;
931 } else if (err != NO_ERROR) {
932 break;
933 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700934 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700935 }
936 //ALOGE("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining);
937 if (usbPeriod - usbSizeFilled <= proxySizeRemaining) {
938 memcpy(usbbuf + usbSizeFilled, proxybuf + proxyPeriod - proxySizeRemaining, usbPeriod - usbSizeFilled);
939 proxySizeRemaining -= (usbPeriod - usbSizeFilled);
940 usbSizeFilled = usbPeriod;
941 }
942 else {
943 memcpy(usbbuf + usbSizeFilled, proxybuf + proxyPeriod - proxySizeRemaining,proxySizeRemaining);
944 usbSizeFilled += proxySizeRemaining;
945 proxySizeRemaining = 0;
946 }
947
948 if (usbSizeFilled == usbPeriod) {
949 for (;;) {
950 if (!musbPlaybackHandle->running) {
951 if (pcm_prepare(musbPlaybackHandle)) {
952 ALOGE("ERROR: pcm_prepare failed for usb");
953 mkillPlayBackThread = true;
954 break;
955 }
956 }
957 /*************USB syncing before write ******************/
958 musbPlaybackHandle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL |
959 SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
960 if (mtimeOut == TIMEOUT_INFINITE && !mkillPlayBackThread) {
961 err = syncPtr(musbPlaybackHandle, &mkillPlayBackThread);
962 if (err == EPIPE) {
963 continue;
964 } else if (err != NO_ERROR) {
965 break;
966 }
967 avail = pcm_avail(musbPlaybackHandle);
968 //ALOGV("Avail USB is: %d", avail);
969 }
970
971 if (avail < musbPlaybackHandle->sw_p->avail_min && !mkillPlayBackThread) {
972 pollForUsbData();
973 if (!mkillPlayBackThread) {
974 continue;
975 } else {
976 break;
977 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700978 } else {
979 break;
980 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700981 }
982 if (mkillPlayBackThread) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700983 break;
984 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700985
Ajay Dudani9746c472012-06-18 16:01:16 -0700986 if (!mkillPlayBackThread) {
987 mdstUsb_addr = dst_address(musbPlaybackHandle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700988
Ajay Dudani9746c472012-06-18 16:01:16 -0700989 /**************End USB syncing before write *************/
Iliyan Malchev4765c432012-06-11 14:36:16 -0700990
Ajay Dudani9746c472012-06-18 16:01:16 -0700991 memcpy(mdstUsb_addr, usbbuf, usbPeriod );
992 usbSizeFilled = 0;
993 memset(usbbuf, 0x0, usbPeriod);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700994 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700995
996 /**************** sync up after write -- USB ************************/
997 musbPlaybackHandle->sync_ptr->c.control.appl_ptr += usbframes;
998 musbPlaybackHandle->sync_ptr->flags = 0;
999 if (!mkillPlayBackThread) {
Iliyan Malchev4765c432012-06-11 14:36:16 -07001000 err = syncPtr(musbPlaybackHandle, &mkillPlayBackThread);
1001 if (err == EPIPE) {
1002 continue;
1003 } else if (err != NO_ERROR) {
1004 break;
1005 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001006 }
1007
Ajay Dudani9746c472012-06-18 16:01:16 -07001008 bytes_written = musbPlaybackHandle->sync_ptr->c.control.appl_ptr - musbPlaybackHandle->sync_ptr->s.status.hw_ptr;
1009 ALOGE("Appl ptr %d , hw_ptr %d, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written);
1010
1011 /*
1012 Following is the check to prevent USB from going to bad state.
1013 This happens in case of an underrun where there is not enough
1014 data from the proxy
1015 */
1016 if (bytes_written <= usbPeriod && musbPlaybackHandle->start) {
1017 ioctl(musbPlaybackHandle->fd, SNDRV_PCM_IOCTL_PAUSE,1);
1018 pcm_prepare(musbPlaybackHandle);
1019 musbPlaybackHandle->start = false;
1020 continue;
1021 }
1022 if ((bytes_written >= musbPlaybackHandle->sw_p->start_threshold) && (!musbPlaybackHandle->start)) {
Iliyan Malchev4765c432012-06-11 14:36:16 -07001023 if (!mkillPlayBackThread) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001024 err = startDevice(musbPlaybackHandle, &mkillPlayBackThread);
1025 if (err == EPIPE) {
1026 continue;
1027 } else if (err != NO_ERROR) {
1028 mkillPlayBackThread = true;
1029 break;
1030 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001031 }
1032 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001033 /*************** End sync up after write -- USB *********************/
Iliyan Malchev4765c432012-06-11 14:36:16 -07001034 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001035 }
1036 if (mkillPlayBackThread) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001037 if (proxybuf)
1038 free(proxybuf);
1039 if (usbbuf)
1040 free(usbbuf);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001041 mproxypfdPlayback = -1;
1042 musbpfdPlayback = -1;
1043 closeDevice(mproxyPlaybackHandle);
1044 closeDevice(musbPlaybackHandle);
1045 }
Iliyan Malchev4113f342012-06-11 14:39:47 -07001046 ALOGD("Exiting USB Playback Thread");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001047}
1048
1049void AudioUsbALSA::startPlayback()
1050{
1051 mkillPlayBackThread = false;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001052 ALOGD("Creating USB Playback Thread");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001053 pthread_create(&mPlaybackUsb, NULL, PlaybackThreadWrapper, this);
1054}
1055
1056void AudioUsbALSA::startRecording()
1057{
1058 //create Thread
1059 mkillRecordingThread = false;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001060 ALOGV("Creating USB recording Thread");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001061 pthread_create(&mRecordingUsb, NULL, RecordingThreadWrapper, this);
1062}
1063}