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