2 * Copyright 2007-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Bek, host.haiku@gmx.de
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
16 format_to_sample_size(uint32 format
)
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
},
49 get_description(void* cookie
, multi_description
* data
)
51 multi_description description
;
53 dprintf("null_audio: %s\n" , __func__
);
55 if (user_memcpy(&description
, data
, sizeof(multi_description
)) != B_OK
) {
59 description
.interface_version
= B_CURRENT_INTERFACE_VERSION
;
60 description
.interface_minimum
= B_CURRENT_INTERFACE_VERSION
;
62 strcpy(description
.friendly_name
,"Virtual audio (null_audio)");
63 strcpy(description
.vendor_info
,"Host/Haiku");
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;
71 description
.output_rates
= B_SR_44100
;
72 description
.input_rates
= B_SR_44100
;
74 description
.max_cvsr_rate
= 0;
75 description
.min_cvsr_rate
= 0;
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;
84 strcpy(description
.control_panel
,"");
86 if (user_memcpy(data
, &description
, sizeof(multi_description
)) != B_OK
)
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
)
101 get_enabled_channels(void* cookie
, multi_channel_enable
* data
)
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);
115 set_global_format(device_t
* device
, multi_format_info
* data
)
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
;
123 device
->record_stream
.format
= data
->input
.format
;
124 device
->record_stream
.rate
= data
->input
.rate
;
131 get_global_format(device_t
* device
, multi_format_info
* data
)
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;
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
;
150 create_group_control(multi_mix_control
* multi
, int32 idx
, int32 parent
,
151 int32 string
, const char* name
)
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
;
159 strcpy(multi
->name
, name
);
166 list_mix_controls(device_t
* device
, multi_mix_control_info
* data
)
169 dprintf("null_audio: %s\n" , __func__
);
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;
180 list_mix_connections(void* cookie
, multi_mix_connection_info
* connection_info
)
182 dprintf("null_audio: %s\n" , __func__
);
188 list_mix_channels(void* cookie
, multi_mix_channel_info
* channel_info
)
190 dprintf("null_audio: %s\n" , __func__
);
196 get_buffers(device_t
* device
, multi_buffer_list
* data
)
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
);
205 dprintf("null_audio: %s\n" , __func__
);
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
;
215 if (data
->request_record_buffers
> STRMAXBUF
216 || data
->request_record_buffers
< STRMINBUF
) {
217 data
->request_record_buffers
= STRMINBUF
;
220 if (data
->request_playback_buffer_size
== 0)
221 data
->request_playback_buffer_size
= FRAMES_PER_BUFFER
;
223 if (data
->request_record_buffer_size
== 0)
224 data
->request_record_buffer_size
= FRAMES_PER_BUFFER
;
226 // ... from here on, we can assume again that
227 // a reasonable request is being made
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
));
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
));
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
;
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
;
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
;
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
;
287 buffer_exchange(device_t
* device
, multi_buffer_info
* info
)
289 //dprintf("null_audio: %s\n" , __func__ );
290 static int debug_buffers_exchanged
= 0;
294 multi_buffer_info buffer_info
;
295 if (user_memcpy(&buffer_info
, info
, sizeof(multi_buffer_info
)) != B_OK
)
296 return B_BAD_ADDRESS
;
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
);
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__
);
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__
);
315 status
= disable_interrupts();
316 acquire_spinlock(&device
->playback_stream
.lock
);
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
;
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
;
326 release_spinlock(&device
->playback_stream
.lock
);
327 restore_interrupts(status
);
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
);
335 if (user_memcpy(info
, &buffer_info
, sizeof(multi_buffer_info
)) != B_OK
)
336 return B_BAD_ADDRESS
;
343 buffer_force_stop(device_t
* device
)
345 dprintf("null_audio: %s\n" , __func__
);
347 if (device
&& device
->running
)
348 null_stop_hardware(device
);
350 delete_area(device
->playback_stream
.buffer_area
);
351 delete_area(device
->record_stream
.buffer_area
);
353 delete_sem(device
->playback_stream
.buffer_ready_sem
);
354 delete_sem(device
->record_stream
.buffer_ready_sem
);
361 multi_audio_control(void* cookie
, uint32 op
, void* arg
, size_t len
)
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
);
386 dprintf("null_audio: %s - unknown op\n" , __func__
);