/media/libsydneyaudio/src/sydney_audio_android.c

http://github.com/zpao/v8monkey · C · 595 lines · 396 code · 104 blank · 95 comment · 72 complexity · 7cc7f4bb642bb5b55f1a8276d17c9bba MD5 · raw file

  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. * Michael Wu <mwu@mozilla.com>
  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 <stdlib.h>
  37. #include <time.h>
  38. #include <jni.h>
  39. #include "sydney_audio.h"
  40. #include "android/log.h"
  41. #ifndef ALOG
  42. #if defined(DEBUG) || defined(FORCE_ALOG)
  43. #define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko - SYDNEY_AUDIO" , ## args)
  44. #else
  45. #define ALOG(args...)
  46. #endif
  47. #endif
  48. /* Android implementation based on sydney_audio_mac.c */
  49. #define NANOSECONDS_PER_SECOND 1000000000
  50. #define NANOSECONDS_IN_MILLISECOND 1000000
  51. #define MILLISECONDS_PER_SECOND 1000
  52. /* android.media.AudioTrack */
  53. struct AudioTrack {
  54. jclass class;
  55. jmethodID constructor;
  56. jmethodID flush;
  57. jmethodID getminbufsz;
  58. jmethodID pause;
  59. jmethodID play;
  60. jmethodID release;
  61. jmethodID setvol;
  62. jmethodID stop;
  63. jmethodID write;
  64. jmethodID getpos;
  65. };
  66. enum AudioTrackMode {
  67. MODE_STATIC = 0,
  68. MODE_STREAM = 1
  69. };
  70. /* android.media.AudioManager */
  71. enum AudioManagerStream {
  72. STREAM_VOICE_CALL = 0,
  73. STREAM_SYSTEM = 1,
  74. STREAM_RING = 2,
  75. STREAM_MUSIC = 3,
  76. STREAM_ALARM = 4,
  77. STREAM_NOTIFICATION = 5,
  78. STREAM_DTMF = 8
  79. };
  80. /* android.media.AudioFormat */
  81. enum AudioFormatChannel {
  82. CHANNEL_OUT_MONO = 4,
  83. CHANNEL_OUT_STEREO = 12
  84. };
  85. enum AudioFormatEncoding {
  86. ENCODING_PCM_16BIT = 2,
  87. ENCODING_PCM_8BIT = 3
  88. };
  89. struct sa_stream {
  90. jobject output_unit;
  91. jbyteArray output_buf;
  92. unsigned int output_buf_size;
  93. unsigned int rate;
  94. unsigned int channels;
  95. unsigned int isPaused;
  96. int64_t lastStartTime;
  97. int64_t timePlaying;
  98. int64_t amountWritten;
  99. unsigned int bufferSize;
  100. jclass at_class;
  101. };
  102. static struct AudioTrack at;
  103. extern JNIEnv * GetJNIForThread();
  104. static jclass
  105. init_jni_bindings(JNIEnv *jenv) {
  106. jclass class = (*jenv)->FindClass(jenv, "android/media/AudioTrack");
  107. if (!class) {
  108. return NULL;
  109. }
  110. at.constructor = (*jenv)->GetMethodID(jenv, class, "<init>", "(IIIIII)V");
  111. at.flush = (*jenv)->GetMethodID(jenv, class, "flush", "()V");
  112. at.getminbufsz = (*jenv)->GetStaticMethodID(jenv, class, "getMinBufferSize", "(III)I");
  113. at.pause = (*jenv)->GetMethodID(jenv, class, "pause", "()V");
  114. at.play = (*jenv)->GetMethodID(jenv, class, "play", "()V");
  115. at.release = (*jenv)->GetMethodID(jenv, class, "release", "()V");
  116. at.setvol = (*jenv)->GetMethodID(jenv, class, "setStereoVolume", "(FF)I");
  117. at.stop = (*jenv)->GetMethodID(jenv, class, "stop", "()V");
  118. at.write = (*jenv)->GetMethodID(jenv, class, "write", "([BII)I");
  119. at.getpos = (*jenv)->GetMethodID(jenv, class, "getPlaybackHeadPosition", "()I");
  120. return (*jenv)->NewGlobalRef(jenv, class);
  121. }
  122. /*
  123. * -----------------------------------------------------------------------------
  124. * Startup and shutdown functions
  125. * -----------------------------------------------------------------------------
  126. */
  127. int
  128. sa_stream_create_pcm(
  129. sa_stream_t ** _s,
  130. const char * client_name,
  131. sa_mode_t mode,
  132. sa_pcm_format_t format,
  133. unsigned int rate,
  134. unsigned int channels
  135. ) {
  136. /*
  137. * Make sure we return a NULL stream pointer on failure.
  138. */
  139. if (_s == NULL) {
  140. return SA_ERROR_INVALID;
  141. }
  142. *_s = NULL;
  143. if (mode != SA_MODE_WRONLY) {
  144. return SA_ERROR_NOT_SUPPORTED;
  145. }
  146. if (format != SA_PCM_FORMAT_S16_NE) {
  147. return SA_ERROR_NOT_SUPPORTED;
  148. }
  149. if (channels != 1 && channels != 2) {
  150. return SA_ERROR_NOT_SUPPORTED;
  151. }
  152. /*
  153. * Allocate the instance and required resources.
  154. */
  155. sa_stream_t *s;
  156. if ((s = malloc(sizeof(sa_stream_t))) == NULL) {
  157. return SA_ERROR_OOM;
  158. }
  159. s->output_unit = NULL;
  160. s->output_buf = NULL;
  161. s->output_buf_size = 0;
  162. s->rate = rate;
  163. s->channels = channels;
  164. s->isPaused = 0;
  165. s->lastStartTime = 0;
  166. s->timePlaying = 0;
  167. s->amountWritten = 0;
  168. s->bufferSize = 0;
  169. *_s = s;
  170. return SA_SUCCESS;
  171. }
  172. int
  173. sa_stream_open(sa_stream_t *s) {
  174. if (s == NULL) {
  175. return SA_ERROR_NO_INIT;
  176. }
  177. if (s->output_unit != NULL) {
  178. return SA_ERROR_INVALID;
  179. }
  180. JNIEnv *jenv = GetJNIForThread();
  181. if (!jenv) {
  182. return SA_ERROR_NO_DEVICE;
  183. }
  184. if ((*jenv)->PushLocalFrame(jenv, 4)) {
  185. return SA_ERROR_OOM;
  186. }
  187. s->at_class = init_jni_bindings(jenv);
  188. if (!s->at_class) {
  189. return SA_ERROR_NO_DEVICE;
  190. }
  191. int32_t chanConfig = s->channels == 1 ?
  192. CHANNEL_OUT_MONO : CHANNEL_OUT_STEREO;
  193. jint minsz = (*jenv)->CallStaticIntMethod(jenv, s->at_class, at.getminbufsz,
  194. s->rate, chanConfig, ENCODING_PCM_16BIT);
  195. if (minsz <= 0) {
  196. (*jenv)->PopLocalFrame(jenv, NULL);
  197. return SA_ERROR_INVALID;
  198. }
  199. s->bufferSize = s->rate * s->channels * sizeof(int16_t);
  200. if (s->bufferSize < minsz) {
  201. s->bufferSize = minsz;
  202. }
  203. jobject obj =
  204. (*jenv)->NewObject(jenv, s->at_class, at.constructor,
  205. STREAM_MUSIC,
  206. s->rate,
  207. chanConfig,
  208. ENCODING_PCM_16BIT,
  209. s->bufferSize,
  210. MODE_STREAM);
  211. jthrowable exception = (*jenv)->ExceptionOccurred(jenv);
  212. if (exception) {
  213. (*jenv)->ExceptionDescribe(jenv);
  214. (*jenv)->ExceptionClear(jenv);
  215. (*jenv)->PopLocalFrame(jenv, NULL);
  216. return SA_ERROR_INVALID;
  217. }
  218. if (!obj) {
  219. (*jenv)->PopLocalFrame(jenv, NULL);
  220. return SA_ERROR_OOM;
  221. }
  222. s->output_unit = (*jenv)->NewGlobalRef(jenv, obj);
  223. /* arbitrary buffer size. using a preallocated buffer avoids churning
  224. the GC every audio write. */
  225. s->output_buf_size = 4096 * s->channels * sizeof(int16_t);
  226. jbyteArray buf = (*jenv)->NewByteArray(jenv, s->output_buf_size);
  227. if (!buf) {
  228. (*jenv)->ExceptionClear(jenv);
  229. (*jenv)->DeleteGlobalRef(jenv, s->output_unit);
  230. (*jenv)->PopLocalFrame(jenv, NULL);
  231. return SA_ERROR_OOM;
  232. }
  233. s->output_buf = (*jenv)->NewGlobalRef(jenv, buf);
  234. (*jenv)->PopLocalFrame(jenv, NULL);
  235. ALOG("%p - New stream %u %u bsz=%u min=%u obsz=%u", s, s->rate, s->channels,
  236. s->bufferSize, minsz, s->output_buf_size);
  237. return SA_SUCCESS;
  238. }
  239. int
  240. sa_stream_destroy(sa_stream_t *s) {
  241. if (s == NULL) {
  242. return SA_ERROR_NO_INIT;
  243. }
  244. JNIEnv *jenv = GetJNIForThread();
  245. if (!jenv) {
  246. return SA_SUCCESS;
  247. }
  248. if (s->output_buf) {
  249. (*jenv)->DeleteGlobalRef(jenv, s->output_buf);
  250. }
  251. if (s->output_unit) {
  252. (*jenv)->CallVoidMethod(jenv, s->output_unit, at.stop);
  253. (*jenv)->CallVoidMethod(jenv, s->output_unit, at.flush);
  254. (*jenv)->CallVoidMethod(jenv, s->output_unit, at.release);
  255. (*jenv)->DeleteGlobalRef(jenv, s->output_unit);
  256. }
  257. if (s->at_class) {
  258. (*jenv)->DeleteGlobalRef(jenv, s->at_class);
  259. }
  260. free(s);
  261. ALOG("%p - Stream destroyed", s);
  262. return SA_SUCCESS;
  263. }
  264. /*
  265. * -----------------------------------------------------------------------------
  266. * Data read and write functions
  267. * -----------------------------------------------------------------------------
  268. */
  269. int
  270. sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
  271. if (s == NULL || s->output_unit == NULL) {
  272. return SA_ERROR_NO_INIT;
  273. }
  274. if (nbytes == 0) {
  275. return SA_SUCCESS;
  276. }
  277. JNIEnv *jenv = GetJNIForThread();
  278. if ((*jenv)->PushLocalFrame(jenv, 2)) {
  279. return SA_ERROR_OOM;
  280. }
  281. unsigned char *p = data;
  282. jint r = 0;
  283. size_t wrote = 0;
  284. do {
  285. size_t towrite = nbytes - wrote;
  286. if (towrite > s->output_buf_size) {
  287. towrite = s->output_buf_size;
  288. }
  289. (*jenv)->SetByteArrayRegion(jenv, s->output_buf, 0, towrite, p);
  290. r = (*jenv)->CallIntMethod(jenv,
  291. s->output_unit,
  292. at.write,
  293. s->output_buf,
  294. 0,
  295. towrite);
  296. if (r < 0) {
  297. ALOG("%p - Write failed %d", s, r);
  298. break;
  299. }
  300. /* AudioTrack::write is blocking when the AudioTrack is playing. When
  301. it's not playing, it's a non-blocking call that will return a short
  302. write when the buffer is full. Use a short write to indicate a good
  303. time to start the AudioTrack playing. */
  304. if (r != towrite) {
  305. ALOG("%p - Buffer full, starting playback", s);
  306. sa_stream_resume(s);
  307. }
  308. p += r;
  309. wrote += r;
  310. } while (wrote < nbytes);
  311. ALOG("%p - Wrote %u", s, nbytes);
  312. s->amountWritten += nbytes;
  313. (*jenv)->PopLocalFrame(jenv, NULL);
  314. return r < 0 ? SA_ERROR_INVALID : SA_SUCCESS;
  315. }
  316. /*
  317. * -----------------------------------------------------------------------------
  318. * General query and support functions
  319. * -----------------------------------------------------------------------------
  320. */
  321. int
  322. sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
  323. if (s == NULL || s->output_unit == NULL) {
  324. return SA_ERROR_NO_INIT;
  325. }
  326. /* No android API for this, so estimate based on how much we have played and
  327. * how much we have written. */
  328. *size = s->bufferSize - ((s->timePlaying * s->channels * s->rate * sizeof(int16_t) /
  329. MILLISECONDS_PER_SECOND) - s->amountWritten);
  330. /* Available buffer space can't exceed bufferSize. */
  331. if (*size > s->bufferSize) {
  332. *size = s->bufferSize;
  333. }
  334. ALOG("%p - Write Size tp=%lld aw=%u sz=%zu", s, s->timePlaying, s->amountWritten, *size);
  335. return SA_SUCCESS;
  336. }
  337. int
  338. sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
  339. if (s == NULL || s->output_unit == NULL) {
  340. return SA_ERROR_NO_INIT;
  341. }
  342. ALOG("%p - get position", s);
  343. JNIEnv *jenv = GetJNIForThread();
  344. *pos = (*jenv)->CallIntMethod(jenv, s->output_unit, at.getpos);
  345. /* android returns number of frames, so:
  346. position = frames * (PCM_16_BIT == 2 bytes) * channels
  347. */
  348. *pos *= s->channels * sizeof(int16_t);
  349. return SA_SUCCESS;
  350. }
  351. int
  352. sa_stream_pause(sa_stream_t *s) {
  353. if (s == NULL || s->output_unit == NULL) {
  354. return SA_ERROR_NO_INIT;
  355. }
  356. JNIEnv *jenv = GetJNIForThread();
  357. s->isPaused = 1;
  358. /* Update stats */
  359. if (s->lastStartTime != 0) {
  360. /* if lastStartTime is not zero, so playback has started */
  361. struct timespec current_time;
  362. clock_gettime(CLOCK_REALTIME, &current_time);
  363. int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
  364. s->timePlaying += ticker - s->lastStartTime;
  365. }
  366. ALOG("%p - Pause total time playing: %lld total written: %lld", s, s->timePlaying, s->amountWritten);
  367. (*jenv)->CallVoidMethod(jenv, s->output_unit, at.pause);
  368. return SA_SUCCESS;
  369. }
  370. int
  371. sa_stream_resume(sa_stream_t *s) {
  372. if (s == NULL || s->output_unit == NULL) {
  373. return SA_ERROR_NO_INIT;
  374. }
  375. ALOG("%p - resume", s);
  376. JNIEnv *jenv = GetJNIForThread();
  377. s->isPaused = 0;
  378. /* Update stats */
  379. struct timespec current_time;
  380. clock_gettime(CLOCK_REALTIME, &current_time);
  381. int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
  382. s->lastStartTime = ticker;
  383. (*jenv)->CallVoidMethod(jenv, s->output_unit, at.play);
  384. return SA_SUCCESS;
  385. }
  386. int
  387. sa_stream_drain(sa_stream_t *s)
  388. {
  389. if (s == NULL || s->output_unit == NULL) {
  390. return SA_ERROR_NO_INIT;
  391. }
  392. /* This is somewhat of a hack (see bug 693131). The AudioTrack documentation
  393. doesn't make it clear how much data must be written before a chunk of data is
  394. played, and experimentation with short streams required filling the entire
  395. allocated buffer. To guarantee that short streams (and the end of longer
  396. streams) are audible, write an entire bufferSize of silence before sleeping.
  397. This guarantees the short write logic in sa_stream_write is hit and the
  398. stream is playing before sleeping. Note that the sleep duration is
  399. calculated from the duration of audio written before writing silence. */
  400. size_t available;
  401. sa_stream_get_write_size(s, &available);
  402. void *p = calloc(1, s->bufferSize);
  403. sa_stream_write(s, p, s->bufferSize);
  404. free(p);
  405. /* There is no way with the Android SDK to determine exactly how
  406. long to playback. So estimate and sleep for that long. */
  407. unsigned long long x = (s->bufferSize - available) * 1000 / s->channels / s->rate /
  408. sizeof(int16_t) * NANOSECONDS_IN_MILLISECOND;
  409. ALOG("%p - Drain - flush %u, sleep for %llu ns", s, available, x);
  410. struct timespec ts = {x / NANOSECONDS_PER_SECOND, x % NANOSECONDS_PER_SECOND};
  411. nanosleep(&ts, NULL);
  412. return SA_SUCCESS;
  413. }
  414. /*
  415. * -----------------------------------------------------------------------------
  416. * Extension functions
  417. * -----------------------------------------------------------------------------
  418. */
  419. int
  420. sa_stream_set_volume_abs(sa_stream_t *s, float vol) {
  421. if (s == NULL || s->output_unit == NULL) {
  422. return SA_ERROR_NO_INIT;
  423. }
  424. JNIEnv *jenv = GetJNIForThread();
  425. (*jenv)->CallIntMethod(jenv, s->output_unit, at.setvol,
  426. (jfloat)vol, (jfloat)vol);
  427. return SA_SUCCESS;
  428. }
  429. /*
  430. * -----------------------------------------------------------------------------
  431. * Unsupported functions
  432. * -----------------------------------------------------------------------------
  433. */
  434. #define UNSUPPORTED(func) func { return SA_ERROR_NOT_SUPPORTED; }
  435. UNSUPPORTED(int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec))
  436. UNSUPPORTED(int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size))
  437. UNSUPPORTED(int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size))
  438. UNSUPPORTED(int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size))
  439. UNSUPPORTED(int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size))
  440. UNSUPPORTED(int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned int n))
  441. UNSUPPORTED(int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode))
  442. UNSUPPORTED(int sa_stream_set_non_interleaved(sa_stream_t *s, int enable))
  443. UNSUPPORTED(int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable))
  444. UNSUPPORTED(int sa_stream_set_driver(sa_stream_t *s, const char *driver))
  445. UNSUPPORTED(int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback))
  446. UNSUPPORTED(int sa_stream_stop_thread(sa_stream_t *s))
  447. UNSUPPORTED(int sa_stream_change_device(sa_stream_t *s, const char *device_name))
  448. UNSUPPORTED(int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
  449. UNSUPPORTED(int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
  450. UNSUPPORTED(int sa_stream_change_rate(sa_stream_t *s, unsigned int rate))
  451. UNSUPPORTED(int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size))
  452. UNSUPPORTED(int sa_stream_change_user_data(sa_stream_t *s, const void *value))
  453. UNSUPPORTED(int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction))
  454. UNSUPPORTED(int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction))
  455. UNSUPPORTED(int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction))
  456. UNSUPPORTED(int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction))
  457. UNSUPPORTED(int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode))
  458. UNSUPPORTED(int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size))
  459. UNSUPPORTED(int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format))
  460. UNSUPPORTED(int sa_stream_get_rate(sa_stream_t *s, unsigned int *rate))
  461. UNSUPPORTED(int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels))
  462. UNSUPPORTED(int sa_stream_get_user_data(sa_stream_t *s, void **value))
  463. UNSUPPORTED(int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size))
  464. UNSUPPORTED(int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size))
  465. UNSUPPORTED(int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size))
  466. UNSUPPORTED(int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size))
  467. UNSUPPORTED(int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned int *n))
  468. UNSUPPORTED(int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode))
  469. UNSUPPORTED(int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled))
  470. UNSUPPORTED(int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled))
  471. UNSUPPORTED(int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size))
  472. UNSUPPORTED(int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size))
  473. UNSUPPORTED(int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
  474. UNSUPPORTED(int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
  475. UNSUPPORTED(int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size))
  476. UNSUPPORTED(int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction))
  477. UNSUPPORTED(int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction))
  478. UNSUPPORTED(int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction))
  479. UNSUPPORTED(int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction))
  480. UNSUPPORTED(int sa_stream_get_state(sa_stream_t *s, sa_state_t *state))
  481. UNSUPPORTED(int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error))
  482. UNSUPPORTED(int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify))
  483. UNSUPPORTED(int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes))
  484. UNSUPPORTED(int sa_stream_read_ni(sa_stream_t *s, unsigned int channel, void *data, size_t nbytes))
  485. UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes))
  486. UNSUPPORTED(int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
  487. 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))
  488. UNSUPPORTED(int sa_stream_get_read_size(sa_stream_t *s, size_t *size))
  489. UNSUPPORTED(int sa_stream_get_volume_abs(sa_stream_t *s, float *vol))
  490. UNSUPPORTED(int sa_stream_get_min_write(sa_stream_t *s, size_t *size))
  491. const char *sa_strerror(int code) { return NULL; }