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
MultiAudioDevice(const char * name,const char * path)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
~MultiAudioDevice()32 MultiAudioDevice::~MultiAudioDevice()
33 {
34 CALLED();
35 if (fDevice >= 0)
36 close(fDevice);
37 }
38
39
40 status_t
InitCheck() const41 MultiAudioDevice::InitCheck() const
42 {
43 CALLED();
44 return fInitStatus;
45 }
46
47
48 status_t
BufferExchange(multi_buffer_info * info)49 MultiAudioDevice::BufferExchange(multi_buffer_info *info)
50 {
51 return buffer_exchange(fDevice, info);
52 }
53
54
55 status_t
SetMix(multi_mix_value_info * info)56 MultiAudioDevice::SetMix(multi_mix_value_info *info)
57 {
58 return set_mix(fDevice, info);
59 }
60
61
62 status_t
GetMix(multi_mix_value_info * info)63 MultiAudioDevice::GetMix(multi_mix_value_info *info)
64 {
65 return get_mix(fDevice, info);
66 }
67
68
69 status_t
SetInputFrameRate(uint32 multiAudioRate)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
SetOutputFrameRate(uint32 multiAudioRate)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
_InitDriver()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
_GetBuffers()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