1 /// Translated from C to D 2 module soundio.dummy; 3 4 extern(C): @nogc: nothrow: __gshared: 5 import core.stdc.config: c_long, c_ulong; 6 7 import soundio.soundio_internal; 8 import soundio.os; 9 import soundio.api; 10 import soundio.atomics; 11 import soundio.soundio_private; 12 13 import soundio.ring_buffer: SoundIoRingBufferImpl, soundio_ring_buffer_deinit, soundio_ring_buffer_init; 14 import core.stdc.stdio; 15 import core.stdc..string; 16 import core.atomic; 17 18 struct SoundIoDummy { 19 SoundIoOsMutex* mutex; 20 SoundIoOsCond* cond; 21 bool devices_emitted; 22 } 23 24 struct SoundIoDeviceDummy { 25 int make_the_struct_not_empty; 26 } 27 28 struct SoundIoOutStreamDummy { 29 SoundIoOsThread* thread; 30 SoundIoOsCond* cond; 31 SoundIoAtomicFlag abort_flag; 32 double period_duration; 33 int buffer_frame_count; 34 int frames_left; 35 int write_frame_count; 36 SoundIoRingBufferImpl ring_buffer; 37 auto ring_buffer_ptr() {return cast(SoundIoRingBuffer*) &ring_buffer;} 38 double playback_start_time; 39 SoundIoAtomicFlag clear_buffer_flag; 40 SoundIoAtomicBool pause_requested; 41 SoundIoChannelArea[SOUNDIO_MAX_CHANNELS] areas; 42 } 43 44 struct SoundIoInStreamDummy { 45 SoundIoOsThread* thread; 46 SoundIoOsCond* cond; 47 SoundIoAtomicFlag abort_flag; 48 double period_duration; 49 int frames_left; 50 int read_frame_count; 51 int buffer_frame_count; 52 SoundIoRingBufferImpl ring_buffer; 53 auto ring_buffer_ptr() {return cast(SoundIoRingBuffer*) &ring_buffer;} 54 SoundIoAtomicBool pause_requested; 55 SoundIoChannelArea[SOUNDIO_MAX_CHANNELS] areas; 56 } 57 58 static void playback_thread_run(void* arg) { 59 SoundIoOutStreamPrivate* os = cast(SoundIoOutStreamPrivate*)arg; 60 SoundIoOutStream* outstream = &os.pub; 61 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 62 63 { 64 int fill_bytes = soundio_ring_buffer_fill_count(osd.ring_buffer_ptr); 65 int free_bytes = soundio_ring_buffer_capacity(osd.ring_buffer_ptr) - fill_bytes; 66 int free_frames = free_bytes / outstream.bytes_per_frame; 67 osd.frames_left = free_frames; 68 if (free_frames > 0) 69 outstream.write_callback(outstream, 0, free_frames); 70 } 71 double start_time = soundio_os_get_time(); 72 c_long frames_consumed = 0; 73 74 while (SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd.abort_flag)) { 75 double now = soundio_os_get_time(); 76 double time_passed = now - start_time; 77 double next_period = start_time + 78 ceil_dbl(time_passed / osd.period_duration) * osd.period_duration; 79 double relative_time = next_period - now; 80 soundio_os_cond_timed_wait(osd.cond, null, relative_time); 81 if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd.clear_buffer_flag)) { 82 soundio_ring_buffer_clear(osd.ring_buffer_ptr); 83 int free_bytes = soundio_ring_buffer_capacity(osd.ring_buffer_ptr); 84 int free_frames = free_bytes / outstream.bytes_per_frame; 85 osd.frames_left = free_frames; 86 if (free_frames > 0) 87 outstream.write_callback(outstream, 0, free_frames); 88 frames_consumed = 0; 89 start_time = soundio_os_get_time(); 90 continue; 91 } 92 93 if (SOUNDIO_ATOMIC_LOAD(osd.pause_requested)) { 94 start_time = now; 95 frames_consumed = 0; 96 continue; 97 } 98 99 int fill_bytes = soundio_ring_buffer_fill_count(osd.ring_buffer_ptr); 100 int fill_frames = fill_bytes / outstream.bytes_per_frame; 101 int free_bytes = soundio_ring_buffer_capacity(osd.ring_buffer_ptr) - fill_bytes; 102 int free_frames = free_bytes / outstream.bytes_per_frame; 103 104 double total_time = soundio_os_get_time() - start_time; 105 c_long total_frames = cast(c_long) (total_time * outstream.sample_rate); 106 int frames_to_kill = cast(int) (total_frames - frames_consumed); 107 int read_count = soundio_int_min(frames_to_kill, fill_frames); 108 int byte_count = read_count * outstream.bytes_per_frame; 109 soundio_ring_buffer_advance_read_ptr(osd.ring_buffer_ptr, byte_count); 110 frames_consumed += read_count; 111 112 if (frames_to_kill > fill_frames) { 113 outstream.underflow_callback(outstream); 114 osd.frames_left = free_frames; 115 if (free_frames > 0) 116 outstream.write_callback(outstream, 0, free_frames); 117 frames_consumed = 0; 118 start_time = soundio_os_get_time(); 119 } else if (free_frames > 0) { 120 osd.frames_left = free_frames; 121 outstream.write_callback(outstream, 0, free_frames); 122 } 123 } 124 } 125 126 static void capture_thread_run(void* arg) { 127 SoundIoInStreamPrivate* is_ = cast(SoundIoInStreamPrivate*)arg; 128 SoundIoInStream* instream = &is_.pub; 129 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 130 131 c_long frames_consumed = 0; 132 double start_time = soundio_os_get_time(); 133 while (SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(isd.abort_flag)) { 134 double now = soundio_os_get_time(); 135 double time_passed = now - start_time; 136 double next_period = start_time + 137 ceil_dbl(time_passed / isd.period_duration) * isd.period_duration; 138 double relative_time = next_period - now; 139 soundio_os_cond_timed_wait(isd.cond, null, relative_time); 140 141 if (SOUNDIO_ATOMIC_LOAD(isd.pause_requested)) { 142 start_time = now; 143 frames_consumed = 0; 144 continue; 145 } 146 147 int fill_bytes = soundio_ring_buffer_fill_count(isd.ring_buffer_ptr); 148 int free_bytes = soundio_ring_buffer_capacity(isd.ring_buffer_ptr) - fill_bytes; 149 int fill_frames = fill_bytes / instream.bytes_per_frame; 150 int free_frames = free_bytes / instream.bytes_per_frame; 151 152 double total_time = soundio_os_get_time() - start_time; 153 c_long total_frames = cast(c_long) (total_time * instream.sample_rate); 154 int frames_to_kill = cast(int) (total_frames - frames_consumed); 155 int write_count = soundio_int_min(frames_to_kill, free_frames); 156 int byte_count = write_count * instream.bytes_per_frame; 157 soundio_ring_buffer_advance_write_ptr(isd.ring_buffer_ptr, byte_count); 158 frames_consumed += write_count; 159 160 if (frames_to_kill > free_frames) { 161 instream.overflow_callback(instream); 162 frames_consumed = 0; 163 start_time = soundio_os_get_time(); 164 } 165 if (fill_frames > 0) { 166 isd.frames_left = fill_frames; 167 instream.read_callback(instream, 0, fill_frames); 168 } 169 } 170 } 171 172 static void destroy_dummy(SoundIoPrivate* si) { 173 SoundIoDummy* sid = &si.backend_data.dummy; 174 175 if (sid.cond) 176 soundio_os_cond_destroy(sid.cond); 177 178 if (sid.mutex) 179 soundio_os_mutex_destroy(sid.mutex); 180 } 181 182 static void flush_events_dummy(SoundIoPrivate* si) { 183 SoundIo* soundio = &si.pub; 184 SoundIoDummy* sid = &si.backend_data.dummy; 185 if (sid.devices_emitted) 186 return; 187 sid.devices_emitted = true; 188 soundio.on_devices_change(soundio); 189 } 190 191 static void wait_events_dummy(SoundIoPrivate* si) { 192 SoundIoDummy* sid = &si.backend_data.dummy; 193 flush_events_dummy(si); 194 soundio_os_cond_wait(sid.cond, null); 195 } 196 197 static void wakeup_dummy(SoundIoPrivate* si) { 198 SoundIoDummy* sid = &si.backend_data.dummy; 199 soundio_os_cond_signal(sid.cond, null); 200 } 201 202 static void force_device_scan_dummy(SoundIoPrivate* si) { 203 // nothing to do; dummy devices never change 204 } 205 206 static void outstream_destroy_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os) { 207 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 208 209 if (osd.thread) { 210 SOUNDIO_ATOMIC_FLAG_CLEAR(osd.abort_flag); 211 soundio_os_cond_signal(osd.cond, null); 212 soundio_os_thread_destroy(osd.thread); 213 osd.thread = null; 214 } 215 soundio_os_cond_destroy(osd.cond); 216 osd.cond = null; 217 218 soundio_ring_buffer_deinit(osd.ring_buffer_ptr); 219 } 220 221 static int outstream_open_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os) { 222 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 223 SoundIoOutStream* outstream = &os.pub; 224 SoundIoDevice* device = outstream.device; 225 226 SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd.clear_buffer_flag); 227 SOUNDIO_ATOMIC_STORE(osd.pause_requested, false); 228 229 if (outstream.software_latency == 0.0) { 230 outstream.software_latency = soundio_double_clamp( 231 device.software_latency_min, 1.0, device.software_latency_max); 232 } 233 234 osd.period_duration = outstream.software_latency / 2.0; 235 236 int buffer_size = cast(int) (outstream.bytes_per_frame * outstream.sample_rate * outstream.software_latency); 237 if (auto err = soundio_ring_buffer_init(osd.ring_buffer_ptr, buffer_size)) { 238 outstream_destroy_dummy(si, os); 239 return err; 240 } 241 int actual_capacity = soundio_ring_buffer_capacity(osd.ring_buffer_ptr); 242 osd.buffer_frame_count = actual_capacity / outstream.bytes_per_frame; 243 outstream.software_latency = osd.buffer_frame_count / cast(double) outstream.sample_rate; 244 245 osd.cond = soundio_os_cond_create(); 246 if (!osd.cond) { 247 outstream_destroy_dummy(si, os); 248 return SoundIoError.NoMem; 249 } 250 251 return 0; 252 } 253 254 static int outstream_pause_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os, bool pause) { 255 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 256 SOUNDIO_ATOMIC_STORE(osd.pause_requested, pause); 257 return 0; 258 } 259 260 static int outstream_start_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os) { 261 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 262 SoundIo* soundio = &si.pub; 263 assert(!osd.thread); 264 SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osd.abort_flag); 265 if (auto err = soundio_os_thread_create(&playback_thread_run, os, 266 soundio.emit_rtprio_warning, &osd.thread)) 267 { 268 return err; 269 } 270 return 0; 271 } 272 273 static int outstream_begin_write_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os, SoundIoChannelArea** out_areas, int* frame_count) { 274 SoundIoOutStream* outstream = &os.pub; 275 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 276 277 if (*frame_count > osd.frames_left) 278 return SoundIoError.Invalid; 279 280 char* write_ptr = soundio_ring_buffer_write_ptr(osd.ring_buffer_ptr); 281 for (int ch = 0; ch < outstream.layout.channel_count; ch += 1) { 282 osd.areas[ch].ptr = write_ptr + outstream.bytes_per_sample * ch; 283 osd.areas[ch].step = outstream.bytes_per_frame; 284 } 285 286 osd.write_frame_count = *frame_count; 287 *out_areas = osd.areas.ptr; 288 return 0; 289 } 290 291 static int outstream_end_write_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os) { 292 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 293 SoundIoOutStream* outstream = &os.pub; 294 int byte_count = osd.write_frame_count * outstream.bytes_per_frame; 295 soundio_ring_buffer_advance_write_ptr(osd.ring_buffer_ptr, byte_count); 296 osd.frames_left -= osd.write_frame_count; 297 return 0; 298 } 299 300 static int outstream_clear_buffer_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os) { 301 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 302 SOUNDIO_ATOMIC_FLAG_CLEAR(osd.clear_buffer_flag); 303 soundio_os_cond_signal(osd.cond, null); 304 return 0; 305 } 306 307 static int outstream_get_latency_dummy(SoundIoPrivate* si, SoundIoOutStreamPrivate* os, double* out_latency) { 308 SoundIoOutStream* outstream = &os.pub; 309 SoundIoOutStreamDummy* osd = &os.backend_data.dummy; 310 int fill_bytes = soundio_ring_buffer_fill_count(osd.ring_buffer_ptr); 311 312 *out_latency = (fill_bytes / outstream.bytes_per_frame) / cast(double)outstream.sample_rate; 313 return 0; 314 } 315 316 static void instream_destroy_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_) { 317 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 318 319 if (isd.thread) { 320 SOUNDIO_ATOMIC_FLAG_CLEAR(isd.abort_flag); 321 soundio_os_cond_signal(isd.cond, null); 322 soundio_os_thread_destroy(isd.thread); 323 isd.thread = null; 324 } 325 soundio_os_cond_destroy(isd.cond); 326 isd.cond = null; 327 328 soundio_ring_buffer_deinit(isd.ring_buffer_ptr); 329 } 330 331 static int instream_open_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_) { 332 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 333 SoundIoInStream* instream = &is_.pub; 334 SoundIoDevice* device = instream.device; 335 336 SOUNDIO_ATOMIC_STORE(isd.pause_requested, false); 337 338 if (instream.software_latency == 0.0) { 339 instream.software_latency = soundio_double_clamp( 340 device.software_latency_min, 1.0, device.software_latency_max); 341 } 342 343 isd.period_duration = instream.software_latency; 344 345 double target_buffer_duration = isd.period_duration * 4.0; 346 347 int buffer_size = cast(int) (instream.bytes_per_frame * instream.sample_rate * target_buffer_duration); 348 if (auto err = soundio_ring_buffer_init(isd.ring_buffer_ptr, buffer_size)) { 349 instream_destroy_dummy(si, is_); 350 return err; 351 } 352 353 int actual_capacity = soundio_ring_buffer_capacity(isd.ring_buffer_ptr); 354 isd.buffer_frame_count = actual_capacity / instream.bytes_per_frame; 355 356 isd.cond = soundio_os_cond_create(); 357 if (!isd.cond) { 358 instream_destroy_dummy(si, is_); 359 return SoundIoError.NoMem; 360 } 361 362 return 0; 363 } 364 365 static int instream_pause_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_, bool pause) { 366 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 367 SOUNDIO_ATOMIC_STORE(isd.pause_requested, pause); 368 return 0; 369 } 370 371 static int instream_start_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_) { 372 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 373 SoundIo* soundio = &si.pub; 374 assert(!isd.thread); 375 SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(isd.abort_flag); 376 if (auto err = soundio_os_thread_create(&capture_thread_run, is_, 377 soundio.emit_rtprio_warning, &isd.thread)) 378 { 379 return err; 380 } 381 return 0; 382 } 383 384 static int instream_begin_read_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_, SoundIoChannelArea** out_areas, int* frame_count) { 385 SoundIoInStream* instream = &is_.pub; 386 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 387 388 assert(*frame_count <= isd.frames_left); 389 390 char* read_ptr = soundio_ring_buffer_read_ptr(isd.ring_buffer_ptr); 391 for (int ch = 0; ch < instream.layout.channel_count; ch += 1) { 392 isd.areas[ch].ptr = read_ptr + instream.bytes_per_sample * ch; 393 isd.areas[ch].step = instream.bytes_per_frame; 394 } 395 396 isd.read_frame_count = *frame_count; 397 *out_areas = isd.areas.ptr; 398 399 return 0; 400 } 401 402 static int instream_end_read_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_) { 403 SoundIoInStreamDummy* isd = &is_.backend_data.dummy; 404 SoundIoInStream* instream = &is_.pub; 405 int byte_count = isd.read_frame_count * instream.bytes_per_frame; 406 soundio_ring_buffer_advance_read_ptr(isd.ring_buffer_ptr, byte_count); 407 isd.frames_left -= isd.read_frame_count; 408 return 0; 409 } 410 411 static int instream_get_latency_dummy(SoundIoPrivate* si, SoundIoInStreamPrivate* is_, double* out_latency) { 412 SoundIoInStream* instream = &is_.pub; 413 SoundIoInStreamDummy* osd = &is_.backend_data.dummy; 414 int fill_bytes = soundio_ring_buffer_fill_count(osd.ring_buffer_ptr); 415 416 *out_latency = (fill_bytes / instream.bytes_per_frame) / cast(double)instream.sample_rate; 417 return 0; 418 } 419 420 extern(D) int set_all_device_formats(SoundIoDevice* device) { 421 device.format_count = 18; 422 device.formats = ALLOCATE!SoundIoFormat(device.format_count); 423 if (!device.formats) 424 return SoundIoError.NoMem; 425 426 device.formats[0] = SoundIoFormat.Float32NE; 427 device.formats[1] = SoundIoFormat.Float32FE; 428 device.formats[2] = SoundIoFormat.S32NE; 429 device.formats[3] = SoundIoFormat.S32FE; 430 device.formats[4] = SoundIoFormat.U32NE; 431 device.formats[5] = SoundIoFormat.U32FE; 432 device.formats[6] = SoundIoFormat.S24NE; 433 device.formats[7] = SoundIoFormat.S24FE; 434 device.formats[8] = SoundIoFormat.U24NE; 435 device.formats[9] = SoundIoFormat.U24FE; 436 device.formats[10] = SoundIoFormat.Float64NE; 437 device.formats[11] = SoundIoFormat.Float64FE; 438 device.formats[12] = SoundIoFormat.S16NE; 439 device.formats[13] = SoundIoFormat.S16FE; 440 device.formats[14] = SoundIoFormat.U16NE; 441 device.formats[15] = SoundIoFormat.U16FE; 442 device.formats[16] = SoundIoFormat.S8; 443 device.formats[17] = SoundIoFormat.U8; 444 445 return 0; 446 } 447 448 extern(D) void set_all_device_sample_rates(SoundIoDevice* device) { 449 SoundIoDevicePrivate* dev = cast(SoundIoDevicePrivate*)device; 450 device.sample_rate_count = 1; 451 device.sample_rates = &dev.prealloc_sample_rate_range; 452 device.sample_rates[0].min = SOUNDIO_MIN_SAMPLE_RATE; 453 device.sample_rates[0].max = SOUNDIO_MAX_SAMPLE_RATE; 454 } 455 456 extern(D) int set_all_device_channel_layouts(SoundIoDevice* device) { 457 device.layout_count = soundio_channel_layout_builtin_count(); 458 device.layouts = ALLOCATE!SoundIoChannelLayout(device.layout_count); 459 if (!device.layouts) 460 return SoundIoError.NoMem; 461 for (int i = 0; i < device.layout_count; i += 1) 462 device.layouts[i] = *soundio_channel_layout_get_builtin(i); 463 return 0; 464 } 465 466 int soundio_dummy_init(SoundIoPrivate* si) { 467 SoundIo* soundio = &si.pub; 468 SoundIoDummy* sid = &si.backend_data.dummy; 469 470 sid.mutex = soundio_os_mutex_create(); 471 if (!sid.mutex) { 472 destroy_dummy(si); 473 return SoundIoError.NoMem; 474 } 475 476 sid.cond = soundio_os_cond_create(); 477 if (!sid.cond) { 478 destroy_dummy(si); 479 return SoundIoError.NoMem; 480 } 481 482 assert(!si.safe_devices_info); 483 si.safe_devices_info = ALLOCATE!SoundIoDevicesInfo(1); 484 if (!si.safe_devices_info) { 485 destroy_dummy(si); 486 return SoundIoError.NoMem; 487 } 488 489 si.safe_devices_info.default_input_index = 0; 490 si.safe_devices_info.default_output_index = 0; 491 492 // create output device 493 { 494 SoundIoDevicePrivate* dev = ALLOCATE!SoundIoDevicePrivate(1); 495 if (!dev) { 496 destroy_dummy(si); 497 return SoundIoError.NoMem; 498 } 499 SoundIoDevice* device = &dev.pub; 500 501 device.ref_count = 1; 502 device.soundio = soundio; 503 device.id = strdup("dummy-out"); 504 device.name = strdup("Dummy Output Device"); 505 if (!device.id || !device.name) { 506 soundio_device_unref(device); 507 destroy_dummy(si); 508 return SoundIoError.NoMem; 509 } 510 511 if (auto err = set_all_device_channel_layouts(device)) { 512 soundio_device_unref(device); 513 destroy_dummy(si); 514 return err; 515 } 516 if (auto err = set_all_device_formats(device)) { 517 soundio_device_unref(device); 518 destroy_dummy(si); 519 return err; 520 } 521 set_all_device_sample_rates(device); 522 523 device.software_latency_current = 0.1; 524 device.software_latency_min = 0.01; 525 device.software_latency_max = 4.0; 526 527 device.sample_rate_current = 48000; 528 device.aim = SoundIoDeviceAim.Output; 529 530 if (si.safe_devices_info.output_devices.append(device)) { 531 soundio_device_unref(device); 532 destroy_dummy(si); 533 return SoundIoError.NoMem; 534 } 535 } 536 537 // create input device 538 { 539 SoundIoDevicePrivate* dev = ALLOCATE!SoundIoDevicePrivate(1); 540 if (!dev) { 541 destroy_dummy(si); 542 return SoundIoError.NoMem; 543 } 544 SoundIoDevice* device = &dev.pub; 545 546 device.ref_count = 1; 547 device.soundio = soundio; 548 device.id = strdup("dummy-in"); 549 device.name = strdup("Dummy Input Device"); 550 if (!device.id || !device.name) { 551 soundio_device_unref(device); 552 destroy_dummy(si); 553 return SoundIoError.NoMem; 554 } 555 556 if (auto err = set_all_device_channel_layouts(device)) { 557 soundio_device_unref(device); 558 destroy_dummy(si); 559 return err; 560 } 561 562 if (auto err = set_all_device_formats(device)) { 563 soundio_device_unref(device); 564 destroy_dummy(si); 565 return err; 566 } 567 set_all_device_sample_rates(device); 568 device.software_latency_current = 0.1; 569 device.software_latency_min = 0.01; 570 device.software_latency_max = 4.0; 571 device.sample_rate_current = 48000; 572 device.aim = SoundIoDeviceAim.Input; 573 574 if (si.safe_devices_info.input_devices.append(device)) { 575 soundio_device_unref(device); 576 destroy_dummy(si); 577 return SoundIoError.NoMem; 578 } 579 } 580 581 si.destroy = &destroy_dummy; 582 si.flush_events = &flush_events_dummy; 583 si.wait_events = &wait_events_dummy; 584 si.wakeup = &wakeup_dummy; 585 si.force_device_scan = &force_device_scan_dummy; 586 587 si.outstream_open = &outstream_open_dummy; 588 si.outstream_destroy = &outstream_destroy_dummy; 589 si.outstream_start = &outstream_start_dummy; 590 si.outstream_begin_write = &outstream_begin_write_dummy; 591 si.outstream_end_write = &outstream_end_write_dummy; 592 si.outstream_clear_buffer = &outstream_clear_buffer_dummy; 593 si.outstream_pause = &outstream_pause_dummy; 594 si.outstream_get_latency = &outstream_get_latency_dummy; 595 596 si.instream_open = &instream_open_dummy; 597 si.instream_destroy = &instream_destroy_dummy; 598 si.instream_start = &instream_start_dummy; 599 si.instream_begin_read = &instream_begin_read_dummy; 600 si.instream_end_read = &instream_end_read_dummy; 601 si.instream_pause = &instream_pause_dummy; 602 si.instream_get_latency = &instream_get_latency_dummy; 603 604 return 0; 605 }