1a2c1ac3886e5a312005a12d6fc5fa45202cf2f9
[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="focusMask">The focus mask that user wants to acquire</param>
213         /// <param name="extraInformation">The Extra information for this request (optional, this can be null)</param>
214         /// <remarks>
215         /// Do not call this API within event handlers of FocuStateChanged and StreamFocusStateWatch else it will throw and exception
216         /// </remarks>
217         public void AcquireFocus(AudioStreamFocusOptions options, AudioStreamBehavior audioStreamBehavior, string extraInformation)
218         {
219             int ret = Interop.AudioStreamPolicy.AcquireFocus(_streamInfo, options, (int)audioStreamBehavior, extraInformation);
220             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Acquire focus return: " + ret);
221             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to acquire focus");
222         }
223
224         /// <summary>
225         /// Releases the acquired focus.
226         /// </summary>
227         /// <param name="options">The focus mask that user wants to release</param>
228         /// <param name="extraInformation">he Extra information for this request (optional, this can be null)</param>
229         /// <remarks>
230         /// Do not call this API within event handlers of FocuStateChanged and StreamFocusStateWatch else it will throw and exception
231         /// </remarks>
232         public void ReleaseFocus(AudioStreamFocusOptions options, AudioStreamBehavior audioStreamBehavior, string extraInformation)
233         {
234             int ret = Interop.AudioStreamPolicy.ReleaseFocus(_streamInfo, options, (int)audioStreamBehavior, extraInformation);
235             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Release focus return: " + ret);
236             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to release focus");
237         }
238
239         /// <summary>
240         /// Applies the stream routing.
241         /// </summary>
242         /// <remarks>
243         /// If the stream has not been made yet, this setting will be applied when the stream starts to play.
244         /// Precondition: Call AddDeviceForStreamRouting() before calling this function.
245         /// </remarks>
246         public void ApplyStreamRouting()
247         {
248             int ret = Interop.AudioStreamPolicy.ApplyStreamRouting(_streamInfo);
249             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Apply Routing: " + (AudioManagerError)ret);
250             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to apply stream routing");
251         }
252
253         /// <summary>
254         /// Adds the device to the stream information for the stream routing.
255         /// </summary>
256         /// <remarks>
257         /// Remarks: Use SoundManager.GetCurrentDeviceList() to get the device.
258         /// The available types of the StreamInfo for this API are SoundStreamTypeVoip and SoundStreamTypeMediaExternalOnly.
259         /// Postcondition: You can apply this setting by calling ApplyStreamRouting().
260         /// </remarks>
261         /// <param name="soundDevice">The device item from the current sound devices list.</param>
262         public void AddDeviceForStreamRouting(AudioDevice soundDevice)
263         {
264             int ret = Interop.AudioStreamPolicy.AddDeviceForStreamRouting(_streamInfo, soundDevice.Handle);
265             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Add stream routing: " + (AudioManagerError)ret);
266
267             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to add device for stream routing");
268         }
269
270         /// <summary>
271         /// Removes the device to the stream information for the stream routing.
272         /// </summary>
273         /// <remarks>
274         /// Remarks: Use SoundManager.GetCurrentDeviceList() to get the device.
275         /// The available types of the StreamInfo for this API are SoundStreamTypeVoip and SoundStreamTypeMediaExternalOnly.
276         /// Postcondition: You can apply this setting by calling ApplyStreamRouting().
277         /// </remarks>
278         /// <param name="soundDevice">The device item from the current sound devices list.</param>
279         public void RemoveDeviceForStreamRouting(AudioDevice soundDevice)
280         {
281             int ret = Interop.AudioStreamPolicy.RemoveDeviceForStreamRouting(_streamInfo, soundDevice.Handle);
282             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "Remove stream routing: " + (AudioManagerError)ret);
283             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to remove device for stream routing");
284         }
285
286         public void Dispose()
287         {
288             Dispose(true);
289             GC.SuppressFinalize(this);
290         }
291
292         protected virtual void Dispose(bool disposing)
293         {
294             if(!_disposed) {
295                 if(disposing) {
296                     // to be used if there are any other disposable objects
297                 }
298                 if(_streamInfo != IntPtr.Zero) {
299                     Interop.AudioStreamPolicy.DestroyStreamInformation(_streamInfo);  // Destroy the handle
300                     _streamInfo = IntPtr.Zero;
301                 }
302                 _disposed = true;
303             }
304         }
305
306         private static void RegisterFocusStateWatchEvent()
307         {
308             _focusStateWatchCallback = (int id, AudioStreamFocusOptions options, AudioStreamFocusState focusState, AudioStreamFocusChangedReason reason, string extraInfo, IntPtr userData) => {
309                 Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _Inside _focusStateWatchCallback : id = " + id + "options = " + options);
310                 FocusStateChangedEventArgs eventArgs = new FocusStateChangedEventArgs(focusState, reason, extraInfo);
311                 if(options == AudioStreamFocusOptions.Playback) {
312                     Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _eventArgs =  " + eventArgs);
313                     _focusStateWatchForPlayback?.Invoke(null, eventArgs);
314                 } else if(options == AudioStreamFocusOptions.Recording) {
315                     _focusStateWatchForRecording?.Invoke(null, eventArgs);
316                 } else if(options == (AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording)) {
317                     _focusStateWatchForPlayback?.Invoke(null, eventArgs);
318                     _focusStateWatchForRecording?.Invoke(null, eventArgs);
319                 }
320             };
321             int ret = Interop.AudioStreamPolicy.AddFocusStateWatchCallback(AudioStreamFocusOptions.Playback | AudioStreamFocusOptions.Recording, _focusStateWatchCallback, IntPtr.Zero, out _focusWatchCbId);
322             Tizen.Log.Info(AudioStreamPolicyLog.Tag, "############# _AddFocusStateWatchCallback : ret  =  " + ret + " ID = " + _focusWatchCbId);
323             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to set focus state watch callback");
324         }
325
326         private static void UnregisterFocusStateWatch()
327         {
328             int ret = Interop.AudioStreamPolicy.RemoveFocusStateWatchCallback(_focusWatchCbId);
329             AudioManagerErrorFactory.CheckAndThrowException(ret, "Unable to unset focus state watch callback");
330         }
331     }
332 }