#include "MixerOutput.h"
#include <MediaNode.h>
#include "MixerCore.h"
#include "MixerDebug.h"
#include "MixerUtils.h"
MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
:
fCore(core),
fOutput(output),
fOutputChannelCount(0),
fOutputChannelInfo(0),
fOutputByteSwap(0),
fMuted(false)
{
fix_multiaudio_format(&fOutput.format.u.raw_audio);
PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput);
PRINT_CHANNEL_MASK(fOutput.format);
UpdateOutputChannels();
UpdateByteOrderSwap();
}
MixerOutput::~MixerOutput()
{
delete fOutputChannelInfo;
delete fOutputByteSwap;
}
media_output &
MixerOutput::MediaOutput()
{
return fOutput;
}
void
MixerOutput::ChangeFormat(const media_multi_audio_format &format)
{
fOutput.format.u.raw_audio = format;
fix_multiaudio_format(&fOutput.format.u.raw_audio);
PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput);
PRINT_CHANNEL_MASK(fOutput.format);
UpdateOutputChannels();
UpdateByteOrderSwap();
}
void
MixerOutput::UpdateByteOrderSwap()
{
delete fOutputByteSwap;
fOutputByteSwap = 0;
if (fOutput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
if ( fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
|| fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
|| fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
fOutputByteSwap = new ByteSwap(fOutput.format.u.raw_audio.format);
}
}
}
void
MixerOutput::UpdateOutputChannels()
{
output_chan_info *oldInfo = fOutputChannelInfo;
int oldCount = fOutputChannelCount;
fOutputChannelCount = fOutput.format.u.raw_audio.channel_count;
fOutputChannelInfo = new output_chan_info[fOutputChannelCount];
for (int i = 0; i < fOutputChannelCount; i++) {
fOutputChannelInfo[i].channel_type = GetChannelType(i, fOutput.format.u.raw_audio.channel_mask);
fOutputChannelInfo[i].channel_gain = 1.0;
fOutputChannelInfo[i].source_count = 1;
fOutputChannelInfo[i].source_gain[0] = 1.0;
fOutputChannelInfo[i].source_type[0] = fOutputChannelInfo[i].channel_type;
for (int j = 0; j < MAX_CHANNEL_TYPES; j++)
fOutputChannelInfo[i].source_gain_cache[j] = 0.0;
}
AssignDefaultSources();
if (oldInfo != 0 && oldCount != 0) {
for (int i = 0; i < fOutputChannelCount; i++) {
for (int j = 0; j < oldCount; j++) {
if (fOutputChannelInfo[i].channel_type == oldInfo[j].channel_type) {
fOutputChannelInfo[i].channel_gain = oldInfo[j].channel_gain;
fOutputChannelInfo[i].source_count = oldInfo[j].source_count;
for (int k = 0; k < fOutputChannelInfo[i].source_count; k++) {
fOutputChannelInfo[i].source_gain[k] = oldInfo[j].source_gain[k];
fOutputChannelInfo[i].source_type[k] = oldInfo[j].source_type[k];
}
for (int k = 0; k < MAX_CHANNEL_TYPES; k++)
fOutputChannelInfo[i].source_gain_cache[k] = oldInfo[j].source_gain_cache[k];
break;
}
}
}
delete [] oldInfo;
}
for (int i = 0; i < fOutputChannelCount; i++)
TRACE("UpdateOutputChannels: output channel %d, type %2d, gain %.3f\n", i, fOutputChannelInfo[i].channel_type, fOutputChannelInfo[i].channel_gain);
}
void
MixerOutput::AssignDefaultSources()
{
uint32 mask = fOutput.format.u.raw_audio.channel_mask;
int count = fOutputChannelCount;
if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
TRACE("AssignDefaultSources: 1 channel setup\n");
fOutputChannelInfo[0].source_count = 9;
fOutputChannelInfo[0].source_gain[0] = 1.0;
fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
fOutputChannelInfo[0].source_gain[1] = 1.0;
fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
fOutputChannelInfo[0].source_gain[2] = 0.8;
fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
fOutputChannelInfo[0].source_gain[3] = 0.8;
fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
fOutputChannelInfo[0].source_gain[4] = 0.7;
fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
fOutputChannelInfo[0].source_gain[5] = 0.6;
fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[0].source_gain[6] = 1.0;
fOutputChannelInfo[0].source_type[6] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[0].source_gain[7] = 0.7;
fOutputChannelInfo[0].source_type[7] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
fOutputChannelInfo[0].source_gain[8] = 0.7;
fOutputChannelInfo[0].source_type[8] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
} else if (count == 2 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
TRACE("AssignDefaultSources: 2 channel setup\n");
fOutputChannelInfo[0].source_count = 6;
fOutputChannelInfo[0].source_gain[0] = 1.0;
fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
fOutputChannelInfo[0].source_gain[1] = 0.8;
fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
fOutputChannelInfo[0].source_gain[2] = 0.7;
fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
fOutputChannelInfo[0].source_gain[3] = 0.6;
fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[0].source_gain[4] = 1.0;
fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[0].source_gain[5] = 0.7;
fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
fOutputChannelInfo[1].source_count = 6;
fOutputChannelInfo[1].source_gain[0] = 1.0;
fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
fOutputChannelInfo[1].source_gain[1] = 0.8;
fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
fOutputChannelInfo[1].source_gain[2] = 0.7;
fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
fOutputChannelInfo[1].source_gain[3] = 0.6;
fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[1].source_gain[4] = 1.0;
fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[1].source_gain[5] = 0.7;
fOutputChannelInfo[1].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
} else if (count == 4 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT)) {
TRACE("AssignDefaultSources: 4 channel setup\n");
fOutputChannelInfo[0].source_count = 5;
fOutputChannelInfo[0].source_gain[0] = 1.0;
fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
fOutputChannelInfo[0].source_gain[1] = 0.7;
fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
fOutputChannelInfo[0].source_gain[2] = 0.6;
fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[0].source_gain[3] = 1.0;
fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[0].source_gain[4] = 0.6;
fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
fOutputChannelInfo[1].source_count = 5;
fOutputChannelInfo[1].source_gain[0] = 1.0;
fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
fOutputChannelInfo[1].source_gain[1] = 0.7;
fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
fOutputChannelInfo[1].source_gain[2] = 0.6;
fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[1].source_gain[3] = 1.0;
fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[1].source_gain[4] = 0.6;
fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
fOutputChannelInfo[2].source_count = 4;
fOutputChannelInfo[2].source_gain[0] = 1.0;
fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
fOutputChannelInfo[2].source_gain[1] = 0.6;
fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[2].source_gain[2] = 0.9;
fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[2].source_gain[3] = 0.6;
fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
fOutputChannelInfo[3].source_count = 4;
fOutputChannelInfo[3].source_gain[0] = 1.0;
fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
fOutputChannelInfo[3].source_gain[1] = 0.6;
fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[3].source_gain[2] = 0.9;
fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[3].source_gain[3] = 0.6;
fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
} else if (count == 5 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER)) {
TRACE("AssignDefaultSources: 5 channel setup\n");
fOutputChannelInfo[0].source_count = 4;
fOutputChannelInfo[0].source_gain[0] = 1.0;
fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
fOutputChannelInfo[0].source_gain[1] = 0.6;
fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[0].source_gain[2] = 1.0;
fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[0].source_gain[3] = 0.6;
fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
fOutputChannelInfo[1].source_count = 4;
fOutputChannelInfo[1].source_gain[0] = 1.0;
fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
fOutputChannelInfo[1].source_gain[1] = 0.6;
fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[1].source_gain[2] = 1.0;
fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[1].source_gain[3] = 0.6;
fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
fOutputChannelInfo[2].source_count = 4;
fOutputChannelInfo[2].source_gain[0] = 1.0;
fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
fOutputChannelInfo[2].source_gain[1] = 0.6;
fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[2].source_gain[2] = 0.9;
fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[2].source_gain[3] = 0.6;
fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
fOutputChannelInfo[3].source_count = 4;
fOutputChannelInfo[3].source_gain[0] = 1.0;
fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
fOutputChannelInfo[3].source_gain[1] = 0.6;
fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[3].source_gain[2] = 0.9;
fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[3].source_gain[3] = 0.6;
fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
fOutputChannelInfo[4].source_count = 3;
fOutputChannelInfo[4].source_gain[0] = 1.0;
fOutputChannelInfo[4].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
fOutputChannelInfo[4].source_gain[1] = 0.5;
fOutputChannelInfo[4].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
fOutputChannelInfo[4].source_gain[2] = 0.8;
fOutputChannelInfo[4].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
} else {
TRACE("AssignDefaultSources: no default setup, adding mono channel to first two channels\n");
if (count >= 1) {
fOutputChannelInfo[0].source_gain[fOutputChannelInfo[0].source_count] = 1.0;
fOutputChannelInfo[0].source_type[fOutputChannelInfo[0].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[0].source_count++;
}
if (count >= 2) {
fOutputChannelInfo[1].source_gain[fOutputChannelInfo[1].source_count] = 1.0;
fOutputChannelInfo[1].source_type[fOutputChannelInfo[1].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
fOutputChannelInfo[1].source_count++;
}
}
for (int i = 0; i < fOutputChannelCount; i++) {
for (int j = 0; j < fOutputChannelInfo[i].source_count; j++) {
TRACE("AssignDefaultSources: output channel %d, source index %d: source_type %2d, source_gain %.3f\n", i, j, fOutputChannelInfo[i].source_type[j], fOutputChannelInfo[i].source_gain[j]);
}
}
}
int
MixerOutput::GetOutputChannelType(int channel)
{
if (channel < 0 || channel >= fOutputChannelCount)
return 0;
return fOutputChannelInfo[channel].channel_type;
}
void
MixerOutput::SetOutputChannelGain(int channel, float gain)
{
TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain);
if (channel < 0 || channel >= fOutputChannelCount)
return;
fOutputChannelInfo[channel].channel_gain = gain;
}
void
MixerOutput::AddOutputChannelSource(int channel, int source_type)
{
if (channel < 0 || channel >= fOutputChannelCount)
return;
if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
return;
if (fOutputChannelInfo[channel].source_count == MAX_SOURCE_ENTRIES)
return;
for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
if (fOutputChannelInfo[channel].source_type[i] == source_type)
return;
}
float source_gain = fOutputChannelInfo[channel].source_gain_cache[source_type];
fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count] = source_type;
fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count] = source_gain;
fOutputChannelInfo[channel].source_count++;
}
void
MixerOutput::RemoveOutputChannelSource(int channel, int source_type)
{
if (channel < 0 || channel >= fOutputChannelCount)
return;
for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
if (fOutputChannelInfo[channel].source_type[i] == source_type) {
fOutputChannelInfo[channel].source_gain_cache[source_type] = fOutputChannelInfo[channel].source_gain[i];
fOutputChannelInfo[channel].source_type[i] = fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count - 1];
fOutputChannelInfo[channel].source_gain[i] = fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count - 1];
fOutputChannelInfo[channel].source_count--;
return;
}
}
}
void
MixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float source_gain)
{
if (channel < 0 || channel >= fOutputChannelCount)
return;
for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
if (fOutputChannelInfo[channel].source_type[i] == source_type) {
fOutputChannelInfo[channel].source_gain[i] = source_gain;
return;
}
}
if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
return;
fOutputChannelInfo[channel].source_gain_cache[source_type] = source_gain;
}
float
MixerOutput::GetOutputChannelSourceGain(int channel, int source_type)
{
if (channel < 0 || channel >= fOutputChannelCount)
return 0.0;
for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
if (fOutputChannelInfo[channel].source_type[i] == source_type) {
return fOutputChannelInfo[channel].source_gain[i];
}
}
if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
return 0.0;
return fOutputChannelInfo[channel].source_gain_cache[source_type];
}
bool
MixerOutput::HasOutputChannelSource(int channel, int source_type)
{
if (channel < 0 || channel >= fOutputChannelCount)
return false;
for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
if (fOutputChannelInfo[channel].source_type[i] == source_type) {
return true;
}
}
return false;
}
void
MixerOutput::SetMuted(bool yesno)
{
fMuted = yesno;
}