1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Initial Developer of the Original Code is
15 : * CSIRO
16 : * Portions created by the Initial Developer are Copyright (C) 2007
17 : * the Initial Developer. All Rights Reserved.
18 : *
19 : * Contributor(s): Michael Martin
20 : * Chris Double (chris.double@double.co.nz)
21 : *
22 : * Alternatively, the contents of this file may be used under the terms of
23 : * either the GNU General Public License Version 2 or later (the "GPL"), or
24 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25 : * in which case the provisions of the GPL or the LGPL are applicable instead
26 : * of those above. If you wish to allow use of your version of this file only
27 : * under the terms of either the GPL or the LGPL, and not to allow others to
28 : * use your version of this file under the terms of the MPL, indicate your
29 : * decision by deleting the provisions above and replace them with the notice
30 : * and other provisions required by the GPL or the LGPL. If you do not delete
31 : * the provisions above, a recipient may use your version of this file under
32 : * the terms of any one of the MPL, the GPL or the LGPL.
33 : *
34 : * ***** END LICENSE BLOCK ***** *
35 : */
36 : #include <pthread.h>
37 : #include <stdlib.h>
38 : #include <alsa/asoundlib.h>
39 : #include "sydney_audio.h"
40 :
41 : /* ALSA implementation based heavily on sydney_audio_mac.c */
42 :
43 : pthread_mutex_t sa_alsa_mutex = PTHREAD_MUTEX_INITIALIZER;
44 :
45 : struct sa_stream {
46 : snd_pcm_t* output_unit;
47 : int64_t bytes_written;
48 : int64_t last_position;
49 :
50 : /* audio format info */
51 : unsigned int rate;
52 : unsigned int n_channels;
53 :
54 : /* work around bug 573924 */
55 : int pulseaudio;
56 : int resumed;
57 : };
58 :
59 : /*
60 : * -----------------------------------------------------------------------------
61 : * Error Handler to prevent output to stderr
62 : * ----------------------------------------------------------------------------
63 : */
64 : static void
65 0 : quiet_error_handler(const char* file,
66 : int line,
67 : const char* function,
68 : int err,
69 : const char* format,
70 : ...)
71 : {
72 0 : }
73 :
74 : /*
75 : * -----------------------------------------------------------------------------
76 : * Startup and shutdown functions
77 : * -----------------------------------------------------------------------------
78 : */
79 :
80 : int
81 0 : sa_stream_create_pcm(
82 : sa_stream_t ** _s,
83 : const char * client_name,
84 : sa_mode_t mode,
85 : sa_pcm_format_t format,
86 : unsigned int rate,
87 : unsigned int n_channels
88 : ) {
89 0 : sa_stream_t * s = 0;
90 :
91 : /*
92 : * Make sure we return a NULL stream pointer on failure.
93 : */
94 0 : if (_s == NULL) {
95 0 : return SA_ERROR_INVALID;
96 : }
97 0 : *_s = NULL;
98 :
99 0 : if (mode != SA_MODE_WRONLY) {
100 0 : return SA_ERROR_NOT_SUPPORTED;
101 : }
102 0 : if (format != SA_PCM_FORMAT_S16_NE) {
103 0 : return SA_ERROR_NOT_SUPPORTED;
104 : }
105 :
106 : /*
107 : * Allocate the instance and required resources.
108 : */
109 0 : if ((s = malloc(sizeof(sa_stream_t))) == NULL) {
110 0 : return SA_ERROR_OOM;
111 : }
112 :
113 0 : s->output_unit = NULL;
114 0 : s->bytes_written = 0;
115 0 : s->last_position = 0;
116 0 : s->rate = rate;
117 0 : s->n_channels = n_channels;
118 0 : s->pulseaudio = 0;
119 0 : s->resumed = 0;
120 :
121 0 : *_s = s;
122 0 : return SA_SUCCESS;
123 : }
124 :
125 :
126 : int
127 0 : sa_stream_open(sa_stream_t *s) {
128 : snd_output_t* out;
129 : char* buf;
130 : size_t bufsz;
131 : snd_pcm_hw_params_t* hwparams;
132 : snd_pcm_sw_params_t* swparams;
133 : int dir;
134 : snd_pcm_uframes_t period;
135 :
136 0 : if (s == NULL) {
137 0 : return SA_ERROR_NO_INIT;
138 : }
139 0 : if (s->output_unit != NULL) {
140 0 : return SA_ERROR_INVALID;
141 : }
142 :
143 0 : pthread_mutex_lock(&sa_alsa_mutex);
144 :
145 : /* Turn off debug output to stderr */
146 0 : snd_lib_error_set_handler(quiet_error_handler);
147 :
148 0 : if (snd_pcm_open(&s->output_unit,
149 : "default",
150 : SND_PCM_STREAM_PLAYBACK,
151 : 0) < 0) {
152 0 : pthread_mutex_unlock(&sa_alsa_mutex);
153 0 : return SA_ERROR_NO_DEVICE;
154 : }
155 :
156 0 : if (snd_pcm_set_params(s->output_unit,
157 : #ifdef SA_LITTLE_ENDIAN
158 : SND_PCM_FORMAT_S16_LE,
159 : #else
160 : SND_PCM_FORMAT_S16_BE,
161 : #endif
162 : SND_PCM_ACCESS_RW_INTERLEAVED,
163 : s->n_channels,
164 : s->rate,
165 : 1,
166 : 500000) < 0) {
167 0 : snd_pcm_close(s->output_unit);
168 0 : s->output_unit = NULL;
169 0 : pthread_mutex_unlock(&sa_alsa_mutex);
170 0 : return SA_ERROR_NOT_SUPPORTED;
171 : }
172 :
173 : /* ugly alsa-pulse plugin detection */
174 0 : snd_output_buffer_open(&out);
175 0 : snd_pcm_dump(s->output_unit, out);
176 0 : bufsz = snd_output_buffer_string(out, &buf);
177 0 : if (strncmp(buf, "ALSA <-> PulseAudio PCM I/O Plugin", bufsz) > 0 ) {
178 0 : s->pulseaudio = 1;
179 : }
180 0 : snd_output_close(out);
181 :
182 0 : snd_pcm_hw_params_alloca(&hwparams);
183 0 : snd_pcm_hw_params_current(s->output_unit, hwparams);
184 0 : snd_pcm_hw_params_get_period_size(hwparams, &period, &dir);
185 :
186 0 : pthread_mutex_unlock(&sa_alsa_mutex);
187 :
188 0 : return SA_SUCCESS;
189 : }
190 :
191 :
192 : int
193 0 : sa_stream_get_min_write(sa_stream_t *s, size_t *size) {
194 : int r;
195 : snd_pcm_uframes_t threshold;
196 : snd_pcm_sw_params_t* swparams;
197 0 : if (s == NULL || s->output_unit == NULL) {
198 0 : return SA_ERROR_NO_INIT;
199 : }
200 0 : snd_pcm_sw_params_alloca(&swparams);
201 0 : snd_pcm_sw_params_current(s->output_unit, swparams);
202 0 : r = snd_pcm_sw_params_get_start_threshold(swparams, &threshold);
203 0 : if (r < 0) {
204 0 : return SA_ERROR_NO_INIT;
205 : }
206 0 : *size = snd_pcm_frames_to_bytes(s->output_unit, threshold);
207 :
208 0 : return SA_SUCCESS;
209 : }
210 :
211 :
212 : int
213 0 : sa_stream_destroy(sa_stream_t *s) {
214 0 : int result = SA_SUCCESS;
215 :
216 0 : if (s == NULL) {
217 0 : return result;
218 : }
219 : /*
220 : * Shut down the audio output device.
221 : */
222 0 : if (s->output_unit != NULL) {
223 0 : pthread_mutex_lock(&sa_alsa_mutex);
224 0 : if (snd_pcm_close(s->output_unit) < 0) {
225 0 : result = SA_ERROR_SYSTEM;
226 : }
227 0 : pthread_mutex_unlock(&sa_alsa_mutex);
228 : }
229 0 : free(s);
230 0 : return result;
231 : }
232 :
233 :
234 :
235 : /*
236 : * -----------------------------------------------------------------------------
237 : * Data read and write functions
238 : * -----------------------------------------------------------------------------
239 : */
240 :
241 : int
242 0 : sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
243 : snd_pcm_sframes_t frames, nframes, avail;
244 :
245 0 : if (s == NULL || s->output_unit == NULL) {
246 0 : return SA_ERROR_NO_INIT;
247 : }
248 0 : if (nbytes == 0) {
249 0 : return SA_SUCCESS;
250 : }
251 :
252 0 : nframes = snd_pcm_bytes_to_frames(s->output_unit, nbytes);
253 0 : while(nframes>0) {
254 0 : if (s->resumed) {
255 0 : avail = snd_pcm_avail_update(s->output_unit);
256 0 : frames = snd_pcm_writei(s->output_unit, data, nframes > avail ? avail : nframes);
257 0 : avail = snd_pcm_avail_update(s->output_unit);
258 0 : s->resumed = avail != 0;
259 : } else {
260 0 : avail = snd_pcm_avail_update(s->output_unit);
261 0 : avail = avail < 64 ? 64 : avail;
262 0 : frames = snd_pcm_writei(s->output_unit, data, nframes > avail ? avail : nframes);
263 : }
264 0 : if (frames < 0) {
265 0 : int r = snd_pcm_recover(s->output_unit, frames, 1);
266 0 : if (r < 0) {
267 0 : return SA_ERROR_SYSTEM;
268 : }
269 : } else {
270 0 : size_t bytes = snd_pcm_frames_to_bytes(s->output_unit, frames);
271 0 : nframes -= frames;
272 0 : data = ((unsigned char *)data) + bytes;
273 0 : s->bytes_written += bytes;
274 : }
275 : }
276 :
277 0 : return SA_SUCCESS;
278 : }
279 :
280 : /*
281 : * -----------------------------------------------------------------------------
282 : * General query and support functions
283 : * -----------------------------------------------------------------------------
284 : */
285 :
286 : int
287 0 : sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
288 : snd_pcm_sframes_t avail;
289 :
290 0 : if (s == NULL || s->output_unit == NULL) {
291 0 : return SA_ERROR_NO_INIT;
292 : }
293 :
294 : do {
295 0 : avail = snd_pcm_avail_update(s->output_unit);
296 0 : if (avail < 0) {
297 0 : int r = snd_pcm_recover(s->output_unit, avail, 1);
298 0 : if (r < 0) {
299 0 : return SA_ERROR_SYSTEM;
300 : }
301 0 : continue;
302 : }
303 : break;
304 0 : } while (1);
305 :
306 0 : *size = snd_pcm_frames_to_bytes(s->output_unit, avail);
307 :
308 0 : return SA_SUCCESS;
309 : }
310 :
311 : int
312 0 : sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
313 : snd_pcm_sframes_t delay;
314 :
315 0 : if (s == NULL || s->output_unit == NULL) {
316 0 : return SA_ERROR_NO_INIT;
317 : }
318 :
319 0 : if (position != SA_POSITION_WRITE_SOFTWARE) {
320 0 : return SA_ERROR_NOT_SUPPORTED;
321 : }
322 :
323 0 : if (snd_pcm_state(s->output_unit) != SND_PCM_STATE_RUNNING) {
324 0 : *pos = s->last_position;
325 0 : return SA_SUCCESS;
326 : }
327 :
328 0 : if (snd_pcm_delay(s->output_unit, &delay) != 0) {
329 0 : return SA_ERROR_SYSTEM;
330 : }
331 :
332 : /* delay means audio is 'x' frames behind what we've written. We need to
333 : subtract the delay from the data written to return the actual bytes played.
334 :
335 : due to buffering, the delay can be larger than the amount we've
336 : written--in this case, report position as zero. */
337 0 : *pos = s->bytes_written;
338 0 : if (*pos >= snd_pcm_frames_to_bytes(s->output_unit, delay)) {
339 0 : *pos -= snd_pcm_frames_to_bytes(s->output_unit, delay);
340 : } else {
341 0 : *pos = 0;
342 : }
343 0 : s->last_position = *pos;
344 :
345 0 : return SA_SUCCESS;
346 : }
347 :
348 :
349 : int
350 0 : sa_stream_pause(sa_stream_t *s) {
351 :
352 0 : if (s == NULL || s->output_unit == NULL) {
353 0 : return SA_ERROR_NO_INIT;
354 : }
355 :
356 0 : if (snd_pcm_pause(s->output_unit, 1) != 0)
357 0 : return SA_ERROR_NOT_SUPPORTED;
358 :
359 0 : return SA_SUCCESS;
360 : }
361 :
362 :
363 : int
364 0 : sa_stream_resume(sa_stream_t *s) {
365 :
366 0 : if (s == NULL || s->output_unit == NULL) {
367 0 : return SA_ERROR_NO_INIT;
368 : }
369 :
370 0 : if (s->pulseaudio) {
371 0 : s->resumed = 1;
372 : }
373 :
374 0 : if (snd_pcm_pause(s->output_unit, 0) != 0)
375 0 : return SA_ERROR_NOT_SUPPORTED;
376 0 : return SA_SUCCESS;
377 : }
378 :
379 :
380 : int
381 0 : sa_stream_drain(sa_stream_t *s)
382 : {
383 0 : if (s == NULL || s->output_unit == NULL) {
384 0 : return SA_ERROR_NO_INIT;
385 : }
386 :
387 0 : if (snd_pcm_state(s->output_unit) == SND_PCM_STATE_PREPARED) {
388 0 : size_t min_samples = 0;
389 0 : size_t min_bytes = 0;
390 : void *buf;
391 :
392 0 : if (sa_stream_get_min_write(s, &min_samples) < 0)
393 0 : return SA_ERROR_SYSTEM;
394 0 : min_bytes = snd_pcm_frames_to_bytes(s->output_unit, min_samples);
395 :
396 0 : buf = malloc(min_bytes);
397 0 : if (!buf)
398 0 : return SA_ERROR_SYSTEM;
399 0 : memset(buf, 0, min_bytes);
400 0 : sa_stream_write(s, buf, min_bytes);
401 0 : free(buf);
402 : }
403 :
404 0 : if (snd_pcm_state(s->output_unit) != SND_PCM_STATE_RUNNING) {
405 0 : return SA_ERROR_INVALID;
406 : }
407 0 : snd_pcm_drain(s->output_unit);
408 0 : return SA_SUCCESS;
409 : }
410 :
411 :
412 :
413 : /*
414 : * -----------------------------------------------------------------------------
415 : * Extension functions
416 : * -----------------------------------------------------------------------------
417 : */
418 :
419 : int
420 0 : sa_stream_set_volume_abs(sa_stream_t *s, float vol) {
421 0 : snd_mixer_t* mixer = 0;
422 0 : snd_mixer_elem_t* elem = 0;
423 0 : if (s == NULL || s->output_unit == NULL) {
424 0 : return SA_ERROR_NO_INIT;
425 : }
426 :
427 0 : if (snd_mixer_open(&mixer, 0) < 0) {
428 0 : return SA_ERROR_SYSTEM;
429 : }
430 :
431 0 : if (snd_mixer_attach(mixer, "default") < 0) {
432 0 : snd_mixer_close(mixer);
433 0 : return SA_ERROR_SYSTEM;
434 : }
435 :
436 0 : if (snd_mixer_selem_register(mixer, NULL, NULL) < 0) {
437 0 : snd_mixer_close(mixer);
438 0 : return SA_ERROR_SYSTEM;
439 : }
440 :
441 0 : if (snd_mixer_load(mixer) < 0) {
442 0 : snd_mixer_close(mixer);
443 0 : return SA_ERROR_SYSTEM;
444 : }
445 :
446 : #if 0
447 : snd_mixer_elem_t* elem = 0;
448 : for (elem = snd_mixer_first_elem(mixer); elem != NULL; elem = snd_mixer_elem_next(elem)) {
449 : if (snd_mixer_selem_has_playback_volume(elem)) {
450 : printf("Playback %s\n", snd_mixer_selem_get_name(elem));
451 : }
452 : else {
453 : printf("No Playback: %s\n", snd_mixer_selem_get_name(elem));
454 : }
455 : }
456 : #endif
457 0 : elem = snd_mixer_first_elem(mixer);
458 0 : if (elem && snd_mixer_selem_has_playback_volume(elem)) {
459 0 : long min = 0;
460 0 : long max = 0;
461 0 : if (snd_mixer_selem_get_playback_volume_range(elem, &min, &max) >= 0) {
462 0 : snd_mixer_selem_set_playback_volume_all(elem, (max-min)*vol + min);
463 : }
464 : }
465 0 : snd_mixer_close(mixer);
466 :
467 0 : return SA_SUCCESS;
468 : }
469 :
470 :
471 : int
472 0 : sa_stream_get_volume_abs(sa_stream_t *s, float *vol) {
473 0 : snd_mixer_t* mixer = 0;
474 0 : snd_mixer_elem_t* elem = 0;
475 0 : long value = 0;
476 :
477 0 : if (s == NULL || s->output_unit == NULL) {
478 0 : return SA_ERROR_NO_INIT;
479 : }
480 :
481 0 : if (snd_mixer_open(&mixer, 0) < 0) {
482 0 : return SA_ERROR_SYSTEM;
483 : }
484 :
485 0 : if (snd_mixer_attach(mixer, "default") < 0) {
486 0 : snd_mixer_close(mixer);
487 0 : return SA_ERROR_SYSTEM;
488 : }
489 :
490 0 : if (snd_mixer_selem_register(mixer, NULL, NULL) < 0) {
491 0 : snd_mixer_close(mixer);
492 0 : return SA_ERROR_SYSTEM;
493 : }
494 :
495 0 : if (snd_mixer_load(mixer) < 0) {
496 0 : snd_mixer_close(mixer);
497 0 : return SA_ERROR_SYSTEM;
498 : }
499 :
500 0 : elem = snd_mixer_first_elem(mixer);
501 0 : if (elem && snd_mixer_selem_get_playback_volume(elem, 0, &value) >= 0) {
502 0 : long min = 0;
503 0 : long max = 0;
504 0 : if (snd_mixer_selem_get_playback_volume_range(elem, &min, &max) >= 0) {
505 0 : *vol = (float)(value-min)/(float)(max-min);
506 : }
507 : }
508 0 : snd_mixer_close(mixer);
509 :
510 0 : return SA_SUCCESS;
511 : }
512 :
513 :
514 :
515 : /*
516 : * -----------------------------------------------------------------------------
517 : * Unsupported functions
518 : * -----------------------------------------------------------------------------
519 : */
520 : #define UNSUPPORTED(func) func { return SA_ERROR_NOT_SUPPORTED; }
521 :
522 0 : UNSUPPORTED(int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec))
523 0 : UNSUPPORTED(int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size))
524 0 : UNSUPPORTED(int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size))
525 0 : UNSUPPORTED(int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size))
526 0 : UNSUPPORTED(int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size))
527 0 : UNSUPPORTED(int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned int n))
528 0 : UNSUPPORTED(int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode))
529 0 : UNSUPPORTED(int sa_stream_set_non_interleaved(sa_stream_t *s, int enable))
530 0 : UNSUPPORTED(int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable))
531 0 : UNSUPPORTED(int sa_stream_set_driver(sa_stream_t *s, const char *driver))
532 0 : UNSUPPORTED(int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback))
533 0 : UNSUPPORTED(int sa_stream_stop_thread(sa_stream_t *s))
534 0 : UNSUPPORTED(int sa_stream_change_device(sa_stream_t *s, const char *device_name))
535 0 : UNSUPPORTED(int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
536 0 : UNSUPPORTED(int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
537 0 : UNSUPPORTED(int sa_stream_change_rate(sa_stream_t *s, unsigned int rate))
538 0 : UNSUPPORTED(int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size))
539 0 : UNSUPPORTED(int sa_stream_change_user_data(sa_stream_t *s, const void *value))
540 0 : UNSUPPORTED(int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction))
541 0 : UNSUPPORTED(int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction))
542 0 : UNSUPPORTED(int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction))
543 0 : UNSUPPORTED(int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction))
544 0 : UNSUPPORTED(int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode))
545 0 : UNSUPPORTED(int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size))
546 0 : UNSUPPORTED(int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format))
547 0 : UNSUPPORTED(int sa_stream_get_rate(sa_stream_t *s, unsigned int *rate))
548 0 : UNSUPPORTED(int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels))
549 0 : UNSUPPORTED(int sa_stream_get_user_data(sa_stream_t *s, void **value))
550 0 : UNSUPPORTED(int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size))
551 0 : UNSUPPORTED(int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size))
552 0 : UNSUPPORTED(int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size))
553 0 : UNSUPPORTED(int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size))
554 0 : UNSUPPORTED(int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned int *n))
555 0 : UNSUPPORTED(int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode))
556 0 : UNSUPPORTED(int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled))
557 0 : UNSUPPORTED(int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled))
558 0 : UNSUPPORTED(int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size))
559 0 : UNSUPPORTED(int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size))
560 0 : UNSUPPORTED(int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
561 0 : UNSUPPORTED(int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
562 0 : UNSUPPORTED(int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size))
563 0 : UNSUPPORTED(int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction))
564 0 : UNSUPPORTED(int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction))
565 0 : UNSUPPORTED(int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction))
566 0 : UNSUPPORTED(int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction))
567 0 : UNSUPPORTED(int sa_stream_get_state(sa_stream_t *s, sa_state_t *state))
568 0 : UNSUPPORTED(int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error))
569 0 : UNSUPPORTED(int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify))
570 0 : UNSUPPORTED(int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes))
571 0 : UNSUPPORTED(int sa_stream_read_ni(sa_stream_t *s, unsigned int channel, void *data, size_t nbytes))
572 0 : UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes))
573 0 : UNSUPPORTED(int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
574 0 : UNSUPPORTED(int sa_stream_pwrite_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
575 0 : UNSUPPORTED(int sa_stream_get_read_size(sa_stream_t *s, size_t *size))
576 :
577 0 : const char *sa_strerror(int code) { return NULL; }
578 :
|