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
11status_t
12null_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
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
43static int32
44null_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
98status_t
99null_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
109void
110null_stop_hardware(device_t* device)
111{
112	device->running = false;
113}
114
115