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
format_to_sample_size(uint32 format)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
get_description(void * cookie,multi_description * data)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 ((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
99 static status_t
get_enabled_channels(void * cookie,multi_channel_enable * data)100 get_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
113 static status_t
set_global_format(device_t * device,multi_format_info * data)114 set_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
129 static status_t
get_global_format(device_t * device,multi_format_info * data)130 get_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
148 static int32
create_group_control(multi_mix_control * multi,int32 idx,int32 parent,int32 string,const char * name)149 create_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
164 static status_t
list_mix_controls(device_t * device,multi_mix_control_info * data)165 list_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
177 static status_t
list_mix_connections(void * cookie,multi_mix_connection_info * connection_info)178 list_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
185 static status_t
list_mix_channels(void * cookie,multi_mix_channel_info * channel_info)186 list_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
193 static status_t
get_buffers(device_t * device,multi_buffer_list * data)194 get_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
279 static status_t
buffer_exchange(device_t * device,multi_buffer_info * info)280 buffer_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
335 static status_t
buffer_force_stop(device_t * device)336 buffer_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
356 status_t
multi_audio_control(void * cookie,uint32 op,void * arg,size_t len)357 multi_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