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(("%" B_PRId32 " outputs\t%" B_PRId32 " inputs\n%" B_PRId32 147 " out busses\t%" B_PRId32 " in busses\n", 148 fDescription.output_channel_count, fDescription.input_channel_count, 149 fDescription.output_bus_channel_count, 150 fDescription.input_bus_channel_count)); 151 PRINT(("\nChannels\n" 152 "ID\tKind\tDesig\tConnectors\n")); 153 154 for (int32 i = 0; i < fDescription.output_channel_count 155 + fDescription.input_channel_count; i++) { 156 PRINT(("%" B_PRId32 "\t%d\t0x%" B_PRIx32 "\t0x%" B_PRIx32 "\n", 157 fDescription.channels[i].channel_id, 158 fDescription.channels[i].kind, 159 fDescription.channels[i].designations, 160 fDescription.channels[i].connectors)); 161 } 162 PRINT(("\n")); 163 164 PRINT(("Output rates\t\t0x%" B_PRIx32 "\n", fDescription.output_rates)); 165 PRINT(("Input rates\t\t0x%" B_PRIx32 "\n", fDescription.input_rates)); 166 PRINT(("Max CVSR\t\t%.0f\n", fDescription.max_cvsr_rate)); 167 PRINT(("Min CVSR\t\t%.0f\n", fDescription.min_cvsr_rate)); 168 PRINT(("Output formats\t\t0x%" B_PRIx32 "\n", fDescription.output_formats)); 169 PRINT(("Input formats\t\t0x%" B_PRIx32 "\n", fDescription.input_formats)); 170 PRINT(("Lock sources\t\t0x%" B_PRIx32 "\n", fDescription.lock_sources)); 171 PRINT(("Timecode sources\t0x%" B_PRIx32 "\n", fDescription.timecode_sources)); 172 PRINT(("Interface flags\t\t0x%" B_PRIx32 "\n", fDescription.interface_flags)); 173 PRINT(("Control panel string:\t\t%s\n", fDescription.control_panel)); 174 PRINT(("\n")); 175 176 num_outputs = fDescription.output_channel_count; 177 num_inputs = fDescription.input_channel_count; 178 num_channels = num_outputs + num_inputs; 179 180 // Get and set enabled channels 181 182 multi_channel_enable enable; 183 uint32 enableBits; 184 enable.info_size = sizeof(enable); 185 enable.enable_bits = (uchar*)&enableBits; 186 187 status = get_enabled_channels(fDevice, &enable); 188 if (status != B_OK) { 189 fprintf(stderr, "Failed on B_MULTI_GET_ENABLED_CHANNELS: %s\n", 190 strerror(status)); 191 return status; 192 } 193 194 enableBits = (1 << num_channels) - 1; 195 enable.lock_source = B_MULTI_LOCK_INTERNAL; 196 197 status = set_enabled_channels(fDevice, &enable); 198 if (status != B_OK) { 199 fprintf(stderr, "Failed on B_MULTI_SET_ENABLED_CHANNELS 0x%x: %s\n", 200 *enable.enable_bits, strerror(status)); 201 return status; 202 } 203 204 // Set the sample rate 205 206 fFormatInfo.info_size = sizeof(multi_format_info); 207 fFormatInfo.output.rate = select_sample_rate(fDescription.output_rates); 208 fFormatInfo.output.cvsr = 0; 209 fFormatInfo.output.format = select_format(fDescription.output_formats); 210 fFormatInfo.input.rate = select_sample_rate(fDescription.input_rates); 211 fFormatInfo.input.cvsr = fFormatInfo.output.cvsr; 212 fFormatInfo.input.format = select_format(fDescription.input_formats); 213 214 status = set_global_format(fDevice, &fFormatInfo); 215 if (status != B_OK) { 216 fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n", 217 strerror(status)); 218 } 219 220 status = get_global_format(fDevice, &fFormatInfo); 221 if (status != B_OK) { 222 fprintf(stderr, "Failed on B_MULTI_GET_GLOBAL_FORMAT: %s\n", 223 strerror(status)); 224 return status; 225 } 226 227 // Get the buffers 228 status = _GetBuffers(); 229 if (status != B_OK) 230 return status; 231 232 233 fMixControlInfo.info_size = sizeof(fMixControlInfo); 234 fMixControlInfo.control_count = MAX_CONTROLS; 235 fMixControlInfo.controls = fMixControl; 236 237 status = list_mix_controls(fDevice, &fMixControlInfo); 238 if (status != B_OK) { 239 fprintf(stderr, "Failed on DRIVER_LIST_MIX_CONTROLS: %s\n", 240 strerror(status)); 241 return status; 242 } 243 244 return B_OK; 245 } 246 247 248 status_t 249 MultiAudioDevice::_GetBuffers() 250 { 251 for (uint32 i = 0; i < MAX_BUFFERS; i++) { 252 fPlayBuffers[i] = &fPlayBufferList[i * MAX_CHANNELS]; 253 fRecordBuffers[i] = &fRecordBufferList[i * MAX_CHANNELS]; 254 } 255 fBufferList.info_size = sizeof(multi_buffer_list); 256 fBufferList.request_playback_buffer_size = 0; 257 // use the default... 258 fBufferList.request_playback_buffers = MAX_BUFFERS; 259 fBufferList.request_playback_channels = fDescription.output_channel_count; 260 fBufferList.playback_buffers = (buffer_desc **) fPlayBuffers; 261 fBufferList.request_record_buffer_size = 0; 262 // use the default... 263 fBufferList.request_record_buffers = MAX_BUFFERS; 264 fBufferList.request_record_channels = fDescription.input_channel_count; 265 fBufferList.record_buffers = /*(buffer_desc **)*/ fRecordBuffers; 266 267 status_t status = get_buffers(fDevice, &fBufferList); 268 if (status != B_OK) { 269 fprintf(stderr, "Failed on B_MULTI_GET_BUFFERS: %s\n", 270 strerror(status)); 271 return status; 272 } 273 274 for (int32 i = 0; i < fBufferList.return_playback_buffers; i++) { 275 for (int32 j = 0; j < fBufferList.return_playback_channels; j++) { 276 PRINT(("fBufferList.playback_buffers[%" B_PRId32 "][%" B_PRId32 277 "].base: %p\n", 278 i, j, fBufferList.playback_buffers[i][j].base)); 279 PRINT(("fBufferList.playback_buffers[%" B_PRId32 "][%" B_PRId32 280 "].stride: %li\n", 281 i, j, fBufferList.playback_buffers[i][j].stride)); 282 } 283 } 284 285 for (int32 i = 0; i < fBufferList.return_record_buffers; i++) { 286 for (int32 j = 0; j < fBufferList.return_record_channels; j++) { 287 PRINT(("fBufferList.record_buffers[%" B_PRId32 "][%" B_PRId32 288 "].base: %p\n", 289 i, j, fBufferList.record_buffers[i][j].base)); 290 PRINT(("fBufferList.record_buffers[%" B_PRId32 "][%" B_PRId32 291 "].stride: %li\n", 292 i, j, fBufferList.record_buffers[i][j].stride)); 293 } 294 } 295 296 return B_OK; 297 } 298