Merge remote-tracking branch 'shortcut/tizen'
[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
19 namespace Tizen.Multimedia
20 {
21     internal static class AudioStreamPolicyLog
22     {
23         internal const string Tag = "Tizen.Multimedia.AudioStreamPolicy";
24     }
25
26     /// <summary>
27     /// The Stream Policy API provides functions to control a sound stream.
28     /// </summary>
29     public class AudioStreamPolicy : IDisposable
30     {
31         private static int _focusStateWatchCounter = 0;
32         private static EventHandler<FocusStateChangedEventArgs> _focusStateWatchForPlayback;
33         private static EventHandler<FocusStateChangedEventArgs> _focusStateWatchForRecording;
34         private static Interop.SoundStreamFocusStateWatchCallback _focusStateWatchCallback;
35         private static int _focusWatchCbId;
36
37         private IntPtr _streamInfo;
38         private AudioStreamType _streamType;
39         private bool _disposed = false;
40         private EventHandler<StreamFocusStateChangedEventArgs> _focusStateChanged;
41         private Interop.SoundStreamFocusStateChangedCallback _focusStateChangedCallback;
42
43         /// <summary>
44         /// Creates and returns an AudioStreamPolicy object
45         /// </summary>
46         /// <remarks>
47         /// To apply the stream policy according to this stream information, this object should be passed to other APIs
48         /// related to playback or recording. (e.g., player, wav-player, audio-io, etc.)
49         /// </remarks>
50         /// <param name="streamType">Type of sound stream for which policy needs to be created</param>
51         /// <returns>StreamPolicy object</returns>
52         public AudioStreamPolicy(AudioStreamType streamType)
53         {
54             _streamType = streamType;
55
56             _focusStateChangedCallback = (IntPtr streamInfo, AudioStreamFocusOptions focusMask, AudioStreamFocusState focusState, int reason, int audioStreamBehavior, string extraInfo, IntPtr userData) => {
57                 StreamFocusStateChangedEventArgs eventArgs = new StreamFocusStateChangedEventArgs((AudioStreamFocusChangedReason)reason, extraInfo);
58                 _focusStateChanged?.Invoke(this, eventArgs);
59             };
60             int ret = Interop.AudioStreamPolicy.CreateStreamInformation((int)streamType, _focusStateChangedCallback, IntPtr.Zero, out _streamInfo);
61             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to create stream information");
62         }
63
64         ~AudioStreamPolicy()
65         {
66             Dispose(false);
67         }
68
69         /// <summary>
70         /// Registers the watch function to be invoked when the focus state for each sound stream type is changed regardless of the process.
71         /// <remarks>
72         /// Remarks: You can set this only once per process.
73         /// </remarks>
74         /// </summary>
75         public static event EventHandler<FocusStateChangedEventArgs> PlaybackFocusStateWatch {
76             add {
77                 Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _focusStateWatchCounter" + _focusStateWatchCounter);
78                 if(_focusStateWatchCounter == 0) {
79                     RegisterFocusStateWatchEvent();
80                 }
81                 _focusStateWatchCounter++;
82                 _focusStateWatchForPlayback += value;
83             }
84             remove {
85                 Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _focusStateWatchCounter" + _focusStateWatchCounter);
86                 _focusStateWatchForPlayback -= value;
87                 _focusStateWatchCounter--;
88                 if(_focusStateWatchCounter == 0) {
89                     UnregisterFocusStateWatch();
90                 }
91             }
92         }
93
94         /// <summary>
95         /// Registers the watch function to be invoked when the focus state for each sound stream type is changed regardless of the process.
96         /// <remarks>
97         /// Remarks: You can set this only once per process.
98         /// </remarks>
99         /// </summary>
100         public static event EventHandler<FocusStateChangedEventArgs> RecordingFocusStateWatch {
101             add {
102                 if(_focusStateWatchCounter == 0) {
103                     RegisterFocusStateWatchEvent();
104                 }
105                 _focusStateWatchCounter++;
106                 _focusStateWatchForRecording += value;
107             }
108             remove {
109                 _focusStateWatchForRecording -= value;
110                 _focusStateWatchCounter--;
111                 if(_focusStateWatchCounter == 0) {
112                     UnregisterFocusStateWatch();
113                 }
114             }
115         }
116
117         /// <summary>
118         /// Registers function to be called when the state of focus that belongs to the current 
119         /// streamInfo is changed.
120         /// </summary>
121         /// <remarks>
122         /// Remarks: This function is issued in the internal thread of the sound manager. Therefore it is recommended not to call UI update function in this function.
123         /// Postcondition : Check PlaybackFocusState and RecordingFocusState in the registered event handler to figure out how the focus state of the StreamInfo has been changed.
124         /// </remarks>
125         public event EventHandler<StreamFocusStateChangedEventArgs> StreamFocusStateChanged {
126             add {
127                 _focusStateChanged += value;
128             }
129             remove {
130                 _focusStateChanged -= value;
131             }
132         }
133
134         /// <summary>
135         ///  The sound type of the stream information.
136         /// </summary>
137         public AudioVolumeType VolumeType {
138             get {
139                 AudioVolumeType soundType;
140                 int ret = Interop.AudioStreamPolicy.GetSoundType(_streamInfo, out soundType);
141                 if(ret != 0) {
142                     Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Unable to get sound type:" + (AudioManagerError)ret);
143                     return AudioVolumeType.None;
144                 }
145                 return soundType;
146             }
147         }
148
149         /// <summary>
150         /// The state of focus for playback.
151         /// </summary>
152         public AudioStreamFocusState PlaybackFocusState {
153             get {
154                 AudioStreamFocusState stateForPlayback;
155                 AudioStreamFocusState stateForRecording;
156                 int ret = Interop.AudioStreamPolicy.GetFocusState(_streamInfo, out stateForPlayback, out stateForRecording);
157                 if(ret != 0) {
158                     Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Unable to get focus state" + (AudioManagerError)ret);
159                     return AudioStreamFocusState.Released;
160                 }
161                 return stateForPlayback;
162             }
163         }
164
165         /// <summary>
166         /// The state of focus for recording.
167         /// </summary>
168         public AudioStreamFocusState RecordingFocusState {
169             get {
170                 AudioStreamFocusState stateForPlayback;
171                 AudioStreamFocusState stateForRecording;
172                 int ret = Interop.AudioStreamPolicy.GetFocusState(_streamInfo, out stateForPlayback, out stateForRecording);
173                 if(ret != 0) {
174                     Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Unable to get focus state" + (AudioManagerError)ret);
175                     return AudioStreamFocusState.Released;
176                 }
177                 return stateForRecording;
178             }
179         }
180
181         /// <summary>
182         /// Auto focus reacquisition property
183         /// </summary>
184         /// <remarks>
185         /// The focus reacquistion is set as default. If you don't want to reacquire the focus you've lost automatically, disable the focus reacqusition setting by using this API and vice versa.
186         /// </remarks>
187         public bool FocusReacquisitionEnabled {
188             get {
189                 bool enabled;
190                 int ret = Interop.AudioStreamPolicy.GetFocusReacquisition(_streamInfo, out enabled);
191                 if(ret != 0) {
192                     Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Unable to get focus reacquisition" + (AudioManagerError)ret);
193                     return true;
194                 }
195                 return enabled;
196             }
197             set {
198                 int ret = Interop.AudioStreamPolicy.SetFocusReacquisition(_streamInfo, value);
199                 AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to set focus reacquisition");
200             }
201         }
202
203         public IntPtr Handle {
204             get {
205                 return _streamInfo;
206             }
207         }
208
209         /// <summary>
210         /// Acquires the stream focus.
211         /// </summary>
212         /// <param name="options">The focus mask that user wants to acquire</param>
213         /// <param name="audioStreamBehavior">The required action for releaser</param>
214         /// <param name="extraInformation">The Extra information for this request (optional, this can be null)</param>
215         /// <remarks>
216         /// Do not call this API within event handlers of FocuStateChanged and StreamFocusStateWatch else it will throw and exception
217         /// </remarks>
218         public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehavior audioStreamBehavior, string extraInformation)
219         {
220             int ret = Interop.AudioStreamPolicy.AcquireFocus(_streamInfo, options, (int)audioStreamBehavior, extraInformation);
221             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Acquire focus return: " + ret);
222             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to acquire focus");
223         }
224
225         /// <summary>
226         /// Releases the acquired focus.
227         /// </summary>
228         /// <param name="options">The focus mask that user wants to release</param>
229         /// <param name="audioStreamBehavior">The required action for acquirer</param>
230         /// <param name="extraInformation">he Extra information for this request (optional, this can be null)</param>
231         /// <remarks>
232         /// Do not call this API within event handlers of FocuStateChanged and StreamFocusStateWatch else it will throw and exception
233         /// </remarks>
234         public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehavior audioStreamBehavior, string extraInformation)
235         {
236             int ret = Interop.AudioStreamPolicy.ReleaseFocus(_streamInfo, options, (int)audioStreamBehavior, extraInformation);
237             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Release focus return: " + ret);
238             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to release focus");
239         }
240
241         /// <summary>
242         /// Applies the stream routing.
243         /// </summary>
244         /// <remarks>
245         /// If the stream has not been made yet, this setting will be applied when the stream starts to play.
246         /// Precondition: Call AddDeviceForStreamRouting() before calling this function.
247         /// </remarks>
248         public void ApplyStreamRouting()
249         {
250             int ret = Interop.AudioStreamPolicy.ApplyStreamRouting(_streamInfo);
251             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Apply Routing: " + (AudioManagerError)ret);
252             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to apply stream routing");
253         }
254
255         /// <summary>
256         /// Adds the device to the stream information for the stream routing.
257         /// </summary>
258         /// <remarks>
259         /// Remarks: Use SoundManager.GetCurrentDeviceList() to get the device.
260         /// The available types of the StreamInfo for this API are SoundStreamTypeVoip and SoundStreamTypeMediaExternalOnly.
261         /// Postcondition: You can apply this setting by calling ApplyStreamRouting().
262         /// </remarks>
263         /// <param name="soundDevice">The device item from the current sound devices list.</param>
264         public void AddDeviceForStreamRouting(AudioDevice soundDevice)
265         {
266             int ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(_streamInfo, soundDevice.Handle);
267             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Add stream routing: " + (AudioManagerError)ret);
268
269             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to add device for stream routing");
270         }
271
272         /// <summary>
273         /// Removes the device to the stream information for the stream routing.
274         /// </summary>
275         /// <remarks>
276         /// Remarks: Use SoundManager.GetCurrentDeviceList() to get the device.
277         /// The available types of the StreamInfo for this API are SoundStreamTypeVoip and SoundStreamTypeMediaExternalOnly.
278         /// Postcondition: You can apply this setting by calling ApplyStreamRouting().
279         /// </remarks>
280         /// <param name="soundDevice">The device item from the current sound devices list.</param>
281         public void RemoveDeviceForStreamRouting(AudioDevice soundDevice)
282         {
283             int ret = Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(_streamInfo, soundDevice.Handle);
284             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Remove stream routing: " + (AudioManagerError)ret);
285             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to remove device for stream routing");
286         }
287
288         public void Dispose()
289         {
290             Dispose(true);
291             GC.SuppressFinalize(this);
292         }
293
294         protected virtual void Dispose(bool disposing)
295         {
296             if(!_disposed) {
297                 if(disposing) {
298                     // to be used if there are any other disposable objects
299                 }
300                 if(_streamInfo != IntPtr.Zero) {
301                     Interop.AudioStreamPolicy.DestroyStreamInformation(_streamInfo);  // Destroy the handle
302                     _streamInfo = IntPtr.Zero;
303                 }
304                 _disposed = true;
305             }
306         }
307
308         private static void RegisterFocusStateWatchEvent()
309         {
310             _focusStateWatchCallback = (int id, AudioStreamFocusOptions options, AudioStreamFocusState focusState, AudioStreamFocusChangedReason reason, string extraInfo, IntPtr userData) => {
311                 Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _Inside _focusStateWatchCallback : id = " + id + "options = " + options);
312                 FocusStateChangedEventArgs eventArgs = new FocusStateChangedEventArgs(focusState, reason, extraInfo);
313                 if(options == AudioStreamFocusOptions.Playback) {
314                     Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _eventArgs =  " + eventArgs);
315                     _focusStateWatchForPlayback?.Invoke(null, eventArgs);
316                 } else if(options == AudioStreamFocusOptions.Recording) {
317                     _focusStateWatchForRecording?.Invoke(null, eventArgs);
318                 } else if(options == (AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording)) {
319                     _focusStateWatchForPlayback?.Invoke(null, eventArgs);
320                     _focusStateWatchForRecording?.Invoke(null, eventArgs);
321                 }
322             };
323             int ret = Interop.AudioStreamPolicy.AddFocusStateWatchCallback(AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording, _focusStateWatchCallback, IntPtr.Zero, out _focusWatchCbId);
324             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _AddFocusStateWatchCallback : ret  =  " + ret + " ID = " + _focusWatchCbId);
325             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to set focus state watch callback");
326         }
327
328         private static void UnregisterFocusStateWatch()
329         {
330             int ret = Interop.AudioStreamPolicy.RemoveFocusStateWatchCallback(_focusWatchCbId);
331             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to unset focus state watch callback");
332         }
333     }
334 }