1be4e0101Sbeveloper/*
2f96df43fSJérôme Duval * Copyright (c) 2002-2007, Jerome Duval (jerome.duval@free.fr)
3f96df43fSJérôme Duval * Distributed under the terms of the MIT License.
4be4e0101Sbeveloper */
5f96df43fSJérôme Duval
65da3fbc8SAxel Dörfler
7be4e0101Sbeveloper#include "MultiAudioDevice.h"
85da3fbc8SAxel Dörfler
943404c50SJérôme Duval#include <errno.h>
10be4e0101Sbeveloper#include <string.h>
11be4e0101Sbeveloper
125da3fbc8SAxel Dörfler#include <MediaDefs.h>
13f616df6aSJérôme Duval
145da3fbc8SAxel Dörfler#include "debug.h"
155da3fbc8SAxel Dörfler#include "MultiAudioUtility.h"
16f616df6aSJérôme Duval
17f616df6aSJérôme Duval
185da3fbc8SAxel Dörflerusing namespace MultiAudio;
19be4e0101Sbeveloper
20f96df43fSJérôme Duval
215da3fbc8SAxel DörflerMultiAudioDevice::MultiAudioDevice(const char* name, const char* path)
22be4e0101Sbeveloper{
235da3fbc8SAxel Dörfler	CALLED();
24be4e0101Sbeveloper
255da3fbc8SAxel Dörfler	strlcpy(fPath, path, B_PATH_NAME_LENGTH);
265da3fbc8SAxel Dörfler	PRINT(("name: %s, path: %s\n", name, fPath));
27f96df43fSJérôme Duval
285da3fbc8SAxel Dörfler	fInitStatus = _InitDriver();
29be4e0101Sbeveloper}
30be4e0101Sbeveloper
31be4e0101Sbeveloper
32be4e0101SbeveloperMultiAudioDevice::~MultiAudioDevice()
33be4e0101Sbeveloper{
34be4e0101Sbeveloper	CALLED();
355da3fbc8SAxel Dörfler	if (fDevice >= 0)
365da3fbc8SAxel Dörfler		close(fDevice);
37be4e0101Sbeveloper}
38be4e0101Sbeveloper
39f96df43fSJérôme Duval
405da3fbc8SAxel Dörflerstatus_t
415da3fbc8SAxel DörflerMultiAudioDevice::InitCheck() const
42be4e0101Sbeveloper{
43be4e0101Sbeveloper	CALLED();
445da3fbc8SAxel Dörfler	return fInitStatus;
45be4e0101Sbeveloper}
46be4e0101Sbeveloper
47be4e0101Sbeveloper
48d473f576SIngo Weinholdstatus_t
49d473f576SIngo WeinholdMultiAudioDevice::BufferExchange(multi_buffer_info *info)
50d473f576SIngo Weinhold{
51d473f576SIngo Weinhold	return buffer_exchange(fDevice, info);
52d473f576SIngo Weinhold}
53d473f576SIngo Weinhold
54d473f576SIngo Weinhold
55d473f576SIngo Weinholdstatus_t
56d473f576SIngo WeinholdMultiAudioDevice::SetMix(multi_mix_value_info *info)
57d473f576SIngo Weinhold{
58d473f576SIngo Weinhold	return set_mix(fDevice, info);
59d473f576SIngo Weinhold}
60d473f576SIngo Weinhold
61d473f576SIngo Weinhold
62d473f576SIngo Weinholdstatus_t
63d473f576SIngo WeinholdMultiAudioDevice::GetMix(multi_mix_value_info *info)
64d473f576SIngo Weinhold{
65d473f576SIngo Weinhold	return get_mix(fDevice, info);
66d473f576SIngo Weinhold}
67d473f576SIngo Weinhold
68d473f576SIngo Weinhold
69d473f576SIngo Weinholdstatus_t
70d473f576SIngo WeinholdMultiAudioDevice::SetInputFrameRate(uint32 multiAudioRate)
71d473f576SIngo Weinhold{
72d473f576SIngo Weinhold	if ((fDescription.input_rates & multiAudioRate) == 0)
73d473f576SIngo Weinhold		return B_BAD_VALUE;
74d473f576SIngo Weinhold
75d473f576SIngo Weinhold	if (fFormatInfo.input.rate == multiAudioRate)
76d473f576SIngo Weinhold		return B_OK;
77d473f576SIngo Weinhold
78d473f576SIngo Weinhold	uint32 oldRate = fFormatInfo.input.rate;
79d473f576SIngo Weinhold	fFormatInfo.input.rate = multiAudioRate;
80d473f576SIngo Weinhold
81d473f576SIngo Weinhold	status_t status = set_global_format(fDevice, &fFormatInfo);
82d473f576SIngo Weinhold	if (status != B_OK) {
83d473f576SIngo Weinhold		fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
84d473f576SIngo Weinhold			strerror(status));
85d473f576SIngo Weinhold		fFormatInfo.input.rate = oldRate;
86d473f576SIngo Weinhold		return status;
87d473f576SIngo Weinhold	}
88d473f576SIngo Weinhold
89d473f576SIngo Weinhold	return _GetBuffers();
90d473f576SIngo Weinhold}
91d473f576SIngo Weinhold
92d473f576SIngo Weinhold
93d473f576SIngo Weinholdstatus_t
94d473f576SIngo WeinholdMultiAudioDevice::SetOutputFrameRate(uint32 multiAudioRate)
95d473f576SIngo Weinhold{
96d473f576SIngo Weinhold	if ((fDescription.output_rates & multiAudioRate) == 0)
97d473f576SIngo Weinhold		return B_BAD_VALUE;
98d473f576SIngo Weinhold
99d473f576SIngo Weinhold	if (fFormatInfo.output.rate == multiAudioRate)
100d473f576SIngo Weinhold		return B_OK;
101d473f576SIngo Weinhold
102d473f576SIngo Weinhold	uint32 oldRate = fFormatInfo.output.rate;
103d473f576SIngo Weinhold	fFormatInfo.output.rate = multiAudioRate;
104d473f576SIngo Weinhold
105d473f576SIngo Weinhold	status_t status = set_global_format(fDevice, &fFormatInfo);
106d473f576SIngo Weinhold	if (status != B_OK) {
107d473f576SIngo Weinhold		fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
108d473f576SIngo Weinhold			strerror(status));
109d473f576SIngo Weinhold		fFormatInfo.output.rate = oldRate;
110d473f576SIngo Weinhold		return status;
111d473f576SIngo Weinhold	}
112d473f576SIngo Weinhold
113d473f576SIngo Weinhold	return _GetBuffers();
114d473f576SIngo Weinhold}
115d473f576SIngo Weinhold
116d473f576SIngo Weinhold
1175da3fbc8SAxel Dörflerstatus_t
1185da3fbc8SAxel DörflerMultiAudioDevice::_InitDriver()
119be4e0101Sbeveloper{
1205da3fbc8SAxel Dörfler	int num_outputs, num_inputs, num_channels;
121f96df43fSJérôme Duval
122be4e0101Sbeveloper	CALLED();
123be4e0101Sbeveloper
1245da3fbc8SAxel Dörfler	// open the device driver
125be4e0101Sbeveloper
1265da3fbc8SAxel Dörfler	fDevice = open(fPath, O_WRONLY);
1275da3fbc8SAxel Dörfler	if (fDevice == -1) {
1285da3fbc8SAxel Dörfler		fprintf(stderr, "Failed to open %s: %s\n", fPath, strerror(errno));
129be4e0101Sbeveloper		return B_ERROR;
130be4e0101Sbeveloper	}
131f96df43fSJérôme Duval
132be4e0101Sbeveloper	// Get description
1335da3fbc8SAxel Dörfler
1345da3fbc8SAxel Dörfler	fDescription.info_size = sizeof(fDescription);
1355da3fbc8SAxel Dörfler	fDescription.request_channel_count = MAX_CHANNELS;
1365da3fbc8SAxel Dörfler	fDescription.channels = fChannelInfo;
1375da3fbc8SAxel Dörfler	status_t status = get_description(fDevice, &fDescription);
1385da3fbc8SAxel Dörfler	if (status != B_OK) {
1395da3fbc8SAxel Dörfler		fprintf(stderr, "Failed on B_MULTI_GET_DESCRIPTION: %s\n",
1405da3fbc8SAxel Dörfler			strerror(status));
1415da3fbc8SAxel Dörfler		return status;
142be4e0101Sbeveloper	}
143be4e0101Sbeveloper
144c8093d3cSJérôme Duval	PRINT(("Friendly name:\t%s\nVendor:\t\t%s\n",
1455da3fbc8SAxel Dörfler		fDescription.friendly_name, fDescription.vendor_info));
1461a7bcf69SOliver Tappe	PRINT(("%" B_PRId32 " outputs\t%" B_PRId32 " inputs\n%" B_PRId32
1471a7bcf69SOliver Tappe			" out busses\t%" B_PRId32 " in busses\n",
1485da3fbc8SAxel Dörfler		fDescription.output_channel_count, fDescription.input_channel_count,
1495da3fbc8SAxel Dörfler		fDescription.output_bus_channel_count,
1505da3fbc8SAxel Dörfler		fDescription.input_bus_channel_count));
151c8093d3cSJérôme Duval	PRINT(("\nChannels\n"
152f96df43fSJérôme Duval		"ID\tKind\tDesig\tConnectors\n"));
153be4e0101Sbeveloper
1545da3fbc8SAxel Dörfler	for (int32 i = 0; i < fDescription.output_channel_count
1555da3fbc8SAxel Dörfler			+ fDescription.input_channel_count; i++) {
1561a7bcf69SOliver Tappe		PRINT(("%" B_PRId32 "\t%d\t0x%" B_PRIx32 "\t0x%" B_PRIx32 "\n",
1571a7bcf69SOliver Tappe			fDescription.channels[i].channel_id,
1585da3fbc8SAxel Dörfler			fDescription.channels[i].kind,
1595da3fbc8SAxel Dörfler			fDescription.channels[i].designations,
1605da3fbc8SAxel Dörfler			fDescription.channels[i].connectors));
161f96df43fSJérôme Duval	}
162c8093d3cSJérôme Duval	PRINT(("\n"));
163f96df43fSJérôme Duval
1641a7bcf69SOliver Tappe	PRINT(("Output rates\t\t0x%" B_PRIx32 "\n", fDescription.output_rates));
1651a7bcf69SOliver Tappe	PRINT(("Input rates\t\t0x%" B_PRIx32 "\n", fDescription.input_rates));
1665da3fbc8SAxel Dörfler	PRINT(("Max CVSR\t\t%.0f\n", fDescription.max_cvsr_rate));
1675da3fbc8SAxel Dörfler	PRINT(("Min CVSR\t\t%.0f\n", fDescription.min_cvsr_rate));
1681a7bcf69SOliver Tappe	PRINT(("Output formats\t\t0x%" B_PRIx32 "\n", fDescription.output_formats));
1691a7bcf69SOliver Tappe	PRINT(("Input formats\t\t0x%" B_PRIx32 "\n", fDescription.input_formats));
1701a7bcf69SOliver Tappe	PRINT(("Lock sources\t\t0x%" B_PRIx32 "\n", fDescription.lock_sources));
1711a7bcf69SOliver Tappe	PRINT(("Timecode sources\t0x%" B_PRIx32 "\n", fDescription.timecode_sources));
1721a7bcf69SOliver Tappe	PRINT(("Interface flags\t\t0x%" B_PRIx32 "\n", fDescription.interface_flags));
1735da3fbc8SAxel Dörfler	PRINT(("Control panel string:\t\t%s\n", fDescription.control_panel));
174c8093d3cSJérôme Duval	PRINT(("\n"));
175f96df43fSJérôme Duval
1765da3fbc8SAxel Dörfler	num_outputs = fDescription.output_channel_count;
1775da3fbc8SAxel Dörfler	num_inputs = fDescription.input_channel_count;
178be4e0101Sbeveloper	num_channels = num_outputs + num_inputs;
179f96df43fSJérôme Duval
180be4e0101Sbeveloper	// Get and set enabled channels
1815da3fbc8SAxel Dörfler
1825da3fbc8SAxel Dörfler	multi_channel_enable enable;
1835da3fbc8SAxel Dörfler	uint32 enableBits;
1845da3fbc8SAxel Dörfler	enable.info_size = sizeof(enable);
1855da3fbc8SAxel Dörfler	enable.enable_bits = (uchar*)&enableBits;
1865da3fbc8SAxel Dörfler
1875da3fbc8SAxel Dörfler	status = get_enabled_channels(fDevice, &enable);
1885da3fbc8SAxel Dörfler	if (status != B_OK) {
1895da3fbc8SAxel Dörfler		fprintf(stderr, "Failed on B_MULTI_GET_ENABLED_CHANNELS: %s\n",
1905da3fbc8SAxel Dörfler			strerror(status));
1915da3fbc8SAxel Dörfler		return status;
192be4e0101Sbeveloper	}
193f96df43fSJérôme Duval
1945da3fbc8SAxel Dörfler	enableBits = (1 << num_channels) - 1;
1955da3fbc8SAxel Dörfler	enable.lock_source = B_MULTI_LOCK_INTERNAL;
1965da3fbc8SAxel Dörfler
1975da3fbc8SAxel Dörfler	status = set_enabled_channels(fDevice, &enable);
1985da3fbc8SAxel Dörfler	if (status != B_OK) {
1995da3fbc8SAxel Dörfler		fprintf(stderr, "Failed on B_MULTI_SET_ENABLED_CHANNELS 0x%x: %s\n",
2005da3fbc8SAxel Dörfler			*enable.enable_bits, strerror(status));
2015da3fbc8SAxel Dörfler		return status;
202be4e0101Sbeveloper	}
203f96df43fSJérôme Duval
204be4e0101Sbeveloper	// Set the sample rate
205f96df43fSJérôme Duval
2065da3fbc8SAxel Dörfler	fFormatInfo.info_size = sizeof(multi_format_info);
2075da3fbc8SAxel Dörfler	fFormatInfo.output.rate = select_sample_rate(fDescription.output_rates);
2085da3fbc8SAxel Dörfler	fFormatInfo.output.cvsr = 0;
2095da3fbc8SAxel Dörfler	fFormatInfo.output.format = select_format(fDescription.output_formats);
2105da3fbc8SAxel Dörfler	fFormatInfo.input.rate = select_sample_rate(fDescription.input_rates);
2115da3fbc8SAxel Dörfler	fFormatInfo.input.cvsr = fFormatInfo.output.cvsr;
2125da3fbc8SAxel Dörfler	fFormatInfo.input.format = select_format(fDescription.input_formats);
2135da3fbc8SAxel Dörfler
2145da3fbc8SAxel Dörfler	status = set_global_format(fDevice, &fFormatInfo);
2155da3fbc8SAxel Dörfler	if (status != B_OK) {
2165da3fbc8SAxel Dörfler		fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
2175da3fbc8SAxel Dörfler			strerror(status));
218c7116c91SJérôme Duval	}
2195da3fbc8SAxel Dörfler
2205da3fbc8SAxel Dörfler	status = get_global_format(fDevice, &fFormatInfo);
2215da3fbc8SAxel Dörfler	if (status != B_OK) {
2225da3fbc8SAxel Dörfler		fprintf(stderr, "Failed on B_MULTI_GET_GLOBAL_FORMAT: %s\n",
2235da3fbc8SAxel Dörfler			strerror(status));
2245da3fbc8SAxel Dörfler		return status;
225be4e0101Sbeveloper	}
226f96df43fSJérôme Duval
2275da3fbc8SAxel Dörfler	// Get the buffers
228d473f576SIngo Weinhold	status = _GetBuffers();
229d473f576SIngo Weinhold	if (status != B_OK)
230d473f576SIngo Weinhold		return status;
231f96df43fSJérôme Duval
232d473f576SIngo Weinhold
233d473f576SIngo Weinhold	fMixControlInfo.info_size = sizeof(fMixControlInfo);
234d473f576SIngo Weinhold	fMixControlInfo.control_count = MAX_CONTROLS;
235d473f576SIngo Weinhold	fMixControlInfo.controls = fMixControl;
236d473f576SIngo Weinhold
237d473f576SIngo Weinhold	status = list_mix_controls(fDevice, &fMixControlInfo);
238d473f576SIngo Weinhold	if (status != B_OK) {
239d473f576SIngo Weinhold		fprintf(stderr, "Failed on DRIVER_LIST_MIX_CONTROLS: %s\n",
240d473f576SIngo Weinhold			strerror(status));
241d473f576SIngo Weinhold		return status;
242d473f576SIngo Weinhold	}
243d473f576SIngo Weinhold
244d473f576SIngo Weinhold	return B_OK;
245d473f576SIngo Weinhold}
246d473f576SIngo Weinhold
247d473f576SIngo Weinhold
248d473f576SIngo Weinholdstatus_t
249d473f576SIngo WeinholdMultiAudioDevice::_GetBuffers()
250d473f576SIngo Weinhold{
2515da3fbc8SAxel Dörfler	for (uint32 i = 0; i < MAX_BUFFERS; i++) {
2525da3fbc8SAxel Dörfler		fPlayBuffers[i] = &fPlayBufferList[i * MAX_CHANNELS];
2535da3fbc8SAxel Dörfler		fRecordBuffers[i] = &fRecordBufferList[i * MAX_CHANNELS];
2545da3fbc8SAxel Dörfler	}
2555da3fbc8SAxel Dörfler	fBufferList.info_size = sizeof(multi_buffer_list);
2565da3fbc8SAxel Dörfler	fBufferList.request_playback_buffer_size = 0;
2575da3fbc8SAxel Dörfler		// use the default...
2585da3fbc8SAxel Dörfler	fBufferList.request_playback_buffers = MAX_BUFFERS;
259d473f576SIngo Weinhold	fBufferList.request_playback_channels = fDescription.output_channel_count;
2605da3fbc8SAxel Dörfler	fBufferList.playback_buffers = (buffer_desc **) fPlayBuffers;
2615da3fbc8SAxel Dörfler	fBufferList.request_record_buffer_size = 0;
2625da3fbc8SAxel Dörfler		// use the default...
2635da3fbc8SAxel Dörfler	fBufferList.request_record_buffers = MAX_BUFFERS;
264d473f576SIngo Weinhold	fBufferList.request_record_channels = fDescription.input_channel_count;
2655da3fbc8SAxel Dörfler	fBufferList.record_buffers = /*(buffer_desc **)*/ fRecordBuffers;
2665da3fbc8SAxel Dörfler
267d473f576SIngo Weinhold	status_t status = get_buffers(fDevice, &fBufferList);
2685da3fbc8SAxel Dörfler	if (status != B_OK) {
2695da3fbc8SAxel Dörfler		fprintf(stderr, "Failed on B_MULTI_GET_BUFFERS: %s\n",
2705da3fbc8SAxel Dörfler			strerror(status));
2715da3fbc8SAxel Dörfler		return status;
2725da3fbc8SAxel Dörfler	}
2735da3fbc8SAxel Dörfler
2745da3fbc8SAxel Dörfler	for (int32 i = 0; i < fBufferList.return_playback_buffers; i++) {
2755da3fbc8SAxel Dörfler		for (int32 j = 0; j < fBufferList.return_playback_channels; j++) {
2761a7bcf69SOliver Tappe			PRINT(("fBufferList.playback_buffers[%" B_PRId32 "][%" B_PRId32
2771a7bcf69SOliver Tappe					"].base: %p\n",
2785da3fbc8SAxel Dörfler				i, j, fBufferList.playback_buffers[i][j].base));
2791a7bcf69SOliver Tappe			PRINT(("fBufferList.playback_buffers[%" B_PRId32 "][%" B_PRId32
2801a7bcf69SOliver Tappe					"].stride: %li\n",
2815da3fbc8SAxel Dörfler				i, j, fBufferList.playback_buffers[i][j].stride));
282be4e0101Sbeveloper		}
2835da3fbc8SAxel Dörfler	}
284f96df43fSJérôme Duval
2855da3fbc8SAxel Dörfler	for (int32 i = 0; i < fBufferList.return_record_buffers; i++) {
2865da3fbc8SAxel Dörfler		for (int32 j = 0; j < fBufferList.return_record_channels; j++) {
2871a7bcf69SOliver Tappe			PRINT(("fBufferList.record_buffers[%" B_PRId32 "][%" B_PRId32
2881a7bcf69SOliver Tappe					"].base: %p\n",
2895da3fbc8SAxel Dörfler				i, j, fBufferList.record_buffers[i][j].base));
2901a7bcf69SOliver Tappe			PRINT(("fBufferList.record_buffers[%" B_PRId32 "][%" B_PRId32
2911a7bcf69SOliver Tappe					"].stride: %li\n",
2925da3fbc8SAxel Dörfler				i, j, fBufferList.record_buffers[i][j].stride));
2935da3fbc8SAxel Dörfler		}
2945da3fbc8SAxel Dörfler	}
295f96df43fSJérôme Duval
296be4e0101Sbeveloper	return B_OK;
297be4e0101Sbeveloper}
298