2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIDialogAudioSettings.h"
11 #include "GUIPassword.h"
12 #include "ServiceBroker.h"
13 #include "addons/Skin.h"
14 #include "application/ApplicationComponents.h"
15 #include "application/ApplicationPlayer.h"
16 #include "application/ApplicationVolumeHandling.h"
17 #include "cores/AudioEngine/Utils/AEUtil.h"
18 #include "cores/IPlayer.h"
19 #include "dialogs/GUIDialogYesNo.h"
20 #include "guilib/GUIMessage.h"
21 #include "guilib/LocalizeStrings.h"
22 #include "profiles/ProfileManager.h"
23 #include "settings/AdvancedSettings.h"
24 #include "settings/MediaSettings.h"
25 #include "settings/Settings.h"
26 #include "settings/SettingsComponent.h"
27 #include "settings/lib/Setting.h"
28 #include "settings/lib/SettingDefinitions.h"
29 #include "settings/lib/SettingsManager.h"
30 #include "utils/LangCodeExpander.h"
31 #include "utils/StringUtils.h"
32 #include "utils/Variant.h"
33 #include "utils/log.h"
34 #include "video/VideoDatabase.h"
40 #define SETTING_AUDIO_VOLUME "audio.volume"
41 #define SETTING_AUDIO_VOLUME_AMPLIFICATION "audio.volumeamplification"
42 #define SETTING_AUDIO_CENTERMIXLEVEL "audio.centermixlevel"
43 #define SETTING_AUDIO_DELAY "audio.delay"
44 #define SETTING_AUDIO_STREAM "audio.stream"
45 #define SETTING_AUDIO_PASSTHROUGH "audio.digitalanalog"
46 #define SETTING_AUDIO_MAKE_DEFAULT "audio.makedefault"
48 CGUIDialogAudioSettings::CGUIDialogAudioSettings()
49 : CGUIDialogSettingsManualBase(WINDOW_DIALOG_AUDIO_OSD_SETTINGS
, "DialogSettings.xml")
52 CGUIDialogAudioSettings::~CGUIDialogAudioSettings() = default;
54 void CGUIDialogAudioSettings::FrameMove()
56 // update the volume setting if necessary
57 const auto& components
= CServiceBroker::GetAppComponents();
58 const auto appVolume
= components
.GetComponent
<CApplicationVolumeHandling
>();
59 float newVolume
= appVolume
->GetVolumeRatio();
60 if (newVolume
!= m_volume
)
61 GetSettingsManager()->SetNumber(SETTING_AUDIO_VOLUME
, static_cast<double>(newVolume
));
63 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
64 if (appPlayer
->HasPlayer())
66 const CVideoSettings videoSettings
= appPlayer
->GetVideoSettings();
68 // these settings can change on the fly
69 //! @todo (needs special handling): m_settingsManager->SetInt(SETTING_AUDIO_STREAM, g_application.GetAppPlayer().GetAudioStream());
70 GetSettingsManager()->SetNumber(SETTING_AUDIO_DELAY
,
71 static_cast<double>(videoSettings
.m_AudioDelay
));
72 GetSettingsManager()->SetBool(SETTING_AUDIO_PASSTHROUGH
, CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
));
75 CGUIDialogSettingsManualBase::FrameMove();
78 std::string
CGUIDialogAudioSettings::FormatDelay(float value
, float interval
)
80 if (fabs(value
) < 0.5f
* interval
)
81 return StringUtils::Format(g_localizeStrings
.Get(22003), 0.0);
83 return StringUtils::Format(g_localizeStrings
.Get(22004), fabs(value
));
85 return StringUtils::Format(g_localizeStrings
.Get(22005), value
);
88 std::string
CGUIDialogAudioSettings::FormatDecibel(float value
)
90 return StringUtils::Format(g_localizeStrings
.Get(14054), value
);
93 std::string
CGUIDialogAudioSettings::FormatPercentAsDecibel(float value
)
95 return StringUtils::Format(g_localizeStrings
.Get(14054), CAEUtil::PercentToGain(value
));
98 void CGUIDialogAudioSettings::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
103 CGUIDialogSettingsManualBase::OnSettingChanged(setting
);
105 auto& components
= CServiceBroker::GetAppComponents();
106 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
108 const std::string
&settingId
= setting
->GetId();
109 if (settingId
== SETTING_AUDIO_VOLUME
)
111 m_volume
= static_cast<float>(std::static_pointer_cast
<const CSettingNumber
>(setting
)->GetValue());
112 const auto appVolume
= components
.GetComponent
<CApplicationVolumeHandling
>();
113 appVolume
->SetVolume(m_volume
, false); // false - value is not in percent
115 else if (settingId
== SETTING_AUDIO_VOLUME_AMPLIFICATION
)
117 float value
= static_cast<float>(std::static_pointer_cast
<const CSettingNumber
>(setting
)->GetValue());
118 appPlayer
->SetDynamicRangeCompression((long)(value
* 100));
120 else if (settingId
== SETTING_AUDIO_CENTERMIXLEVEL
)
122 CVideoSettings vs
= appPlayer
->GetVideoSettings();
123 vs
.m_CenterMixLevel
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
124 appPlayer
->SetVideoSettings(vs
);
126 else if (settingId
== SETTING_AUDIO_DELAY
)
128 float value
= static_cast<float>(std::static_pointer_cast
<const CSettingNumber
>(setting
)->GetValue());
129 appPlayer
->SetAVDelay(value
);
131 else if (settingId
== SETTING_AUDIO_STREAM
)
133 m_audioStream
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
134 // only change the audio stream if a different one has been asked for
135 if (appPlayer
->GetAudioStream() != m_audioStream
)
137 appPlayer
->SetAudioStream(m_audioStream
); // Set the audio stream to the one selected
140 else if (settingId
== SETTING_AUDIO_PASSTHROUGH
)
142 m_passthrough
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
143 CServiceBroker::GetSettingsComponent()->GetSettings()->SetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
, m_passthrough
);
147 void CGUIDialogAudioSettings::OnSettingAction(const std::shared_ptr
<const CSetting
>& setting
)
152 CGUIDialogSettingsManualBase::OnSettingAction(setting
);
154 const std::string
&settingId
= setting
->GetId();
155 if (settingId
== SETTING_AUDIO_MAKE_DEFAULT
)
159 bool CGUIDialogAudioSettings::Save()
161 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
163 if (!g_passwordManager
.CheckSettingLevelLock(SettingLevel::Expert
) &&
164 profileManager
->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE
)
167 // prompt user if they are sure
168 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant
{12376}, CVariant
{12377}))
171 // reset the settings
176 db
.EraseAllVideoSettings();
179 const auto& components
= CServiceBroker::GetAppComponents();
180 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
181 CMediaSettings::GetInstance().GetDefaultVideoSettings() = appPlayer
->GetVideoSettings();
182 CMediaSettings::GetInstance().GetDefaultVideoSettings().m_AudioStream
= -1;
183 CServiceBroker::GetSettingsComponent()->GetSettings()->Save();
188 void CGUIDialogAudioSettings::SetupView()
190 CGUIDialogSettingsManualBase::SetupView();
193 SET_CONTROL_HIDDEN(CONTROL_SETTINGS_OKAY_BUTTON
);
194 SET_CONTROL_HIDDEN(CONTROL_SETTINGS_CUSTOM_BUTTON
);
195 SET_CONTROL_LABEL(CONTROL_SETTINGS_CANCEL_BUTTON
, 15067);
198 void CGUIDialogAudioSettings::InitializeSettings()
200 CGUIDialogSettingsManualBase::InitializeSettings();
202 const std::shared_ptr
<CSettingCategory
> category
= AddCategory("audiosubtitlesettings", -1);
203 if (category
== NULL
)
205 CLog::Log(LOGERROR
, "CGUIDialogAudioSettings: unable to setup settings");
209 // get all necessary setting groups
210 const std::shared_ptr
<CSettingGroup
> groupAudio
= AddGroup(category
);
211 if (groupAudio
== NULL
)
213 CLog::Log(LOGERROR
, "CGUIDialogAudioSettings: unable to setup settings");
216 const std::shared_ptr
<CSettingGroup
> groupSubtitles
= AddGroup(category
);
217 if (groupSubtitles
== NULL
)
219 CLog::Log(LOGERROR
, "CGUIDialogAudioSettings: unable to setup settings");
222 const std::shared_ptr
<CSettingGroup
> groupSaveAsDefault
= AddGroup(category
);
223 if (groupSaveAsDefault
== NULL
)
225 CLog::Log(LOGERROR
, "CGUIDialogAudioSettings: unable to setup settings");
229 bool usePopup
= g_SkinInfo
->HasSkinFile("DialogSlider.xml");
231 const auto& components
= CServiceBroker::GetAppComponents();
232 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
234 const CVideoSettings videoSettings
= appPlayer
->GetVideoSettings();
235 if (appPlayer
->HasPlayer())
237 appPlayer
->GetAudioCapabilities(m_audioCaps
);
240 // register IsPlayingPassthrough condition
241 GetSettingsManager()->AddDynamicCondition("IsPlayingPassthrough", IsPlayingPassthrough
);
243 CSettingDependency
dependencyAudioOutputPassthroughDisabled(SettingDependencyType::Enable
, GetSettingsManager());
244 dependencyAudioOutputPassthroughDisabled
.Or()
245 ->Add(std::make_shared
<CSettingDependencyCondition
>(SETTING_AUDIO_PASSTHROUGH
, "false",
246 SettingDependencyOperator::Equals
, false,
247 GetSettingsManager()))
248 ->Add(std::make_shared
<CSettingDependencyCondition
>("IsPlayingPassthrough", "", "", true,
249 GetSettingsManager()));
250 SettingDependencies depsAudioOutputPassthroughDisabled
;
251 depsAudioOutputPassthroughDisabled
.push_back(dependencyAudioOutputPassthroughDisabled
);
254 // audio volume setting
255 const auto appVolume
= components
.GetComponent
<CApplicationVolumeHandling
>();
256 m_volume
= appVolume
->GetVolumeRatio();
257 std::shared_ptr
<CSettingNumber
> settingAudioVolume
=
258 AddSlider(groupAudio
, SETTING_AUDIO_VOLUME
, 13376, SettingLevel::Basic
, m_volume
, 14054,
259 CApplicationVolumeHandling::VOLUME_MINIMUM
,
260 CApplicationVolumeHandling::VOLUME_MAXIMUM
/ 100.0f
,
261 CApplicationVolumeHandling::VOLUME_MAXIMUM
);
262 settingAudioVolume
->SetDependencies(depsAudioOutputPassthroughDisabled
);
263 std::static_pointer_cast
<CSettingControlSlider
>(settingAudioVolume
->GetControl())->SetFormatter(SettingFormatterPercentAsDecibel
);
265 // audio volume amplification setting
266 if (SupportsAudioFeature(IPlayerAudioCaps::VOLUME_AMP
))
268 std::shared_ptr
<CSettingNumber
> settingAudioVolumeAmplification
= AddSlider(groupAudio
, SETTING_AUDIO_VOLUME_AMPLIFICATION
, 660, SettingLevel::Basic
, videoSettings
.m_VolumeAmplification
, 14054, VOLUME_DRC_MINIMUM
* 0.01f
, (VOLUME_DRC_MAXIMUM
- VOLUME_DRC_MINIMUM
) / 6000.0f
, VOLUME_DRC_MAXIMUM
* 0.01f
);
269 settingAudioVolumeAmplification
->SetDependencies(depsAudioOutputPassthroughDisabled
);
272 // downmix: center mix level
274 AddSlider(groupAudio
, SETTING_AUDIO_CENTERMIXLEVEL
, 39112, SettingLevel::Basic
,
275 videoSettings
.m_CenterMixLevel
, 14050, -10, 1, 30,
276 -1, false, false, true, 39113);
279 // audio delay setting
280 if (SupportsAudioFeature(IPlayerAudioCaps::OFFSET
))
282 std::shared_ptr
<CSettingNumber
> settingAudioDelay
= AddSlider(
283 groupAudio
, SETTING_AUDIO_DELAY
, 297, SettingLevel::Basic
, videoSettings
.m_AudioDelay
, 0,
284 -CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoAudioDelayRange
,
286 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoAudioDelayRange
, 297,
288 std::static_pointer_cast
<CSettingControlSlider
>(settingAudioDelay
->GetControl())->SetFormatter(SettingFormatterDelay
);
291 // audio stream setting
292 if (SupportsAudioFeature(IPlayerAudioCaps::SELECT_STREAM
))
293 AddAudioStreams(groupAudio
, SETTING_AUDIO_STREAM
);
295 // audio digital/analog setting
296 if (SupportsAudioFeature(IPlayerAudioCaps::SELECT_OUTPUT
))
298 m_passthrough
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_PASSTHROUGH
);
299 AddToggle(groupAudio
, SETTING_AUDIO_PASSTHROUGH
, 348, SettingLevel::Basic
, m_passthrough
);
302 // subtitle stream setting
303 AddButton(groupSaveAsDefault
, SETTING_AUDIO_MAKE_DEFAULT
, 12376, SettingLevel::Basic
);
306 bool CGUIDialogAudioSettings::SupportsAudioFeature(IPlayerAudioCaps feature
)
308 for (IPlayerAudioCaps cap
: m_audioCaps
)
310 if (cap
== feature
|| cap
== IPlayerAudioCaps::ALL
)
317 void CGUIDialogAudioSettings::AddAudioStreams(const std::shared_ptr
<CSettingGroup
>& group
,
318 const std::string
& settingId
)
320 if (group
== NULL
|| settingId
.empty())
323 auto& components
= CServiceBroker::GetAppComponents();
324 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
325 m_audioStream
= appPlayer
->GetAudioStream();
326 if (m_audioStream
< 0)
329 AddList(group
, settingId
, 460, SettingLevel::Basic
, m_audioStream
, AudioStreamsOptionFiller
, 460);
332 bool CGUIDialogAudioSettings::IsPlayingPassthrough(const std::string
& condition
,
333 const std::string
& value
,
334 const SettingConstPtr
& setting
,
337 const auto& components
= CServiceBroker::GetAppComponents();
338 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
339 return appPlayer
->IsPassthrough();
342 void CGUIDialogAudioSettings::AudioStreamsOptionFiller(const SettingConstPtr
& setting
,
343 std::vector
<IntegerSettingOption
>& list
,
347 const auto& components
= CServiceBroker::GetAppComponents();
348 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
349 const int audioStreamCount
= appPlayer
->GetAudioStreamCount();
351 std::string channelsLabel
= g_localizeStrings
.Get(10127);
352 std::string strUnknown
= "[" + g_localizeStrings
.Get(13205) + "]";
354 // cycle through each audio stream and add it to our list control
355 for (int i
= 0; i
< audioStreamCount
; ++i
)
357 std::string strLanguage
;
359 AudioStreamInfo info
;
360 appPlayer
->GetAudioStreamInfo(i
, info
);
362 if (!g_LangCodeExpander
.Lookup(info
.language
, strLanguage
))
363 strLanguage
= strUnknown
;
365 std::string textInfo
= strLanguage
;
366 if (!info
.name
.empty())
367 textInfo
+= " - " + info
.name
;
370 if (!info
.codecDesc
.empty())
371 textInfo
+= info
.codecDesc
+ ", ";
373 textInfo
+= std::to_string(info
.channels
) + " " + channelsLabel
+ ")";
375 textInfo
+= FormatFlags(info
.flags
);
376 textInfo
+= StringUtils::Format(" ({}/{})", i
+ 1, audioStreamCount
);
377 list
.emplace_back(textInfo
, i
);
382 list
.emplace_back(g_localizeStrings
.Get(231), -1);
387 std::string
CGUIDialogAudioSettings::SettingFormatterDelay(
388 const std::shared_ptr
<const CSettingControlSlider
>& control
,
389 const CVariant
& value
,
390 const CVariant
& minimum
,
391 const CVariant
& step
,
392 const CVariant
& maximum
)
394 if (!value
.isDouble())
397 float fValue
= value
.asFloat();
398 float fStep
= step
.asFloat();
400 if (fabs(fValue
) < 0.5f
* fStep
)
401 return StringUtils::Format(g_localizeStrings
.Get(22003), 0.0);
403 return StringUtils::Format(g_localizeStrings
.Get(22004), fabs(fValue
));
405 return StringUtils::Format(g_localizeStrings
.Get(22005), fValue
);
408 std::string
CGUIDialogAudioSettings::SettingFormatterPercentAsDecibel(
409 const std::shared_ptr
<const CSettingControlSlider
>& control
,
410 const CVariant
& value
,
411 const CVariant
& minimum
,
412 const CVariant
& step
,
413 const CVariant
& maximum
)
415 if (control
== NULL
|| !value
.isDouble())
418 std::string formatString
= control
->GetFormatString();
419 if (control
->GetFormatLabel() > -1)
420 formatString
= g_localizeStrings
.Get(control
->GetFormatLabel());
422 return StringUtils::Format(formatString
, CAEUtil::PercentToGain(value
.asFloat()));
425 std::string
CGUIDialogAudioSettings::FormatFlags(StreamFlags flags
)
427 std::vector
<std::string
> localizedFlags
;
428 if (flags
& StreamFlags::FLAG_DEFAULT
)
429 localizedFlags
.emplace_back(g_localizeStrings
.Get(39105));
430 if (flags
& StreamFlags::FLAG_FORCED
)
431 localizedFlags
.emplace_back(g_localizeStrings
.Get(39106));
432 if (flags
& StreamFlags::FLAG_HEARING_IMPAIRED
)
433 localizedFlags
.emplace_back(g_localizeStrings
.Get(39107));
434 if (flags
& StreamFlags::FLAG_VISUAL_IMPAIRED
)
435 localizedFlags
.emplace_back(g_localizeStrings
.Get(39108));
436 if (flags
& StreamFlags::FLAG_ORIGINAL
)
437 localizedFlags
.emplace_back(g_localizeStrings
.Get(39111));
439 std::string formated
= StringUtils::Join(localizedFlags
, ", ");
441 if (!formated
.empty())
442 formated
= StringUtils::Format(" [{}]", formated
);