#include "MultiAudioDevice.h"
#include <errno.h>
#include <string.h>
#include <MediaDefs.h>
#include "debug.h"
#include "MultiAudioUtility.h"
using namespace MultiAudio;
MultiAudioDevice::MultiAudioDevice(const char* name, const char* path)
{
CALLED();
strlcpy(fPath, path, B_PATH_NAME_LENGTH);
PRINT(("name: %s, path: %s\n", name, fPath));
fInitStatus = _InitDriver();
}
MultiAudioDevice::~MultiAudioDevice()
{
CALLED();
if (fDevice >= 0)
close(fDevice);
}
status_t
MultiAudioDevice::InitCheck() const
{
CALLED();
return fInitStatus;
}
status_t
MultiAudioDevice::BufferExchange(multi_buffer_info *info)
{
return buffer_exchange(fDevice, info);
}
status_t
MultiAudioDevice::SetMix(multi_mix_value_info *info)
{
return set_mix(fDevice, info);
}
status_t
MultiAudioDevice::GetMix(multi_mix_value_info *info)
{
return get_mix(fDevice, info);
}
status_t
MultiAudioDevice::SetInputFrameRate(uint32 multiAudioRate)
{
if ((fDescription.input_rates & multiAudioRate) == 0)
return B_BAD_VALUE;
if (fFormatInfo.input.rate == multiAudioRate)
return B_OK;
uint32 oldRate = fFormatInfo.input.rate;
fFormatInfo.input.rate = multiAudioRate;
status_t status = set_global_format(fDevice, &fFormatInfo);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
strerror(status));
fFormatInfo.input.rate = oldRate;
return status;
}
return _GetBuffers();
}
status_t
MultiAudioDevice::SetOutputFrameRate(uint32 multiAudioRate)
{
if ((fDescription.output_rates & multiAudioRate) == 0)
return B_BAD_VALUE;
if (fFormatInfo.output.rate == multiAudioRate)
return B_OK;
uint32 oldRate = fFormatInfo.output.rate;
fFormatInfo.output.rate = multiAudioRate;
status_t status = set_global_format(fDevice, &fFormatInfo);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
strerror(status));
fFormatInfo.output.rate = oldRate;
return status;
}
return _GetBuffers();
}
status_t
MultiAudioDevice::_InitDriver()
{
int num_outputs, num_inputs, num_channels;
CALLED();
fDevice = open(fPath, O_WRONLY);
if (fDevice == -1) {
fprintf(stderr, "Failed to open %s: %s\n", fPath, strerror(errno));
return B_ERROR;
}
fDescription.info_size = sizeof(fDescription);
fDescription.request_channel_count = MAX_CHANNELS;
fDescription.channels = fChannelInfo;
status_t status = get_description(fDevice, &fDescription);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_GET_DESCRIPTION: %s\n",
strerror(status));
return status;
}
PRINT(("Friendly name:\t%s\nVendor:\t\t%s\n",
fDescription.friendly_name, fDescription.vendor_info));
PRINT(("%" B_PRId32 " outputs\t%" B_PRId32 " inputs\n%" B_PRId32
" out busses\t%" B_PRId32 " in busses\n",
fDescription.output_channel_count, fDescription.input_channel_count,
fDescription.output_bus_channel_count,
fDescription.input_bus_channel_count));
PRINT(("\nChannels\n"
"ID\tKind\tDesig\tConnectors\n"));
for (int32 i = 0; i < fDescription.output_channel_count
+ fDescription.input_channel_count; i++) {
PRINT(("%" B_PRId32 "\t%d\t0x%" B_PRIx32 "\t0x%" B_PRIx32 "\n",
fDescription.channels[i].channel_id,
fDescription.channels[i].kind,
fDescription.channels[i].designations,
fDescription.channels[i].connectors));
}
PRINT(("\n"));
PRINT(("Output rates\t\t0x%" B_PRIx32 "\n", fDescription.output_rates));
PRINT(("Input rates\t\t0x%" B_PRIx32 "\n", fDescription.input_rates));
PRINT(("Max CVSR\t\t%.0f\n", fDescription.max_cvsr_rate));
PRINT(("Min CVSR\t\t%.0f\n", fDescription.min_cvsr_rate));
PRINT(("Output formats\t\t0x%" B_PRIx32 "\n", fDescription.output_formats));
PRINT(("Input formats\t\t0x%" B_PRIx32 "\n", fDescription.input_formats));
PRINT(("Lock sources\t\t0x%" B_PRIx32 "\n", fDescription.lock_sources));
PRINT(("Timecode sources\t0x%" B_PRIx32 "\n", fDescription.timecode_sources));
PRINT(("Interface flags\t\t0x%" B_PRIx32 "\n", fDescription.interface_flags));
PRINT(("Control panel string:\t\t%s\n", fDescription.control_panel));
PRINT(("\n"));
num_outputs = fDescription.output_channel_count;
num_inputs = fDescription.input_channel_count;
num_channels = num_outputs + num_inputs;
multi_channel_enable enable;
uint32 enableBits;
enable.info_size = sizeof(enable);
enable.enable_bits = (uchar*)&enableBits;
status = get_enabled_channels(fDevice, &enable);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_GET_ENABLED_CHANNELS: %s\n",
strerror(status));
return status;
}
enableBits = (1 << num_channels) - 1;
enable.lock_source = B_MULTI_LOCK_INTERNAL;
status = set_enabled_channels(fDevice, &enable);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_SET_ENABLED_CHANNELS 0x%x: %s\n",
*enable.enable_bits, strerror(status));
return status;
}
fFormatInfo.info_size = sizeof(multi_format_info);
fFormatInfo.output.rate = select_sample_rate(fDescription.output_rates);
fFormatInfo.output.cvsr = 0;
fFormatInfo.output.format = select_format(fDescription.output_formats);
fFormatInfo.input.rate = select_sample_rate(fDescription.input_rates);
fFormatInfo.input.cvsr = fFormatInfo.output.cvsr;
fFormatInfo.input.format = select_format(fDescription.input_formats);
status = set_global_format(fDevice, &fFormatInfo);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_SET_GLOBAL_FORMAT: %s\n",
strerror(status));
}
status = get_global_format(fDevice, &fFormatInfo);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_GET_GLOBAL_FORMAT: %s\n",
strerror(status));
return status;
}
status = _GetBuffers();
if (status != B_OK)
return status;
fMixControlInfo.info_size = sizeof(fMixControlInfo);
fMixControlInfo.control_count = MAX_CONTROLS;
fMixControlInfo.controls = fMixControl;
status = list_mix_controls(fDevice, &fMixControlInfo);
if (status != B_OK) {
fprintf(stderr, "Failed on DRIVER_LIST_MIX_CONTROLS: %s\n",
strerror(status));
return status;
}
return B_OK;
}
status_t
MultiAudioDevice::_GetBuffers()
{
for (uint32 i = 0; i < MAX_BUFFERS; i++) {
fPlayBuffers[i] = &fPlayBufferList[i * MAX_CHANNELS];
fRecordBuffers[i] = &fRecordBufferList[i * MAX_CHANNELS];
}
fBufferList.info_size = sizeof(multi_buffer_list);
fBufferList.request_playback_buffer_size = 0;
fBufferList.request_playback_buffers = MAX_BUFFERS;
fBufferList.request_playback_channels = fDescription.output_channel_count;
fBufferList.playback_buffers = (buffer_desc **) fPlayBuffers;
fBufferList.request_record_buffer_size = 0;
fBufferList.request_record_buffers = MAX_BUFFERS;
fBufferList.request_record_channels = fDescription.input_channel_count;
fBufferList.record_buffers = fRecordBuffers;
status_t status = get_buffers(fDevice, &fBufferList);
if (status != B_OK) {
fprintf(stderr, "Failed on B_MULTI_GET_BUFFERS: %s\n",
strerror(status));
return status;
}
for (int32 i = 0; i < fBufferList.return_playback_buffers; i++) {
for (int32 j = 0; j < fBufferList.return_playback_channels; j++) {
PRINT(("fBufferList.playback_buffers[%" B_PRId32 "][%" B_PRId32
"].base: %p\n",
i, j, fBufferList.playback_buffers[i][j].base));
PRINT(("fBufferList.playback_buffers[%" B_PRId32 "][%" B_PRId32
"].stride: %li\n",
i, j, fBufferList.playback_buffers[i][j].stride));
}
}
for (int32 i = 0; i < fBufferList.return_record_buffers; i++) {
for (int32 j = 0; j < fBufferList.return_record_channels; j++) {
PRINT(("fBufferList.record_buffers[%" B_PRId32 "][%" B_PRId32
"].base: %p\n",
i, j, fBufferList.record_buffers[i][j].base));
PRINT(("fBufferList.record_buffers[%" B_PRId32 "][%" B_PRId32
"].stride: %li\n",
i, j, fBufferList.record_buffers[i][j].stride));
}
}
return B_OK;
}