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