3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / media / media-add-ons / mixer / MixerSettings.cpp
blobbb53321a4deea8215a4cccca5f11208e4c7c1478
1 /*
2 * Copyright 2003-2009 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marcus Overhagen
7 */
10 #include "MixerSettings.h"
12 #include <string.h>
14 #include <File.h>
15 #include <Locker.h>
16 #include <MediaDefs.h>
17 #include <OS.h>
18 #include <Path.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")),
35 fSettingsFile(0),
36 fSettingsDirty(false),
37 fSettingsLastChange(0),
38 fSaveThread(-1),
39 fSaveThreadWaitSem(-1),
40 fSaveThreadRunning(false)
42 Load();
46 MixerSettings::~MixerSettings()
48 StopDeferredSave();
49 if (fSettingsDirty)
50 Save();
51 delete fLocker;
52 delete fSettingsFile;
56 void
57 MixerSettings::SetSettingsFile(const char *file)
59 fLocker->Lock();
60 delete fSettingsFile;
61 fSettingsFile = new BPath(file);
62 fLocker->Unlock();
63 Load();
67 bool
68 MixerSettings::AttenuateOutput()
70 bool temp;
71 fLocker->Lock();
72 temp = fSettings.AttenuateOutput;
73 fLocker->Unlock();
74 return temp;
78 void
79 MixerSettings::SetAttenuateOutput(bool yesno)
81 fLocker->Lock();
82 fSettings.AttenuateOutput = yesno;
83 fLocker->Unlock();
84 StartDeferredSave();
88 bool
89 MixerSettings::NonLinearGainSlider()
91 bool temp;
92 fLocker->Lock();
93 temp = fSettings.NonLinearGainSlider;
94 fLocker->Unlock();
95 return temp;
99 void
100 MixerSettings::SetNonLinearGainSlider(bool yesno)
102 fLocker->Lock();
103 fSettings.NonLinearGainSlider = yesno;
104 fLocker->Unlock();
105 StartDeferredSave();
109 bool
110 MixerSettings::UseBalanceControl()
112 bool temp;
113 fLocker->Lock();
114 temp = fSettings.UseBalanceControl;
115 fLocker->Unlock();
116 return temp;
120 void
121 MixerSettings::SetUseBalanceControl(bool yesno)
123 fLocker->Lock();
124 fSettings.UseBalanceControl = yesno;
125 fLocker->Unlock();
126 StartDeferredSave();
130 bool
131 MixerSettings::AllowOutputChannelRemapping()
133 bool temp;
134 fLocker->Lock();
135 temp = fSettings.AllowOutputChannelRemapping;
136 fLocker->Unlock();
137 return temp;
141 void
142 MixerSettings::SetAllowOutputChannelRemapping(bool yesno)
144 fLocker->Lock();
145 fSettings.AllowOutputChannelRemapping = yesno;
146 fLocker->Unlock();
147 StartDeferredSave();
151 bool
152 MixerSettings::AllowInputChannelRemapping()
154 bool temp;
155 fLocker->Lock();
156 temp = fSettings.AllowInputChannelRemapping;
157 fLocker->Unlock();
158 return temp;
162 void
163 MixerSettings::SetAllowInputChannelRemapping(bool yesno)
165 fLocker->Lock();
166 fSettings.AllowInputChannelRemapping = yesno;
167 fLocker->Unlock();
168 StartDeferredSave();
173 MixerSettings::InputGainControls()
175 int temp;
176 fLocker->Lock();
177 temp = fSettings.InputGainControls;
178 fLocker->Unlock();
179 return temp;
183 void
184 MixerSettings::SetInputGainControls(int value)
186 fLocker->Lock();
187 fSettings.InputGainControls = value;
188 fLocker->Unlock();
189 StartDeferredSave();
194 MixerSettings::ResamplingAlgorithm()
196 int temp;
197 fLocker->Lock();
198 temp = fSettings.ResamplingAlgorithm;
199 fLocker->Unlock();
200 return temp;
204 void
205 MixerSettings::SetResamplingAlgorithm(int value)
207 fLocker->Lock();
208 fSettings.ResamplingAlgorithm = value;
209 fLocker->Unlock();
210 StartDeferredSave();
214 bool
215 MixerSettings::RefuseOutputFormatChange()
217 bool temp;
218 fLocker->Lock();
219 temp = fSettings.RefuseOutputFormatChange;
220 fLocker->Unlock();
221 return temp;
225 void
226 MixerSettings::SetRefuseOutputFormatChange(bool yesno)
228 fLocker->Lock();
229 fSettings.RefuseOutputFormatChange = yesno;
230 fLocker->Unlock();
231 StartDeferredSave();
235 bool
236 MixerSettings::RefuseInputFormatChange()
238 bool temp;
239 fLocker->Lock();
240 temp = fSettings.RefuseInputFormatChange;
241 fLocker->Unlock();
242 return temp;
246 void
247 MixerSettings::SetRefuseInputFormatChange(bool yesno)
249 fLocker->Lock();
250 fSettings.RefuseInputFormatChange = yesno;
251 fLocker->Unlock();
252 StartDeferredSave();
256 void
257 MixerSettings::SaveConnectionSettings(MixerInput *input)
259 fLocker->Lock();
260 int index = -1;
262 // try to find matching name first
263 for (int i = 0; i < MAX_INPUT_SETTINGS; i++) {
264 if (fInputSetting[i].IsEmpty())
265 continue;
266 if (!strcmp(fInputSetting[i].FindString("name"), input->MediaInput().name)) {
267 index = i;
268 break;
271 if (index == -1) {
272 // try to find empty location
273 for (int i = 0; i < MAX_INPUT_SETTINGS; i++) {
274 if (fInputSetting[i].IsEmpty()) {
275 index = i;
276 break;
280 if (index == -1) {
281 // find lru location
282 index = 0;
283 for (int i = 0; i < MAX_INPUT_SETTINGS; i++) {
284 if (fInputSetting[i].FindInt64("lru") < fInputSetting[index].FindInt64("lru"))
285 index = i;
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
304 fLocker->Unlock();
305 StartDeferredSave();
309 void
310 MixerSettings::LoadConnectionSettings(MixerInput *input)
312 fLocker->Lock();
313 int index;
314 for (index = 0; index < MAX_INPUT_SETTINGS; index++) {
315 if (fInputSetting[index].IsEmpty())
316 continue;
317 if (!strcmp(fInputSetting[index].FindString("name"), input->MediaInput().name))
318 break;
320 if (index == MAX_INPUT_SETTINGS) {
321 TRACE("LoadConnectionSettings: entry not found\n");
322 fLocker->Unlock();
323 return;
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());
338 fLocker->Unlock();
339 StartDeferredSave();
343 void
344 MixerSettings::SaveConnectionSettings(MixerOutput *output)
346 fLocker->Lock();
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
358 fLocker->Unlock();
359 StartDeferredSave();
363 void
364 MixerSettings::LoadConnectionSettings(MixerOutput *output)
366 fLocker->Lock();
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
376 fLocker->Unlock();
380 void
381 MixerSettings::Save()
383 fLocker->Lock();
384 // if we don't have a settings file, don't continue
385 if (!fSettingsFile) {
386 fLocker->Unlock();
387 return;
389 TRACE("MixerSettings: SAVE!\n");
391 BMessage msg;
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]);
398 char *buffer;
399 size_t length;
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);
408 delete [] buffer;
410 fSettingsDirty = false;
411 fLocker->Unlock();
415 void
416 MixerSettings::Load()
418 fLocker->Lock();
419 // setup defaults
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) {
432 fLocker->Unlock();
433 return;
436 BFile file(fSettingsFile->Path(), B_READ_WRITE);
437 off_t size = 0;
438 file.GetSize(&size);
439 if (size == 0) {
440 fLocker->Unlock();
441 TRACE("MixerSettings: no settings file\n");
442 return;
445 char * buffer = new char[size];
446 if (size != file.Read(buffer, size)) {
447 delete [] buffer;
448 fLocker->Unlock();
449 TRACE("MixerSettings: can't read settings file\n");
450 return;
453 BMessage msg;
454 if (B_OK != msg.Unflatten(buffer)) {
455 delete [] buffer;
456 fLocker->Unlock();
457 TRACE("MixerSettings: can't unflatten settings\n");
458 return;
461 delete [] buffer;
463 if (msg.FindInt32("version") != SETTINGS_VERSION) {
464 fLocker->Unlock();
465 TRACE("MixerSettings: settings have wrong version\n");
466 return;
469 const void *data;
470 ssize_t datasize = 0;
472 msg.FindData("settings", B_RAW_TYPE, &data, &datasize);
473 if (datasize != sizeof(fSettings)) {
474 fLocker->Unlock();
475 TRACE("MixerSettings: settings have wrong size\n");
476 return;
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]);
484 fLocker->Unlock();
488 void
489 MixerSettings::StartDeferredSave()
491 fLocker->Lock();
493 // if we don't have a settings file, don't save the settings
494 if (!fSettingsFile) {
495 fLocker->Unlock();
496 return;
499 fSettingsDirty = true;
500 fSettingsLastChange = system_time();
502 if (fSaveThreadRunning) {
503 fLocker->Unlock();
504 return;
507 StopDeferredSave();
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");
513 Save();
514 fLocker->Unlock();
515 return;
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;
523 Save();
524 fLocker->Unlock();
525 return;
527 resume_thread(fSaveThread);
529 fSaveThreadRunning = true;
530 fLocker->Unlock();
534 void
535 MixerSettings::StopDeferredSave()
537 fLocker->Lock();
539 if (fSaveThread >= 0) {
540 ASSERT(fSaveThreadWaitSem > 0);
542 status_t unused;
543 delete_sem(fSaveThreadWaitSem);
544 wait_for_thread(fSaveThread, &unused);
546 fSaveThread = -1;
547 fSaveThreadWaitSem = -1;
550 fLocker->Unlock();
554 void
555 MixerSettings::SaveThread()
557 bigtime_t timeout;
558 status_t rv;
560 TRACE("MixerSettings: save thread started\n");
562 fLocker->Lock();
563 timeout = fSettingsLastChange + SAVE_DELAY;
564 fLocker->Unlock();
566 for (;;) {
567 rv = acquire_sem_etc(fSaveThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout);
568 if (rv == B_INTERRUPTED)
569 continue;
570 if (rv != B_TIMED_OUT && rv < B_OK)
571 break;
572 if (B_OK != fLocker->LockWithTimeout(200000))
573 continue;
575 TRACE("MixerSettings: save thread running\n");
577 bigtime_t delta = system_time() - fSettingsLastChange;
579 if (fSettingsDirty && delta > SAVE_DELAY) {
580 Save();
583 if (delta > SAVE_RUNTIME) {
584 fSaveThreadRunning = false;
585 fLocker->Unlock();
586 break;
589 timeout = system_time() + SAVE_DELAY;
590 fLocker->Unlock();
593 TRACE("MixerSettings: save thread ended\n");
597 int32
598 MixerSettings::_save_thread_(void *arg)
600 static_cast<MixerSettings *>(arg)->SaveThread();
601 return 0;