1 /* 2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #define USE_ERROR 27 #define USE_TRACE 28 29 #include "PLATFORM_API_BsdOS_ALSA_PCMUtils.h" 30 #include "PLATFORM_API_BsdOS_ALSA_CommonUtils.h" 31 #include "DirectAudio.h" 32 33 #if USE_DAUDIO == TRUE 34 35 // GetPosition method 1: based on how many bytes are passed to the kernel driver 36 // + does not need much processor resources 37 // - not very exact, "jumps" 38 // GetPosition method 2: ask kernel about actual position of playback. 39 // - very exact 40 // - switch to kernel layer for each call 41 // GetPosition method 3: use snd_pcm_avail() call - not yet in official ALSA 42 // quick tests on a Pentium 200MMX showed max. 1.5% processor usage 43 // for playing back a CD-quality file and printing 20x per second a line 44 // on the console with the current time. So I guess performance is not such a 45 // factor here. 46 //#define GET_POSITION_METHOD1 47 #define GET_POSITION_METHOD2 48 49 50 // The default time for a period in microseconds. 51 // For very small buffers, only 2 periods are used. 52 #define DEFAULT_PERIOD_TIME 20000 /* 20ms */ 53 54 ///// implemented functions of DirectAudio.h 55 56 INT32 DAUDIO_GetDirectAudioDeviceCount() { 57 return (INT32) getAudioDeviceCount(); 58 } 59 60 61 INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, DirectAudioDeviceDescription* description) { 62 ALSA_AudioDeviceDescription adesc; 63 64 adesc.index = (int) mixerIndex; 65 adesc.strLen = DAUDIO_STRING_LENGTH; 66 67 adesc.maxSimultaneousLines = (int*) (&(description->maxSimulLines)); 68 adesc.deviceID = &(description->deviceID); 69 adesc.name = description->name; 70 adesc.vendor = description->vendor; 71 adesc.description = description->description; 72 adesc.version = description->version; 73 74 return getAudioDeviceDescriptionByIndex(&adesc); 75 } 76 77 #define MAX_BIT_INDEX 6 78 // returns 79 // 6: for anything above 24-bit 80 // 5: for 4 bytes sample size, 24-bit 81 // 4: for 3 bytes sample size, 24-bit 82 // 3: for 3 bytes sample size, 20-bit 83 // 2: for 2 bytes sample size, 16-bit 84 // 1: for 1 byte sample size, 8-bit 85 // 0: for anything else 86 int getBitIndex(int sampleSizeInBytes, int significantBits) { 87 if (significantBits > 24) return 6; 88 if (sampleSizeInBytes == 4 && significantBits == 24) return 5; 89 if (sampleSizeInBytes == 3) { 90 if (significantBits == 24) return 4; 91 if (significantBits == 20) return 3; 92 } 93 if (sampleSizeInBytes == 2 && significantBits == 16) return 2; 94 if (sampleSizeInBytes == 1 && significantBits == 8) return 1; 95 return 0; 96 } 97 98 int getSampleSizeInBytes(int bitIndex, int sampleSizeInBytes) { 99 switch(bitIndex) { 100 case 1: return 1; 101 case 2: return 2; 102 case 3: /* fall through */ 103 case 4: return 3; 104 case 5: return 4; 105 } 106 return sampleSizeInBytes; 107 } 108 109 int getSignificantBits(int bitIndex, int significantBits) { 110 switch(bitIndex) { 111 case 1: return 8; 112 case 2: return 16; 113 case 3: return 20; 114 case 4: /* fall through */ 115 case 5: return 24; 116 } 117 return significantBits; 118 } 119 120 void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { 121 snd_pcm_t* handle; 122 snd_pcm_format_mask_t* formatMask; 123 snd_pcm_format_t format; 124 snd_pcm_hw_params_t* hwParams; 125 int handledBits[MAX_BIT_INDEX+1]; 126 127 int ret; 128 int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; 129 int origSampleSizeInBytes, origSignificantBits; 130 unsigned int channels, minChannels, maxChannels; 131 int rate, bitIndex; 132 133 for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; 134 if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) { 135 return; 136 } 137 ret = snd_pcm_format_mask_malloc(&formatMask); 138 if (ret != 0) { 139 ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret); 140 } else { 141 ret = snd_pcm_hw_params_malloc(&hwParams); 142 if (ret != 0) { 143 ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); 144 } else { 145 ret = snd_pcm_hw_params_any(handle, hwParams); 146 /* snd_pcm_hw_params_any can return a positive value on success too */ 147 if (ret < 0) { 148 ERROR1("snd_pcm_hw_params_any returned error %d\n", ret); 149 } else { 150 /* for the logic following this code, set ret to 0 to indicate success */ 151 ret = 0; 152 } 153 } 154 snd_pcm_hw_params_get_format_mask(hwParams, formatMask); 155 if (ret == 0) { 156 ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); 157 if (ret != 0) { 158 ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret); 159 } 160 } 161 if (ret == 0) { 162 ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels); 163 if (ret != 0) { 164 ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); 165 } 166 } 167 168 // since we queried the hw: device, for many soundcards, it will only 169 // report the maximum number of channels (which is the only way to talk 170 // to the hw: device). Since we will, however, open the plughw: device 171 // when opening the Source/TargetDataLine, we can safely assume that 172 // also the channels 1..maxChannels are available. 173 #ifdef ALSA_PCM_USE_PLUGHW 174 minChannels = 1; 175 #endif 176 if (ret == 0) { 177 // plughw: supports any sample rate 178 rate = -1; 179 for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { 180 if (snd_pcm_format_mask_test(formatMask, format)) { 181 // format exists 182 if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes, 183 &origSignificantBits, 184 &isSigned, &isBigEndian, &enc)) { 185 // now if we use plughw:, we can use any bit size below the 186 // natively supported ones. Some ALSA drivers only support the maximum 187 // bit size, so we add any sample rates below the reported one. 188 // E.g. this iteration reports support for 16-bit. 189 // getBitIndex will return 2, so it will add entries for 190 // 16-bit (bitIndex=2) and in the next do-while loop iteration, 191 // it will decrease bitIndex and will therefore add 8-bit support. 192 bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits); 193 do { 194 if (bitIndex == 0 195 || bitIndex == MAX_BIT_INDEX 196 || !handledBits[bitIndex]) { 197 handledBits[bitIndex] = TRUE; 198 sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes); 199 significantBits = getSignificantBits(bitIndex, origSignificantBits); 200 if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) { 201 // avoid too many channels explicitly listed 202 // just add -1, min, and max 203 DAUDIO_AddAudioFormat(creator, significantBits, 204 -1, -1, rate, 205 enc, isSigned, isBigEndian); 206 DAUDIO_AddAudioFormat(creator, significantBits, 207 sampleSizeInBytes * minChannels, 208 minChannels, rate, 209 enc, isSigned, isBigEndian); 210 DAUDIO_AddAudioFormat(creator, significantBits, 211 sampleSizeInBytes * maxChannels, 212 maxChannels, rate, 213 enc, isSigned, isBigEndian); 214 } else { 215 for (channels = minChannels; channels <= maxChannels; channels++) { 216 DAUDIO_AddAudioFormat(creator, significantBits, 217 sampleSizeInBytes * channels, 218 channels, rate, 219 enc, isSigned, isBigEndian); 220 } 221 } 222 } 223 #ifndef ALSA_PCM_USE_PLUGHW 224 // without plugin, do not add fake formats 225 break; 226 #endif 227 } while (--bitIndex > 0); 228 } else { 229 TRACE1("could not get format from alsa for format %d\n", format); 230 } 231 } else { 232 //TRACE1("Format %d not supported\n", format); 233 } 234 } // for loop 235 snd_pcm_hw_params_free(hwParams); 236 } 237 snd_pcm_format_mask_free(formatMask); 238 } 239 snd_pcm_close(handle); 240 } 241 242 /** Workaround for cr 7033899, 7030629: 243 * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty 244 * (just opened, underruned or already flushed). 245 * Sometimes it causes PCM falls to -EBADFD error, 246 * sometimes causes bufferSize change. 247 * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used. 248 */ 249 /* ******* ALSA PCM INFO ******************** */ 250 typedef struct tag_AlsaPcmInfo { 251 snd_pcm_t* handle; 252 snd_pcm_hw_params_t* hwParams; 253 snd_pcm_sw_params_t* swParams; 254 int bufferSizeInBytes; 255 int frameSize; // storage size in Bytes 256 unsigned int periods; 257 snd_pcm_uframes_t periodSize; 258 short int isRunning; // see comment above 259 short int isFlushed; // see comment above 260 #ifdef GET_POSITION_METHOD2 261 // to be used exclusively by getBytePosition! 262 snd_pcm_status_t* positionStatus; 263 #endif 264 } AlsaPcmInfo; 265 266 267 int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) { 268 int ret; 269 int threshold; 270 271 if (useThreshold) { 272 // start device whenever anything is written to the buffer 273 threshold = 1; 274 } else { 275 // never start the device automatically 276 threshold = 2000000000; /* near UINT_MAX */ 277 } 278 ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold); 279 if (ret < 0) { 280 ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret)); 281 return FALSE; 282 } 283 return TRUE; 284 } 285 286 int setStartThreshold(AlsaPcmInfo* info, int useThreshold) { 287 int ret = 0; 288 289 if (!setStartThresholdNoCommit(info, useThreshold)) { 290 ret = -1; 291 } 292 if (ret == 0) { 293 // commit it 294 ret = snd_pcm_sw_params(info->handle, info->swParams); 295 if (ret < 0) { 296 ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); 297 } 298 } 299 return (ret == 0)?TRUE:FALSE; 300 } 301 302 303 // returns TRUE if successful 304 int setHWParams(AlsaPcmInfo* info, 305 float sampleRate, 306 int channels, 307 int bufferSizeInFrames, 308 snd_pcm_format_t format) { 309 unsigned int rrate, periodTime, periods; 310 int ret, dir; 311 snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; 312 313 /* choose all parameters */ 314 ret = snd_pcm_hw_params_any(info->handle, info->hwParams); 315 if (ret < 0) { 316 ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret)); 317 return FALSE; 318 } 319 /* set the interleaved read/write format */ 320 ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED); 321 if (ret < 0) { 322 ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret)); 323 return FALSE; 324 } 325 /* set the sample format */ 326 ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format); 327 if (ret < 0) { 328 ERROR1("Sample format not available: %s\n", snd_strerror(ret)); 329 return FALSE; 330 } 331 /* set the count of channels */ 332 ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels); 333 if (ret < 0) { 334 ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret)); 335 return FALSE; 336 } 337 /* set the stream rate */ 338 rrate = (int) (sampleRate + 0.5f); 339 dir = 0; 340 ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); 341 if (ret < 0) { 342 ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); 343 return FALSE; 344 } 345 if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) { 346 ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate); 347 return FALSE; 348 } 349 /* set the buffer time */ 350 ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); 351 if (ret < 0) { 352 ERROR2("Unable to set buffer size to %d frames: %s\n", 353 (int) alsaBufferSizeInFrames, snd_strerror(ret)); 354 return FALSE; 355 } 356 bufferSizeInFrames = (int) alsaBufferSizeInFrames; 357 /* set the period time */ 358 if (bufferSizeInFrames > 1024) { 359 dir = 0; 360 periodTime = DEFAULT_PERIOD_TIME; 361 ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); 362 if (ret < 0) { 363 ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); 364 return FALSE; 365 } 366 } else { 367 /* set the period count for very small buffer sizes to 2 */ 368 dir = 0; 369 periods = 2; 370 ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); 371 if (ret < 0) { 372 ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); 373 return FALSE; 374 } 375 } 376 /* write the parameters to device */ 377 ret = snd_pcm_hw_params(info->handle, info->hwParams); 378 if (ret < 0) { 379 ERROR1("Unable to set hw params: %s\n", snd_strerror(ret)); 380 return FALSE; 381 } 382 return TRUE; 383 } 384 385 // returns 1 if successful 386 int setSWParams(AlsaPcmInfo* info) { 387 int ret; 388 389 /* get the current swparams */ 390 ret = snd_pcm_sw_params_current(info->handle, info->swParams); 391 if (ret < 0) { 392 ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret)); 393 return FALSE; 394 } 395 /* never start the transfer automatically */ 396 if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) { 397 return FALSE; 398 } 399 400 /* allow the transfer when at least period_size samples can be processed */ 401 ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize); 402 if (ret < 0) { 403 ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret)); 404 return FALSE; 405 } 406 /* write the parameters to the playback device */ 407 ret = snd_pcm_sw_params(info->handle, info->swParams); 408 if (ret < 0) { 409 ERROR1("Unable to set sw params: %s\n", snd_strerror(ret)); 410 return FALSE; 411 } 412 return TRUE; 413 } 414 415 static snd_output_t* ALSA_OUTPUT = NULL; 416 417 void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, 418 int encoding, float sampleRate, int sampleSizeInBits, 419 int frameSize, int channels, 420 int isSigned, int isBigEndian, int bufferSizeInBytes) { 421 snd_pcm_format_mask_t* formatMask; 422 snd_pcm_format_t format; 423 int dir; 424 int ret = 0; 425 AlsaPcmInfo* info = NULL; 426 /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ 427 snd_pcm_uframes_t alsaBufferSizeInFrames = 0; 428 429 430 TRACE0("> DAUDIO_Open\n"); 431 #ifdef USE_TRACE 432 // for using ALSA debug dump methods 433 if (ALSA_OUTPUT == NULL) { 434 snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0); 435 } 436 #endif 437 if (channels <= 0) { 438 ERROR1("ERROR: Invalid number of channels=%d!\n", channels); 439 return NULL; 440 } 441 info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo)); 442 if (!info) { 443 ERROR0("Out of memory\n"); 444 return NULL; 445 } 446 memset(info, 0, sizeof(AlsaPcmInfo)); 447 // initial values are: stopped, flushed 448 info->isRunning = 0; 449 info->isFlushed = 1; 450 451 ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/); 452 if (ret == 0) { 453 // set to blocking mode 454 snd_pcm_nonblock(info->handle, 0); 455 ret = snd_pcm_hw_params_malloc(&(info->hwParams)); 456 if (ret != 0) { 457 ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret); 458 } else { 459 ret = -1; 460 if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits, 461 isSigned, isBigEndian, encoding)) { 462 if (setHWParams(info, 463 sampleRate, 464 channels, 465 bufferSizeInBytes / frameSize, 466 format)) { 467 info->frameSize = frameSize; 468 ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir); 469 if (ret < 0) { 470 ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); 471 } 472 snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); 473 snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); 474 info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; 475 TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", 476 (int) info->periodSize, info->periods, info->bufferSizeInBytes); 477 } 478 } 479 } 480 if (ret == 0) { 481 // set software parameters 482 ret = snd_pcm_sw_params_malloc(&(info->swParams)); 483 if (ret != 0) { 484 ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); 485 } else { 486 if (!setSWParams(info)) { 487 ret = -1; 488 } 489 } 490 } 491 if (ret == 0) { 492 // prepare device 493 ret = snd_pcm_prepare(info->handle); 494 if (ret < 0) { 495 ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); 496 } 497 } 498 499 #ifdef GET_POSITION_METHOD2 500 if (ret == 0) { 501 ret = snd_pcm_status_malloc(&(info->positionStatus)); 502 if (ret != 0) { 503 ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret)); 504 } 505 } 506 #endif 507 } 508 if (ret != 0) { 509 DAUDIO_Close((void*) info, isSource); 510 info = NULL; 511 } else { 512 // set to non-blocking mode 513 snd_pcm_nonblock(info->handle, 1); 514 TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n", 515 (void*) info->handle); 516 } 517 return (void*) info; 518 } 519 520 #ifdef USE_TRACE 521 void printState(snd_pcm_state_t state) { 522 if (state == SND_PCM_STATE_OPEN) { 523 TRACE0("State: SND_PCM_STATE_OPEN\n"); 524 } 525 else if (state == SND_PCM_STATE_SETUP) { 526 TRACE0("State: SND_PCM_STATE_SETUP\n"); 527 } 528 else if (state == SND_PCM_STATE_PREPARED) { 529 TRACE0("State: SND_PCM_STATE_PREPARED\n"); 530 } 531 else if (state == SND_PCM_STATE_RUNNING) { 532 TRACE0("State: SND_PCM_STATE_RUNNING\n"); 533 } 534 else if (state == SND_PCM_STATE_XRUN) { 535 TRACE0("State: SND_PCM_STATE_XRUN\n"); 536 } 537 else if (state == SND_PCM_STATE_DRAINING) { 538 TRACE0("State: SND_PCM_STATE_DRAINING\n"); 539 } 540 else if (state == SND_PCM_STATE_PAUSED) { 541 TRACE0("State: SND_PCM_STATE_PAUSED\n"); 542 } 543 else if (state == SND_PCM_STATE_SUSPENDED) { 544 TRACE0("State: SND_PCM_STATE_SUSPENDED\n"); 545 } 546 } 547 #endif 548 549 int DAUDIO_Start(void* id, int isSource) { 550 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 551 int ret; 552 snd_pcm_state_t state; 553 554 TRACE0("> DAUDIO_Start\n"); 555 // set to blocking mode 556 snd_pcm_nonblock(info->handle, 0); 557 // set start mode so that it always starts as soon as data is there 558 setStartThreshold(info, TRUE /* use threshold */); 559 state = snd_pcm_state(info->handle); 560 if (state == SND_PCM_STATE_PAUSED) { 561 // in case it was stopped previously 562 TRACE0(" Un-pausing...\n"); 563 ret = snd_pcm_pause(info->handle, FALSE); 564 if (ret != 0) { 565 ERROR2(" NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret)); 566 } 567 } 568 if (state == SND_PCM_STATE_SUSPENDED) { 569 TRACE0(" Resuming...\n"); 570 ret = snd_pcm_resume(info->handle); 571 if (ret < 0) { 572 if ((ret != -EAGAIN) && (ret != -ENOSYS)) { 573 ERROR2(" ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret)); 574 } 575 } 576 } 577 if (state == SND_PCM_STATE_SETUP) { 578 TRACE0("need to call prepare again...\n"); 579 // prepare device 580 ret = snd_pcm_prepare(info->handle); 581 if (ret < 0) { 582 ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); 583 } 584 } 585 // in case there is still data in the buffers 586 ret = snd_pcm_start(info->handle); 587 if (ret != 0) { 588 if (ret != -EPIPE) { 589 ERROR2(" NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret)); 590 } 591 } 592 // set to non-blocking mode 593 ret = snd_pcm_nonblock(info->handle, 1); 594 if (ret != 0) { 595 ERROR1(" ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret)); 596 } 597 state = snd_pcm_state(info->handle); 598 #ifdef USE_TRACE 599 printState(state); 600 #endif 601 ret = (state == SND_PCM_STATE_PREPARED) 602 || (state == SND_PCM_STATE_RUNNING) 603 || (state == SND_PCM_STATE_XRUN) 604 || (state == SND_PCM_STATE_SUSPENDED); 605 if (ret) { 606 info->isRunning = 1; 607 // source line should keep isFlushed value until Write() is called; 608 // for target data line reset it right now. 609 if (!isSource) { 610 info->isFlushed = 0; 611 } 612 } 613 TRACE1("< DAUDIO_Start %s\n", ret?"success":"error"); 614 return ret?TRUE:FALSE; 615 } 616 617 int DAUDIO_Stop(void* id, int isSource) { 618 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 619 int ret; 620 621 TRACE0("> DAUDIO_Stop\n"); 622 // set to blocking mode 623 snd_pcm_nonblock(info->handle, 0); 624 setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun 625 ret = snd_pcm_pause(info->handle, 1); 626 // set to non-blocking mode 627 snd_pcm_nonblock(info->handle, 1); 628 if (ret != 0) { 629 ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret)); 630 return FALSE; 631 } 632 info->isRunning = 0; 633 TRACE0("< DAUDIO_Stop success\n"); 634 return TRUE; 635 } 636 637 void DAUDIO_Close(void* id, int isSource) { 638 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 639 640 TRACE0("DAUDIO_Close\n"); 641 if (info != NULL) { 642 if (info->handle != NULL) { 643 snd_pcm_close(info->handle); 644 } 645 if (info->hwParams) { 646 snd_pcm_hw_params_free(info->hwParams); 647 } 648 if (info->swParams) { 649 snd_pcm_sw_params_free(info->swParams); 650 } 651 #ifdef GET_POSITION_METHOD2 652 if (info->positionStatus) { 653 snd_pcm_status_free(info->positionStatus); 654 } 655 #endif 656 free(info); 657 } 658 } 659 660 /* 661 * Underrun and suspend recovery 662 * returns 663 * 0: exit native and return 0 664 * 1: try again to write/read 665 * -1: error - exit native with return value -1 666 */ 667 int xrun_recovery(AlsaPcmInfo* info, int err) { 668 int ret; 669 670 if (err == -EPIPE) { /* underrun / overflow */ 671 TRACE0("xrun_recovery: underrun/overflow.\n"); 672 ret = snd_pcm_prepare(info->handle); 673 if (ret < 0) { 674 ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); 675 return -1; 676 } 677 return 1; 678 } else if (err == -ESTRPIPE) { 679 TRACE0("xrun_recovery: suspended.\n"); 680 ret = snd_pcm_resume(info->handle); 681 if (ret < 0) { 682 if (ret == -EAGAIN) { 683 return 0; /* wait until the suspend flag is released */ 684 } 685 return -1; 686 } 687 ret = snd_pcm_prepare(info->handle); 688 if (ret < 0) { 689 ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret)); 690 return -1; 691 } 692 return 1; 693 } else if (err == -EAGAIN) { 694 TRACE0("xrun_recovery: EAGAIN try again flag.\n"); 695 return 0; 696 } 697 698 TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err)); 699 return -1; 700 } 701 702 // returns -1 on error 703 int DAUDIO_Write(void* id, char* data, int byteSize) { 704 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 705 int ret, count; 706 snd_pcm_sframes_t frameSize, writtenFrames; 707 708 TRACE1("> DAUDIO_Write %d bytes\n", byteSize); 709 710 /* sanity */ 711 if (byteSize <= 0 || info->frameSize <= 0) { 712 ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n", 713 (int) byteSize, (int) info->frameSize); 714 TRACE0("< DAUDIO_Write returning -1\n"); 715 return -1; 716 } 717 718 count = 2; // maximum number of trials to recover from underrun 719 //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); 720 frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); 721 do { 722 writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize); 723 724 if (writtenFrames < 0) { 725 ret = xrun_recovery(info, (int) writtenFrames); 726 if (ret <= 0) { 727 TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret); 728 return ret; 729 } 730 if (count-- <= 0) { 731 ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n"); 732 return -1; 733 } 734 } else { 735 break; 736 } 737 } while (TRUE); 738 //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames); 739 740 if (writtenFrames > 0) { 741 // reset "flushed" flag 742 info->isFlushed = 0; 743 } 744 745 ret = (int) (writtenFrames * info->frameSize); 746 TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); 747 return ret; 748 } 749 750 // returns -1 on error 751 int DAUDIO_Read(void* id, char* data, int byteSize) { 752 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 753 int ret, count; 754 snd_pcm_sframes_t frameSize, readFrames; 755 756 TRACE1("> DAUDIO_Read %d bytes\n", byteSize); 757 /*TRACE3(" info=%p, data=%p, byteSize=%d\n", 758 (void*) info, (void*) data, (int) byteSize); 759 TRACE2(" info->frameSize=%d, info->handle=%p\n", 760 (int) info->frameSize, (void*) info->handle); 761 */ 762 /* sanity */ 763 if (byteSize <= 0 || info->frameSize <= 0) { 764 ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n", 765 (int) byteSize, (int) info->frameSize); 766 TRACE0("< DAUDIO_Read returning -1\n"); 767 return -1; 768 } 769 if (!info->isRunning && info->isFlushed) { 770 // PCM has nothing to read 771 return 0; 772 } 773 774 count = 2; // maximum number of trials to recover from error 775 //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); 776 frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); 777 do { 778 readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize); 779 if (readFrames < 0) { 780 ret = xrun_recovery(info, (int) readFrames); 781 if (ret <= 0) { 782 TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret); 783 return ret; 784 } 785 if (count-- <= 0) { 786 ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n"); 787 return -1; 788 } 789 } else { 790 break; 791 } 792 } while (TRUE); 793 //ret = snd_pcm_frames_to_bytes(info->handle, readFrames); 794 ret = (int) (readFrames * info->frameSize); 795 TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); 796 return ret; 797 } 798 799 800 int DAUDIO_GetBufferSize(void* id, int isSource) { 801 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 802 803 return info->bufferSizeInBytes; 804 } 805 806 int DAUDIO_StillDraining(void* id, int isSource) { 807 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 808 snd_pcm_state_t state; 809 810 state = snd_pcm_state(info->handle); 811 //printState(state); 812 //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE"); 813 return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE; 814 } 815 816 817 int DAUDIO_Flush(void* id, int isSource) { 818 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 819 int ret; 820 821 TRACE0("DAUDIO_Flush\n"); 822 823 if (info->isFlushed) { 824 // nothing to drop 825 return 1; 826 } 827 828 ret = snd_pcm_drop(info->handle); 829 if (ret != 0) { 830 ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret)); 831 return FALSE; 832 } 833 834 info->isFlushed = 1; 835 if (info->isRunning) { 836 ret = DAUDIO_Start(id, isSource); 837 } 838 return ret; 839 } 840 841 int DAUDIO_GetAvailable(void* id, int isSource) { 842 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 843 snd_pcm_sframes_t availableInFrames; 844 snd_pcm_state_t state; 845 int ret; 846 847 state = snd_pcm_state(info->handle); 848 if (info->isFlushed || state == SND_PCM_STATE_XRUN) { 849 // if in xrun state then we have the entire buffer available, 850 // not 0 as alsa reports 851 ret = info->bufferSizeInBytes; 852 } else { 853 availableInFrames = snd_pcm_avail_update(info->handle); 854 if (availableInFrames < 0) { 855 ret = 0; 856 } else { 857 //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames); 858 ret = (int) (availableInFrames * info->frameSize); 859 } 860 } 861 TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); 862 return ret; 863 } 864 865 INT64 estimatePositionFromAvail(AlsaPcmInfo* info, int isSource, INT64 javaBytePos, int availInBytes) { 866 // estimate the current position with the buffer size and 867 // the available bytes to read or write in the buffer. 868 // not an elegant solution - bytePos will stop on xruns, 869 // and in race conditions it may jump backwards 870 // Advantage is that it is indeed based on the samples that go through 871 // the system (rather than time-based methods) 872 if (isSource) { 873 // javaBytePos is the position that is reached when the current 874 // buffer is played completely 875 return (INT64) (javaBytePos - info->bufferSizeInBytes + availInBytes); 876 } else { 877 // javaBytePos is the position that was when the current buffer was empty 878 return (INT64) (javaBytePos + availInBytes); 879 } 880 } 881 882 INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { 883 AlsaPcmInfo* info = (AlsaPcmInfo*) id; 884 int ret; 885 INT64 result = javaBytePos; 886 snd_pcm_state_t state; 887 state = snd_pcm_state(info->handle); 888 889 if (!info->isFlushed && state != SND_PCM_STATE_XRUN) { 890 #ifdef GET_POSITION_METHOD2 891 snd_timestamp_t* ts; 892 snd_pcm_uframes_t framesAvail; 893 894 // note: slight race condition if this is called simultaneously from 2 threads 895 ret = snd_pcm_status(info->handle, info->positionStatus); 896 if (ret != 0) { 897 ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret)); 898 result = javaBytePos; 899 } else { 900 // calculate from time value, or from available bytes 901 framesAvail = snd_pcm_status_get_avail(info->positionStatus); 902 result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); 903 } 904 #endif 905 #ifdef GET_POSITION_METHOD3 906 snd_pcm_uframes_t framesAvail; 907 ret = snd_pcm_avail(info->handle, &framesAvail); 908 if (ret != 0) { 909 ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret)); 910 result = javaBytePos; 911 } else { 912 result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); 913 } 914 #endif 915 #ifdef GET_POSITION_METHOD1 916 result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource)); 917 #endif 918 } 919 //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); 920 return result; 921 } 922 923 924 925 void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { 926 /* save to ignore, since GetBytePosition 927 * takes the javaBytePos param into account 928 */ 929 } 930 931 int DAUDIO_RequiresServicing(void* id, int isSource) { 932 // never need servicing on Bsd 933 return FALSE; 934 } 935 936 void DAUDIO_Service(void* id, int isSource) { 937 // never need servicing on Bsd 938 } 939 940 941 #endif // USE_DAUDIO