added support for a settings file,
some fixes in the deferred saving code, added save/load to mixer connections git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4294 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
f825dfe370
commit
1165d5e18a
@ -8,6 +8,8 @@
|
||||
#include <TimeSource.h>
|
||||
#include <ParameterWeb.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Path.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -40,7 +42,7 @@ static void multi_audio_format_specialize(media_multi_audio_format *format, cons
|
||||
#define FORMAT_USER_DATA_MAGIC_1 0xc84173bd
|
||||
#define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d
|
||||
|
||||
AudioMixer::AudioMixer(BMediaAddOn *addOn)
|
||||
AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
|
||||
: BMediaNode("Audio Mixer"),
|
||||
BBufferConsumer(B_MEDIA_RAW_AUDIO),
|
||||
BBufferProducer(B_MEDIA_RAW_AUDIO),
|
||||
@ -67,6 +69,18 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn)
|
||||
fDefaultFormat.u.raw_audio.valid_bits = 0;
|
||||
fDefaultFormat.u.raw_audio.matrix_mask = 0;
|
||||
|
||||
if (isSystemMixer) {
|
||||
// to get persistent settings, assign a settings file
|
||||
BPath path;
|
||||
if (B_OK != find_directory (B_USER_SETTINGS_DIRECTORY, &path))
|
||||
path.SetTo("/boot/home/config/settings/");
|
||||
path.Append("System Audio Mixer");
|
||||
fCore->Settings()->SetSettingsFile(path.Path());
|
||||
|
||||
// disable stop on the auto started (system) mixer
|
||||
DisableNodeStop();
|
||||
}
|
||||
|
||||
ApplySettings();
|
||||
}
|
||||
|
||||
@ -328,7 +342,10 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
|
||||
sprintf(out_input->name, "Input %ld", out_input->destination.id);
|
||||
|
||||
// add a new input to the mixer engine
|
||||
fCore->AddInput(*out_input);
|
||||
MixerInput *input;
|
||||
input = fCore->AddInput(*out_input);
|
||||
|
||||
fCore->Settings()->LoadConnectionSettings(input);
|
||||
|
||||
fCore->Unlock();
|
||||
|
||||
@ -786,6 +803,9 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
||||
fCore->EnableOutput(true);
|
||||
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
|
||||
fCore->SetOutputBufferGroup(fBufferGroup);
|
||||
|
||||
fCore->Settings()->LoadConnectionSettings(fCore->Output());
|
||||
|
||||
fCore->Unlock();
|
||||
|
||||
UpdateParameterWeb();
|
||||
@ -1353,6 +1373,7 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when,
|
||||
goto err;
|
||||
output->SetOutputChannelSourceGain(PARAM_CHAN(id), PARAM_SRC(id), PERCENT_TO_GAIN(static_cast<const float *>(value)[0]));
|
||||
}
|
||||
fCore->Settings()->SaveConnectionSettings(output);
|
||||
} else {
|
||||
MixerInput *input;
|
||||
for (int i = 0; (input = fCore->Input(i)); i++)
|
||||
@ -1457,6 +1478,7 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when,
|
||||
// but it will change the fokus from tab 3 to tab 1
|
||||
update = true;
|
||||
}
|
||||
fCore->Settings()->SaveConnectionSettings(input);
|
||||
}
|
||||
BroadcastNewParameterValue(when, id, const_cast<void *>(value), size);
|
||||
err:
|
||||
|
@ -34,7 +34,7 @@ class AudioMixer :
|
||||
|
||||
public:
|
||||
|
||||
AudioMixer(BMediaAddOn *addOn);
|
||||
AudioMixer(BMediaAddOn *addOn, bool isSystemMixer);
|
||||
~AudioMixer();
|
||||
|
||||
|
||||
|
@ -83,7 +83,7 @@ BMediaNode *
|
||||
AudioMixerAddon::InstantiateNodeFor(const flavor_info* info, BMessage* config,
|
||||
status_t* out_error)
|
||||
{
|
||||
return new AudioMixer(this);
|
||||
return new AudioMixer(this, false);
|
||||
}
|
||||
|
||||
status_t
|
||||
@ -110,11 +110,7 @@ AudioMixerAddon::AutoStart(int in_index, BMediaNode ** out_node,
|
||||
return B_ERROR;
|
||||
|
||||
*out_internal_id = 0;
|
||||
AudioMixer *mixer = new AudioMixer(this);
|
||||
|
||||
// disable stop on the auto started (system) mixer
|
||||
mixer->DisableNodeStop();
|
||||
|
||||
AudioMixer *mixer = new AudioMixer(this, true);
|
||||
*out_node = mixer;
|
||||
|
||||
return B_OK;
|
||||
|
@ -100,23 +100,23 @@ MixerCore::SetOutputAttenuation(float gain)
|
||||
fOutputGain = gain;
|
||||
}
|
||||
|
||||
bool
|
||||
MixerInput *
|
||||
MixerCore::AddInput(const media_input &input)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
if (HasKawamba())
|
||||
fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate * 1.5, fMixBufferFrameCount * 2));
|
||||
else
|
||||
fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount));
|
||||
return true;
|
||||
MixerInput *in = new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount);
|
||||
fInputs->AddItem(in);
|
||||
return in;
|
||||
}
|
||||
|
||||
bool
|
||||
MixerOutput *
|
||||
MixerCore::AddOutput(const media_output &output)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
if (fOutput)
|
||||
return false;
|
||||
if (fOutput) {
|
||||
ERROR("MixerCore::AddOutput: already connected\n");
|
||||
return fOutput;
|
||||
}
|
||||
fOutput = new MixerOutput(this, output);
|
||||
// the output format might have been adjusted inside MixerOutput
|
||||
ApplyOutputFormat();
|
||||
@ -124,6 +124,8 @@ MixerCore::AddOutput(const media_output &output)
|
||||
ASSERT(!fRunning);
|
||||
if (fStarted && fOutputEnabled)
|
||||
StartMixThread();
|
||||
|
||||
return fOutput;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -29,8 +29,8 @@ public:
|
||||
// the audio mixer node using SetOutputAttenuation()
|
||||
void SetOutputAttenuation(float gain);
|
||||
|
||||
bool AddInput(const media_input &input);
|
||||
bool AddOutput(const media_output &output);
|
||||
MixerInput * AddInput(const media_input &input);
|
||||
MixerOutput * AddOutput(const media_output &output);
|
||||
|
||||
bool RemoveInput(int32 inputID);
|
||||
bool RemoveOutput();
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <MediaDefs.h>
|
||||
#include <Locker.h>
|
||||
#include <Path.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "MixerCore.h"
|
||||
@ -8,15 +9,17 @@
|
||||
#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
|
||||
#define SAVE_DELAY 5000000 // delay saving of settings for 5s
|
||||
#define SAVE_RUNTIME 30000000 // stop save thread after 30s inactivity
|
||||
|
||||
MixerSettings::MixerSettings()
|
||||
: fLocker(new BLocker),
|
||||
fSettingsFile(0),
|
||||
fSettingsDirty(false),
|
||||
fSettingsLastChange(0),
|
||||
fSaveThread(-1),
|
||||
fSaveThreadWaitSem(-1)
|
||||
fSaveThreadWaitSem(-1),
|
||||
fSaveThreadRunning(false)
|
||||
{
|
||||
Load();
|
||||
}
|
||||
@ -27,6 +30,16 @@ MixerSettings::~MixerSettings()
|
||||
if (fSettingsDirty)
|
||||
Save();
|
||||
delete fLocker;
|
||||
delete fSettingsFile;
|
||||
}
|
||||
|
||||
void
|
||||
MixerSettings::SetSettingsFile(const char *file)
|
||||
{
|
||||
fLocker->Lock();
|
||||
delete fSettingsFile;
|
||||
fSettingsFile = new BPath(file);
|
||||
fLocker->Unlock();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -201,27 +214,29 @@ MixerSettings::SetRefuseInputFormatChange(bool yesno)
|
||||
}
|
||||
|
||||
void
|
||||
MixerSettings::SaveGain(MixerInput *input)
|
||||
MixerSettings::SaveConnectionSettings(MixerInput *input)
|
||||
{
|
||||
StartDeferredSave();
|
||||
}
|
||||
|
||||
void
|
||||
MixerSettings::LoadConnectionSettings(MixerInput *input)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MixerSettings::LoadGain(MixerInput *input)
|
||||
MixerSettings::SaveConnectionSettings(MixerOutput *output)
|
||||
{
|
||||
StartDeferredSave();
|
||||
}
|
||||
|
||||
void
|
||||
MixerSettings::LoadConnectionSettings(MixerOutput *output)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
MixerSettings::SaveConnectionSettingsSetting(const char *name, uint32 channel_mask, const float *gain, int gain_count)
|
||||
{
|
||||
fLocker->Lock();
|
||||
|
||||
@ -232,7 +247,7 @@ MixerSettings::SaveGainSetting(const char *name, uint32 channel_mask, const floa
|
||||
}
|
||||
|
||||
void
|
||||
MixerSettings::LoadGainSetting(const char *name, uint32 channel_mask, float *gain, int gain_count)
|
||||
MixerSettings::LoadConnectionSettingsSetting(const char *name, uint32 channel_mask, float *gain, int gain_count)
|
||||
{
|
||||
fLocker->Lock();
|
||||
|
||||
@ -266,8 +281,15 @@ void
|
||||
MixerSettings::Save()
|
||||
{
|
||||
fLocker->Lock();
|
||||
// if we don't have a settings file, don't continue
|
||||
if (!fSettingsFile) {
|
||||
fLocker->Unlock();
|
||||
return;
|
||||
}
|
||||
TRACE("MixerSettings: SAVE!\n");
|
||||
|
||||
|
||||
|
||||
|
||||
// XXX work
|
||||
|
||||
@ -279,9 +301,7 @@ void
|
||||
MixerSettings::Load()
|
||||
{
|
||||
fLocker->Lock();
|
||||
|
||||
// XXX work
|
||||
|
||||
// setup defaults
|
||||
fSettings.AttenuateOutput = true;
|
||||
fSettings.NonLinearGainSlider = true;
|
||||
fSettings.UseBalanceControl = false;
|
||||
@ -292,6 +312,12 @@ MixerSettings::Load()
|
||||
fSettings.RefuseOutputFormatChange = false;
|
||||
fSettings.RefuseInputFormatChange = false;
|
||||
|
||||
// if we don't have a settings file, don't continue
|
||||
if (!fSettingsFile) {
|
||||
fLocker->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
fLocker->Unlock();
|
||||
}
|
||||
|
||||
@ -299,29 +325,45 @@ void
|
||||
MixerSettings::StartDeferredSave()
|
||||
{
|
||||
fLocker->Lock();
|
||||
|
||||
// if we don't have a settings file, don't save the settings
|
||||
if (!fSettingsFile) {
|
||||
fLocker->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (fSaveThreadRunning) {
|
||||
fLocker->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
StopDeferredSave();
|
||||
|
||||
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;
|
||||
}
|
||||
ASSERT(fSaveThread < 0);
|
||||
fSaveThread = spawn_thread(_save_thread_, "Attack of the Killer Tomatoes", 7, this);
|
||||
if (fSaveThread < B_OK) {
|
||||
ERROR("MixerSettings: can't spawn thread\n");
|
||||
delete_sem(fSaveThreadWaitSem);
|
||||
fSaveThreadWaitSem = -1;
|
||||
Save();
|
||||
fLocker->Unlock();
|
||||
return;
|
||||
}
|
||||
resume_thread(fSaveThread);
|
||||
|
||||
fSaveThreadRunning = true;
|
||||
|
||||
fLocker->Unlock();
|
||||
}
|
||||
|
||||
@ -374,6 +416,7 @@ MixerSettings::SaveThread()
|
||||
}
|
||||
|
||||
if (delta > SAVE_RUNTIME) {
|
||||
fSaveThreadRunning = false;
|
||||
fLocker->Unlock();
|
||||
break;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ class MixerSettings
|
||||
public:
|
||||
MixerSettings();
|
||||
~MixerSettings();
|
||||
|
||||
void SetSettingsFile(const char *file);
|
||||
|
||||
bool AttenuateOutput();
|
||||
void SetAttenuateOutput(bool yesno);
|
||||
@ -37,16 +39,16 @@ public:
|
||||
bool RefuseInputFormatChange();
|
||||
void SetRefuseInputFormatChange(bool yesno);
|
||||
|
||||
void SaveGain(MixerInput *input);
|
||||
void LoadGain(MixerInput *input);
|
||||
void SaveConnectionSettings(MixerInput *input);
|
||||
void LoadConnectionSettings(MixerInput *input);
|
||||
|
||||
void SaveGain(MixerOutput *output);
|
||||
void LoadGain(MixerOutput *output);
|
||||
void SaveConnectionSettings(MixerOutput *output);
|
||||
void LoadConnectionSettings(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 SaveConnectionSettingsSetting(const char *name, uint32 channel_mask, const float *gain, int gain_count);
|
||||
void LoadConnectionSettingsSetting(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);
|
||||
@ -61,11 +63,13 @@ protected:
|
||||
void SaveThread();
|
||||
|
||||
BLocker *fLocker;
|
||||
bool fSettingsDirty;
|
||||
bigtime_t fSettingsLastChange;
|
||||
|
||||
thread_id fSaveThread;
|
||||
sem_id fSaveThreadWaitSem;
|
||||
BPath *fSettingsFile;
|
||||
|
||||
volatile bool fSettingsDirty;
|
||||
volatile bigtime_t fSettingsLastChange;
|
||||
volatile thread_id fSaveThread;
|
||||
volatile sem_id fSaveThreadWaitSem;
|
||||
volatile bool fSaveThreadRunning;
|
||||
|
||||
struct settings
|
||||
{
|
||||
@ -80,7 +84,7 @@ protected:
|
||||
bool RefuseInputFormatChange;
|
||||
};
|
||||
|
||||
settings fSettings;
|
||||
volatile settings fSettings;
|
||||
};
|
||||
|
||||
#endif //_MIXER_SETTINGS_H
|
||||
|
Loading…
Reference in New Issue
Block a user