2 * Copyright 2003-2009 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
10 #include "MixerSettings.h"
16 #include <MediaDefs.h>
20 #include "MixerCore.h"
21 #include "MixerDebug.h"
22 #include "MixerInput.h"
23 #include "MixerOutput.h"
26 #define SAVE_DELAY 5000000 // delay saving of settings for 5s
27 #define SAVE_RUNTIME 30000000 // stop save thread after 30s inactivity
29 #define SETTINGS_VERSION ((int32)0x94251601)
32 MixerSettings::MixerSettings()
34 fLocker(new BLocker("mixer settings lock")),
36 fSettingsDirty(false),
37 fSettingsLastChange(0),
39 fSaveThreadWaitSem(-1),
40 fSaveThreadRunning(false)
46 MixerSettings::~MixerSettings()
57 MixerSettings::SetSettingsFile(const char *file
)
61 fSettingsFile
= new BPath(file
);
68 MixerSettings::AttenuateOutput()
72 temp
= fSettings
.AttenuateOutput
;
79 MixerSettings::SetAttenuateOutput(bool yesno
)
82 fSettings
.AttenuateOutput
= yesno
;
89 MixerSettings::NonLinearGainSlider()
93 temp
= fSettings
.NonLinearGainSlider
;
100 MixerSettings::SetNonLinearGainSlider(bool yesno
)
103 fSettings
.NonLinearGainSlider
= yesno
;
110 MixerSettings::UseBalanceControl()
114 temp
= fSettings
.UseBalanceControl
;
121 MixerSettings::SetUseBalanceControl(bool yesno
)
124 fSettings
.UseBalanceControl
= yesno
;
131 MixerSettings::AllowOutputChannelRemapping()
135 temp
= fSettings
.AllowOutputChannelRemapping
;
142 MixerSettings::SetAllowOutputChannelRemapping(bool yesno
)
145 fSettings
.AllowOutputChannelRemapping
= yesno
;
152 MixerSettings::AllowInputChannelRemapping()
156 temp
= fSettings
.AllowInputChannelRemapping
;
163 MixerSettings::SetAllowInputChannelRemapping(bool yesno
)
166 fSettings
.AllowInputChannelRemapping
= yesno
;
173 MixerSettings::InputGainControls()
177 temp
= fSettings
.InputGainControls
;
184 MixerSettings::SetInputGainControls(int value
)
187 fSettings
.InputGainControls
= value
;
194 MixerSettings::ResamplingAlgorithm()
198 temp
= fSettings
.ResamplingAlgorithm
;
205 MixerSettings::SetResamplingAlgorithm(int value
)
208 fSettings
.ResamplingAlgorithm
= value
;
215 MixerSettings::RefuseOutputFormatChange()
219 temp
= fSettings
.RefuseOutputFormatChange
;
226 MixerSettings::SetRefuseOutputFormatChange(bool yesno
)
229 fSettings
.RefuseOutputFormatChange
= yesno
;
236 MixerSettings::RefuseInputFormatChange()
240 temp
= fSettings
.RefuseInputFormatChange
;
247 MixerSettings::SetRefuseInputFormatChange(bool yesno
)
250 fSettings
.RefuseInputFormatChange
= yesno
;
257 MixerSettings::SaveConnectionSettings(MixerInput
*input
)
262 // try to find matching name first
263 for (int i
= 0; i
< MAX_INPUT_SETTINGS
; i
++) {
264 if (fInputSetting
[i
].IsEmpty())
266 if (!strcmp(fInputSetting
[i
].FindString("name"), input
->MediaInput().name
)) {
272 // try to find empty location
273 for (int i
= 0; i
< MAX_INPUT_SETTINGS
; i
++) {
274 if (fInputSetting
[i
].IsEmpty()) {
283 for (int i
= 0; i
< MAX_INPUT_SETTINGS
; i
++) {
284 if (fInputSetting
[i
].FindInt64("lru") < fInputSetting
[index
].FindInt64("lru"))
289 TRACE("SaveConnectionSettings: using entry %d\n", index
);
291 fInputSetting
[index
].MakeEmpty();
292 fInputSetting
[index
].AddInt64("lru", system_time());
293 fInputSetting
[index
].AddString("name", input
->MediaInput().name
);
295 int count
= input
->GetInputChannelCount();
296 fInputSetting
[index
].AddInt32("InputChannelCount", count
);
297 fInputSetting
[index
].AddBool("InputIsEnabled", input
->IsEnabled());
299 for (int i
= 0; i
< count
; i
++)
300 fInputSetting
[index
].AddFloat("InputChannelGain", input
->GetInputChannelGain(i
));
302 // XXX should save channel destinations and mixer channels
310 MixerSettings::LoadConnectionSettings(MixerInput
*input
)
314 for (index
= 0; index
< MAX_INPUT_SETTINGS
; index
++) {
315 if (fInputSetting
[index
].IsEmpty())
317 if (!strcmp(fInputSetting
[index
].FindString("name"), input
->MediaInput().name
))
320 if (index
== MAX_INPUT_SETTINGS
) {
321 TRACE("LoadConnectionSettings: entry not found\n");
326 TRACE("LoadConnectionSettings: found entry %d\n", index
);
328 int count
= input
->GetInputChannelCount();
329 if (fInputSetting
[index
].FindInt32("InputChannelCount") == count
) {
330 for (int i
= 0; i
< count
; i
++)
331 input
->SetInputChannelGain(i
, fInputSetting
[index
].FindFloat("InputChannelGain", i
));
332 input
->SetEnabled(fInputSetting
[index
].FindBool("InputIsEnabled"));
335 // XXX should load channel destinations and mixer channels
337 fInputSetting
[index
].ReplaceInt64("lru", system_time());
344 MixerSettings::SaveConnectionSettings(MixerOutput
*output
)
348 fOutputSetting
.MakeEmpty();
350 int count
= output
->GetOutputChannelCount();
351 fOutputSetting
.AddInt32("OutputChannelCount", count
);
352 for (int i
= 0; i
< count
; i
++)
353 fOutputSetting
.AddFloat("OutputChannelGain", output
->GetOutputChannelGain(i
));
354 fOutputSetting
.AddBool("OutputIsMuted", output
->IsMuted());
356 // XXX should save channel sources and source gains
364 MixerSettings::LoadConnectionSettings(MixerOutput
*output
)
368 int count
= output
->GetOutputChannelCount();
369 if (fOutputSetting
.FindInt32("OutputChannelCount") == count
) {
370 for (int i
= 0; i
< count
; i
++)
371 output
->SetOutputChannelGain(i
, fOutputSetting
.FindFloat("OutputChannelGain", i
));
372 output
->SetMuted(fOutputSetting
.FindBool("OutputIsMuted"));
375 // XXX should load channel sources and source gains
381 MixerSettings::Save()
384 // if we don't have a settings file, don't continue
385 if (!fSettingsFile
) {
389 TRACE("MixerSettings: SAVE!\n");
392 msg
.AddInt32("version", SETTINGS_VERSION
);
393 msg
.AddData("settings", B_RAW_TYPE
, (void *)&fSettings
, sizeof(fSettings
));
394 msg
.AddMessage("output", &fOutputSetting
);
395 for (int i
= 0; i
< MAX_INPUT_SETTINGS
; i
++)
396 msg
.AddMessage("input", &fInputSetting
[i
]);
401 length
= msg
.FlattenedSize();
402 buffer
= new char [length
];
403 msg
.Flatten(buffer
, length
);
405 BFile
file(fSettingsFile
->Path(), B_READ_WRITE
| B_CREATE_FILE
);
406 file
.Write(buffer
, length
);
410 fSettingsDirty
= false;
416 MixerSettings::Load()
420 fSettings
.AttenuateOutput
= true;
421 fSettings
.NonLinearGainSlider
= true;
422 fSettings
.UseBalanceControl
= false;
423 fSettings
.AllowOutputChannelRemapping
= false;
424 fSettings
.AllowInputChannelRemapping
= false;
425 fSettings
.InputGainControls
= 0;
426 fSettings
.ResamplingAlgorithm
= 2;
427 fSettings
.RefuseOutputFormatChange
= true;
428 fSettings
.RefuseInputFormatChange
= true;
430 // if we don't have a settings file, don't continue
431 if (!fSettingsFile
) {
436 BFile
file(fSettingsFile
->Path(), B_READ_WRITE
);
441 TRACE("MixerSettings: no settings file\n");
445 char * buffer
= new char[size
];
446 if (size
!= file
.Read(buffer
, size
)) {
449 TRACE("MixerSettings: can't read settings file\n");
454 if (B_OK
!= msg
.Unflatten(buffer
)) {
457 TRACE("MixerSettings: can't unflatten settings\n");
463 if (msg
.FindInt32("version") != SETTINGS_VERSION
) {
465 TRACE("MixerSettings: settings have wrong version\n");
470 ssize_t datasize
= 0;
472 msg
.FindData("settings", B_RAW_TYPE
, &data
, &datasize
);
473 if (datasize
!= sizeof(fSettings
)) {
475 TRACE("MixerSettings: settings have wrong size\n");
478 memcpy((void *)&fSettings
, data
, sizeof(fSettings
));
480 msg
.FindMessage("output", &fOutputSetting
);
481 for (int i
= 0; i
< MAX_INPUT_SETTINGS
; i
++)
482 msg
.FindMessage("input", i
, &fInputSetting
[i
]);
489 MixerSettings::StartDeferredSave()
493 // if we don't have a settings file, don't save the settings
494 if (!fSettingsFile
) {
499 fSettingsDirty
= true;
500 fSettingsLastChange
= system_time();
502 if (fSaveThreadRunning
) {
509 ASSERT(fSaveThreadWaitSem
< 0);
510 fSaveThreadWaitSem
= create_sem(0, "save thread wait");
511 if (fSaveThreadWaitSem
< B_OK
) {
512 ERROR("MixerSettings: can't create semaphore\n");
517 ASSERT(fSaveThread
< 0);
518 fSaveThread
= spawn_thread(_save_thread_
, "Attack of the Killer Tomatoes", 7, this);
519 if (fSaveThread
< B_OK
) {
520 ERROR("MixerSettings: can't spawn thread\n");
521 delete_sem(fSaveThreadWaitSem
);
522 fSaveThreadWaitSem
= -1;
527 resume_thread(fSaveThread
);
529 fSaveThreadRunning
= true;
535 MixerSettings::StopDeferredSave()
539 if (fSaveThread
>= 0) {
540 ASSERT(fSaveThreadWaitSem
> 0);
543 delete_sem(fSaveThreadWaitSem
);
544 wait_for_thread(fSaveThread
, &unused
);
547 fSaveThreadWaitSem
= -1;
555 MixerSettings::SaveThread()
560 TRACE("MixerSettings: save thread started\n");
563 timeout
= fSettingsLastChange
+ SAVE_DELAY
;
567 rv
= acquire_sem_etc(fSaveThreadWaitSem
, 1, B_ABSOLUTE_TIMEOUT
, timeout
);
568 if (rv
== B_INTERRUPTED
)
570 if (rv
!= B_TIMED_OUT
&& rv
< B_OK
)
572 if (B_OK
!= fLocker
->LockWithTimeout(200000))
575 TRACE("MixerSettings: save thread running\n");
577 bigtime_t delta
= system_time() - fSettingsLastChange
;
579 if (fSettingsDirty
&& delta
> SAVE_DELAY
) {
583 if (delta
> SAVE_RUNTIME
) {
584 fSaveThreadRunning
= false;
589 timeout
= system_time() + SAVE_DELAY
;
593 TRACE("MixerSettings: save thread ended\n");
598 MixerSettings::_save_thread_(void *arg
)
600 static_cast<MixerSettings
*>(arg
)->SaveThread();