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 
DAUDIO_GetDirectAudioDeviceCount()56 INT32 DAUDIO_GetDirectAudioDeviceCount() {
57     return (INT32) getAudioDeviceCount();
58 }
59 
60 
DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex,DirectAudioDeviceDescription * description)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
getBitIndex(int sampleSizeInBytes,int significantBits)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 
getSampleSizeInBytes(int bitIndex,int sampleSizeInBytes)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 
getSignificantBits(int bitIndex,int significantBits)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 
DAUDIO_GetFormats(INT32 mixerIndex,INT32 deviceID,int isSource,void * creator)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 
setStartThresholdNoCommit(AlsaPcmInfo * info,int useThreshold)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 
setStartThreshold(AlsaPcmInfo * info,int useThreshold)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
setHWParams(AlsaPcmInfo * info,float sampleRate,int channels,int bufferSizeInFrames,snd_pcm_format_t format)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
setSWParams(AlsaPcmInfo * info)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 
DAUDIO_Open(INT32 mixerIndex,INT32 deviceID,int isSource,int encoding,float sampleRate,int sampleSizeInBits,int frameSize,int channels,int isSigned,int isBigEndian,int bufferSizeInBytes)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
printState(snd_pcm_state_t state)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 
DAUDIO_Start(void * id,int isSource)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 
DAUDIO_Stop(void * id,int isSource)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 
DAUDIO_Close(void * id,int isSource)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  */
xrun_recovery(AlsaPcmInfo * info,int err)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
DAUDIO_Write(void * id,char * data,int byteSize)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
DAUDIO_Read(void * id,char * data,int byteSize)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 
DAUDIO_GetBufferSize(void * id,int isSource)800 int DAUDIO_GetBufferSize(void* id, int isSource) {
801     AlsaPcmInfo* info = (AlsaPcmInfo*) id;
802 
803     return info->bufferSizeInBytes;
804 }
805 
DAUDIO_StillDraining(void * id,int isSource)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 
DAUDIO_Flush(void * id,int isSource)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 
DAUDIO_GetAvailable(void * id,int isSource)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 
estimatePositionFromAvail(AlsaPcmInfo * info,int isSource,INT64 javaBytePos,int availInBytes)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 
DAUDIO_GetBytePosition(void * id,int isSource,INT64 javaBytePos)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 
DAUDIO_SetBytePosition(void * id,int isSource,INT64 javaBytePos)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 
DAUDIO_RequiresServicing(void * id,int isSource)931 int DAUDIO_RequiresServicing(void* id, int isSource) {
932     // never need servicing on Linux
933     return FALSE;
934 }
935 
DAUDIO_Service(void * id,int isSource)936 void DAUDIO_Service(void* id, int isSource) {
937     // never need servicing on Linux
938 }
939 
940 
941 #endif // USE_DAUDIO
942