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