1 /* 2 * Copyright (c) 2002-2007, Jerome Duval (jerome.duval@free.fr) 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "MultiAudioDevice.h" 8 9 #include <errno.h> 10 #include <string.h> 11 12 #include <MediaDefs.h> 13 14 #include "debug.h" 15 #include "MultiAudioUtility.h" 16 17 18 using namespace MultiAudio; 19 20 21 MultiAudioDevice::MultiAudioDevice(const char* name, const char* path) 22 { 23 CALLED(); 24 25 strlcpy(fPath, path, B_PATH_NAME_LENGTH); 26 PRINT(("name: %s, path: %s\n", name, fPath)); 27 28 fInitStatus = _InitDriver(); 29 } 30 31 32 MultiAudioDevice::~MultiAudioDevice() 33 { 34 CALLED(); 35 if (fDevice >= 0) 36 close(fDevice); 37 } 38 39 40 status_t 41 MultiAudioDevice::InitCheck() const 42 { 43 CALLED(); 44 return fInitStatus; 45 } 46 47 48 status_t 49 MultiAudioDevice::BufferExchange(multi_buffer_info *info) 50 { 51 return buffer_exchange(fDevice, info); 52 } 53 54 55 status_t 56 MultiAudioDevice::SetMix(multi_mix_value_info *info) 57 { 58 return set_mix(fDevice, info); 59 } 60 61 62 status_t 63 MultiAudioDevice::GetMix(multi_mix_value_info *info) 64 { 65 return get_mix(fDevice, info); 66 } 67 68 69 status_t 70 MultiAudioDevice::SetInputFrameRate(uint32 multiAudioRate) 71 { 72 if ((fDescription.input_rates & multiAudioRate) == 0) 73 return B_BAD_VALUE; 74 75 if (fFormatInfo.input.rate == multiAudioRate) 76 return B_OK; 77 78 uint32 oldRate = fFormatInfo.input.rate; 79 fFormatInfo.input.rate = multiAudioRate; 80 81 status_t status = set_global_format(fDevice, &fFormatInfo); 82 if (status != B_OK) { 83 fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n", 84 strerror(status)); 85 fFormatInfo.input.rate = oldRate; 86 return status; 87 } 88 89 return _GetBuffers(); 90 } 91 92 93 status_t 94 MultiAudioDevice::SetOutputFrameRate(uint32 multiAudioRate) 95 { 96 if ((fDescription.output_rates & multiAudioRate) == 0) 97 return B_BAD_VALUE; 98 99 if (fFormatInfo.output.rate == multiAudioRate) 100 return B_OK; 101 102 uint32 oldRate = fFormatInfo.output.rate; 103 fFormatInfo.output.rate = multiAudioRate; 104 105 status_t status = set_global_format(fDevice, &fFormatInfo); 106 if (status != B_OK) { 107 fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n", 108 strerror(status)); 109 fFormatInfo.output.rate = oldRate; 110 return status; 111 } 112 113 return _GetBuffers(); 114 } 115 116 117 status_t 118 MultiAudioDevice::_InitDriver() 119 { 120 int num_outputs, num_inputs, num_channels; 121 122 CALLED(); 123 124 // open the device driver 125 126 fDevice = open(fPath, O_WRONLY); 127 if (fDevice == -1) { 128 fprintf(stderr, "Failed to open %s: %s\n", fPath, strerror(errno)); 129 return B_ERROR; 130 } 131 132 // Get description 133 134 fDescription.info_size = sizeof(fDescription); 135 fDescription.request_channel_count = MAX_CHANNELS; 136 fDescription.channels = fChannelInfo; 137 status_t status = get_description(fDevice, &fDescription); 138 if (status != B_OK) { 139 fprintf(stderr, "Failed on B_MULTI_GET_DESCRIPTION: %s\n", 140 strerror(status)); 141 return status; 142 } 143 144 PRINT(("Friendly name:\t%s\nVendor:\t\t%s\n", 145 fDescription.friendly_name, fDescription.vendor_info)); 146 PRINT(("%ld outputs\t%ld inputs\n%ld out busses\t%ld in busses\n", 147 fDescription.output_channel_count, fDescription.input_channel_count, 148 fDescription.output_bus_channel_count, 149 fDescription.input_bus_channel_count)); 150 PRINT(("\nChannels\n" 151 "ID\tKind\tDesig\tConnectors\n")); 152 153 for (int32 i = 0; i < fDescription.output_channel_count 154 + fDescription.input_channel_count; i++) { 155 PRINT(("%ld\t%d\t0x%lx\t0x%lx\n", fDescription.channels[i].channel_id, 156 fDescription.channels[i].kind, 157 fDescription.channels[i].designations, 158 fDescription.channels[i].connectors)); 159 } 160 PRINT(("\n")); 161 162 PRINT(("Output rates\t\t0x%lx\n", fDescription.output_rates)); 163 PRINT(("Input rates\t\t0x%lx\n", fDescription.input_rates)); 164 PRINT(("Max CVSR\t\t%.0f\n", fDescription.max_cvsr_rate)); 165 PRINT(("Min CVSR\t\t%.0f\n", fDescription.min_cvsr_rate)); 166 PRINT(("Output formats\t\t0x%lx\n", fDescription.output_formats)); 167 PRINT(("Input formats\t\t0x%lx\n", fDescription.input_formats)); 168 PRINT(("Lock sources\t\t0x%lx\n", fDescription.lock_sources)); 169 PRINT(("Timecode sources\t0x%lx\n", fDescription.timecode_sources)); 170 PRINT(("Interface flags\t\t0x%lx\n", fDescription.interface_flags)); 171 PRINT(("Control panel string:\t\t%s\n", fDescription.control_panel)); 172 PRINT(("\n")); 173 174 num_outputs = fDescription.output_channel_count; 175 num_inputs = fDescription.input_channel_count; 176 num_channels = num_outputs + num_inputs; 177 178 // Get and set enabled channels 179 180 multi_channel_enable enable; 181 uint32 enableBits; 182 enable.info_size = sizeof(enable); 183 enable.enable_bits = (uchar*)&enableBits; 184 185 status = get_enabled_channels(fDevice, &enable); 186 if (status != B_OK) { 187 fprintf(stderr, "Failed on B_MULTI_GET_ENABLED_CHANNELS: %s\n", 188 strerror(status)); 189 return status; 190 } 191 192 enableBits = (1 << num_channels) - 1; 193 enable.lock_source = B_MULTI_LOCK_INTERNAL; 194 195 status = set_enabled_channels(fDevice, &enable); 196 if (status != B_OK) { 197 fprintf(stderr, "Failed on B_MULTI_SET_ENABLED_CHANNELS 0x%x: %s\n", 198 *enable.enable_bits, strerror(status)); 199 return status; 200 } 201 202 // Set the sample rate 203 204 fFormatInfo.info_size = sizeof(multi_format_info); 205 fFormatInfo.output.rate = select_sample_rate(fDescription.output_rates); 206 fFormatInfo.output.cvsr = 0; 207 fFormatInfo.output.format = select_format(fDescription.output_formats); 208 fFormatInfo.input.rate = select_sample_rate(fDescription.input_rates); 209 fFormatInfo.input.cvsr = fFormatInfo.output.cvsr; 210 fFormatInfo.input.format = select_format(fDescription.input_formats); 211 212 status = set_global_format(fDevice, &fFormatInfo); 213 if (status != B_OK) { 214 fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n", 215 strerror(status)); 216 } 217 218 status = get_global_format(fDevice, &fFormatInfo); 219 if (status != B_OK) { 220 fprintf(stderr, "Failed on B_MULTI_GET_GLOBAL_FORMAT: %s\n", 221 strerror(status)); 222 return status; 223 } 224 225 // Get the buffers 226 status = _GetBuffers(); 227 if (status != B_OK) 228 return status; 229 230 231 fMixControlInfo.info_size = sizeof(fMixControlInfo); 232 fMixControlInfo.control_count = MAX_CONTROLS; 233 fMixControlInfo.controls = fMixControl; 234 235 status = list_mix_controls(fDevice, &fMixControlInfo); 236 if (status != B_OK) { 237 fprintf(stderr, "Failed on DRIVER_LIST_MIX_CONTROLS: %s\n", 238 strerror(status)); 239 return status; 240 } 241 242 return B_OK; 243 } 244 245 246 status_t 247 MultiAudioDevice::_GetBuffers() 248 { 249 for (uint32 i = 0; i < MAX_BUFFERS; i++) { 250 fPlayBuffers[i] = &fPlayBufferList[i * MAX_CHANNELS]; 251 fRecordBuffers[i] = &fRecordBufferList[i * MAX_CHANNELS]; 252 } 253 fBufferList.info_size = sizeof(multi_buffer_list); 254 fBufferList.request_playback_buffer_size = 0; 255 // use the default... 256 fBufferList.request_playback_buffers = MAX_BUFFERS; 257 fBufferList.request_playback_channels = fDescription.output_channel_count; 258 fBufferList.playback_buffers = (buffer_desc **) fPlayBuffers; 259 fBufferList.request_record_buffer_size = 0; 260 // use the default... 261 fBufferList.request_record_buffers = MAX_BUFFERS; 262 fBufferList.request_record_channels = fDescription.input_channel_count; 263 fBufferList.record_buffers = /*(buffer_desc **)*/ fRecordBuffers; 264 265 status_t status = get_buffers(fDevice, &fBufferList); 266 if (status != B_OK) { 267 fprintf(stderr, "Failed on B_MULTI_GET_BUFFERS: %s\n", 268 strerror(status)); 269 return status; 270 } 271 272 for (int32 i = 0; i < fBufferList.return_playback_buffers; i++) { 273 for (int32 j = 0; j < fBufferList.return_playback_channels; j++) { 274 PRINT(("fBufferList.playback_buffers[%ld][%ld].base: %p\n", 275 i, j, fBufferList.playback_buffers[i][j].base)); 276 PRINT(("fBufferList.playback_buffers[%ld][%ld].stride: %li\n", 277 i, j, fBufferList.playback_buffers[i][j].stride)); 278 } 279 } 280 281 for (int32 i = 0; i < fBufferList.return_record_buffers; i++) { 282 for (int32 j = 0; j < fBufferList.return_record_channels; j++) { 283 PRINT(("fBufferList.record_buffers[%ld][%ld].base: %p\n", 284 i, j, fBufferList.record_buffers[i][j].base)); 285 PRINT(("fBufferList.record_buffers[%ld][%ld].stride: %li\n", 286 i, j, fBufferList.record_buffers[i][j].stride)); 287 } 288 } 289 290 return B_OK; 291 } 292