xref: /haiku/src/add-ons/media/media-add-ons/multi_audio/MultiAudioDevice.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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