| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:fidl/fidl.dart'; |
| import 'package:fidl_fuchsia_media/fidl.dart'; |
| import 'package:fidl_fuchsia_sys/fidl.dart'; |
| import 'package:lib.app.dart/app.dart'; |
| import 'package:lib.app.dart/logging.dart'; |
| import 'package:settings_protos/audio.pb.dart' as stored_audio; |
| import 'package:settings_protos/setting_store_legacy.dart'; |
| import 'package:settings_protos/setting_store_factory_legacy.dart'; |
| |
| /// Type for |Audio| update callbacks. |
| typedef UpdateCallback = void Function(); |
| |
| /// System audio. |
| class AudioLegacy { |
| static const double _minLevelGainDb = -60.0; |
| static const double _unityGainDb = 0.0; |
| static const double _initialGainDb = -12.0; |
| |
| // These values determine what counts as a 'significant' change when deciding |
| // whether to call |updateCallback|. |
| static const double _minDbDiff = 0.006; |
| static const double _minPerceivedDiff = 0.0001; |
| |
| final AudioProxy _audioService = new AudioProxy(); |
| |
| double _systemAudioGainDb = _initialGainDb; |
| bool _systemAudioMuted = false; |
| double _systemAudioPerceivedLevel = gainToLevel(_initialGainDb); |
| |
| SettingStoreLegacy<stored_audio.Audio> _store; |
| |
| /// Constructs an Audio object. |
| AudioLegacy(ServiceProvider services) { |
| connectToService(services, _audioService.ctrl); |
| _audioService.ctrl.onConnectionError = _handleConnectionError; |
| _audioService.ctrl.error |
| .then((ProxyError error) => _handleConnectionError(error: error)); |
| _audioService.systemGainMuteChanged = _handleGainMuteChanged; |
| _store = new SettingStoreFactoryLegacy(services).createAudioStore() |
| ..addlistener(_onSettingChanged) |
| ..connect(); |
| } |
| |
| /// Called when properties have changed significantly. |
| UpdateCallback updateCallback; |
| |
| void _onSettingChanged(stored_audio.Audio value) { |
| systemAudioGainDb = value.gain; |
| systemAudioMuted = value.muted; |
| } |
| |
| /// Disposes this object. |
| void dispose() { |
| _audioService.ctrl.close(); |
| } |
| |
| /// Gets the system-wide audio gain in decibels. Gain values are in the range |
| /// -160db to 0db inclusive. |
| double get systemAudioGainDb => _systemAudioGainDb; |
| |
| /// Sets the system-wide audio gain in db. |value| is clamped to the range |
| /// -160db to 0db inclusive. When gain is set to -160db, |systemAudioMuted| is |
| /// implicitly set to true. When gain is changed from -160db to a higher |
| /// value, |systemAudioMuted| is implicitly set to false. |
| set systemAudioGainDb(double value) { |
| double clampedValue = value.clamp(mutedGainDb, _unityGainDb); |
| if (_systemAudioGainDb == clampedValue) { |
| return; |
| } |
| |
| _systemAudioGainDb = clampedValue; |
| _systemAudioPerceivedLevel = gainToLevel(clampedValue); |
| |
| if (_systemAudioGainDb == mutedGainDb) { |
| _systemAudioMuted = true; |
| } |
| |
| _audioService.setSystemGain(_systemAudioGainDb); |
| } |
| |
| /// Gets system-wide audio muted state. |systemAudioMuted| is always true |
| /// when |systemAudioGainDb| is -160db. |
| bool get systemAudioMuted => _systemAudioMuted; |
| |
| /// Sets system-wide audio muted state. Setting this value to false when |
| /// |systemAudioGainDb| is -160db has no effect. |
| set systemAudioMuted(bool value) { |
| bool muted = value || _systemAudioGainDb == mutedGainDb; |
| if (_systemAudioMuted == muted) { |
| return; |
| } |
| |
| _systemAudioMuted = muted; |
| _audioService.setSystemMute(_systemAudioMuted); |
| |
| _persistUserSetting(); |
| } |
| |
| void _persistUserSetting() { |
| final stored_audio.Audio audio = new stored_audio.Audio() |
| ..clear() |
| ..muted = _systemAudioMuted |
| ..gain = _systemAudioGainDb; |
| _store.commit(audio); |
| } |
| |
| /// Gets the perceived system-wide audio level in the range [0,1]. This value |
| /// is intended to be used for volume sliders. If there is no separate mute |
| /// control, use (systemAudioMuted ? 0.0 : systemAudioPerceivedLevel). |
| double get systemAudioPerceivedLevel => _systemAudioPerceivedLevel; |
| |
| /// Sets the perceived system-wide audio level in the range [0,1]. When this |
| /// property is set to 0.0, |systemAudioGainDb| is set to -160db. |
| set systemAudioPerceivedLevel(double value) { |
| _systemAudioPerceivedLevel = value.clamp(0.0, 1.0); |
| _systemAudioGainDb = levelToGain(_systemAudioPerceivedLevel); |
| |
| _persistUserSetting(); |
| _audioService.setSystemGain(_systemAudioGainDb); |
| } |
| |
| // Handles a status update from the audio service. Call with |
| // kInitialStatus, null to initiate status updates. |
| void _handleGainMuteChanged(double gainDb, bool muted) { |
| bool callUpdate = _systemAudioMuted != muted || |
| (_systemAudioGainDb - gainDb).abs() > _minDbDiff; |
| |
| _systemAudioGainDb = gainDb; |
| _systemAudioMuted = muted; |
| |
| double newPerceivedLevel = gainToLevel(_systemAudioGainDb); |
| if ((_systemAudioPerceivedLevel - newPerceivedLevel).abs() > |
| _minPerceivedDiff) { |
| _systemAudioPerceivedLevel = newPerceivedLevel; |
| callUpdate = true; |
| } |
| |
| if (callUpdate && updateCallback != null) { |
| updateCallback(); |
| } |
| } |
| |
| /// Handles connection error to the audio service. |
| void _handleConnectionError({ProxyError error}) { |
| log.severe('Unable to connect to audio service', error); |
| } |
| |
| void setRoutingPolicy(AudioOutputRoutingPolicy policy) { |
| _audioService.setRoutingPolicy(policy); |
| } |
| |
| /// Converts a gain in db to an audio 'level' in the range 0.0 to 1.0 |
| /// inclusive. |
| static double gainToLevel(double gainDb) { |
| if (gainDb <= _minLevelGainDb) { |
| return 0.0; |
| } |
| |
| if (gainDb >= _unityGainDb) { |
| return 1.0; |
| } |
| |
| return 1.0 - gainDb / _minLevelGainDb; |
| } |
| |
| /// Converts an audio 'level' in the range 0.0 to 1.0 inclusive to a gain in |
| /// db. |
| static double levelToGain(double level) { |
| if (level <= 0.0) { |
| return mutedGainDb; |
| } |
| |
| if (level >= 1.0) { |
| return _unityGainDb; |
| } |
| |
| return (1.0 - level) * _minLevelGainDb; |
| } |
| } |