[Camera] Remove wrong feature tag (#4613)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Camera / Camera / CameraDeviceManager.cs
1 /*
2  * Copyright (c) 2021 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.Collections.Generic;
19 using System.ComponentModel;
20 using System.Linq;
21 using Native = Interop.CameraDeviceManager;
22
23 namespace Tizen.Multimedia
24 {
25     /// <summary>
26     /// This CameraDeviceManager class provides methods to control current camera devices and get its information.
27     /// </summary>
28     /// <remarks>
29     /// This supports the product infrastructure and is not intended to be used directly from 3rd party application code.
30     /// </remarks>
31     /// <since_tizen> 10 </since_tizen>
32     public class CameraDeviceManager : IDisposable
33     {
34         private IntPtr _handle;
35         private bool _disposed;
36         private Native.DeviceConnectionChangedCallback _deviceConnectionChangedCallback;
37
38         /// <summary>
39         /// Initializes a new instance of the <see cref="CameraDeviceManager"/> class.
40         /// </summary>
41         /// <exception cref="InvalidOperationException">Invalid operation.</exception>
42         /// <exception cref="NotSupportedException">The camera device manager is not supported.</exception>
43         /// <since_tizen> 10 </since_tizen>
44         public CameraDeviceManager()
45         {
46             Native.Initialize(out _handle).ThrowIfFailed("Failed to initialize CameraDeviceManager");
47         }
48
49         /// <summary>
50         /// Finalizes an instance of the Camera class.
51         /// </summary>
52         ~CameraDeviceManager()
53         {
54             Dispose(false);
55         }
56
57         /// <summary>
58         /// Gets the status whether camera device(usb, network) is connected or not.
59         /// </summary>
60         /// <returns>true if usb or network camera is connected.</returns>
61         /// <exception cref="ObjectDisposedException">The CameraDeviceManager already has been disposed.</exception>
62         /// <since_tizen> 10 </since_tizen>
63         public bool IsExternalCameraConnected =>
64             SupportedDevices.Where(d => d.Type == CameraDeviceType.Usb ||
65                                         d.Type == CameraDeviceType.Network)
66                             .Any();
67
68         /// <summary>
69         /// Retrieves all the supported camera devices and returns its information.
70         /// </summary>
71         /// <returns>
72         /// if camera device exist, returns list of <see cref="CameraDeviceInformation"/>; otherwise returns Enumerable.Empty.
73         /// </returns>
74         /// <exception cref="ArgumentException">Invalid enumeration.</exception>
75         /// <exception cref="ArgumentNullException">name or id is null.</exception>
76         /// <exception cref="ObjectDisposedException">The CameraDeviceManager already has been disposed.</exception>
77         /// <since_tizen> 10 </since_tizen>
78         public IEnumerable<CameraDeviceInformation> SupportedDevices
79         {
80             get
81             {
82                 var deviceList = new List<CameraDeviceInformation>();
83
84                 Exception caught = null;
85
86                 Native.SupportedDeviceCallback callback = (ref Native.CameraDeviceStruct supportedDevice, IntPtr userData) =>
87                 {
88                     try
89                     {
90                         var deviceInfo = new CameraDeviceInformation(supportedDevice.type, supportedDevice.device, supportedDevice.name,
91                             supportedDevice.id, supportedDevice.extraStreamNum);
92                         Log.Debug(CameraLog.Tag, deviceInfo.ToString());
93
94                         deviceList.Add(deviceInfo);
95                         return true;
96                     }
97                     catch (Exception e)
98                     {
99                         caught = e;
100                         return false;
101                     }
102                 };
103
104                 Native.SupportedDevices(Handle, callback, IntPtr.Zero).
105                     ThrowIfFailed("failed to get supported devices");
106
107                 if (caught != null)
108                 {
109                     throw caught;
110                 }
111
112                 return deviceList.Any() ? deviceList.AsReadOnly() : Enumerable.Empty<CameraDeviceInformation>();
113             }
114         }
115
116         /// <summary>
117         /// Gets the current camera device information.
118         /// Retrieves all the supported camera devices and returns its information.
119         /// </summary>
120         /// <remarks>This method is only for backward compatibility. Please use SupportedDevices instead.</remarks>
121         /// <returns>
122         /// if camera device exist, returns list of <see cref="CameraDeviceInformation"/>; otherwise returns Enumerable.Empty.
123         /// </returns>
124         /// <see also="WebRTCState"/>
125         [EditorBrowsable(EditorBrowsableState.Never)]
126         public IEnumerable<CameraDeviceInformation> GetDeviceInformation() => SupportedDevices;
127
128         private event EventHandler<CameraDeviceConnectionChangedEventArgs> _deviceConnectionChanged;
129         /// <summary>
130         /// An event that occurs when camera device is connected or disconnected.
131         /// </summary>
132         /// <exception cref="ObjectDisposedException">The CameraDeviceManager already has been disposed.</exception>
133         /// <since_tizen> 10 </since_tizen>
134         public event EventHandler<CameraDeviceConnectionChangedEventArgs> DeviceConnectionChanged
135         {
136             add
137             {
138                 if (_deviceConnectionChanged == null)
139                 {
140                     RegisterDeviceConnectionChangedCallback();
141                 }
142
143                 _deviceConnectionChanged += value;
144             }
145             remove
146             {
147                 _deviceConnectionChanged -= value;
148
149                 if (_deviceConnectionChanged == null)
150                 {
151                     UnregisterDeviceConnectionChangedCallback();
152                 }
153             }
154         }
155
156         private IntPtr Handle
157         {
158             get
159             {
160                 ValidateNotDisposed();
161                 return _handle;
162             }
163         }
164
165         private int _connectionCallbackId = -1;
166         private void RegisterDeviceConnectionChangedCallback()
167         {
168             _deviceConnectionChangedCallback = (ref Native.CameraDeviceStruct supportedDevice, bool isConnected, IntPtr userData) =>
169             {
170                 var deviceInfo = new CameraDeviceInformation(supportedDevice.type, supportedDevice.device, supportedDevice.name,
171                     supportedDevice.id, supportedDevice.extraStreamNum);
172                 Log.Debug(CameraLog.Tag, deviceInfo.ToString());
173
174                 _deviceConnectionChanged?.Invoke(this, new CameraDeviceConnectionChangedEventArgs(deviceInfo, isConnected));
175             };
176
177             Native.SetDeviceConnectionChangedCallback(Handle, _deviceConnectionChangedCallback, IntPtr.Zero, out _connectionCallbackId).
178                 ThrowIfFailed("Failed to set device connection changed callback");
179
180             Log.Debug(CameraLog.Tag, $"callbackId[{_connectionCallbackId}]");
181         }
182
183         private void UnregisterDeviceConnectionChangedCallback()
184         {
185             Log.Debug(CameraLog.Tag, $"callbackId[{_connectionCallbackId}]");
186
187             if (_connectionCallbackId >= 0)
188             {
189                 Native.UnsetDeviceConnectionChangedCallback(Handle, _connectionCallbackId).
190                     ThrowIfFailed("Failed to unset device connection changed callback");
191             }
192         }
193
194         #region Dispose support
195         /// <summary>
196         /// Releases the unmanaged resources used by the camera.
197         /// </summary>
198         /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
199         /// <since_tizen> 10 </since_tizen>
200         protected virtual void Dispose(bool disposing)
201         {
202             if (!_disposed)
203             {
204                 Log.Debug(CameraLog.Tag, $"Enter. disposing:{disposing.ToString()}");
205
206                 if (disposing)
207                 {
208                     // to be used if there are any other disposable objects
209                 }
210
211                 if (_handle != IntPtr.Zero)
212                 {
213                     UnregisterDeviceConnectionChangedCallback();
214
215                     Native.Deinitialize(_handle);
216                     _handle = IntPtr.Zero;
217                 }
218
219                 _disposed = true;
220             }
221         }
222
223         /// <summary>
224         /// Releases all resources used by the camera.
225         /// </summary>
226         /// <since_tizen> 10 </since_tizen>
227         public void Dispose()
228         {
229             Dispose(true);
230             GC.SuppressFinalize(this);
231         }
232
233         internal void ValidateNotDisposed()
234         {
235             if (_disposed)
236             {
237                 Log.Error(CameraLog.Tag, "CameraDeviceManager handle is disposed.");
238                 throw new ObjectDisposedException(nameof(Camera));
239             }
240         }
241         #endregion Dispose support
242     }
243
244     /// <summary>
245     /// Provides the ability to get camera device information.
246     /// </summary>
247     /// <since_tizen> 10 </since_tizen>
248     public struct CameraDeviceInformation
249     {
250         /// <summary>
251         /// Initializes a new instance of the <see cref="CameraDeviceInformation"/> class.
252         /// </summary>
253         /// <param name="type">The camera type</param>
254         /// <param name="device">The camera device</param>
255         /// <param name="name">The name of camera device</param>
256         /// <param name="id">The ID of camera device</param>
257         /// <param name="numberOfExtraStream">The number of extra streams</param>
258         /// <exception cref="ArgumentException">Invalid enumeration.</exception>
259         /// <exception cref="ArgumentNullException">name or id is null.</exception>
260         /// <since_tizen> 10 </since_tizen>
261         internal CameraDeviceInformation(CameraDeviceType type, CameraDevice device, string name, string id, int numberOfExtraStream)
262         {
263             ValidationUtil.ValidateEnum(typeof(CameraDeviceType), type, nameof(type));
264             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
265
266             Type = type;
267             Device = device;
268             Name = name ?? throw new ArgumentNullException(nameof(name), "name is null");
269             Id = id ?? throw new ArgumentNullException(nameof(id), "id is null");
270             NumberOfExtraStream = numberOfExtraStream;
271
272             Log.Debug(CameraLog.Tag, this.ToString());
273         }
274
275         /// <summary>
276         /// Gets the camera device type.
277         /// </summary>
278         /// <value><see cref="CameraDeviceType"/></value>
279         /// <since_tizen> 10 </since_tizen>
280         public CameraDeviceType Type { get; }
281
282         /// <summary>
283         /// Gets the <see cref="CameraDevice"/>.
284         /// </summary>
285         /// <value><see cref="CameraDevice"/></value>
286         /// <since_tizen> 10 </since_tizen>
287         public CameraDevice Device { get; }
288
289         /// <summary>
290         /// Gets the camera device name.
291         /// </summary>
292         /// <value>The camera device name</value>
293         /// <since_tizen> 10 </since_tizen>
294         public string Name { get; }
295
296         /// <summary>
297         /// Gets the camera device ID.
298         /// </summary>
299         /// <value>The camera device ID.</value>
300         /// <since_tizen> 10 </since_tizen>
301         public string Id { get; }
302
303         /// <summary>
304         /// Gets the number of extra streams.
305         /// </summary>
306         /// <value>The number of extra streams.</value>
307         /// <since_tizen> 10 </since_tizen>
308         public int NumberOfExtraStream { get; }
309
310         /// <summary>
311         /// Returns a string that represents the current object.
312         /// </summary>
313         /// <returns>A string that represents the current object.</returns>
314         /// <since_tizen> 10 </since_tizen>
315         public override string ToString() =>
316             $"Type:{Type.ToString()}, Device:{Device.ToString()}, Name:{Name}, Id:{Id}, NumberOfExtraStream:{NumberOfExtraStream}";
317     }
318 }