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
18using namespace MultiAudio;
19
20
21MultiAudioDevice::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
32MultiAudioDevice::~MultiAudioDevice()
33{
34	CALLED();
35	if (fDevice >= 0)
36		close(fDevice);
37}
38
39
40status_t
41MultiAudioDevice::InitCheck() const
42{
43	CALLED();
44	return fInitStatus;
45}
46
47
48status_t
49MultiAudioDevice::BufferExchange(multi_buffer_info *info)
50{
51	return buffer_exchange(fDevice, info);
52}
53
54
55status_t
56MultiAudioDevice::SetMix(multi_mix_value_info *info)
57{
58	return set_mix(fDevice, info);
59}
60
61
62status_t
63MultiAudioDevice::GetMix(multi_mix_value_info *info)
64{
65	return get_mix(fDevice, info);
66}
67
68
69status_t
70MultiAudioDevice::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
93status_t
94MultiAudioDevice::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
117status_t
118MultiAudioDevice::_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
246status_t
247MultiAudioDevice::_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