xref: /haiku/src/add-ons/kernel/drivers/audio/null/null_multi.c (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
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
15 int32
16 format_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 
36 multi_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 
48 static status_t
49 get_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 (description.request_channel_count
90 			>= sizeof(channel_descriptions) / sizeof(channel_descriptions[0])) {
91 		if (user_memcpy(data->channels,
92 					&channel_descriptions, sizeof(channel_descriptions)) != B_OK)
93 			return B_BAD_ADDRESS;
94 	}
95 
96 	return B_OK;
97 }
98 
99 
100 static status_t
101 get_enabled_channels(void* cookie, multi_channel_enable* data)
102 {
103 	dprintf("null_audio: %s\n" , __func__ );
104 	// By default we say, that all channels are enabled
105 	// and that this cannot be changed
106 	B_SET_CHANNEL(data->enable_bits, 0, true);
107 	B_SET_CHANNEL(data->enable_bits, 1, true);
108 	B_SET_CHANNEL(data->enable_bits, 2, true);
109 	B_SET_CHANNEL(data->enable_bits, 3, true);
110 	return B_OK;
111 }
112 
113 
114 static status_t
115 set_global_format(device_t* device, multi_format_info* data)
116 {
117 	// The media kit asks us to set our streams
118 	// according to its settings
119 	dprintf("null_audio: %s\n" , __func__ );
120 	device->playback_stream.format = data->output.format;
121 	device->playback_stream.rate = data->output.rate;
122 
123 	device->record_stream.format = data->input.format;
124 	device->record_stream.rate = data->input.rate;
125 
126 	return B_OK;
127 }
128 
129 
130 static status_t
131 get_global_format(device_t* device, multi_format_info* data)
132 {
133 	dprintf("null_audio: %s\n" , __func__ );
134 	// Zero latency is unlikely to happen, so we fake some
135 	// additional latency
136 	data->output_latency = 30;
137 	data->input_latency = 30;
138 	data->timecode_kind = 0;
139 
140 	data->output.format = device->playback_stream.format;
141 	data->output.rate = device->playback_stream.rate;
142 	data->input.format = device->record_stream.format;
143 	data->input.rate = device->record_stream.rate;
144 
145 	return B_OK;
146 }
147 
148 
149 static int32
150 create_group_control(multi_mix_control* multi, int32 idx, int32 parent,
151 					int32 string, const char* name)
152 {
153 	multi->id = MULTI_AUDIO_BASE_ID + idx;
154 	multi->parent = parent;
155 	multi->flags = B_MULTI_MIX_GROUP;
156 	multi->master = MULTI_AUDIO_MASTER_ID;
157 	multi->string = string;
158 	if (name)
159 		strcpy(multi->name, name);
160 
161 	return multi->id;
162 }
163 
164 
165 static status_t
166 list_mix_controls(device_t* device, multi_mix_control_info * data)
167 {
168 	int32 parent;
169 	dprintf("null_audio: %s\n" , __func__ );
170 
171 	parent = create_group_control(data->controls +0, 0, 0, 0, "Record");
172 	parent = create_group_control(data->controls +1, 1, 0, 0, "Playback");
173 	data->control_count = 2;
174 
175 	return B_OK;
176 }
177 
178 
179 static status_t
180 list_mix_connections(void* cookie, multi_mix_connection_info* connection_info)
181 {
182 	dprintf("null_audio: %s\n" , __func__ );
183 	return B_ERROR;
184 }
185 
186 
187 static status_t
188 list_mix_channels(void* cookie, multi_mix_channel_info* channel_info)
189 {
190 	dprintf("null_audio: %s\n" , __func__ );
191 	return B_ERROR;
192 }
193 
194 
195 static status_t
196 get_buffers(device_t* device, multi_buffer_list* data)
197 {
198  	uint32 playback_sample_size
199 	 	= format_to_sample_size(device->playback_stream.format);
200  	uint32 record_sample_size
201 		= format_to_sample_size(device->record_stream.format);
202  	uint32 cidx, bidx;
203  	status_t result;
204 
205 	dprintf("null_audio: %s\n" , __func__ );
206 
207 	// Workaround for Haiku multi_audio API, since it prefers
208 	// to let the driver pick values, while the BeOS multi_audio
209 	// actually gives the user's defaults.
210 	if (data->request_playback_buffers > STRMAXBUF
211 		|| data->request_playback_buffers < STRMINBUF) {
212 		data->request_playback_buffers = STRMINBUF;
213 	}
214 
215 	if (data->request_record_buffers > STRMAXBUF
216 		|| data->request_record_buffers < STRMINBUF) {
217 		data->request_record_buffers = STRMINBUF;
218 	}
219 
220 	if (data->request_playback_buffer_size == 0)
221 		data->request_playback_buffer_size = FRAMES_PER_BUFFER;
222 
223 	if (data->request_record_buffer_size == 0)
224 		data->request_record_buffer_size = FRAMES_PER_BUFFER;
225 
226 	// ... from here on, we can assume again that
227 	// a reasonable request is being made
228 
229 	data->flags = 0;
230 
231 	// Copy the requested settings into the streams
232 	// and initialize the virtual buffers properly
233 	device->playback_stream.num_buffers = data->request_playback_buffers;
234 	device->playback_stream.num_channels = data->request_playback_channels;
235 	device->playback_stream.buffer_length = data->request_playback_buffer_size;
236 	result = null_hw_create_virtual_buffers(&device->playback_stream,
237 				"null_audio_playback_sem");
238 	if (result != B_OK) {
239 		dprintf("null_audio %s: Error setting up playback buffers (%s)\n",
240 													__func__, strerror(result));
241 		return result;
242 	}
243 
244 	device->record_stream.num_buffers = data->request_record_buffers;
245 	device->record_stream.num_channels = data->request_record_channels;
246 	device->record_stream.buffer_length = data->request_record_buffer_size;
247 	result = null_hw_create_virtual_buffers(&device->record_stream,
248 				"null_audio_record_sem");
249 	if (result != B_OK) {
250 		dprintf("null_audio %s: Error setting up recording buffers (%s)\n",
251 													__func__, strerror(result));
252 		return result;
253 	}
254 
255 	/* Setup data structure for multi_audio API... */
256 	data->return_playback_buffers = data->request_playback_buffers;
257 	data->return_playback_channels = data->request_playback_channels;
258 	data->return_playback_buffer_size = data->request_playback_buffer_size;
259 
260 	for (bidx = 0; bidx < data->return_playback_buffers; bidx++) {
261 		for (cidx = 0; cidx < data->return_playback_channels; cidx++) {
262 			data->playback_buffers[bidx][cidx].base
263 				= device->playback_stream.buffers[bidx] + (playback_sample_size * cidx);
264 			data->playback_buffers[bidx][cidx].stride
265 				= playback_sample_size * data->return_playback_channels;
266 		}
267 	}
268 
269 	data->return_record_buffers = data->request_record_buffers;
270 	data->return_record_channels = data->request_record_channels;
271 	data->return_record_buffer_size = data->request_record_buffer_size;
272 
273 	for (bidx = 0; bidx < data->return_record_buffers; bidx++) {
274 		for (cidx = 0; cidx < data->return_record_channels; cidx++) {
275 			data->record_buffers[bidx][cidx].base
276 				= device->record_stream.buffers[bidx] + (record_sample_size * cidx);
277 			data->record_buffers[bidx][cidx].stride
278 				= record_sample_size * data->return_record_channels;
279 		}
280 	}
281 
282 	return B_OK;
283 }
284 
285 
286 static status_t
287 buffer_exchange(device_t* device, multi_buffer_info* info)
288 {
289 	//dprintf("null_audio: %s\n" , __func__ );
290 	static int debug_buffers_exchanged = 0;
291 	cpu_status status;
292 	status_t result;
293 
294 	multi_buffer_info buffer_info;
295 	if (user_memcpy(&buffer_info, info, sizeof(multi_buffer_info)) != B_OK)
296 		return B_BAD_ADDRESS;
297 
298 	// On first call, we start our fake hardware.
299 	// Usually one would jump into his interrupt handler now
300 	if (!device->running)
301 		null_start_hardware(device);
302 
303 	result = acquire_sem(device->playback_stream.buffer_ready_sem);
304 	if (result != B_OK) {
305 		dprintf("null_audio: %s, Could not get playback buffer\n", __func__);
306 		return result;
307 	}
308 
309 	result = acquire_sem(device->record_stream.buffer_ready_sem);
310 	if (result != B_OK) {
311 		dprintf("null_audio: %s, Could not get record buffer\n", __func__);
312 		return result;
313 	}
314 
315 	status = disable_interrupts();
316 	acquire_spinlock(&device->playback_stream.lock);
317 
318 	buffer_info.playback_buffer_cycle = device->playback_stream.buffer_cycle;
319 	buffer_info.played_real_time = device->playback_stream.real_time;
320 	buffer_info.played_frames_count = device->playback_stream.frames_count;
321 
322 	buffer_info.record_buffer_cycle = device->record_stream.buffer_cycle;
323 	buffer_info.recorded_real_time = device->record_stream.real_time;
324 	buffer_info.recorded_frames_count = device->record_stream.frames_count;
325 
326 	release_spinlock(&device->playback_stream.lock);
327 	restore_interrupts(status);
328 
329 	debug_buffers_exchanged++;
330 	if (((debug_buffers_exchanged % 5000) == 0) ) {
331 		dprintf("null_audio: %s: %d buffers processed\n",
332 				__func__, debug_buffers_exchanged);
333 	}
334 
335 	if (user_memcpy(info, &buffer_info, sizeof(multi_buffer_info)) != B_OK)
336 		return B_BAD_ADDRESS;
337 
338 	return B_OK;
339 }
340 
341 
342 static status_t
343 buffer_force_stop(device_t* device)
344 {
345 	dprintf("null_audio: %s\n" , __func__ );
346 
347 	if (device && device->running)
348 		null_stop_hardware(device);
349 
350 	delete_area(device->playback_stream.buffer_area);
351 	delete_area(device->record_stream.buffer_area);
352 
353 	delete_sem(device->playback_stream.buffer_ready_sem);
354 	delete_sem(device->record_stream.buffer_ready_sem);
355 
356 	return B_OK;
357 }
358 
359 
360 status_t
361 multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
362 {
363 	switch(op) {
364 		case B_MULTI_GET_DESCRIPTION:		return get_description(cookie, arg);
365 		case B_MULTI_GET_EVENT_INFO:		return B_ERROR;
366 		case B_MULTI_SET_EVENT_INFO:		return B_ERROR;
367 		case B_MULTI_GET_EVENT:				return B_ERROR;
368 		case B_MULTI_GET_ENABLED_CHANNELS:	return get_enabled_channels(cookie, arg);
369 		case B_MULTI_SET_ENABLED_CHANNELS:	return B_OK;
370 		case B_MULTI_GET_GLOBAL_FORMAT:		return get_global_format(cookie, arg);
371 		case B_MULTI_SET_GLOBAL_FORMAT:		return set_global_format(cookie, arg);
372 		case B_MULTI_GET_CHANNEL_FORMATS:	return B_ERROR;
373 		case B_MULTI_SET_CHANNEL_FORMATS:	return B_ERROR;
374 		case B_MULTI_GET_MIX:				return B_ERROR;
375 		case B_MULTI_SET_MIX:				return B_ERROR;
376 		case B_MULTI_LIST_MIX_CHANNELS:		return list_mix_channels(cookie, arg);
377 		case B_MULTI_LIST_MIX_CONTROLS:		return list_mix_controls(cookie, arg);
378 		case B_MULTI_LIST_MIX_CONNECTIONS:	return list_mix_connections(cookie, arg);
379 		case B_MULTI_GET_BUFFERS:			return get_buffers(cookie, arg);
380 		case B_MULTI_SET_BUFFERS:			return B_ERROR;
381 		case B_MULTI_SET_START_TIME:		return B_ERROR;
382 		case B_MULTI_BUFFER_EXCHANGE:		return buffer_exchange(cookie, arg);
383 		case B_MULTI_BUFFER_FORCE_STOP:		return buffer_force_stop(cookie);
384 	}
385 
386 	dprintf("null_audio: %s - unknown op\n" , __func__);
387 	return B_BAD_VALUE;
388 }
389 
390