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
56INT32 DAUDIO_GetDirectAudioDeviceCount() {
57    return (INT32) getAudioDeviceCount();
58}
59
60
61INT32 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
86int 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
98int 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
109int 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
120void 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 ******************** */
250typedef 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
267int 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
286int 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
304int 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
386int 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
415static snd_output_t* ALSA_OUTPUT = NULL;
416
417void* 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
521void 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
549int 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
617int 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
637void 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 */
667int 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
703int 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
751int 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
800int DAUDIO_GetBufferSize(void* id, int isSource) {
801    AlsaPcmInfo* info = (AlsaPcmInfo*) id;
802
803    return info->bufferSizeInBytes;
804}
805
806int 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
817int 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
841int 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
865INT64 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
882INT64 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
925void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
926    /* save to ignore, since GetBytePosition
927     * takes the javaBytePos param into account
928     */
929}
930
931int DAUDIO_RequiresServicing(void* id, int isSource) {
932    // never need servicing on Linux
933    return FALSE;
934}
935
936void DAUDIO_Service(void* id, int isSource) {
937    // never need servicing on Linux
938}
939
940
941#endif // USE_DAUDIO
942