f82dfb47abb4a88e6e2c1ddb443197b84724e977
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia / AudioManager / AudioStreamPolicy.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 using System;
18 using System.Diagnostics;
19
20 namespace Tizen.Multimedia
21 {
22     /// <summary>
23     /// Provides the ability to control a sound stream.
24     /// </summary>
25     public class AudioStreamPolicy : IDisposable
26     {
27         private AudioStreamPolicyHandle _handle;
28         private bool _disposed = false;
29         private Interop.AudioStreamPolicy.FocusStateChangedCallback _focusStateChangedCallback;
30
31         /// <summary>
32         ///  Initializes a new instance of the <see cref="AudioStreamPolicy"/> class with <see cref="AudioStreamType"/>
33         /// </summary>
34         /// <remarks>
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.)
37         /// </remarks>
38         /// <param name="streamType">Type of sound stream for which policy needs to be created.</param>
39         public AudioStreamPolicy(AudioStreamType streamType)
40         {
41             ValidationUtil.ValidateEnum(typeof(AudioStreamType), streamType, nameof(streamType));
42
43             _focusStateChangedCallback = (IntPtr streamInfo, AudioStreamFocusOptions focusMask,
44                 AudioStreamFocusState state, AudioStreamFocusChangedReason reason, AudioStreamBehaviors behaviors,
45                 string extraInfo, IntPtr userData) =>
46             {
47                 FocusStateChanged?.Invoke(this,
48                     new AudioStreamPolicyFocusStateChangedEventArgs(focusMask, state, reason, behaviors, extraInfo));
49             };
50
51             Interop.AudioStreamPolicy.Create(streamType, _focusStateChangedCallback,
52                 IntPtr.Zero, out _handle).Validate("Unable to create stream information");
53
54             Debug.Assert(_handle != null);
55         }
56
57         /// <summary>
58         /// Occurs when the state of focus that belongs to the current AudioStreamPolicy is changed.
59         /// </summary>
60         /// <remarks>
61         /// The event is raised in the internal thread.
62         /// </remarks>
63         public event EventHandler<AudioStreamPolicyFocusStateChangedEventArgs> FocusStateChanged;
64
65         /// <summary>
66         /// Gets the <see cref="AudioVolumeType"/>.
67         /// </summary>
68         /// <remarks>
69         /// If the <see cref="AudioStreamType"/> of the current AudioStreamPolicy is <see cref="AudioStreamType.Emergency"/>,
70         /// it returns <see cref="AudioVolumeType.None"/>.
71         /// </remarks>
72         /// <value>The <see cref="AudioVolumeType"/> of the policy instance.</value>
73         public AudioVolumeType VolumeType
74         {
75             get
76             {
77                 AudioVolumeType type;
78                 var ret = Interop.AudioStreamPolicy.GetSoundType(Handle, out type);
79                 if (ret == AudioManagerError.NoData)
80                 {
81                     return AudioVolumeType.None;
82                 }
83
84                 ret.Validate("Failed to get volume type");
85
86                 return type;
87             }
88         }
89
90         private AudioStreamFocusState GetFocusState(bool playback)
91         {
92             int ret = Interop.AudioStreamPolicy.GetFocusState(Handle, out var stateForPlayback, out var stateForRecording);
93             MultimediaDebug.AssertNoError(ret);
94
95             return playback ? stateForPlayback : stateForRecording;
96         }
97
98         /// <summary>
99         /// Gets the state of focus for playback.
100         /// </summary>
101         /// <value>The state of focus for playback.</value>
102         public AudioStreamFocusState PlaybackFocusState => GetFocusState(true);
103
104         /// <summary>
105         /// Gets the state of focus for recording.
106         /// </summary>
107         /// <value>The state of focus for recording.</value>
108         public AudioStreamFocusState RecordingFocusState => GetFocusState(false);
109
110         /// <summary>
111         /// Gets or sets the auto focus reacquisition.
112         /// </summary>
113         /// <value>
114         /// true if the auto focus reacquisition is enabled; otherwise, false.\n
115         /// The default is true.
116         /// </value>
117         /// <remarks>
118         /// If you don't want to reacquire the focus you've lost automatically,
119         /// disable the focus reacquisition.
120         /// </remarks>
121         public bool FocusReacquisitionEnabled
122         {
123             get
124             {
125                 Interop.AudioStreamPolicy.GetFocusReacquisition(Handle, out var enabled).
126                     Validate("Failed to get focus reacquisition state");
127
128                 return enabled;
129             }
130             set
131             {
132                 Interop.AudioStreamPolicy.SetFocusReacquisition(Handle, value).
133                     Validate("Failed to set focus reacquisition");
134             }
135         }
136
137         internal AudioStreamPolicyHandle Handle
138         {
139             get
140             {
141                 if (_disposed)
142                 {
143                     throw new ObjectDisposedException(nameof(AudioStreamPolicy));
144                 }
145                 return _handle;
146             }
147         }
148
149         /// <summary>
150         /// Acquires the stream focus.
151         /// </summary>
152         /// <param name="options">The focuses that you want to acquire.</param>
153         /// <param name="behaviors">The requesting behaviors.</param>
154         /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
155         public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
156         {
157             if (options == 0)
158             {
159                 throw new ArgumentException("options can't be zero.", nameof(options));
160             }
161
162             if (options.IsValid() == false)
163             {
164                 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
165             }
166
167             if (behaviors.IsValid() == false)
168             {
169                 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
170             }
171
172             Interop.AudioStreamPolicy.AcquireFocus(Handle, options, behaviors, extraInfo).
173                 Validate("Failed to acquire focus");
174         }
175
176         /// <summary>
177         /// Releases the acquired focus.
178         /// </summary>
179         /// <param name="options">The focus mask that you want to release.</param>
180         /// <param name="behaviors">The requesting behaviors.</param>
181         /// <param name="extraInfo">The extra information for this request. This value can be null.</param>
182         public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehaviors behaviors, string extraInfo)
183         {
184             if (options == 0)
185             {
186                 throw new ArgumentException("options can't be zero.", nameof(options));
187             }
188
189             if (options.IsValid() == false)
190             {
191                 throw new ArgumentOutOfRangeException(nameof(options), options, "options contains a invalid bit.");
192             }
193
194             if (behaviors.IsValid() == false)
195             {
196                 throw new ArgumentOutOfRangeException(nameof(behaviors), behaviors, "behaviors contains a invalid bit.");
197             }
198
199             Interop.AudioStreamPolicy.ReleaseFocus(Handle, options, behaviors, extraInfo).
200                 Validate("Failed to release focus");
201         }
202
203         /// <summary>
204         /// Applies the stream routing.
205         /// </summary>
206         /// <remarks>
207         /// If the stream has not been made yet, this will be applied when the stream starts to play.
208         /// </remarks>
209         /// <seealso cref="AddDeviceForStreamRouting(AudioDevice)"/>
210         /// <seealso cref="RemoveDeviceForStreamRouting(AudioDevice)"/>
211         public void ApplyStreamRouting()
212         {
213             Interop.AudioStreamPolicy.ApplyStreamRouting(Handle).Validate("Failed to apply stream routing");
214         }
215
216         /// <summary>
217         /// Adds a device for the stream routing.
218         /// </summary>
219         /// <param name="device">The device to add.</param>
220         /// <remarks>
221         /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
222         /// </remarks>
223         /// <seealso cref="AudioManager.GetConnectedDevices()"/>
224         /// <seealso cref="ApplyStreamRouting"/>
225         public void AddDeviceForStreamRouting(AudioDevice device)
226         {
227             if (device == null)
228             {
229                 throw new ArgumentNullException(nameof(device));
230             }
231             var ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(Handle, device.Id);
232
233             if (ret == AudioManagerError.NoData)
234             {
235                 throw new ArgumentException("The device seems not connected.", nameof(device));
236             }
237
238             ret.Validate("Failed to add device for stream routing");
239         }
240
241         /// <summary>
242         /// Removes the device for the stream routing.
243         /// </summary>
244         /// <param name="device">The device to remove.</param>
245         /// <remarks>
246         /// The available <see cref="AudioStreamType"/> is <see cref="AudioStreamType.Voip"/> and <see cref="AudioStreamType.MediaExternalOnly"/>.
247         /// </remarks>
248         public void RemoveDeviceForStreamRouting(AudioDevice device)
249         {
250             if (device == null)
251             {
252                 throw new ArgumentNullException(nameof(device));
253             }
254
255             Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(Handle, device.Id).
256                 Validate("Failed to remove device for stream routing");
257         }
258
259         /// <summary>
260         /// Releases all resources used by the <see cref="AudioStreamPolicy"/>.
261         /// </summary>
262         public void Dispose()
263         {
264             Dispose(true);
265         }
266
267         /// <summary>
268         /// Releases the unmanaged resources used by the <see cref="AudioStreamPolicy"/>.
269         /// </summary>
270         /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
271         protected virtual void Dispose(bool disposing)
272         {
273             if (!_disposed)
274             {
275                 if (_handle != null)
276                 {
277                     _handle.Dispose();
278                 }
279                 _disposed = true;
280             }
281         }
282
283         #region Static events
284
285         private static bool _isWatchCallbackRegistered;
286         private static EventHandler<StreamFocusStateChangedEventArgs> _streamFocusStateChanged;
287         private static Interop.AudioStreamPolicy.FocusStateWatchCallback _focusStateWatchCallback;
288         private static object _streamFocusEventLock = new object();
289
290         /// <summary>
291         /// Occurs when the focus state for stream types is changed regardless of the process.
292         /// </summary>
293         public static event EventHandler<StreamFocusStateChangedEventArgs> StreamFocusStateChanged
294         {
295             add
296             {
297                 lock (_streamFocusEventLock)
298                 {
299                     if (_isWatchCallbackRegistered == false)
300                     {
301                         RegisterFocusStateWatch();
302                         _isWatchCallbackRegistered = true;
303                     }
304                     _streamFocusStateChanged += value;
305                 }
306             }
307             remove
308             {
309                 lock (_streamFocusEventLock)
310                 {
311                     _streamFocusStateChanged -= value;
312                 }
313             }
314         }
315
316         private static void RegisterFocusStateWatch()
317         {
318             _focusStateWatchCallback = (int id, AudioStreamFocusOptions options, AudioStreamFocusState focusState,
319                 AudioStreamFocusChangedReason reason, string extraInfo, IntPtr userData) =>
320             {
321                 _streamFocusStateChanged?.Invoke(null,
322                     new StreamFocusStateChangedEventArgs(options, focusState, reason, extraInfo));
323             };
324
325             Interop.AudioStreamPolicy.AddFocusStateWatchCallback(
326                 AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording,
327                 _focusStateWatchCallback, IntPtr.Zero, out var cbId).
328                 Validate("Failed to initialize focus state event");
329         }
330         #endregion
331     }
332 }