SEBWIN-303: Implemented audio settings.

This commit is contained in:
dbuechel 2019-08-16 08:26:11 +02:00
parent 4381be2647
commit 758b61084a
9 changed files with 154 additions and 14 deletions

View file

@ -67,10 +67,6 @@ namespace SafeExamBrowser.Client
private IProcessMonitor processMonitor; private IProcessMonitor processMonitor;
private INativeMethods nativeMethods; private INativeMethods nativeMethods;
private IRuntimeProxy runtimeProxy; private IRuntimeProxy runtimeProxy;
private ISystemComponent<ISystemAudioControl> audio;
private ISystemComponent<ISystemKeyboardLayoutControl> keyboardLayout;
private ISystemComponent<ISystemPowerSupplyControl> powerSupply;
private ISystemComponent<ISystemWirelessNetworkControl> wirelessNetwork;
private ISystemInfo systemInfo; private ISystemInfo systemInfo;
private ITaskbar taskbar; private ITaskbar taskbar;
private ITerminationActivator terminationActivator; private ITerminationActivator terminationActivator;
@ -94,17 +90,13 @@ namespace SafeExamBrowser.Client
InitializeText(); InitializeText();
actionCenter = BuildActionCenter(); actionCenter = BuildActionCenter();
audio = new Audio(new ModuleLogger(logger, nameof(Audio)), text);
keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text);
messageBox = BuildMessageBox(); messageBox = BuildMessageBox();
powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text);
processMonitor = new ProcessMonitor(new ModuleLogger(logger, nameof(ProcessMonitor)), nativeMethods); processMonitor = new ProcessMonitor(new ModuleLogger(logger, nameof(ProcessMonitor)), nativeMethods);
uiFactory = BuildUserInterfaceFactory(); uiFactory = BuildUserInterfaceFactory();
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(RuntimeProxy)), Interlocutor.Client); runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(RuntimeProxy)), Interlocutor.Client);
taskbar = BuildTaskbar(); taskbar = BuildTaskbar();
terminationActivator = new TerminationActivator(new ModuleLogger(logger, nameof(TerminationActivator))); terminationActivator = new TerminationActivator(new ModuleLogger(logger, nameof(TerminationActivator)));
windowMonitor = new WindowMonitor(new ModuleLogger(logger, nameof(WindowMonitor)), nativeMethods); windowMonitor = new WindowMonitor(new ModuleLogger(logger, nameof(WindowMonitor)), nativeMethods);
wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text);
var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, nameof(DisplayMonitor)), nativeMethods, systemInfo); var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, nameof(DisplayMonitor)), nativeMethods, systemInfo);
var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods); var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods);
@ -263,8 +255,12 @@ namespace SafeExamBrowser.Client
{ {
var aboutInfo = new AboutNotificationInfo(text); var aboutInfo = new AboutNotificationInfo(text);
var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory); var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory);
var audio = new Audio(configuration.Settings.Audio, new ModuleLogger(logger, nameof(Audio)), text);
var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text);
var logInfo = new LogNotificationInfo(text); var logInfo = new LogNotificationInfo(text);
var logController = new LogNotificationController(logger, uiFactory); var logController = new LogNotificationController(logger, uiFactory);
var powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text);
var wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text);
var activators = new IActionCenterActivator[] var activators = new IActionCenterActivator[]
{ {
new KeyboardActivator(new ModuleLogger(logger, nameof(KeyboardActivator))), new KeyboardActivator(new ModuleLogger(logger, nameof(KeyboardActivator))),

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Configuration.Settings;
namespace SafeExamBrowser.Configuration.ConfigurationData
{
internal partial class DataMapper
{
private void MapInitialVolumeLevel(Settings settings, object value)
{
if (value is int volume)
{
settings.Audio.InitialVolume = volume;
}
}
private void MapMuteAudio(Settings settings, object value)
{
if (value is bool mute)
{
settings.Audio.MuteAudio = mute;
}
}
private void MapSetInitialVolumeLevel(Settings settings, object value)
{
if (value is bool initialize)
{
settings.Audio.InitializeVolume = initialize;
}
}
}
}

View file

@ -17,6 +17,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
foreach (var item in rawData) foreach (var item in rawData)
{ {
MapAudioSettings(item.Key, item.Value, settings);
MapBrowserSettings(item.Key, item.Value, settings); MapBrowserSettings(item.Key, item.Value, settings);
MapConfigurationFileSettings(item.Key, item.Value, settings); MapConfigurationFileSettings(item.Key, item.Value, settings);
MapGeneralSettings(item.Key, item.Value, settings); MapGeneralSettings(item.Key, item.Value, settings);
@ -30,6 +31,22 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
MapUserAgentMode(rawData, settings); MapUserAgentMode(rawData, settings);
} }
private void MapAudioSettings(string key, object value, Settings settings)
{
switch (key)
{
case Keys.Audio.InitialVolumeLevel:
MapInitialVolumeLevel(settings, value);
break;
case Keys.Audio.MuteAudio:
MapMuteAudio(settings, value);
break;
case Keys.Audio.SetInitialVolumeLevel:
MapSetInitialVolumeLevel(settings, value);
break;
}
}
private void MapBrowserSettings(string key, object value, Settings settings) private void MapBrowserSettings(string key, object value, Settings settings)
{ {
switch (key) switch (key)

View file

@ -18,6 +18,13 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
} }
internal static class Audio
{
internal const string InitialVolumeLevel = "audioVolumeLevel";
internal const string MuteAudio = "audioMute";
internal const string SetInitialVolumeLevel = "audioSetVolumeLevel";
}
internal static class Browser internal static class Browser
{ {
internal const string AllowConfigurationDownloads = "downloadAndOpenSebConfig"; internal const string AllowConfigurationDownloads = "downloadAndOpenSebConfig";

View file

@ -66,6 +66,9 @@
<Compile Include="DataFormats\BinarySerializer.cs" /> <Compile Include="DataFormats\BinarySerializer.cs" />
<Compile Include="DataFormats\BinaryBlock.cs" /> <Compile Include="DataFormats\BinaryBlock.cs" />
<Compile Include="ConfigurationData\DataMapper.cs" /> <Compile Include="ConfigurationData\DataMapper.cs" />
<Compile Include="ConfigurationData\DataMapper.Audio.cs">
<DependentUpon>DataMapper.cs</DependentUpon>
</Compile>
<Compile Include="ConfigurationData\DataMapper.Browser.cs"> <Compile Include="ConfigurationData\DataMapper.Browser.cs">
<DependentUpon>DataMapper.cs</DependentUpon> <DependentUpon>DataMapper.cs</DependentUpon>
</Compile> </Compile>

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
namespace SafeExamBrowser.Contracts.Configuration.Settings
{
/// <summary>
/// Defines all configuration options for the audio device of the computer.
/// </summary>
[Serializable]
public class AudioSettings
{
/// <summary>
/// Defines whether the audio volume should be initialized to the value of <see cref="InitialVolume"/> during application startup.
/// </summary>
public bool InitializeVolume { get; set; }
/// <summary>
/// Defines the initial audio volume (from 0 to 100) to be used if <see cref="InitializeVolume"/> is active.
/// </summary>
public int InitialVolume { get; set; }
/// <summary>
/// Defines whether the audio device should be muted during application startup.
/// </summary>
public bool MuteAudio { get; set; }
}
}

View file

@ -32,6 +32,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// </summary> /// </summary>
public bool AllowApplicationLogAccess { get; set; } public bool AllowApplicationLogAccess { get; set; }
/// <summary>
/// All audio-related settings.
/// </summary>
public AudioSettings Audio { get; set; }
/// <summary> /// <summary>
/// All browser-related settings. /// All browser-related settings.
/// </summary> /// </summary>
@ -85,6 +90,7 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
public Settings() public Settings()
{ {
ActionCenter = new ActionCenterSettings(); ActionCenter = new ActionCenterSettings();
Audio = new AudioSettings();
Browser = new BrowserSettings(); Browser = new BrowserSettings();
Keyboard = new KeyboardSettings(); Keyboard = new KeyboardSettings();
Mouse = new MouseSettings(); Mouse = new MouseSettings();

View file

@ -84,6 +84,7 @@
<Compile Include="Configuration\SaveStatus.cs" /> <Compile Include="Configuration\SaveStatus.cs" />
<Compile Include="Configuration\ServiceConfiguration.cs" /> <Compile Include="Configuration\ServiceConfiguration.cs" />
<Compile Include="Configuration\Settings\ActionCenterSettings.cs" /> <Compile Include="Configuration\Settings\ActionCenterSettings.cs" />
<Compile Include="Configuration\Settings\AudioSettings.cs" />
<Compile Include="Configuration\Settings\BrowserWindowSettings.cs" /> <Compile Include="Configuration\Settings\BrowserWindowSettings.cs" />
<Compile Include="Configuration\Settings\ServiceSettings.cs" /> <Compile Include="Configuration\Settings\ServiceSettings.cs" />
<Compile Include="Configuration\Settings\UserInterfaceMode.cs" /> <Compile Include="Configuration\Settings\UserInterfaceMode.cs" />

View file

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NAudio.CoreAudioApi; using NAudio.CoreAudioApi;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.SystemComponents;
@ -21,15 +22,18 @@ namespace SafeExamBrowser.SystemComponents
{ {
private readonly object @lock = new object(); private readonly object @lock = new object();
private AudioSettings settings;
private MMDevice audioDevice; private MMDevice audioDevice;
private string audioDeviceShortName; private string audioDeviceShortName;
private List<ISystemAudioControl> controls; private List<ISystemAudioControl> controls;
private float originalVolume;
private ILogger logger; private ILogger logger;
private IText text; private IText text;
public Audio(ILogger logger, IText text) public Audio(AudioSettings settings, ILogger logger, IText text)
{ {
this.controls = new List<ISystemAudioControl>(); this.controls = new List<ISystemAudioControl>();
this.settings = settings;
this.logger = logger; this.logger = logger;
this.text = text; this.text = text;
} }
@ -64,9 +68,8 @@ namespace SafeExamBrowser.SystemComponents
{ {
if (audioDevice != default(MMDevice)) if (audioDevice != default(MMDevice))
{ {
audioDevice.AudioEndpointVolume.OnVolumeNotification -= AudioEndpointVolume_OnVolumeNotification; RevertSettings();
audioDevice.Dispose(); FinalizeAudioDevice();
logger.Info("Stopped monitoring the audio device.");
} }
foreach (var control in controls) foreach (var control in controls)
@ -100,9 +103,43 @@ namespace SafeExamBrowser.SystemComponents
logger.Info("Started monitoring the audio device."); logger.Info("Started monitoring the audio device.");
} }
private void FinalizeAudioDevice()
{
audioDevice.AudioEndpointVolume.OnVolumeNotification -= AudioEndpointVolume_OnVolumeNotification;
audioDevice.Dispose();
logger.Info("Stopped monitoring the audio device.");
}
private void InitializeSettings() private void InitializeSettings()
{ {
// TODO: Mute on startup & initial volume! if (settings.InitializeVolume)
{
originalVolume = audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar;
logger.Info($"Saved original volume of {Math.Round(originalVolume * 100)}%.");
audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar = settings.InitialVolume / 100f;
logger.Info($"Set initial volume to {settings.InitialVolume}%.");
}
if (settings.MuteAudio)
{
audioDevice.AudioEndpointVolume.Mute = true;
logger.Info("Muted audio device.");
}
}
private void RevertSettings()
{
if (settings.InitializeVolume)
{
audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar = originalVolume;
logger.Info($"Reverted volume to original value of {Math.Round(originalVolume * 100)}%.");
}
if (settings.MuteAudio)
{
audioDevice.AudioEndpointVolume.Mute = false;
logger.Info("Unmuted audio device.");
}
} }
private void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data) private void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
@ -111,7 +148,7 @@ namespace SafeExamBrowser.SystemComponents
{ {
var info = BuildInfoText(data.MasterVolume, data.Muted); var info = BuildInfoText(data.MasterVolume, data.Muted);
logger.Debug($"Detected audio device change: Volume {data.MasterVolume * 100}, {(data.Muted ? "muted" : "unmuted")}"); logger.Debug($"Volume {data.MasterVolume * 100}%, {(data.Muted ? "muted" : "unmuted")}");
foreach (var control in controls) foreach (var control in controls)
{ {