src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c
changeset 49289 148e29df1644
parent 47216 71c04702a3d5
equal deleted inserted replaced
49288:6e2d71029781 49289:148e29df1644
       
     1 /*
       
     2  * Copyright (c) 2002, 2011, 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     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 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