/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Diagnostics; namespace Tizen.Multimedia { /// /// Provides the ability to control the sound stream. /// /// 3 public class AudioStreamPolicy : IDisposable { private AudioStreamPolicyHandle _handle; private bool _disposed = false; private Interop.AudioStreamPolicy.FocusStateChangedCallback _focusStateChangedCallback; /// /// Initializes a new instance of the class with . /// /// /// To apply the stream policy according to this stream information, the AudioStreamPolicy should /// be passed to other APIs related to playback or recording. (For example., , /// , etc.) /// /// The type of the sound stream for which the policy needs to be created. /// is invalid. /// 3 public AudioStreamPolicy(AudioStreamType streamType) { ValidationUtil.ValidateEnum(typeof(AudioStreamType), streamType, nameof(streamType)); _focusStateChangedCallback = (IntPtr streamInfo, AudioStreamFocusOptions focusMask, AudioStreamFocusState state, AudioStreamFocusChangedReason reason, AudioStreamBehaviors behaviors, string extraInfo, IntPtr _) => { FocusStateChanged?.Invoke(this, new AudioStreamPolicyFocusStateChangedEventArgs(focusMask, state, reason, behaviors, extraInfo)); }; Interop.AudioStreamPolicy.Create(streamType, _focusStateChangedCallback, IntPtr.Zero, out _handle).ThrowIfError("Unable to create stream information"); Debug.Assert(_handle != null); } /// /// Occurs when the state of focus that belongs to the current AudioStreamPolicy is changed. /// /// /// The event is raised in the internal thread. /// /// 4 public event EventHandler FocusStateChanged; /// /// Gets the . /// /// /// If the of the current AudioStreamPolicy is , /// it returns . /// /// The of the policy instance. /// The has already been disposed of. /// 3 public AudioVolumeType VolumeType { get { var ret = Interop.AudioStreamPolicy.GetSoundType(Handle, out var type); if (ret == AudioManagerError.NoData) { return AudioVolumeType.None; } ret.ThrowIfError("Failed to get volume type"); return type; } } private AudioStreamFocusState GetFocusState(bool playback) { int ret = Interop.AudioStreamPolicy.GetFocusState(Handle, out var stateForPlayback, out var stateForRecording); MultimediaDebug.AssertNoError(ret); return playback ? stateForPlayback : stateForRecording; } /// /// Gets the state of focus for the playback. /// /// The state of focus for playback. /// The has already been disposed of. /// 3 public AudioStreamFocusState PlaybackFocusState => GetFocusState(true); /// /// Gets the state of focus for the recording. /// /// The state of focus for recording. /// The has already been disposed of. /// 3 public AudioStreamFocusState RecordingFocusState => GetFocusState(false); /// /// Gets or sets the auto focus reacquisition. /// /// /// true if the auto focus reacquisition is enabled; otherwise, false.
/// The default is true. ///
/// /// If you don't want to reacquire the focus you've lost automatically, /// disable the focus reacquisition. /// /// The has already been disposed of. /// 3 public bool FocusReacquisitionEnabled { get { Interop.AudioStreamPolicy.GetFocusReacquisition(Handle, out var enabled). ThrowIfError("Failed to get focus reacquisition state"); return enabled; } set { Interop.AudioStreamPolicy.SetFocusReacquisition(Handle, value). ThrowIfError("Failed to set focus reacquisition"); } } internal AudioStreamPolicyHandle Handle { get { if (_disposed) { throw new ObjectDisposedException(nameof(AudioStreamPolicy)); } return _handle; } } /// /// Acquires the stream focus. /// /// The focuses that you want to acquire. /// The requesting behaviors. /// The extra information for this request. This value can be null. /// is zero. /// /// contain a invalid bit.
/// -or-
/// contain a invalid bit. ///
/// The focus has already been acquired. /// Called in raised by releasing focus. /// The has already been disposed of. /// 3 public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo) { if (options == 0) { throw new ArgumentException("options can't be zero.", nameof(options)); } if (options.IsValid() == false) { throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit."); } if (behaviors.IsValid() == false) { throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit."); } Interop.AudioStreamPolicy.AcquireFocus(Handle, options, behaviors, extraInfo). ThrowIfError("Failed to acquire focus"); } /// /// Releases the acquired focus. /// /// The focus mask that you want to release. /// The requesting behaviors. /// The extra information for this request. This value can be null. /// is zero. /// /// contain a invalid bit.
/// -or-
/// contain a invalid bit. ///
/// The focus has not been acquired. /// The has already been disposed of. /// 3 public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo) { if (options == 0) { throw new ArgumentException("options can't be zero.", nameof(options)); } if (options.IsValid() == false) { throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit."); } if (behaviors.IsValid() == false) { throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit."); } Interop.AudioStreamPolicy.ReleaseFocus(Handle, options, behaviors, extraInfo). ThrowIfError("Failed to release focus"); } /// /// Applies the stream routing. /// /// /// If the stream has not been made yet, this will be applied when the stream starts to play. /// /// /// /// The has already been disposed of. /// 3 public void ApplyStreamRouting() { Interop.AudioStreamPolicy.ApplyStreamRouting(Handle).ThrowIfError("Failed to apply stream routing"); } /// /// Adds a device for the stream routing. /// /// The device to add. /// /// The available is and . /// /// /// The device is not connected.
/// -or-
/// An internal error occurs. ///
/// is null. /// of is unavailable for this. /// The has already been disposed of. /// /// /// 3 public void AddDeviceForStreamRouting(AudioDevice device) { if (device == null) { throw new ArgumentNullException(nameof(device)); } var ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(Handle, device.Id); if (ret == AudioManagerError.NoData) { throw new InvalidOperationException("The device seems not connected."); } ret.ThrowIfError("Failed to add device for stream routing"); } /// /// Removes the device for the stream routing. /// /// The device to remove. /// /// The available is and . /// /// An internal error occurs. /// is null. /// The has already been disposed of. /// /// 3 public void RemoveDeviceForStreamRouting(AudioDevice device) { if (device == null) { throw new ArgumentNullException(nameof(device)); } Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(Handle, device.Id). ThrowIfError("Failed to remove device for stream routing"); } /// /// Releases all resources used by the . /// /// 3 public void Dispose() { Dispose(true); } /// /// Releases the unmanaged resources used by the . /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. /// 3 protected virtual void Dispose(bool disposing) { if (!_disposed) { if (_handle != null) { _handle.Dispose(); } _disposed = true; } } #region Static events private static bool _isWatchCallbackRegistered; private static EventHandler _streamFocusStateChanged; private static Interop.AudioStreamPolicy.FocusStateWatchCallback _focusStateWatchCallback; private static readonly object _streamFocusEventLock = new object(); /// /// Occurs when the focus state for stream types is changed regardless of the process. /// /// 3 public static event EventHandler StreamFocusStateChanged { add { lock (_streamFocusEventLock) { if (_isWatchCallbackRegistered == false) { RegisterFocusStateWatch(); _isWatchCallbackRegistered = true; } _streamFocusStateChanged += value; } } remove { lock (_streamFocusEventLock) { _streamFocusStateChanged -= value; } } } private static void RegisterFocusStateWatch() { _focusStateWatchCallback = (id, options, focusState, reason, extraInfo, _) => { _streamFocusStateChanged?.Invoke(null, new StreamFocusStateChangedEventArgs(options, focusState, reason, extraInfo)); }; Interop.AudioStreamPolicy.AddFocusStateWatchCallback( AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording, _focusStateWatchCallback, IntPtr.Zero, out var cbId). ThrowIfError("Failed to initialize focus state event"); } #endregion } }