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
null_hw_create_virtual_buffers(device_stream_t * stream,const char * name)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
null_fake_interrupt(void * cookie)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
null_start_hardware(device_t * device)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
null_stop_hardware(device_t * device)110 null_stop_hardware(device_t* device)
111 {
112 device->running = false;
113 }
114
115