diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp index 53c43700d0..a41c9d0faf 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -59,6 +59,8 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn) fDefaultFormat.u.raw_audio.channel_mask = 0; fDefaultFormat.u.raw_audio.valid_bits = 0; fDefaultFormat.u.raw_audio.matrix_mask = 0; + + ApplySettings(); } AudioMixer::~AudioMixer() @@ -80,6 +82,14 @@ AudioMixer::~AudioMixer() DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0); } +void +AudioMixer::ApplySettings() +{ + fCore->Lock(); + fCore->SetOutputAttenuation(fCore->Settings()->AttenuateOutput() ? 0.708 : 1.0); + fCore->Unlock(); +} + void AudioMixer::DisableNodeStop() { @@ -984,7 +994,53 @@ AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change, TRACE("GetParameterValue: id 0x%08x, ioSize %ld\n", id, *ioSize); int param = PARAM(id); fCore->Lock(); - if (param == 0) { + if (PARAM_IS_ETC(id)) { + switch (ETC(id)) { + case 10: // Attenuate mixer output by 3dB + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->AttenuateOutput(); + break; + case 20: // Use non linear gain sliders + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->NonLinearGainSlider(); + break; + case 30: // Display balance control for stereo connections + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->UseBalanceControl(); + break; + case 40: // Allow output channel remapping + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->AllowOutputChannelRemapping(); + break; + case 50: // Allow input channel remapping + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->AllowInputChannelRemapping(); + break; + case 60: // Input gain controls + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->InputGainControls(); + break; + case 70: // Resampling algorithm + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->ResamplingAlgorithm(); + break; + case 80: // Refuse output format changes + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->RefuseOutputFormatChange(); + break; + case 90: // Refuse input format changes + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->RefuseInputFormatChange(); + break; + case 100: // Display performance profiling data + *ioSize = sizeof(int32); + static_cast(value)[0] = fCore->Settings()->DisplayProfilingData(); + break; + default: + ERROR("unhandled ETC 0x%08lx\n", id); + break; + } + } else if (param == 0) { MixerOutput *output = fCore->Output(); if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id))) goto err; @@ -1060,7 +1116,74 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when, bool update = false; int param = PARAM(id); fCore->Lock(); - if (param == 0) { + if (PARAM_IS_ETC(id)) { + switch (ETC(id)) { + case 10: // Attenuate mixer output by 3dB + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetAttenuateOutput(static_cast(value)[0]); + // this value is special (see MixerCore.h) and we need to notify the core + fCore->SetOutputAttenuation((static_cast(value)[0]) ? 0.708 : 1.0); + break; + case 20: // Use non linear gain sliders + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetNonLinearGainSlider(static_cast(value)[0]); + update = true; // XXX should use BroadcastChangedParameter() + break; + case 30: // Display balance control for stereo connections + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetUseBalanceControl(static_cast(value)[0]); + update = true; + break; + case 40: // Allow output channel remapping + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetAllowOutputChannelRemapping(static_cast(value)[0]); + update = true; + break; + case 50: // Allow input channel remapping + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetAllowInputChannelRemapping(static_cast(value)[0]); + update = true; + break; + case 60: // Input gain controls represent + // (0, "Physical input channels") + // (1, "Virtual output channels") + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetInputGainControls(static_cast(value)[0]); + update = true; // XXX should use BroadcastChangedParameter() + break; + case 70: // Resampling algorithm + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetResamplingAlgorithm(static_cast(value)[0]); + // XXX tell the core to change the algorithm + break; + case 80: // Refuse output format changes + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetRefuseOutputFormatChange(static_cast(value)[0]); + break; + case 90: // Refuse input format changes + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetRefuseInputFormatChange(static_cast(value)[0]); + break; + case 100: // Display performance profiling data + if (size != sizeof(int32)) + goto err; + fCore->Settings()->SetDisplayProfilingData(static_cast(value)[0]); + // XXX tell the core to display it + break; + default: + ERROR("unhandled ETC 0x%08lx\n", id); + break; + } + } else if (param == 0) { MixerOutput *output = fCore->Output(); if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id))) goto err; @@ -1186,48 +1309,50 @@ AudioMixer::UpdateParameterWeb() ->SetChannelCount(in->GetMixerChannelCount()); group->MakeNullParameter(PARAM_STR3(in->ID()), B_MEDIA_RAW_AUDIO, "To Master", B_WEB_BUFFER_OUTPUT); } + + if (fCore->Settings()->AllowOutputChannelRemapping()) { + top = web->MakeGroup("Output Mapping"); // top level group + outputchannels = top->MakeGroup(""); + outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_GENERIC); - top = web->MakeGroup("Output Mapping"); // top level group - outputchannels = top->MakeGroup(""); - outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_GENERIC); - - group = outputchannels->MakeGroup(""); - group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, "Master Output", B_GENERIC); - group = group->MakeGroup(""); - if (!out) { - group->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC); - } else { - for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) { - subgroup = group->MakeGroup(""); - subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan), B_MEDIA_RAW_AUDIO, - StringForChannelType(buf, out->GetOutputChannelType(chan)), B_GENERIC); - for (int src = 0; src < MAX_CHANNEL_TYPES; src++) { - subsubgroup = subgroup->MakeGroup(""); - subsubgroup->MakeDiscreteParameter(PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", B_ENABLE); - subsubgroup->MakeContinuousParameter(PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO, - StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1); + group = outputchannels->MakeGroup(""); + group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, "Master Output", B_GENERIC); + group = group->MakeGroup(""); + if (!out) { + group->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC); + } else { + for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) { + subgroup = group->MakeGroup(""); + subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan), B_MEDIA_RAW_AUDIO, + StringForChannelType(buf, out->GetOutputChannelType(chan)), B_GENERIC); + for (int src = 0; src < MAX_CHANNEL_TYPES; src++) { + subsubgroup = subgroup->MakeGroup(""); + subsubgroup->MakeDiscreteParameter(PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", B_ENABLE); + subsubgroup->MakeContinuousParameter(PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO, + StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1); + } } - } } - - top = web->MakeGroup("Input Mapping"); // top level group - inputchannels = top->MakeGroup(""); - inputchannels->MakeNullParameter(PARAM_STR7(0), B_MEDIA_RAW_AUDIO, "Input Channel Destinations", B_GENERIC); - - for (int i = 0; (in = fCore->Input(i)); i++) { - group = inputchannels->MakeGroup(""); - group->MakeNullParameter(PARAM_STR4(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_GENERIC); - group = group->MakeGroup(""); - - for (int chan = 0; chan < in->GetInputChannelCount(); chan++) { - subgroup = group->MakeGroup(""); - subgroup->MakeNullParameter(PARAM_DST_STR(in->ID(), chan), B_MEDIA_RAW_AUDIO, - StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC); - for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) { - subgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(), chan, dst), B_MEDIA_RAW_AUDIO, StringForChannelType(buf, dst), B_ENABLE); - } + if (fCore->Settings()->AllowInputChannelRemapping()) { + top = web->MakeGroup("Input Mapping"); // top level group + inputchannels = top->MakeGroup(""); + inputchannels->MakeNullParameter(PARAM_STR7(0), B_MEDIA_RAW_AUDIO, "Input Channel Destinations", B_GENERIC); + + for (int i = 0; (in = fCore->Input(i)); i++) { + group = inputchannels->MakeGroup(""); + group->MakeNullParameter(PARAM_STR4(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_GENERIC); + group = group->MakeGroup(""); + + for (int chan = 0; chan < in->GetInputChannelCount(); chan++) { + subgroup = group->MakeGroup(""); + subgroup->MakeNullParameter(PARAM_DST_STR(in->ID(), chan), B_MEDIA_RAW_AUDIO, + StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC); + for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) { + subgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(), chan, dst), B_MEDIA_RAW_AUDIO, StringForChannelType(buf, dst), B_ENABLE); + } + } } } @@ -1247,10 +1372,11 @@ AudioMixer::UpdateParameterWeb() dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX); dp->AddItem(0, "Drop/repeat samples"); +/* dp->AddItem(1, "Drop/repeat samples (template based)"); dp->AddItem(2, "Linear interpolation"); dp->AddItem(3, "17th order filtering"); - +*/ group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO, "Refuse output format changes", B_ENABLE); group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO, "Refuse input format changes", B_ENABLE); group->MakeDiscreteParameter(PARAM_ETC(100), B_MEDIA_RAW_AUDIO, "Display performance profiling data", B_ENABLE); diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.h b/src/add-ons/media/media-add-ons/mixer/AudioMixer.h index d92cb80c46..bf5c6f1c6e 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.h +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.h @@ -41,6 +41,9 @@ class AudioMixer : void DisableNodeStop(); // AudioMixer support + + void ApplySettings(); + void UpdateParameterWeb(); diff --git a/src/add-ons/media/media-add-ons/mixer/ByteSwap.cpp b/src/add-ons/media/media-add-ons/mixer/ByteSwap.cpp index 54b8f970a0..86fe4c8ca1 100644 --- a/src/add-ons/media/media-add-ons/mixer/ByteSwap.cpp +++ b/src/add-ons/media/media-add-ons/mixer/ByteSwap.cpp @@ -41,7 +41,7 @@ do_nothing(void *buffer, size_t bytecount) { } -#ifdef __INTEL__ +#if __INTEL__ // optimized for IA32 platform diff --git a/src/add-ons/media/media-add-ons/mixer/Jamfile b/src/add-ons/media/media-add-ons/mixer/Jamfile index cf72b389f7..fd414be728 100644 --- a/src/add-ons/media/media-add-ons/mixer/Jamfile +++ b/src/add-ons/media/media-add-ons/mixer/Jamfile @@ -9,6 +9,7 @@ Addon mixer.media_addon : media : MixerCore.cpp MixerInput.cpp MixerOutput.cpp + MixerSettings.cpp MixerUtils.cpp Resampler.cpp ; diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp index 1c09ee3ac7..e8805dc4b8 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -51,16 +51,20 @@ MixerCore::MixerCore(AudioMixer *node) fMixBufferChannelCount(0), fDoubleRateMixing(DOUBLE_RATE_MIXING), fDownstreamLatency(1), + fSettings(new MixerSettings), fNode(node), fBufferGroup(0), fTimeSource(0), fMixThread(-1), - fMixThreadWaitSem(-1) + fMixThreadWaitSem(-1), + fOutputGain(1.0) { } MixerCore::~MixerCore() { + delete fSettings; + delete fLocker; delete fInputs; @@ -83,6 +87,19 @@ MixerCore::~MixerCore() delete fMixBufferChannelTypes; } +MixerSettings * +MixerCore::Settings() +{ + return fSettings; +} + +void +MixerCore::SetOutputAttenuation(float gain) +{ + ASSERT_LOCKED(); + fOutputGain = gain; +} + bool MixerCore::AddInput(const media_input &input) { @@ -542,7 +559,7 @@ MixerCore::MixThread() reinterpret_cast(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)), bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio), - fOutput->GetOutputChannelGain(i)); + fOutputGain * fOutput->GetOutputChannelGain(i)); } PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.h b/src/add-ons/media/media-add-ons/mixer/MixerCore.h index 75f9fd60d3..069a719d8a 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.h @@ -2,6 +2,7 @@ #define _MIXER_CORE_H #include +#include "MixerSettings.h" class AudioMixer; class MixerInput; @@ -21,6 +22,13 @@ public: MixerCore(AudioMixer *node); ~MixerCore(); + MixerSettings *Settings(); + + // To avoid calling Settings()->AttenuateOutput() for every outgoing + // buffer, this setting is cached in fOutputGain and must be set by + // the audio mixer node using SetOutputAttenuation() + void SetOutputAttenuation(float gain); + bool AddInput(const media_input &input); bool AddOutput(const media_output &output); @@ -80,11 +88,14 @@ private: friend class MixerInput; // XXX debug only - AudioMixer *fNode; - BBufferGroup *fBufferGroup; - BTimeSource *fTimeSource; + MixerSettings *fSettings; + AudioMixer *fNode; + BBufferGroup *fBufferGroup; + BTimeSource *fTimeSource; thread_id fMixThread; sem_id fMixThreadWaitSem; + + float fOutputGain; }; diff --git a/src/add-ons/media/media-add-ons/mixer/MixerSettings.cpp b/src/add-ons/media/media-add-ons/mixer/MixerSettings.cpp new file mode 100644 index 0000000000..a54c2a07a9 --- /dev/null +++ b/src/add-ons/media/media-add-ons/mixer/MixerSettings.cpp @@ -0,0 +1,413 @@ +#include +#include +#include + +#include "MixerCore.h" +#include "MixerInput.h" +#include "MixerOutput.h" +#include "MixerSettings.h" +#include "debug.h" + +#define SAVE_DELAY 8000000 // delay saving of settings for 8s +#define SAVE_RUNTIME 40000000 // stop save thread after 40s inactivity + +MixerSettings::MixerSettings() + : fLocker(new BLocker), + fSettingsDirty(false), + fSettingsLastChange(0), + fSaveThread(-1), + fSaveThreadWaitSem(-1) +{ + Load(); +} + +MixerSettings::~MixerSettings() +{ + StopDeferredSave(); + if (fSettingsDirty) + Save(); + delete fLocker; +} + +bool +MixerSettings::AttenuateOutput() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.AttenuateOutput; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetAttenuateOutput(bool yesno) +{ + fLocker->Lock(); + fSettings.AttenuateOutput = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::NonLinearGainSlider() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.NonLinearGainSlider; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetNonLinearGainSlider(bool yesno) +{ + fLocker->Lock(); + fSettings.NonLinearGainSlider = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::UseBalanceControl() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.UseBalanceControl; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetUseBalanceControl(bool yesno) +{ + fLocker->Lock(); + fSettings.UseBalanceControl = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::AllowOutputChannelRemapping() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.AllowOutputChannelRemapping; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetAllowOutputChannelRemapping(bool yesno) +{ + fLocker->Lock(); + fSettings.AllowOutputChannelRemapping = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::AllowInputChannelRemapping() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.AllowInputChannelRemapping; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetAllowInputChannelRemapping(bool yesno) +{ + fLocker->Lock(); + fSettings.AllowInputChannelRemapping = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +int +MixerSettings::InputGainControls() +{ + int temp; + fLocker->Lock(); + temp = fSettings.InputGainControls; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetInputGainControls(int value) +{ + fLocker->Lock(); + fSettings.InputGainControls = value; + fLocker->Unlock(); + StartDeferredSave(); +} + +int +MixerSettings::ResamplingAlgorithm() +{ + int temp; + fLocker->Lock(); + temp = fSettings.ResamplingAlgorithm; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetResamplingAlgorithm(int value) +{ + fLocker->Lock(); + fSettings.ResamplingAlgorithm = value; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::RefuseOutputFormatChange() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.RefuseOutputFormatChange; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetRefuseOutputFormatChange(bool yesno) +{ + fLocker->Lock(); + fSettings.RefuseOutputFormatChange = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::RefuseInputFormatChange() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.RefuseInputFormatChange; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetRefuseInputFormatChange(bool yesno) +{ + fLocker->Lock(); + fSettings.RefuseInputFormatChange = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +bool +MixerSettings::DisplayProfilingData() +{ + bool temp; + fLocker->Lock(); + temp = fSettings.DisplayProfilingData; + fLocker->Unlock(); + return temp; +} + +void +MixerSettings::SetDisplayProfilingData(bool yesno) +{ + fLocker->Lock(); + fSettings.DisplayProfilingData = yesno; + fLocker->Unlock(); + StartDeferredSave(); +} + +void +MixerSettings::SaveGain(MixerInput *input) +{ +} + +void +MixerSettings::LoadGain(MixerInput *input) +{ +} + +void +MixerSettings::SaveGain(MixerOutput *output) +{ +} + +void +MixerSettings::LoadGain(MixerOutput *output) +{ +} + +void +MixerSettings::SaveGainSetting(const char *name, uint32 channel_mask, const float *gain, int gain_count) +{ + fLocker->Lock(); + + // XXX work + + fLocker->Unlock(); + StartDeferredSave(); +} + +void +MixerSettings::LoadGainSetting(const char *name, uint32 channel_mask, float *gain, int gain_count) +{ + fLocker->Lock(); + + // XXX work + + fLocker->Unlock(); +} + +void +MixerSettings::SaveSetting(const char *name, int value) +{ + fLocker->Lock(); + + // XXX work + + fLocker->Unlock(); + StartDeferredSave(); +} + +void +MixerSettings::LoadSetting(const char *name, int *value, int default_value /* = 0 */) +{ + fLocker->Lock(); + + // XXX work + + fLocker->Unlock(); +} + +void +MixerSettings::Save() +{ + fLocker->Lock(); + TRACE("MixerSettings: SAVE!\n"); + + + // XXX work + + fSettingsDirty = false; + fLocker->Unlock(); +} + +void +MixerSettings::Load() +{ + fLocker->Lock(); + + // XXX work + + fSettings.AttenuateOutput = true; + fSettings.NonLinearGainSlider = true; + fSettings.UseBalanceControl = false; + fSettings.AllowOutputChannelRemapping = false; + fSettings.AllowInputChannelRemapping = false; + fSettings.InputGainControls = 0; + fSettings.ResamplingAlgorithm = 0; + fSettings.RefuseOutputFormatChange = false; + fSettings.RefuseInputFormatChange = false; + fSettings.DisplayProfilingData = false; + + fLocker->Unlock(); +} + +void +MixerSettings::StartDeferredSave() +{ + fLocker->Lock(); + + fSettingsDirty = true; + fSettingsLastChange = system_time(); + + if (fSaveThread < 0) { + ASSERT(fSaveThreadWaitSem < 0); + fSaveThreadWaitSem = create_sem(0, "save thread wait"); + if (fSaveThreadWaitSem < B_OK) { + ERROR("MixerSettings: can't create semaphore\n"); + Save(); + fLocker->Unlock(); + return; + } + fSaveThread = spawn_thread(_save_thread_, "deferred settings save", 7, this); + if (fSaveThread < B_OK) { + ERROR("MixerSettings: can't spawn thread\n"); + delete_sem(fSaveThreadWaitSem); + fSaveThreadWaitSem = -1; + Save(); + fLocker->Unlock(); + return; + } + } + fLocker->Unlock(); +} + +void +MixerSettings::StopDeferredSave() +{ + fLocker->Lock(); + + if (fSaveThread > 0) { + ASSERT(fSaveThreadWaitSem > 0); + + status_t unused; + delete_sem(fSaveThreadWaitSem); + wait_for_thread(fSaveThread, &unused); + + fSaveThread = -1; + fSaveThreadWaitSem = -1; + } + + fLocker->Unlock(); +} + +void +MixerSettings::SaveThread() +{ + bigtime_t timeout; + status_t rv; + + TRACE("MixerSettings: save thread started\n"); + + fLocker->Lock(); + timeout = fSettingsLastChange + SAVE_DELAY; + fLocker->Unlock(); + + for (;;) { + rv = acquire_sem_etc(fSaveThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout); + if (rv == B_INTERRUPTED) + continue; + if (rv != B_TIMED_OUT && rv < B_OK) + break; + if (B_OK != fLocker->LockWithTimeout(200000)) + continue; + + TRACE("MixerSettings: save thread running\n"); + + bigtime_t delta = system_time() - fSettingsLastChange; + + if (fSettingsDirty && delta > SAVE_DELAY) { + Save(); + } + + if (delta > SAVE_RUNTIME) { + fLocker->Unlock(); + break; + } + + timeout = system_time() + SAVE_DELAY; + fLocker->Unlock(); + } + + TRACE("MixerSettings: save thread ended\n"); +} + +int32 +MixerSettings::_save_thread_(void *arg) +{ + static_cast(arg)->SaveThread(); + return 0; +} diff --git a/src/add-ons/media/media-add-ons/mixer/MixerSettings.h b/src/add-ons/media/media-add-ons/mixer/MixerSettings.h new file mode 100644 index 0000000000..08d7be9a42 --- /dev/null +++ b/src/add-ons/media/media-add-ons/mixer/MixerSettings.h @@ -0,0 +1,90 @@ +#ifndef _MIXER_SETTINGS_H +#define _MIXER_SETTINGS_H + +class MixerInput; +class MixerOutput; + +class MixerSettings +{ +public: + MixerSettings(); + ~MixerSettings(); + + bool AttenuateOutput(); + void SetAttenuateOutput(bool yesno); + + bool NonLinearGainSlider(); + void SetNonLinearGainSlider(bool yesno); + + bool UseBalanceControl(); + void SetUseBalanceControl(bool yesno); + + bool AllowOutputChannelRemapping(); + void SetAllowOutputChannelRemapping(bool yesno); + + bool AllowInputChannelRemapping(); + void SetAllowInputChannelRemapping(bool yesno); + + int InputGainControls(); + void SetInputGainControls(int value); + + int ResamplingAlgorithm(); + void SetResamplingAlgorithm(int value); + + bool RefuseOutputFormatChange(); + void SetRefuseOutputFormatChange(bool yesno); + + bool RefuseInputFormatChange(); + void SetRefuseInputFormatChange(bool yesno); + + bool DisplayProfilingData(); + void SetDisplayProfilingData(bool yesno); + + void SaveGain(MixerInput *input); + void LoadGain(MixerInput *input); + + void SaveGain(MixerOutput *output); + void LoadGain(MixerOutput *output); + +protected: + + void SaveGainSetting(const char *name, uint32 channel_mask, const float *gain, int gain_count); + void LoadGainSetting(const char *name, uint32 channel_mask, float *gain, int gain_count); + + void SaveSetting(const char *name, int value); + void LoadSetting(const char *name, int *value, int default_value = 0); + + void StartDeferredSave(); + void StopDeferredSave(); + + void Save(); + void Load(); + + static int32 _save_thread_(void *arg); + void SaveThread(); + + BLocker *fLocker; + bool fSettingsDirty; + bigtime_t fSettingsLastChange; + + thread_id fSaveThread; + sem_id fSaveThreadWaitSem; + + struct settings + { + bool AttenuateOutput; + bool NonLinearGainSlider; + bool UseBalanceControl; + bool AllowOutputChannelRemapping; + bool AllowInputChannelRemapping; + int InputGainControls; + int ResamplingAlgorithm; + bool RefuseOutputFormatChange; + bool RefuseInputFormatChange; + bool DisplayProfilingData; + }; + + settings fSettings; +}; + +#endif //_MIXER_SETTINGS_H