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 ((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 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 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 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 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 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 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 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 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 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 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 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