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