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 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. (For example., <see cref="T:Tizen.Multimedia.Player"/>,
37 /// <see cref="T:Tizen.Multimedia.WavPlayer"/> , etc.)
39 /// <param name="streamType">The type of the sound stream for which the policy needs to be created.</param>
40 /// <exception cref="ArgumentException"><paramref name="streamType"/> is invalid.</exception>
41 public AudioStreamPolicy(AudioStreamType streamType)
43 ValidationUtil.ValidateEnum(typeof(AudioStreamType), streamType, nameof(streamType));
45 _focusStateChangedCallback = (IntPtr streamInfo, AudioStreamFocusOptions focusMask,
46 AudioStreamFocusState state, AudioStreamFocusChangedReason reason, AudioStreamBehaviors behaviors,
47 string extraInfo, IntPtr userData) =>
49 FocusStateChanged?.Invoke(this,
50 new AudioStreamPolicyFocusStateChangedEventArgs(focusMask, state, reason, behaviors, extraInfo));
53 Interop.AudioStreamPolicy.Create(streamType, _focusStateChangedCallback,
54 IntPtr.Zero, out _handle).Validate("Unable to create stream information");
56 Debug.Assert(_handle != null);
60 /// Occurs when the state of focus that belongs to the current AudioStreamPolicy is changed.
63 /// The event is raised in the internal thread.
65 public event EventHandler<AudioStreamPolicyFocusStateChangedEventArgs> FocusStateChanged;
68 /// Gets the <see cref="AudioVolumeType"/>.
71 /// If the <see cref="AudioStreamType"/> of the current AudioStreamPolicy is <see cref="AudioStreamType.Emergency"/>,
72 /// it returns <see cref="AudioVolumeType.None"/>.
74 /// <value>The <see cref="AudioVolumeType"/> of the policy instance.</value>
75 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
76 public AudioVolumeType VolumeType
81 var ret = Interop.AudioStreamPolicy.GetSoundType(Handle, out type);
82 if (ret == AudioManagerError.NoData)
84 return AudioVolumeType.None;
87 ret.Validate("Failed to get volume type");
93 private AudioStreamFocusState GetFocusState(bool playback)
95 int ret = Interop.AudioStreamPolicy.GetFocusState(Handle, out var stateForPlayback, out var stateForRecording);
96 MultimediaDebug.AssertNoError(ret);
98 return playback ? stateForPlayback : stateForRecording;
102 /// Gets the state of focus for the playback.
104 /// <value>The state of focus for playback.</value>
105 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
106 public AudioStreamFocusState PlaybackFocusState => GetFocusState(true);
109 /// Gets the state of focus for the recording.
111 /// <value>The state of focus for recording.</value>
112 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
113 public AudioStreamFocusState RecordingFocusState => GetFocusState(false);
116 /// Gets or sets the auto focus reacquisition.
119 /// true if the auto focus reacquisition is enabled; otherwise, false.<br/>
120 /// The default is true.
123 /// If you don't want to reacquire the focus you've lost automatically,
124 /// disable the focus reacquisition.
126 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
127 public bool FocusReacquisitionEnabled
131 Interop.AudioStreamPolicy.GetFocusReacquisition(Handle, out var enabled).
132 Validate("Failed to get focus reacquisition state");
138 Interop.AudioStreamPolicy.SetFocusReacquisition(Handle, value).
139 Validate("Failed to set focus reacquisition");
143 internal AudioStreamPolicyHandle Handle
149 throw new ObjectDisposedException(nameof(AudioStreamPolicy));
156 /// Acquires the stream focus.
158 /// <param name="options">The focuses that you want to acquire.</param>
159 /// <param name="behaviors">The requesting behaviors.</param>
160 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
161 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
162 /// <exception cref="ArgumentOutOfRangeException">
163 /// <paramref name="options"/> contain a invalid bit.<br/>
165 /// <paramref name="behaviors"/> contain a invalid bit.
167 /// <exception cref="InvalidOperationException">The focus has already been acquired.</exception>
168 /// <exception cref="AudioPolicyException">Called in <see cref="FocusStateChanged"/> raised by releasing focus.</exception>
169 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
170 public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
174 throw new ArgumentException("options can't be zero.", nameof(options));
177 if (options.IsValid() == false)
179 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
182 if (behaviors.IsValid() == false)
184 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
187 Interop.AudioStreamPolicy.AcquireFocus(Handle, options, behaviors, extraInfo).
188 Validate("Failed to acquire focus");
192 /// Releases the acquired focus.
194 /// <param name="options">The focus mask that you want to release.</param>
195 /// <param name="behaviors">The requesting behaviors.</param>
196 /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
197 /// <exception cref="ArgumentException"><paramref name="options"/> is zero.</exception>
198 /// <exception cref="ArgumentOutOfRangeException">
199 /// <paramref name="options"/> contain a invalid bit.<br/>
201 /// <paramref name="behaviors"/> contain a invalid bit.
203 /// <exception cref="InvalidOperationException">The focus has not been acquired.</exception>
204 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
205 public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
209 throw new ArgumentException("options can't be zero.", nameof(options));
212 if (options.IsValid() == false)
214 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
217 if (behaviors.IsValid() == false)
219 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
222 Interop.AudioStreamPolicy.ReleaseFocus(Handle, options, behaviors, extraInfo).
223 Validate("Failed to release focus");
227 /// Applies the stream routing.
230 /// If the stream has not been made yet, this will be applied when the stream starts to play.
232 /// <seealso cref="AddDeviceForStreamRouting(AudioDevice)"/>
233 /// <seealso cref="RemoveDeviceForStreamRouting(AudioDevice)"/>
234 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
235 public void ApplyStreamRouting()
237 Interop.AudioStreamPolicy.ApplyStreamRouting(Handle).Validate("Failed to apply stream routing");
241 /// Adds a device for the stream routing.
243 /// <param name="device">The device to add.</param>
245 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
247 /// <exception cref="InvalidOperationException">
248 /// The device is not connected.<br/>
250 /// An internal error occurs.
252 /// <exception cref="ArgumentNullException"><paramref name="device"/> is null.</exception>
253 /// <exception cref="AudioPolicyException"><see cref="AudioStreamType"/> of <paramref name="device"/> is unavailable for this.</exception>
254 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
255 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
256 /// <seealso cref="ApplyStreamRouting"/>
257 public void AddDeviceForStreamRouting(AudioDevice device)
261 throw new ArgumentNullException(nameof(device));
264 var ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(Handle, device.Id);
266 if (ret == AudioManagerError.NoData)
268 throw new InvalidOperationException("The device seems not connected.");
271 ret.Validate("Failed to add device for stream routing");
275 /// Removes the device for the stream routing.
277 /// <param name="device">The device to remove.</param>
279 /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
281 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
282 /// <exception cref="ArgumentNullException"><paramref name="device"/> is null.</exception>
283 /// <exception cref="ObjectDisposedException">The <see cref="AudioStreamPolicy"/> has already been disposed of.</exception>
284 /// <seealso cref="AudioManager.GetConnectedDevices()"/>
285 public void RemoveDeviceForStreamRouting(AudioDevice device)
289 throw new ArgumentNullException(nameof(device));
292 Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(Handle, device.Id).
293 Validate("Failed to remove device for stream routing");
297 /// Releases all resources used by the <see cref="AudioStreamPolicy"/>.
299 public void Dispose()
305 /// Releases the unmanaged resources used by the <see cref="AudioStreamPolicy"/>.
307 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
308 protected virtual void Dispose(bool disposing)
320 #region Static events
322 private static bool _isWatchCallbackRegistered;
323 private static EventHandler<StreamFocusStateChangedEventArgs> _streamFocusStateChanged;
324 private static Interop.AudioStreamPolicy.FocusStateWatchCallback _focusStateWatchCallback;
325 private static object _streamFocusEventLock = new object();
328 /// Occurs when the focus state for stream types is changed regardless of the process.
330 public static event EventHandler<StreamFocusStateChangedEventArgs> StreamFocusStateChanged
334 lock (_streamFocusEventLock)
336 if (_isWatchCallbackRegistered == false)
338 RegisterFocusStateWatch();
339 _isWatchCallbackRegistered = true;
341 _streamFocusStateChanged += value;
346 lock (_streamFocusEventLock)
348 _streamFocusStateChanged -= value;
353 private static void RegisterFocusStateWatch()
355 _focusStateWatchCallback = (int id, AudioStreamFocusOptions options, AudioStreamFocusState focusState,
356 AudioStreamFocusChangedReason reason, string extraInfo, IntPtr userData) =>
358 _streamFocusStateChanged?.Invoke(null,
359 new StreamFocusStateChangedEventArgs(options, focusState, reason, extraInfo));
362 Interop.AudioStreamPolicy.AddFocusStateWatchCallback(
363 AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording,
364 _focusStateWatchCallback, IntPtr.Zero, out var cbId).
365 Validate("Failed to initialize focus state event");