2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Diagnostics;
20 namespace Tizen.Multimedia
23 /// Provides the ability to control a sound stream.
25 public class AudioStreamPolicy : IDisposable
27 private AudioStreamPolicyHandle _handle;
28 private bool _disposed = false;
29 private Interop.AudioStreamPolicy.FocusStateChangedCallback _focusStateChangedCallback;
32 /// Initializes a new instance of the <see cref="AudioStreamPolicy"/> class with <see cref="AudioStreamType"/>
35 /// To apply the stream policy according to this stream information, the AudioStreamPolicy should
36 /// be passed to other APIs related to playback or recording. (e.g., <see cref="Player"/>, <see cref="WavPlayer"/> , etc.)
38 /// <param name="streamType">Type of sound stream for which policy needs to be created.</param>
39 /// <exception cref="ArgumentException"><paramref name="streamType"/> is invalid.</exception>
40 public AudioStreamPolicy(AudioStreamType streamType)
42 ValidationUtil.ValidateEnum(typeof(AudioStreamType), streamType, nameof(streamType));
44 _focusStateChangedCallback = (IntPtr streamInfo, AudioStreamFocusOptions focusMask,
45 AudioStreamFocusState state, AudioStreamFocusChangedReason reason, AudioStreamBehaviors behaviors,
46 string extraInfo, IntPtr userData) =>
48 FocusStateChanged?.Invoke(this,
49 new AudioStreamPolicyFocusStateChangedEventArgs(focusMask, state, reason, behaviors, extraInfo));
52 Interop.AudioStreamPolicy.Create(streamType, _focusStateChangedCallback,
53 IntPtr.Zero, out _handle).Validate("Unable to create stream information");
55 Debug.Assert(_handle != null);
59 /// Occurs when the state of focus that belongs to the current AudioStreamPolicy is changed.
62 /// The event is raised in the internal thread.
64 public event EventHandler<AudioStreamPolicyFocusStateChangedEventArgs> FocusStateChanged;
67 /// Gets the <see cref="AudioVolumeType"/>.
70 /// If the <see cref="AudioStreamType"/> of the current AudioStreamPolicy is <see cref="AudioStreamType.Emergency"/>,
71 /// it returns <see cref="AudioVolumeType.None"/>.
73 /// <value>The <see cref="AudioVolumeType"/> of the policy instance.</value>
74 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
75 public AudioVolumeType VolumeType
80 var ret = Interop.AudioStreamPolicy.GetSoundType(Handle, out type);
81 if (ret == AudioManagerError.NoData)
83 return AudioVolumeType.None;
86 ret.Validate("Failed to get volume type");
92 private AudioStreamFocusState GetFocusState(bool playback)
94 int ret = Interop.AudioStreamPolicy.GetFocusState(Handle, out var stateForPlayback, out var stateForRecording);
95 MultimediaDebug.AssertNoError(ret);
97 return playback ? stateForPlayback : stateForRecording;
101 /// Gets the state of focus for playback.
103 /// <value>The state of focus for playback.</value>
104 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
105 public AudioStreamFocusState PlaybackFocusState => GetFocusState(true);
108 /// Gets the state of focus for recording.
110 /// <value>The state of focus for recording.</value>
111 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
112 public AudioStreamFocusState RecordingFocusState => GetFocusState(false);
115 /// Gets or sets the auto focus reacquisition.
118 /// true if the auto focus reacquisition is enabled; otherwise, false.\n
119 /// The default is true.
122 /// If you don't want to reacquire the focus you've lost automatically,
123 /// disable the focus reacquisition.
125 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
126 public bool FocusReacquisitionEnabled
130 Interop.AudioStreamPolicy.GetFocusReacquisition(Handle, out var enabled).
131 Validate("Failed to get focus reacquisition state");
137 Interop.AudioStreamPolicy.SetFocusReacquisition(Handle, value).
138 Validate("Failed to set focus reacquisition");
142 internal AudioStreamPolicyHandle Handle
148 throw new ObjectDisposedException(nameof(AudioStreamPolicy));
155 /// Acquires the stream focus.
157 /// <param name="options">The focuses that you want to acquire.</param>
158 /// <param name="behaviors">The requesting behaviors.</param>
159 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
160 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
161 /// <exception cref="ArgumentOutOfRangeException">
162 /// <paramref name="options"/> contain a invalid bit.\n
164 /// <paramref name="behaviors"/> contain a invalid bit.\n
166 /// <exception cref="InvalidOperationException">The focus has already been acquired.</exception>
167 /// <exception cref="AudioPolicyException">Called in <see cref="FocusStateChanged"/> raised by releasing focus.</exception>
168 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
169 public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
173 throw new ArgumentException("options can't be zero.", nameof(options));
176 if (options.IsValid() == false)
178 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
181 if (behaviors.IsValid() == false)
183 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
186 Interop.AudioStreamPolicy.AcquireFocus(Handle, options, behaviors, extraInfo).
187 Validate("Failed to acquire focus");
191 /// Releases the acquired focus.
193 /// <param name="options">The focus mask that you want to release.</param>
194 /// <param name="behaviors">The requesting behaviors.</param>
195 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
196 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
197 /// <exception cref="ArgumentOutOfRangeException">
198 /// <paramref name="options"/> contain a invalid bit.\n
200 /// <paramref name="behaviors"/> contain a invalid bit.\n
202 /// <exception cref="InvalidOperationException">The focus has not been acquired.</exception>
203 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
204 public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
208 throw new ArgumentException("options can't be zero.", nameof(options));
211 if (options.IsValid() == false)
213 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
216 if (behaviors.IsValid() == false)
218 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
221 Interop.AudioStreamPolicy.ReleaseFocus(Handle, options, behaviors, extraInfo).
222 Validate("Failed to release focus");
226 /// Applies the stream routing.
229 /// If the stream has not been made yet, this will be applied when the stream starts to play.
231 /// <seealso cref="AddDeviceForStreamRouting(AudioDevice)"/>
232 /// <seealso cref="RemoveDeviceForStreamRouting(AudioDevice)"/>
233 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
234 public void ApplyStreamRouting()
236 Interop.AudioStreamPolicy.ApplyStreamRouting(Handle).Validate("Failed to apply stream routing");
240 /// Adds a device for the stream routing.
242 /// <param name="device">The device to add.</param>
244 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
246 /// <exception cref="InvalidOperationException">
247 /// The device is not connected.\n
249 /// An internal error occurs.
251 /// <exception cref="ArgumentNullException"><paramref name="device"> is null.</exception>
252 /// <exception cref="AudioPolicyException"><see cref="AudioStreamType"/> of <paramref name="device"/> is unavailable for this.</exception>
253 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
254 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
255 /// <seealso cref="ApplyStreamRouting"/>
256 public void AddDeviceForStreamRouting(AudioDevice device)
260 throw new ArgumentNullException(nameof(device));
263 var ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(Handle, device.Id);
265 if (ret == AudioManagerError.NoData)
267 throw new InvalidOperationException("The device seems not connected.");
270 ret.Validate("Failed to add device for stream routing");
274 /// Removes the device for the stream routing.
276 /// <param name="device">The device to remove.</param>
278 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
280 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
281 /// <exception cref="ArgumentNullException"><paramref name="device"> is null.</exception>
282 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
283 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
284 public void RemoveDeviceForStreamRouting(AudioDevice device)
288 throw new ArgumentNullException(nameof(device));
291 Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(Handle, device.Id).
292 Validate("Failed to remove device for stream routing");
296 /// Releases all resources used by the <see cref="AudioStreamPolicy"/>.
298 public void Dispose()
304 /// Releases the unmanaged resources used by the <see cref="AudioStreamPolicy"/>.
306 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
307 protected virtual void Dispose(bool disposing)
319 #region Static events
321 private static bool _isWatchCallbackRegistered;
322 private static EventHandler<StreamFocusStateChangedEventArgs> _streamFocusStateChanged;
323 private static Interop.AudioStreamPolicy.FocusStateWatchCallback _focusStateWatchCallback;
324 private static object _streamFocusEventLock = new object();
327 /// Occurs when the focus state for stream types is changed regardless of the process.
329 public static event EventHandler<StreamFocusStateChangedEventArgs> StreamFocusStateChanged
333 lock (_streamFocusEventLock)
335 if (_isWatchCallbackRegistered == false)
337 RegisterFocusStateWatch();
338 _isWatchCallbackRegistered = true;
340 _streamFocusStateChanged += value;
345 lock (_streamFocusEventLock)
347 _streamFocusStateChanged -= value;
352 private static void RegisterFocusStateWatch()
354 _focusStateWatchCallback = (int id, AudioStreamFocusOptions options, AudioStreamFocusState focusState,
355 AudioStreamFocusChangedReason reason, string extraInfo, IntPtr userData) =>
357 _streamFocusStateChanged?.Invoke(null,
358 new StreamFocusStateChangedEventArgs(options, focusState, reason, extraInfo));
361 Interop.AudioStreamPolicy.AddFocusStateWatchCallback(
362 AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording,
363 _focusStateWatchCallback, IntPtr.Zero, out var cbId).
364 Validate("Failed to initialize focus state event");