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 userData) =>
51 FocusStateChanged?.Invoke(this,
52 new AudioStreamPolicyFocusStateChangedEventArgs(focusMask, state, reason, behaviors, extraInfo));
55 Interop.AudioStreamPolicy.Create(streamType, _focusStateChangedCallback,
56 IntPtr.Zero, out _handle).Validate("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
85 var ret = Interop.AudioStreamPolicy.GetSoundType(Handle, out type);
86 if (ret == AudioManagerError.NoData)
88 return AudioVolumeType.None;
91 ret.Validate("Failed to get volume type");
97 private AudioStreamFocusState GetFocusState(bool playback)
99 int ret = Interop.AudioStreamPolicy.GetFocusState(Handle, out var stateForPlayback, out var stateForRecording);
100 MultimediaDebug.AssertNoError(ret);
102 return playback ? stateForPlayback : stateForRecording;
106 /// Gets the state of focus for the playback.
108 /// <value>The state of focus for playback.</value>
109 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
110 /// <since_tizen> 3 </since_tizen>
111 public AudioStreamFocusState PlaybackFocusState => GetFocusState(true);
114 /// Gets the state of focus for the recording.
116 /// <value>The state of focus for recording.</value>
117 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
118 /// <since_tizen> 3 </since_tizen>
119 public AudioStreamFocusState RecordingFocusState => GetFocusState(false);
122 /// Gets or sets the auto focus reacquisition.
125 /// true if the auto focus reacquisition is enabled; otherwise, false.<br/>
126 /// The default is true.
129 /// If you don't want to reacquire the focus you've lost automatically,
130 /// disable the focus reacquisition.
132 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
133 /// <since_tizen> 3 </since_tizen>
134 public bool FocusReacquisitionEnabled
138 Interop.AudioStreamPolicy.GetFocusReacquisition(Handle, out var enabled).
139 Validate("Failed to get focus reacquisition state");
145 Interop.AudioStreamPolicy.SetFocusReacquisition(Handle, value).
146 Validate("Failed to set focus reacquisition");
150 internal AudioStreamPolicyHandle Handle
156 throw new ObjectDisposedException(nameof(AudioStreamPolicy));
163 /// Acquires the stream focus.
165 /// <param name="options">The focuses that you want to acquire.</param>
166 /// <param name="behaviors">The requesting behaviors.</param>
167 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
168 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
169 /// <exception cref="ArgumentOutOfRangeException">
170 /// <paramref name="options"/> contain a invalid bit.<br/>
172 /// <paramref name="behaviors"/> contain a invalid bit.
174 /// <exception cref="InvalidOperationException">The focus has already been acquired.</exception>
175 /// <exception cref="AudioPolicyException">Called in <see cref="FocusStateChanged"/> raised by releasing focus.</exception>
176 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
177 /// <since_tizen> 3 </since_tizen>
178 public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
182 throw new ArgumentException("options can't be zero.", nameof(options));
185 if (options.IsValid() == false)
187 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
190 if (behaviors.IsValid() == false)
192 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
195 Interop.AudioStreamPolicy.AcquireFocus(Handle, options, behaviors, extraInfo).
196 Validate("Failed to acquire focus");
200 /// Releases the acquired focus.
202 /// <param name="options">The focus mask that you want to release.</param>
203 /// <param name="behaviors">The requesting behaviors.</param>
204 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
205 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
206 /// <exception cref="ArgumentOutOfRangeException">
207 /// <paramref name="options"/> contain a invalid bit.<br/>
209 /// <paramref name="behaviors"/> contain a invalid bit.
211 /// <exception cref="InvalidOperationException">The focus has not been acquired.</exception>
212 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
213 /// <since_tizen> 3 </since_tizen>
214 public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
218 throw new ArgumentException("options can't be zero.", nameof(options));
221 if (options.IsValid() == false)
223 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
226 if (behaviors.IsValid() == false)
228 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
231 Interop.AudioStreamPolicy.ReleaseFocus(Handle, options, behaviors, extraInfo).
232 Validate("Failed to release focus");
236 /// Applies the stream routing.
239 /// If the stream has not been made yet, this will be applied when the stream starts to play.
241 /// <seealso cref="AddDeviceForStreamRouting(AudioDevice)"/>
242 /// <seealso cref="RemoveDeviceForStreamRouting(AudioDevice)"/>
243 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
244 /// <since_tizen> 3 </since_tizen>
245 public void ApplyStreamRouting()
247 Interop.AudioStreamPolicy.ApplyStreamRouting(Handle).Validate("Failed to apply stream routing");
251 /// Adds a device for the stream routing.
253 /// <param name="device">The device to add.</param>
255 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
257 /// <exception cref="InvalidOperationException">
258 /// The device is not connected.<br/>
260 /// An internal error occurs.
262 /// <exception cref="ArgumentNullException"><paramref name="device"/> is null.</exception>
263 /// <exception cref="AudioPolicyException"><see cref="AudioStreamType"/> of <paramref name="device"/> is unavailable for this.</exception>
264 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
265 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
266 /// <seealso cref="ApplyStreamRouting"/>
267 /// <since_tizen> 3 </since_tizen>
268 public void AddDeviceForStreamRouting(AudioDevice device)
272 throw new ArgumentNullException(nameof(device));
275 var ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(Handle, device.Id);
277 if (ret == AudioManagerError.NoData)
279 throw new InvalidOperationException("The device seems not connected.");
282 ret.Validate("Failed to add device for stream routing");
286 /// Removes the device for the stream routing.
288 /// <param name="device">The device to remove.</param>
290 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
292 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
293 /// <exception cref="ArgumentNullException"><paramref name="device"/> is null.</exception>
294 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
295 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
296 /// <since_tizen> 3 </since_tizen>
297 public void RemoveDeviceForStreamRouting(AudioDevice device)
301 throw new ArgumentNullException(nameof(device));
304 Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(Handle, device.Id).
305 Validate("Failed to remove device for stream routing");
309 /// Releases all resources used by the <see cref="AudioStreamPolicy"/>.
311 /// <since_tizen> 3 </since_tizen>
312 public void Dispose()
318 /// Releases the unmanaged resources used by the <see cref="AudioStreamPolicy"/>.
320 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
321 /// <since_tizen> 3 </since_tizen>
322 protected virtual void Dispose(bool disposing)
334 #region Static events
336 private static bool _isWatchCallbackRegistered;
337 private static EventHandler<StreamFocusStateChangedEventArgs> _streamFocusStateChanged;
338 private static Interop.AudioStreamPolicy.FocusStateWatchCallback _focusStateWatchCallback;
339 private static object _streamFocusEventLock = new object();
342 /// Occurs when the focus state for stream types is changed regardless of the process.
344 /// <since_tizen> 3 </since_tizen>
345 public static event EventHandler<StreamFocusStateChangedEventArgs> StreamFocusStateChanged
349 lock (_streamFocusEventLock)
351 if (_isWatchCallbackRegistered == false)
353 RegisterFocusStateWatch();
354 _isWatchCallbackRegistered = true;
356 _streamFocusStateChanged += value;
361 lock (_streamFocusEventLock)
363 _streamFocusStateChanged -= value;
368 private static void RegisterFocusStateWatch()
370 _focusStateWatchCallback = (int id, AudioStreamFocusOptions options, AudioStreamFocusState focusState,
371 AudioStreamFocusChangedReason reason, string extraInfo, IntPtr userData) =>
373 _streamFocusStateChanged?.Invoke(null,
374 new StreamFocusStateChangedEventArgs(options, focusState, reason, extraInfo));
377 Interop.AudioStreamPolicy.AddFocusStateWatchCallback(
378 AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording,
379 _focusStateWatchCallback, IntPtr.Zero, out var cbId).
380 Validate("Failed to initialize focus state event");