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 the sound stream.
25 /// <since_tizen> 3 </since_tizen>
26 public class AudioStreamPolicy : IDisposable
28 private AudioStreamPolicyHandle _handle;
29 private bool _disposed = false;
30 private Interop.AudioStreamPolicy.FocusStateChangedCallback _focusStateChangedCallback;
33 /// Initializes a new instance of the <see cref="AudioStreamPolicy"/> class with <see cref="AudioStreamType"/>.
36 /// To apply the stream policy according to this stream information, the AudioStreamPolicy should
37 /// be passed to other APIs related to playback or recording. (For example., <see cref="T:Tizen.Multimedia.Player"/>,
38 /// <see cref="T:Tizen.Multimedia.WavPlayer"/> , etc.)
40 /// <param name="streamType">The type of the sound stream for which the policy needs to be created.</param>
41 /// <exception cref="ArgumentException"><paramref name="streamType"/> is invalid.</exception>
42 /// <since_tizen> 3 </since_tizen>
43 public AudioStreamPolicy(AudioStreamType streamType)
45 ValidationUtil.ValidateEnum(typeof(AudioStreamType), streamType, nameof(streamType));
47 _focusStateChangedCallback = (IntPtr streamInfo, AudioStreamFocusOptions focusMask,
48 AudioStreamFocusState state, AudioStreamFocusChangedReason reason, AudioStreamBehaviors behaviors,
49 string extraInfo, IntPtr _) =>
51 FocusStateChanged?.Invoke(this,
52 new AudioStreamPolicyFocusStateChangedEventArgs(focusMask, state, reason, behaviors, extraInfo));
55 Interop.AudioStreamPolicy.Create(streamType, _focusStateChangedCallback,
56 IntPtr.Zero, out _handle).ThrowIfError("Unable to create stream information");
58 Debug.Assert(_handle != null);
62 /// Occurs when the state of focus that belongs to the current AudioStreamPolicy is changed.
65 /// The event is raised in the internal thread.
67 /// <since_tizen> 4 </since_tizen>
68 public event EventHandler<AudioStreamPolicyFocusStateChangedEventArgs> FocusStateChanged;
71 /// Gets the <see cref="AudioVolumeType"/>.
74 /// If the <see cref="AudioStreamType"/> of the current AudioStreamPolicy is <see cref="AudioStreamType.Emergency"/>,
75 /// it returns <see cref="AudioVolumeType.None"/>.
77 /// <value>The <see cref="AudioVolumeType"/> of the policy instance.</value>
78 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
79 /// <since_tizen> 3 </since_tizen>
80 public AudioVolumeType VolumeType
84 var ret = Interop.AudioStreamPolicy.GetSoundType(Handle, out var type);
85 if (ret == AudioManagerError.NoData)
87 return AudioVolumeType.None;
90 ret.ThrowIfError("Failed to get volume type");
96 private AudioStreamFocusState GetFocusState(bool playback)
98 int ret = Interop.AudioStreamPolicy.GetFocusState(Handle, out var stateForPlayback, out var stateForRecording);
99 MultimediaDebug.AssertNoError(ret);
101 return playback ? stateForPlayback : stateForRecording;
105 /// Gets the state of focus for the playback.
107 /// <value>The state of focus for playback.</value>
108 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
109 /// <since_tizen> 3 </since_tizen>
110 public AudioStreamFocusState PlaybackFocusState => GetFocusState(true);
113 /// Gets the state of focus for the recording.
115 /// <value>The state of focus for recording.</value>
116 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
117 /// <since_tizen> 3 </since_tizen>
118 public AudioStreamFocusState RecordingFocusState => GetFocusState(false);
121 /// Gets or sets the auto focus reacquisition.
124 /// true if the auto focus reacquisition is enabled; otherwise, false.<br/>
125 /// The default is true.
128 /// If you don't want to reacquire the focus you've lost automatically,
129 /// disable the focus reacquisition.
131 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
132 /// <since_tizen> 3 </since_tizen>
133 public bool FocusReacquisitionEnabled
137 Interop.AudioStreamPolicy.GetFocusReacquisition(Handle, out var enabled).
138 ThrowIfError("Failed to get focus reacquisition state");
144 Interop.AudioStreamPolicy.SetFocusReacquisition(Handle, value).
145 ThrowIfError("Failed to set focus reacquisition");
149 internal AudioStreamPolicyHandle Handle
155 throw new ObjectDisposedException(nameof(AudioStreamPolicy));
162 /// Acquires the stream focus.
164 /// <param name="options">The focuses that you want to acquire.</param>
165 /// <param name="behaviors">The requesting behaviors.</param>
166 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
167 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
168 /// <exception cref="ArgumentOutOfRangeException">
169 /// <paramref name="options"/> contain a invalid bit.<br/>
171 /// <paramref name="behaviors"/> contain a invalid bit.
173 /// <exception cref="InvalidOperationException">The focus has already been acquired.</exception>
174 /// <exception cref="AudioPolicyException">Called in <see cref="FocusStateChanged"/> raised by releasing focus.</exception>
175 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
176 /// <since_tizen> 3 </since_tizen>
177 public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
181 throw new ArgumentException("options can't be zero.", nameof(options));
184 if (options.IsValid() == false)
186 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
189 if (behaviors.IsValid() == false)
191 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
194 Interop.AudioStreamPolicy.AcquireFocus(Handle, options, behaviors, extraInfo).
195 ThrowIfError("Failed to acquire focus");
199 /// Releases the acquired focus.
201 /// <param name="options">The focus mask that you want to release.</param>
202 /// <param name="behaviors">The requesting behaviors.</param>
203 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
204 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
205 /// <exception cref="ArgumentOutOfRangeException">
206 /// <paramref name="options"/> contain a invalid bit.<br/>
208 /// <paramref name="behaviors"/> contain a invalid bit.
210 /// <exception cref="InvalidOperationException">The focus has not been acquired.</exception>
211 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
212 /// <since_tizen> 3 </since_tizen>
213 public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
217 throw new ArgumentException("options can't be zero.", nameof(options));
220 if (options.IsValid() == false)
222 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
225 if (behaviors.IsValid() == false)
227 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
230 Interop.AudioStreamPolicy.ReleaseFocus(Handle, options, behaviors, extraInfo).
231 ThrowIfError("Failed to release focus");
235 /// Applies the stream routing.
238 /// If the stream has not been made yet, this will be applied when the stream starts to play.
240 /// <seealso cref="AddDeviceForStreamRouting(AudioDevice)"/>
241 /// <seealso cref="RemoveDeviceForStreamRouting(AudioDevice)"/>
242 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
243 /// <since_tizen> 3 </since_tizen>
244 public void ApplyStreamRouting()
246 Interop.AudioStreamPolicy.ApplyStreamRouting(Handle).ThrowIfError("Failed to apply stream routing");
250 /// Adds a device for the stream routing.
252 /// <param name="device">The device to add.</param>
254 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
256 /// <exception cref="InvalidOperationException">
257 /// The device is not connected.<br/>
259 /// An internal error occurs.
261 /// <exception cref="ArgumentNullException"><paramref name="device"/> is null.</exception>
262 /// <exception cref="AudioPolicyException"><see cref="AudioStreamType"/> of <paramref name="device"/> is unavailable for this.</exception>
263 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
264 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
265 /// <seealso cref="ApplyStreamRouting"/>
266 /// <since_tizen> 3 </since_tizen>
267 public void AddDeviceForStreamRouting(AudioDevice device)
271 throw new ArgumentNullException(nameof(device));
274 var ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(Handle, device.Id);
276 if (ret == AudioManagerError.NoData)
278 throw new InvalidOperationException("The device seems not connected.");
281 ret.ThrowIfError("Failed to add device for stream routing");
285 /// Removes the device for the stream routing.
287 /// <param name="device">The device to remove.</param>
289 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
291 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
292 /// <exception cref="ArgumentNullException"><paramref name="device"/> is null.</exception>
293 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
294 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
295 /// <since_tizen> 3 </since_tizen>
296 public void RemoveDeviceForStreamRouting(AudioDevice device)
300 throw new ArgumentNullException(nameof(device));
303 Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(Handle, device.Id).
304 ThrowIfError("Failed to remove device for stream routing");
308 /// Releases all resources used by the <see cref="AudioStreamPolicy"/>.
310 /// <since_tizen> 3 </since_tizen>
311 public void Dispose()
317 /// Releases the unmanaged resources used by the <see cref="AudioStreamPolicy"/>.
319 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
320 /// <since_tizen> 3 </since_tizen>
321 protected virtual void Dispose(bool disposing)
333 #region Static events
335 private static bool _isWatchCallbackRegistered;
336 private static EventHandler<StreamFocusStateChangedEventArgs> _streamFocusStateChanged;
337 private static Interop.AudioStreamPolicy.FocusStateWatchCallback _focusStateWatchCallback;
338 private static readonly object _streamFocusEventLock = new object();
341 /// Occurs when the focus state for stream types is changed regardless of the process.
343 /// <since_tizen> 3 </since_tizen>
344 public static event EventHandler<StreamFocusStateChangedEventArgs> StreamFocusStateChanged
348 lock (_streamFocusEventLock)
350 if (_isWatchCallbackRegistered == false)
352 RegisterFocusStateWatch();
353 _isWatchCallbackRegistered = true;
355 _streamFocusStateChanged += value;
360 lock (_streamFocusEventLock)
362 _streamFocusStateChanged -= value;
367 private static void RegisterFocusStateWatch()
369 _focusStateWatchCallback = (id, options, focusState, reason, extraInfo, _) =>
371 _streamFocusStateChanged?.Invoke(null,
372 new StreamFocusStateChangedEventArgs(options, focusState, reason, extraInfo));
375 Interop.AudioStreamPolicy.AddFocusStateWatchCallback(
376 AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording,
377 _focusStateWatchCallback, IntPtr.Zero, out var cbId).
378 ThrowIfError("Failed to initialize focus state event");