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