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