1/*
2 * Copyright 2007-2009, 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// Convenience function to determine the byte count
12// of a sample for a given format.
13// Note: Currently null_audio only supports 16 bit,
14// but that is supposed to change later
15int32
16format_to_sample_size(uint32 format)
17{
18	switch(format) {
19		case B_FMT_8BIT_S:
20			return 1;
21		case B_FMT_16BIT:
22			return 2;
23
24		case B_FMT_18BIT:
25		case B_FMT_24BIT:
26		case B_FMT_32BIT:
27		case B_FMT_FLOAT:
28			return 4;
29
30		default:
31			return 0;
32	}
33}
34
35
36multi_channel_info channel_descriptions[] = {
37	{  0, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
38	{  1, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
39	{  2, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
40	{  3, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
41	{  4, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
42	{  5, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
43	{  6, B_MULTI_INPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
44	{  7, B_MULTI_INPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
45};
46
47
48static status_t
49get_description(void* cookie, multi_description* data)
50{
51	multi_description description;
52
53	dprintf("null_audio: %s\n", __func__ );
54
55	if (user_memcpy(&description, data, sizeof(multi_description)) != B_OK) {
56		return B_BAD_ADDRESS;
57	}
58
59	description.interface_version = B_CURRENT_INTERFACE_VERSION;
60	description.interface_minimum = B_CURRENT_INTERFACE_VERSION;
61
62	strcpy(description.friendly_name,"Virtual audio (null_audio)");
63	strcpy(description.vendor_info,"Host/Haiku");
64
65	description.output_channel_count = 2;
66	description.input_channel_count = 2;
67	description.output_bus_channel_count = 2;
68	description.input_bus_channel_count = 2;
69	description.aux_bus_channel_count = 0;
70
71	description.output_rates = B_SR_44100;
72	description.input_rates = B_SR_44100;
73
74	description.max_cvsr_rate = 0;
75	description.min_cvsr_rate = 0;
76
77	description.output_formats = B_FMT_16BIT;
78	description.input_formats = B_FMT_16BIT;
79	description.lock_sources = B_MULTI_LOCK_INTERNAL;
80	description.timecode_sources = 0;
81	description.interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
82	description.start_latency = 30000;
83
84	strcpy(description.control_panel,"");
85
86	if (user_memcpy(data, &description, sizeof(multi_description)) != B_OK)
87		return B_BAD_ADDRESS;
88
89	if ((size_t)description.request_channel_count >= B_COUNT_OF(channel_descriptions)) {
90		if (user_memcpy(data->channels,
91					&channel_descriptions, sizeof(channel_descriptions)) != B_OK)
92			return B_BAD_ADDRESS;
93	}
94
95	return B_OK;
96}
97
98
99static status_t
100get_enabled_channels(void* cookie, multi_channel_enable* data)
101{
102	dprintf("null_audio: %s\n", __func__ );
103	// By default we say, that all channels are enabled
104	// and that this cannot be changed
105	B_SET_CHANNEL(data->enable_bits, 0, true);
106	B_SET_CHANNEL(data->enable_bits, 1, true);
107	B_SET_CHANNEL(data->enable_bits, 2, true);
108	B_SET_CHANNEL(data->enable_bits, 3, true);
109	return B_OK;
110}
111
112
113static status_t
114set_global_format(device_t* device, multi_format_info* data)
115{
116	// The media kit asks us to set our streams
117	// according to its settings
118	dprintf("null_audio: %s\n", __func__ );
119	device->playback_stream.format = data->output.format;
120	device->playback_stream.rate = data->output.rate;
121
122	device->record_stream.format = data->input.format;
123	device->record_stream.rate = data->input.rate;
124
125	return B_OK;
126}
127
128
129static status_t
130get_global_format(device_t* device, multi_format_info* data)
131{
132	dprintf("null_audio: %s\n", __func__ );
133	// Zero latency is unlikely to happen, so we fake some
134	// additional latency
135	data->output_latency = 30;
136	data->input_latency = 30;
137	data->timecode_kind = 0;
138
139	data->output.format = device->playback_stream.format;
140	data->output.rate = device->playback_stream.rate;
141	data->input.format = device->record_stream.format;
142	data->input.rate = device->record_stream.rate;
143
144	return B_OK;
145}
146
147
148static int32
149create_group_control(multi_mix_control* multi, int32 idx, int32 parent, int32 string,
150	const char* name)
151{
152	multi->id = MULTI_AUDIO_BASE_ID + idx;
153	multi->parent = parent;
154	multi->flags = B_MULTI_MIX_GROUP;
155	multi->master = MULTI_AUDIO_MASTER_ID;
156	multi->string = string;
157	if (name)
158		strcpy(multi->name, name);
159
160	return multi->id;
161}
162
163
164static status_t
165list_mix_controls(device_t* device, multi_mix_control_info * data)
166{
167	dprintf("null_audio: %s\n", __func__ );
168
169	create_group_control(data->controls + 0, 0, 0, 0, "Record");
170	create_group_control(data->controls + 1, 1, 0, 0, "Playback");
171	data->control_count = 2;
172
173	return B_OK;
174}
175
176
177static status_t
178list_mix_connections(void* cookie, multi_mix_connection_info* connection_info)
179{
180	dprintf("null_audio: %s\n", __func__ );
181	return B_ERROR;
182}
183
184
185static status_t
186list_mix_channels(void* cookie, multi_mix_channel_info* channel_info)
187{
188	dprintf("null_audio: %s\n", __func__ );
189	return B_ERROR;
190}
191
192
193static status_t
194get_buffers(device_t* device, multi_buffer_list* data)
195{
196	uint32 playback_sample_size = format_to_sample_size(device->playback_stream.format);
197	uint32 record_sample_size = format_to_sample_size(device->record_stream.format);
198	int32 bidx;
199	int32 cidx;
200	status_t result;
201
202	dprintf("null_audio: %s\n", __func__ );
203
204	// Workaround for Haiku multi_audio API, since it prefers
205	// to let the driver pick values, while the BeOS multi_audio
206	// actually gives the user's defaults.
207	if (data->request_playback_buffers > STRMAXBUF || data->request_playback_buffers < STRMINBUF)
208		data->request_playback_buffers = STRMINBUF;
209
210	if (data->request_record_buffers > STRMAXBUF || data->request_record_buffers < STRMINBUF)
211		data->request_record_buffers = STRMINBUF;
212
213	if (data->request_playback_buffer_size == 0)
214		data->request_playback_buffer_size = FRAMES_PER_BUFFER;
215
216	if (data->request_record_buffer_size == 0)
217		data->request_record_buffer_size = FRAMES_PER_BUFFER;
218
219	// ... from here on, we can assume again that
220	// a reasonable request is being made
221
222	data->flags = 0;
223
224	// Copy the requested settings into the streams
225	// and initialize the virtual buffers properly
226	device->playback_stream.num_buffers = data->request_playback_buffers;
227	device->playback_stream.num_channels = data->request_playback_channels;
228	device->playback_stream.buffer_length = data->request_playback_buffer_size;
229	result = null_hw_create_virtual_buffers(&device->playback_stream,
230				"null_audio_playback_sem");
231	if (result != B_OK) {
232		dprintf("null_audio %s: Error setting up playback buffers (%s)\n",
233													__func__, strerror(result));
234		return result;
235	}
236
237	device->record_stream.num_buffers = data->request_record_buffers;
238	device->record_stream.num_channels = data->request_record_channels;
239	device->record_stream.buffer_length = data->request_record_buffer_size;
240	result = null_hw_create_virtual_buffers(&device->record_stream,
241				"null_audio_record_sem");
242	if (result != B_OK) {
243		dprintf("null_audio %s: Error setting up recording buffers (%s)\n",
244													__func__, strerror(result));
245		return result;
246	}
247
248	/* Setup data structure for multi_audio API... */
249	data->return_playback_buffers = data->request_playback_buffers;
250	data->return_playback_channels = data->request_playback_channels;
251	data->return_playback_buffer_size = data->request_playback_buffer_size;
252
253	for (bidx = 0; bidx < data->return_playback_buffers; bidx++) {
254		for (cidx = 0; cidx < data->return_playback_channels; cidx++) {
255			data->playback_buffers[bidx][cidx].base
256				= (char*)device->playback_stream.buffers[bidx] + (playback_sample_size * cidx);
257			data->playback_buffers[bidx][cidx].stride
258				= playback_sample_size * data->return_playback_channels;
259		}
260	}
261
262	data->return_record_buffers = data->request_record_buffers;
263	data->return_record_channels = data->request_record_channels;
264	data->return_record_buffer_size = data->request_record_buffer_size;
265
266	for (bidx = 0; bidx < data->return_record_buffers; bidx++) {
267		for (cidx = 0; cidx < data->return_record_channels; cidx++) {
268			data->record_buffers[bidx][cidx].base
269				= (char*)device->record_stream.buffers[bidx] + (record_sample_size * cidx);
270			data->record_buffers[bidx][cidx].stride
271				= record_sample_size * data->return_record_channels;
272		}
273	}
274
275	return B_OK;
276}
277
278
279static status_t
280buffer_exchange(device_t* device, multi_buffer_info* info)
281{
282	//dprintf("null_audio: %s\n", __func__ );
283	static int debug_buffers_exchanged = 0;
284	cpu_status status;
285	status_t result;
286
287	multi_buffer_info buffer_info;
288	if (user_memcpy(&buffer_info, info, sizeof(multi_buffer_info)) != B_OK)
289		return B_BAD_ADDRESS;
290
291	// On first call, we start our fake hardware.
292	// Usually one would jump into his interrupt handler now
293	if (!device->running)
294		null_start_hardware(device);
295
296	result = acquire_sem(device->playback_stream.buffer_ready_sem);
297	if (result != B_OK) {
298		dprintf("null_audio: %s, Could not get playback buffer\n", __func__);
299		return result;
300	}
301
302	result = acquire_sem(device->record_stream.buffer_ready_sem);
303	if (result != B_OK) {
304		dprintf("null_audio: %s, Could not get record buffer\n", __func__);
305		return result;
306	}
307
308	status = disable_interrupts();
309	acquire_spinlock(&device->playback_stream.lock);
310
311	buffer_info.playback_buffer_cycle = device->playback_stream.buffer_cycle;
312	buffer_info.played_real_time = device->playback_stream.real_time;
313	buffer_info.played_frames_count = device->playback_stream.frames_count;
314
315	buffer_info.record_buffer_cycle = device->record_stream.buffer_cycle;
316	buffer_info.recorded_real_time = device->record_stream.real_time;
317	buffer_info.recorded_frames_count = device->record_stream.frames_count;
318
319	release_spinlock(&device->playback_stream.lock);
320	restore_interrupts(status);
321
322	debug_buffers_exchanged++;
323	if (((debug_buffers_exchanged % 5000) == 0) ) {
324		dprintf("null_audio: %s: %d buffers processed\n",
325				__func__, debug_buffers_exchanged);
326	}
327
328	if (user_memcpy(info, &buffer_info, sizeof(multi_buffer_info)) != B_OK)
329		return B_BAD_ADDRESS;
330
331	return B_OK;
332}
333
334
335static status_t
336buffer_force_stop(device_t* device)
337{
338	dprintf("null_audio: %s\n", __func__ );
339
340	if (device == NULL)
341		return B_ERROR;
342
343	if (device->running)
344		null_stop_hardware(device);
345
346	delete_area(device->playback_stream.buffer_area);
347	delete_area(device->record_stream.buffer_area);
348
349	delete_sem(device->playback_stream.buffer_ready_sem);
350	delete_sem(device->record_stream.buffer_ready_sem);
351
352	return B_OK;
353}
354
355
356status_t
357multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
358{
359	switch(op) {
360		case B_MULTI_GET_DESCRIPTION:		return get_description(cookie, arg);
361		case B_MULTI_GET_EVENT_INFO:		return B_ERROR;
362		case B_MULTI_SET_EVENT_INFO:		return B_ERROR;
363		case B_MULTI_GET_EVENT:				return B_ERROR;
364		case B_MULTI_GET_ENABLED_CHANNELS:	return get_enabled_channels(cookie, arg);
365		case B_MULTI_SET_ENABLED_CHANNELS:	return B_OK;
366		case B_MULTI_GET_GLOBAL_FORMAT:		return get_global_format(cookie, arg);
367		case B_MULTI_SET_GLOBAL_FORMAT:		return set_global_format(cookie, arg);
368		case B_MULTI_GET_CHANNEL_FORMATS:	return B_ERROR;
369		case B_MULTI_SET_CHANNEL_FORMATS:	return B_ERROR;
370		case B_MULTI_GET_MIX:				return B_ERROR;
371		case B_MULTI_SET_MIX:				return B_ERROR;
372		case B_MULTI_LIST_MIX_CHANNELS:		return list_mix_channels(cookie, arg);
373		case B_MULTI_LIST_MIX_CONTROLS:		return list_mix_controls(cookie, arg);
374		case B_MULTI_LIST_MIX_CONNECTIONS:	return list_mix_connections(cookie, arg);
375		case B_MULTI_GET_BUFFERS:			return get_buffers(cookie, arg);
376		case B_MULTI_SET_BUFFERS:			return B_ERROR;
377		case B_MULTI_SET_START_TIME:		return B_ERROR;
378		case B_MULTI_BUFFER_EXCHANGE:		return buffer_exchange(cookie, arg);
379		case B_MULTI_BUFFER_FORCE_STOP:		return buffer_force_stop(cookie);
380	}
381
382	dprintf("null_audio: %s - unknown op\n", __func__);
383	return B_BAD_VALUE;
384}
385
386