1 /* 2 * Copyright 2007 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Bek, host.haiku@gmx.de 7 */ 8 #include "driver.h" 9 10 11 status_t 12 null_hw_create_virtual_buffers(device_stream_t* stream, const char* name) 13 { 14 uint32 i; 15 int buffer_size; 16 int area_size; 17 uint8* buffer; 18 19 buffer_size = stream->num_channels 20 * format_to_sample_size(stream->format) 21 * stream->buffer_length; 22 buffer_size = (buffer_size + 127) & (~127); 23 24 area_size = buffer_size * stream->num_buffers; 25 area_size = (area_size + B_PAGE_SIZE - 1) & (~(B_PAGE_SIZE -1)); 26 27 stream->buffer_area = create_area("null_audio_buffers", (void**)&buffer, 28 B_ANY_KERNEL_ADDRESS, area_size, 29 B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); 30 if (stream->buffer_area < B_OK) 31 return stream->buffer_area; 32 33 // Get the correct address for setting up the buffers 34 // pointers being passed back to userland 35 for (i = 0; i < stream->num_buffers; i++) 36 stream->buffers[i] = buffer + (i * buffer_size); 37 38 stream->buffer_ready_sem = create_sem(0, name); 39 return B_OK; 40 } 41 42 43 static int32 44 null_fake_interrupt(void* cookie) 45 { 46 // This thread is supposed to fake the interrupt 47 // handling done in communication with the 48 // hardware usually. What it does is nearly the 49 // same like all soundrivers, get the interrupt 50 // exchange the buffer pointer and update the 51 // time information. Instead of exiting, we wait 52 // until the next fake interrupt appears. 53 bigtime_t sleepTime; 54 device_t* device = (device_t*) cookie; 55 int sampleRate; 56 57 switch (device->playback_stream.rate) { 58 case B_SR_48000: 59 sampleRate = 48000; 60 break; 61 case B_SR_44100: 62 default: 63 sampleRate = 44100; 64 break; 65 } 66 67 // The time between until we get a new valid buffer 68 // from our soundcard: buffer_length / samplerate 69 sleepTime = (device->playback_stream.buffer_length * 1000000LL) / sampleRate; 70 71 while (device->running) { 72 cpu_status status; 73 status = disable_interrupts(); 74 acquire_spinlock(&device->playback_stream.lock); 75 device->playback_stream.real_time = system_time(); 76 device->playback_stream.frames_count += device->playback_stream.buffer_length; 77 device->playback_stream.buffer_cycle = (device->playback_stream.buffer_cycle +1) % device->playback_stream.num_buffers; 78 release_spinlock(&device->playback_stream.lock); 79 80 // TODO: Create a simple sinus wave, so that recording from 81 // the virtual device actually returns something useful 82 acquire_spinlock(&device->record_stream.lock); 83 device->record_stream.real_time = device->playback_stream.real_time; 84 device->record_stream.frames_count += device->record_stream.buffer_length; 85 device->record_stream.buffer_cycle = (device->record_stream.buffer_cycle +1) % device->record_stream.num_buffers; 86 release_spinlock(&device->record_stream.lock); 87 88 restore_interrupts(status); 89 90 release_sem_etc(device->playback_stream.buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); 91 release_sem_etc(device->record_stream.buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); 92 snooze(sleepTime); 93 } 94 return B_OK; 95 } 96 97 98 status_t 99 null_start_hardware(device_t* device) 100 { 101 dprintf("null_audio: %s spawning fake interrupter\n", __func__); 102 device->running = true; 103 device->interrupt_thread = spawn_kernel_thread(null_fake_interrupt, "null_audio interrupter", 104 B_REAL_TIME_PRIORITY, (void*)device); 105 return resume_thread(device->interrupt_thread); 106 } 107 108 109 void 110 null_stop_hardware(device_t* device) 111 { 112 device->running = false; 113 } 114 115