1 /*
   2  * Copyright (c) 2002, 2007, 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_LinuxOS_ALSA_PCMUtils.h"
  30 #include "PLATFORM_API_LinuxOS_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     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 #ifdef ALSA_PCM_NEW_HW_PARAMS_API
 156         if (ret == 0) {
 157             ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels);
 158             if (ret != 0) {
 159                 ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret);
 160             }
 161         }
 162         if (ret == 0) {
 163             ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels);
 164             if (ret != 0) {
 165                 ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret);
 166             }
 167         }
 168 #else
 169         minChannels = snd_pcm_hw_params_get_channels_min(hwParams);
 170         maxChannels = snd_pcm_hw_params_get_channels_max(hwParams);
 171         if (minChannels > maxChannels) {
 172             ERROR2("MinChannels=%d, maxChannels=%d\n", minChannels, maxChannels);
 173         }
 174 #endif
 175 
 176         // since we queried the hw: device, for many soundcards, it will only
 177         // report the maximum number of channels (which is the only way to talk
 178         // to the hw: device). Since we will, however, open the plughw: device
 179         // when opening the Source/TargetDataLine, we can safely assume that
 180         // also the channels 1..maxChannels are available.
 181 #ifdef ALSA_PCM_USE_PLUGHW
 182         minChannels = 1;
 183 #endif
 184         if (ret == 0) {
 185             // plughw: supports any sample rate
 186             rate = -1;
 187             for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
 188                 if (snd_pcm_format_mask_test(formatMask, format)) {
 189                     // format exists
 190                     if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes,
 191                                                 &origSignificantBits,
 192                                                 &isSigned, &isBigEndian, &enc)) {
 193                         // now if we use plughw:, we can use any bit size below the
 194                         // natively supported ones. Some ALSA drivers only support the maximum
 195                         // bit size, so we add any sample rates below the reported one.
 196                         // E.g. this iteration reports support for 16-bit.
 197                         // getBitIndex will return 2, so it will add entries for
 198                         // 16-bit (bitIndex=2) and in the next do-while loop iteration,
 199                         // it will decrease bitIndex and will therefore add 8-bit support.
 200                         bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits);
 201                         do {
 202                             if (bitIndex == 0
 203                                 || bitIndex == MAX_BIT_INDEX
 204                                 || !handledBits[bitIndex]) {
 205                                 handledBits[bitIndex] = TRUE;
 206                                 sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes);
 207                                 significantBits = getSignificantBits(bitIndex, origSignificantBits);
 208                                 if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) {
 209                                     // avoid too many channels explicitly listed
 210                                     // just add -1, min, and max
 211                                     DAUDIO_AddAudioFormat(creator, significantBits,
 212                                                           -1, -1, rate,
 213                                                           enc, isSigned, isBigEndian);
 214                                     DAUDIO_AddAudioFormat(creator, significantBits,
 215                                                           sampleSizeInBytes * minChannels,
 216                                                           minChannels, rate,
 217                                                           enc, isSigned, isBigEndian);
 218                                     DAUDIO_AddAudioFormat(creator, significantBits,
 219                                                           sampleSizeInBytes * maxChannels,
 220                                                           maxChannels, rate,
 221                                                           enc, isSigned, isBigEndian);
 222                                 } else {
 223                                     for (channels = minChannels; channels <= maxChannels; channels++) {
 224                                         DAUDIO_AddAudioFormat(creator, significantBits,
 225                                                               (channels < 0)?-1:(sampleSizeInBytes * channels),
 226                                                               channels, rate,
 227                                                               enc, isSigned, isBigEndian);
 228                                     }
 229                                 }
 230                             }
 231 #ifndef ALSA_PCM_USE_PLUGHW
 232                             // without plugin, do not add fake formats
 233                             break;
 234 #endif
 235                         } while (--bitIndex > 0);
 236                     } else {
 237                         TRACE1("could not get format from alsa for format %d\n", format);
 238                     }
 239                 } else {
 240                     //TRACE1("Format %d not supported\n", format);
 241                 }
 242             } // for loop
 243             snd_pcm_hw_params_free(hwParams);
 244         }
 245         snd_pcm_format_mask_free(formatMask);
 246     }
 247     snd_pcm_close(handle);
 248 }
 249 
 250 /* ******* ALSA PCM INFO ******************** */
 251 typedef struct tag_AlsaPcmInfo {
 252     snd_pcm_t* handle;
 253     snd_pcm_hw_params_t* hwParams;
 254     snd_pcm_sw_params_t* swParams;
 255     int bufferSizeInBytes;
 256     int frameSize; // storage size in Bytes
 257     int periods;
 258     snd_pcm_uframes_t periodSize;
 259 #ifdef GET_POSITION_METHOD2
 260     // to be used exclusively by getBytePosition!
 261     snd_pcm_status_t* positionStatus;
 262 #endif
 263 } AlsaPcmInfo;
 264 
 265 
 266 int setStartThresholdNoCommit(AlsaPcmInfo* info, int useThreshold) {
 267     int ret;
 268     int threshold;
 269 
 270     if (useThreshold) {
 271         // start device whenever anything is written to the buffer
 272         threshold = 1;
 273     } else {
 274         // never start the device automatically
 275         threshold = 2000000000; /* near UINT_MAX */
 276     }
 277     ret = snd_pcm_sw_params_set_start_threshold(info->handle, info->swParams, threshold);
 278     if (ret < 0) {
 279         ERROR1("Unable to set start threshold mode: %s\n", snd_strerror(ret));
 280         return FALSE;
 281     }
 282     return TRUE;
 283 }
 284 
 285 int setStartThreshold(AlsaPcmInfo* info, int useThreshold) {
 286     int ret = 0;
 287 
 288     if (!setStartThresholdNoCommit(info, useThreshold)) {
 289         ret = -1;
 290     }
 291     if (ret == 0) {
 292         // commit it
 293         ret = snd_pcm_sw_params(info->handle, info->swParams);
 294         if (ret < 0) {
 295             ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
 296         }
 297     }
 298     return (ret == 0)?TRUE:FALSE;
 299 }
 300 
 301 
 302 // returns TRUE if successful
 303 int setHWParams(AlsaPcmInfo* info,
 304                 float sampleRate,
 305                 int channels,
 306                 int bufferSizeInFrames,
 307                 snd_pcm_format_t format) {
 308     unsigned int rrate;
 309     int ret, dir, periods, periodTime;
 310     snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames;
 311 
 312     /* choose all parameters */
 313     ret = snd_pcm_hw_params_any(info->handle, info->hwParams);
 314     if (ret < 0) {
 315         ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret));
 316         return FALSE;
 317     }
 318     /* set the interleaved read/write format */
 319     ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED);
 320     if (ret < 0) {
 321         ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret));
 322         return FALSE;
 323     }
 324     /* set the sample format */
 325     ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format);
 326     if (ret < 0) {
 327         ERROR1("Sample format not available: %s\n", snd_strerror(ret));
 328         return FALSE;
 329     }
 330     /* set the count of channels */
 331     ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels);
 332     if (ret < 0) {
 333         ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret));
 334         return FALSE;
 335     }
 336     /* set the stream rate */
 337     rrate = (int) (sampleRate + 0.5f);
 338 #ifdef ALSA_PCM_NEW_HW_PARAMS_API
 339     dir = 0;
 340     ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir);
 341 #else
 342     ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, rrate, 0);
 343 #endif
 344     if (ret < 0) {
 345         ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret));
 346         return FALSE;
 347     }
 348     if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) {
 349         ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate);
 350         return FALSE;
 351     }
 352     /* set the buffer time */
 353 #ifdef ALSA_PCM_NEW_HW_PARAMS_API
 354 
 355     ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames);
 356 #else
 357     ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, alsaBufferSizeInFrames);
 358 #endif
 359     if (ret < 0) {
 360         ERROR2("Unable to set buffer size to %d frames: %s\n",
 361                (int) alsaBufferSizeInFrames, snd_strerror(ret));
 362         return FALSE;
 363     }
 364     bufferSizeInFrames = (int) alsaBufferSizeInFrames;
 365     /* set the period time */
 366     if (bufferSizeInFrames > 1024) {
 367         dir = 0;
 368         periodTime = DEFAULT_PERIOD_TIME;
 369 #ifdef ALSA_PCM_NEW_HW_PARAMS_API
 370         ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir);
 371 #else
 372         periodTime = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, periodTime, &dir);
 373         ret = periodTime;
 374 #endif
 375         if (ret < 0) {
 376             ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret));
 377             return FALSE;
 378         }
 379     } else {
 380         /* set the period count for very small buffer sizes to 2 */
 381         dir = 0;
 382         periods = 2;
 383 #ifdef ALSA_PCM_NEW_HW_PARAMS_API
 384         ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir);
 385 #else
 386         periods = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, periods, &dir);
 387         ret = periods;
 388 #endif
 389         if (ret < 0) {
 390             ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret));
 391             return FALSE;
 392         }
 393     }
 394     /* write the parameters to device */
 395     ret = snd_pcm_hw_params(info->handle, info->hwParams);
 396     if (ret < 0) {
 397         ERROR1("Unable to set hw params: %s\n", snd_strerror(ret));
 398         return FALSE;
 399     }
 400     return TRUE;
 401 }
 402 
 403 // returns 1 if successful
 404 int setSWParams(AlsaPcmInfo* info) {
 405     int ret;
 406 
 407     /* get the current swparams */
 408     ret = snd_pcm_sw_params_current(info->handle, info->swParams);
 409     if (ret < 0) {
 410         ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret));
 411         return FALSE;
 412     }
 413     /* never start the transfer automatically */
 414     if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) {
 415         return FALSE;
 416     }
 417 
 418     /* allow the transfer when at least period_size samples can be processed */
 419     ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize);
 420     if (ret < 0) {
 421         ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret));
 422         return FALSE;
 423     }
 424     /* align all transfers to 1 sample */
 425     ret = snd_pcm_sw_params_set_xfer_align(info->handle, info->swParams, 1);
 426     if (ret < 0) {
 427         ERROR1("Unable to set transfer align: %s\n", snd_strerror(ret));
 428         return FALSE;
 429     }
 430     /* write the parameters to the playback device */
 431     ret = snd_pcm_sw_params(info->handle, info->swParams);
 432     if (ret < 0) {
 433         ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
 434         return FALSE;
 435     }
 436     return TRUE;
 437 }
 438 
 439 static snd_output_t* ALSA_OUTPUT = NULL;
 440 
 441 void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
 442                   int encoding, float sampleRate, int sampleSizeInBits,
 443                   int frameSize, int channels,
 444                   int isSigned, int isBigEndian, int bufferSizeInBytes) {
 445     snd_pcm_format_mask_t* formatMask;
 446     snd_pcm_format_t format;
 447     int dir;
 448     int ret = 0;
 449     AlsaPcmInfo* info = NULL;
 450     /* snd_pcm_uframes_t is 64 bit on 64-bit systems */
 451     snd_pcm_uframes_t alsaPeriodSize = 0;
 452     snd_pcm_uframes_t alsaBufferSizeInFrames = 0;
 453 
 454 
 455     TRACE0("> DAUDIO_Open\n");
 456 #ifdef USE_TRACE
 457     // for using ALSA debug dump methods
 458     if (ALSA_OUTPUT == NULL) {
 459         snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0);
 460     }
 461 #endif
 462     if (channels <= 0) {
 463         ERROR1("ERROR: Invalid number of channels=%d!\n", channels);
 464         return NULL;
 465     }
 466     info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo));
 467     if (!info) {
 468         ERROR0("Out of memory\n");
 469         return NULL;
 470     }
 471     memset(info, 0, sizeof(AlsaPcmInfo));
 472 
 473     ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/);
 474     if (ret == 0) {
 475         // set to blocking mode
 476         snd_pcm_nonblock(info->handle, 0);
 477         ret = snd_pcm_hw_params_malloc(&(info->hwParams));
 478         if (ret != 0) {
 479             ERROR1("  snd_pcm_hw_params_malloc returned error %d\n", ret);
 480         } else {
 481             ret = -1;
 482             if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits,
 483                                         isSigned, isBigEndian, encoding)) {
 484                 if (setHWParams(info,
 485                                 sampleRate,
 486                                 channels,
 487                                 bufferSizeInBytes / frameSize,
 488                                 format)) {
 489                     info->frameSize = frameSize;
 490 #ifdef ALSA_PCM_NEW_HW_PARAMS_API
 491                     ret = snd_pcm_hw_params_get_period_size(info->hwParams, &alsaPeriodSize, &dir);
 492                     info->periodSize = (int) alsaPeriodSize;
 493                     if (ret < 0) {
 494                         ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret));
 495                     }
 496                     snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir);
 497                     snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames);
 498                     info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize;
 499 #else
 500                     info->periodSize = snd_pcm_hw_params_get_period_size(info->hwParams, &dir);
 501                     info->periods = snd_pcm_hw_params_get_periods(info->hwParams, &dir);
 502                     info->bufferSizeInBytes = snd_pcm_hw_params_get_buffer_size(info->hwParams) * frameSize;
 503                     ret = 0;
 504 #endif
 505                     TRACE3("  DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n",
 506                            (int) info->periodSize, info->periods, info->bufferSizeInBytes);
 507                 }
 508             }
 509         }
 510         if (ret == 0) {
 511             // set software parameters
 512             ret = snd_pcm_sw_params_malloc(&(info->swParams));
 513             if (ret != 0) {
 514                 ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret);
 515             } else {
 516                 if (!setSWParams(info)) {
 517                     ret = -1;
 518                 }
 519             }
 520         }
 521         if (ret == 0) {
 522             // prepare device
 523             ret = snd_pcm_prepare(info->handle);
 524             if (ret < 0) {
 525                 ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
 526             }
 527         }
 528 
 529 #ifdef GET_POSITION_METHOD2
 530         if (ret == 0) {
 531             ret = snd_pcm_status_malloc(&(info->positionStatus));
 532             if (ret != 0) {
 533                 ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret));
 534             }
 535         }
 536 #endif
 537     }
 538     if (ret != 0) {
 539         DAUDIO_Close((void*) info, isSource);
 540         info = NULL;
 541     } else {
 542         // set to non-blocking mode
 543         snd_pcm_nonblock(info->handle, 1);
 544         TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n",
 545                (void*) info->handle);
 546     }
 547     return (void*) info;
 548 }
 549 
 550 #ifdef USE_TRACE
 551 void printState(snd_pcm_state_t state) {
 552     if (state == SND_PCM_STATE_OPEN) {
 553         TRACE0("State: SND_PCM_STATE_OPEN\n");
 554     }
 555     else if (state == SND_PCM_STATE_SETUP) {
 556         TRACE0("State: SND_PCM_STATE_SETUP\n");
 557     }
 558     else if (state == SND_PCM_STATE_PREPARED) {
 559         TRACE0("State: SND_PCM_STATE_PREPARED\n");
 560     }
 561     else if (state == SND_PCM_STATE_RUNNING) {
 562         TRACE0("State: SND_PCM_STATE_RUNNING\n");
 563     }
 564     else if (state == SND_PCM_STATE_XRUN) {
 565         TRACE0("State: SND_PCM_STATE_XRUN\n");
 566     }
 567     else if (state == SND_PCM_STATE_DRAINING) {
 568         TRACE0("State: SND_PCM_STATE_DRAINING\n");
 569     }
 570     else if (state == SND_PCM_STATE_PAUSED) {
 571         TRACE0("State: SND_PCM_STATE_PAUSED\n");
 572     }
 573     else if (state == SND_PCM_STATE_SUSPENDED) {
 574         TRACE0("State: SND_PCM_STATE_SUSPENDED\n");
 575     }
 576 }
 577 #endif
 578 
 579 int DAUDIO_Start(void* id, int isSource) {
 580     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 581     int ret;
 582     snd_pcm_state_t state;
 583 
 584     TRACE0("> DAUDIO_Start\n");
 585     // set to blocking mode
 586     snd_pcm_nonblock(info->handle, 0);
 587     // set start mode so that it always starts as soon as data is there
 588     setStartThreshold(info, TRUE /* use threshold */);
 589     state = snd_pcm_state(info->handle);
 590     if (state == SND_PCM_STATE_PAUSED) {
 591         // in case it was stopped previously
 592         TRACE0("  Un-pausing...\n");
 593         ret = snd_pcm_pause(info->handle, FALSE);
 594         if (ret != 0) {
 595             ERROR2("  NOTE: error in snd_pcm_pause:%d: %s\n", ret, snd_strerror(ret));
 596         }
 597     }
 598     if (state == SND_PCM_STATE_SUSPENDED) {
 599         TRACE0("  Resuming...\n");
 600         ret = snd_pcm_resume(info->handle);
 601         if (ret < 0) {
 602             if ((ret != -EAGAIN) && (ret != -ENOSYS)) {
 603                 ERROR2("  ERROR: error in snd_pcm_resume:%d: %s\n", ret, snd_strerror(ret));
 604             }
 605         }
 606     }
 607     if (state == SND_PCM_STATE_SETUP) {
 608         TRACE0("need to call prepare again...\n");
 609         // prepare device
 610         ret = snd_pcm_prepare(info->handle);
 611         if (ret < 0) {
 612             ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret));
 613         }
 614     }
 615     // in case there is still data in the buffers
 616     ret = snd_pcm_start(info->handle);
 617     if (ret != 0) {
 618         if (ret != -EPIPE) {
 619             ERROR2("  NOTE: error in snd_pcm_start: %d: %s\n", ret, snd_strerror(ret));
 620         }
 621     }
 622     // set to non-blocking mode
 623     ret = snd_pcm_nonblock(info->handle, 1);
 624     if (ret != 0) {
 625         ERROR1("  ERROR in snd_pcm_nonblock: %s\n", snd_strerror(ret));
 626     }
 627     state = snd_pcm_state(info->handle);
 628 #ifdef USE_TRACE
 629     printState(state);
 630 #endif
 631     ret = (state == SND_PCM_STATE_PREPARED)
 632         || (state == SND_PCM_STATE_RUNNING)
 633         || (state == SND_PCM_STATE_XRUN)
 634         || (state == SND_PCM_STATE_SUSPENDED);
 635     TRACE1("< DAUDIO_Start %s\n", ret?"success":"error");
 636     return ret?TRUE:FALSE;
 637 }
 638 
 639 int DAUDIO_Stop(void* id, int isSource) {
 640     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 641     int ret;
 642 
 643     TRACE0("> DAUDIO_Stop\n");
 644     // set to blocking mode
 645     snd_pcm_nonblock(info->handle, 0);
 646     setStartThreshold(info, FALSE /* don't use threshold */); // device will not start after buffer xrun
 647     ret = snd_pcm_pause(info->handle, 1);
 648     // set to non-blocking mode
 649     snd_pcm_nonblock(info->handle, 1);
 650     if (ret != 0) {
 651         ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret));
 652         return FALSE;
 653     }
 654     TRACE0("< DAUDIO_Stop success\n");
 655     return TRUE;
 656 }
 657 
 658 void DAUDIO_Close(void* id, int isSource) {
 659     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 660 
 661     TRACE0("DAUDIO_Close\n");
 662     if (info != NULL) {
 663         if (info->handle != NULL) {
 664             snd_pcm_close(info->handle);
 665         }
 666         if (info->hwParams) {
 667             snd_pcm_hw_params_free(info->hwParams);
 668         }
 669         if (info->swParams) {
 670             snd_pcm_sw_params_free(info->swParams);
 671         }
 672 #ifdef GET_POSITION_METHOD2
 673         if (info->positionStatus) {
 674             snd_pcm_status_free(info->positionStatus);
 675         }
 676 #endif
 677         free(info);
 678     }
 679 }
 680 
 681 /*
 682  * Underrun and suspend recovery
 683  * returns
 684  * 0:  exit native and return 0
 685  * 1:  try again to write/read
 686  * -1: error - exit native with return value -1
 687  */
 688 int xrun_recovery(AlsaPcmInfo* info, int err) {
 689     int ret;
 690 
 691     if (err == -EPIPE) {    /* underrun / overflow */
 692         TRACE0("xrun_recovery: underrun/overflow.\n");
 693         ret = snd_pcm_prepare(info->handle);
 694         if (ret < 0) {
 695             ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
 696             return -1;
 697         }
 698         return 1;
 699     }
 700     else if (err == -ESTRPIPE) {
 701         TRACE0("xrun_recovery: suspended.\n");
 702         ret = snd_pcm_resume(info->handle);
 703         if (ret < 0) {
 704             if (ret == -EAGAIN) {
 705                 return 0; /* wait until the suspend flag is released */
 706             }
 707             return -1;
 708         }
 709         ret = snd_pcm_prepare(info->handle);
 710         if (ret < 0) {
 711             ERROR1("Can't recover from underrun/overflow, prepare failed: %s\n", snd_strerror(ret));
 712             return -1;
 713         }
 714         return 1;
 715     }
 716     else if (err == -EAGAIN) {
 717         TRACE0("xrun_recovery: EAGAIN try again flag.\n");
 718         return 0;
 719     }
 720     TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err));
 721     return -1;
 722 }
 723 
 724 // returns -1 on error
 725 int DAUDIO_Write(void* id, char* data, int byteSize) {
 726     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 727     int ret, count;
 728     snd_pcm_sframes_t frameSize, writtenFrames;
 729 
 730     TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
 731 
 732     /* sanity */
 733     if (byteSize <= 0 || info->frameSize <= 0) {
 734         ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n",
 735                (int) byteSize, (int) info->frameSize);
 736         TRACE0("< DAUDIO_Write returning -1\n");
 737         return -1;
 738     }
 739     count = 2; // maximum number of trials to recover from underrun
 740     //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
 741     frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
 742     do {
 743         writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize);
 744 
 745         if (writtenFrames < 0) {
 746             ret = xrun_recovery(info, (int) writtenFrames);
 747             if (ret <= 0) {
 748                 TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret);
 749                 return ret;
 750             }
 751             if (count-- <= 0) {
 752                 ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n");
 753                 return -1;
 754             }
 755         } else {
 756             break;
 757         }
 758     } while (TRUE);
 759     //ret =  snd_pcm_frames_to_bytes(info->handle, writtenFrames);
 760     ret =  (int) (writtenFrames * info->frameSize);
 761     TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
 762     return ret;
 763 }
 764 
 765 // returns -1 on error
 766 int DAUDIO_Read(void* id, char* data, int byteSize) {
 767     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 768     int ret, count;
 769     snd_pcm_sframes_t frameSize, readFrames;
 770 
 771     TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
 772     /*TRACE3("  info=%p, data=%p, byteSize=%d\n",
 773       (void*) info, (void*) data, (int) byteSize);
 774       TRACE2("  info->frameSize=%d, info->handle=%p\n",
 775       (int) info->frameSize, (void*) info->handle);
 776     */
 777     /* sanity */
 778     if (byteSize <= 0 || info->frameSize <= 0) {
 779         ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n",
 780                (int) byteSize, (int) info->frameSize);
 781         TRACE0("< DAUDIO_Read returning -1\n");
 782         return -1;
 783     }
 784     count = 2; // maximum number of trials to recover from error
 785     //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
 786     frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
 787     do {
 788         readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize);
 789         if (readFrames < 0) {
 790             ret = xrun_recovery(info, (int) readFrames);
 791             if (ret <= 0) {
 792                 TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret);
 793                 return ret;
 794             }
 795             if (count-- <= 0) {
 796                 ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n");
 797                 return -1;
 798             }
 799         } else {
 800             break;
 801         }
 802     } while (TRUE);
 803     //ret =  snd_pcm_frames_to_bytes(info->handle, readFrames);
 804     ret =  (int) (readFrames * info->frameSize);
 805     TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
 806     return ret;
 807 }
 808 
 809 
 810 int DAUDIO_GetBufferSize(void* id, int isSource) {
 811     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 812 
 813     return info->bufferSizeInBytes;
 814 }
 815 
 816 int DAUDIO_StillDraining(void* id, int isSource) {
 817     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 818     snd_pcm_state_t state;
 819 
 820     state = snd_pcm_state(info->handle);
 821     //printState(state);
 822     //TRACE1("Still draining: %s\n", (state != SND_PCM_STATE_XRUN)?"TRUE":"FALSE");
 823     return (state == SND_PCM_STATE_RUNNING)?TRUE:FALSE;
 824 }
 825 
 826 
 827 int DAUDIO_Flush(void* id, int isSource) {
 828     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
 829     int ret;
 830 
 831     TRACE0("DAUDIO_Flush\n");
 832     ret = snd_pcm_drop(info->handle);
 833     if (ret != 0) {
 834         ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret));
 835         return FALSE;
 836     }
 837     ret = DAUDIO_Start(id, isSource);
 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 (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 (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 Linux
 933     return FALSE;
 934 }
 935 
 936 void DAUDIO_Service(void* id, int isSource) {
 937     // never need servicing on Linux
 938 }
 939 
 940 
 941 #endif // USE_DAUDIO