[Camera] Add internal constructor (#3489)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Camera / Camera / CameraDeviceManager.cs
1 using System.Linq;
2 /*
3  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an AS IS BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
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> 9 </since_tizen>
32     /// <feature> http://tizen.org/feature/camera </feature>
33     [EditorBrowsable(EditorBrowsableState.Never)]
34     public class CameraDeviceManager : IDisposable
35     {
36         private IntPtr _handle;
37         private bool _disposed;
38         private Native.DeviceConnectionChangedCallback _deviceConnectionChangedCallback;
39
40         /// <summary>
41         /// Initializes a new instance of the <see cref="CameraDeviceManager"/> class.
42         /// </summary>
43         /// <exception cref="InvalidOperationException">Invalid operation.</exception>
44         /// <exception cref="NotSupportedException">The camera device manager is not supported.</exception>
45         /// <since_tizen> 9 </since_tizen>
46         [EditorBrowsable(EditorBrowsableState.Never)]
47         public CameraDeviceManager()
48         {
49             Native.Initialize(out _handle).ThrowIfFailed("Failed to initialize CameraDeviceManager");
50         }
51
52         /// <summary>
53         /// Finalizes an instance of the Camera class.
54         /// </summary>
55         [EditorBrowsable(EditorBrowsableState.Never)]
56         ~CameraDeviceManager()
57         {
58             Dispose(false);
59         }
60
61         /// <summary>
62         /// Gets the status whether camera device(usb, network) is connected or not.
63         /// </summary>
64         [EditorBrowsable(EditorBrowsableState.Never)]
65         public bool IsExternalCameraConnected =>
66             GetDeviceInformation().Where(d => d.Type == CameraDeviceType.Usb ||
67                                               d.Type == CameraDeviceType.Network)
68                                   .Any();
69
70         /// <summary>
71         /// Gets the current camera device information.
72         /// </summary>
73         /// <returns></returns>
74         /// <since_tizen> 9 </since_tizen>
75         [EditorBrowsable(EditorBrowsableState.Never)]
76         public IEnumerable<CameraDeviceInformation> GetDeviceInformation()
77         {
78             var deviceList = new Native.CameraDeviceListStruct();
79
80             Native.GetDeviceList(Handle, ref deviceList).
81                 ThrowIfFailed("Failed to get camera device list");
82
83             return GetDeviceInformation(deviceList);
84         }
85
86         internal static bool IsSupported
87         {
88             get
89             {
90                 try
91                 {
92                     using (var cameraDeviceManager = new CameraDeviceManager())
93                     {
94                         return true;
95                     }
96                 }
97                 catch (NotSupportedException)
98                 {
99                     Log.Info(CameraLog.Tag,
100                         $"CameraDeviceManager is not supported. Not error.");
101                 }
102                 return false;
103             }
104         }
105
106         internal static IEnumerable<CameraDeviceInformation> GetDeviceInformation(Native.CameraDeviceListStruct list)
107         {
108             if (list.count == 0)
109             {
110                 return Enumerable.Empty<CameraDeviceInformation>();
111             }
112
113             var deviceList = new List<CameraDeviceInformation>();
114
115             for (int i = 0 ; i < list.count ; i++)
116             {
117                 deviceList.Add(GetDeviceInformation(list.device[i]));
118             }
119
120             return deviceList.AsReadOnly();
121         }
122
123         internal static CameraDeviceInformation GetDeviceInformation(Native.CameraDeviceStruct device) =>
124             new CameraDeviceInformation(device.Type, device.device, device.name, device.id, device.extraStreamNum);
125
126         private event EventHandler<CameraDeviceConnectionChangedEventArgs> _deviceConnectionChanged;
127         /// <summary>
128         /// An event that occurs when camera device is connected or disconnected.
129         /// </summary>
130         /// <since_tizen> 9 </since_tizen>
131         [EditorBrowsable(EditorBrowsableState.Never)]
132         public event EventHandler<CameraDeviceConnectionChangedEventArgs> DeviceConnectionChanged
133         {
134             add
135             {
136                 if (_deviceConnectionChanged == null)
137                 {
138                     RegisterDeviceConnectionChangedCallback();
139                 }
140
141                 _deviceConnectionChanged += value;
142             }
143             remove
144             {
145                 _deviceConnectionChanged -= value;
146
147                 if (_deviceConnectionChanged == null)
148                 {
149                     UnregisterDeviceConnectionChangedCallback();
150                 }
151             }
152         }
153
154         private IntPtr Handle
155         {
156             get
157             {
158                 ValidateNotDisposed();
159                 return _handle;
160             }
161         }
162
163         private int _connectionCallbackId = -1;
164         private void RegisterDeviceConnectionChangedCallback()
165         {
166             Log.Debug(CameraLog.Tag, "Enter");
167
168             _deviceConnectionChangedCallback = (ref Native.CameraDeviceStruct device, bool status, IntPtr userData) =>
169             {
170                 Log.Debug(CameraLog.Tag, "Invoke DeviceConnectionChanged event");
171                 _deviceConnectionChanged?.Invoke(this, new CameraDeviceConnectionChangedEventArgs(ref device, status));
172             };
173
174             Native.SetDeviceConnectionChangedCallback(Handle, _deviceConnectionChangedCallback, IntPtr.Zero, out _connectionCallbackId).
175                 ThrowIfFailed("Failed to set device connection changed callback");
176
177             Log.Debug(CameraLog.Tag, $"Leave. callbackId[{_connectionCallbackId}]");
178         }
179
180         private void UnregisterDeviceConnectionChangedCallback()
181         {
182             Log.Debug(CameraLog.Tag, $"Enter. callbackId[{_connectionCallbackId}]");
183
184             if (_connectionCallbackId >= 0)
185             {
186                 Native.UnsetDeviceConnectionChangedCallback(Handle, _connectionCallbackId).
187                     ThrowIfFailed("Failed to unset device connection changed callback");
188             }
189         }
190
191         #region Dispose support
192         /// <summary>
193         /// Releases the unmanaged resources used by the camera.
194         /// </summary>
195         /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
196         /// <since_tizen> 9 </since_tizen>
197         [EditorBrowsable(EditorBrowsableState.Never)]
198         protected virtual void Dispose(bool disposing)
199         {
200             if (!_disposed)
201             {
202                 Log.Debug(CameraLog.Tag, $"Enter. disposing:{disposing.ToString()}");
203
204                 if (disposing)
205                 {
206                     // to be used if there are any other disposable objects
207                 }
208
209                 if (_handle != IntPtr.Zero)
210                 {
211                     UnregisterDeviceConnectionChangedCallback();
212
213                     Native.Deinitialize(_handle);
214                     _handle = IntPtr.Zero;
215                 }
216
217                 _disposed = true;
218             }
219         }
220
221         /// <summary>
222         /// Releases all resources used by the camera.
223         /// </summary>
224         /// <since_tizen> 9 </since_tizen>
225         [EditorBrowsable(EditorBrowsableState.Never)]
226         public void Dispose()
227         {
228             Dispose(true);
229             GC.SuppressFinalize(this);
230         }
231
232         internal void ValidateNotDisposed()
233         {
234             if (_disposed)
235             {
236                 Log.Error(CameraLog.Tag, "CameraDeviceManager handle is disposed.");
237                 throw new ObjectDisposedException(nameof(Camera));
238             }
239         }
240         #endregion Dispose support
241     }
242
243     /// <summary>
244     /// Provides the ability to get camera device information.
245     /// </summary>
246     /// <since_tizen> 9 </since_tizen>
247     [EditorBrowsable(EditorBrowsableState.Never)]
248     public struct CameraDeviceInformation
249     {
250         /// <summary>
251         /// Initializes a new instance of the <see cref="CameraDeviceInformation"/> class.
252         /// </summary>
253         /// <param name="type"><see cref="CameraDeviceType"/></param>
254         /// <param name="device"><see cref="CameraDevice"/></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 stream</param>
258         /// <exception cref="ArgumentException">Invalid enumeration.</exception>
259         /// <exception cref="ArgumentNullException">name or id is null.</exception>
260         /// <since_tizen> 9 </since_tizen>
261         [EditorBrowsable(EditorBrowsableState.Never)]
262         internal CameraDeviceInformation(CameraDeviceType type, CameraDevice device, string name, string id, int numberOfExtraStream)
263         {
264             ValidationUtil.ValidateEnum(typeof(CameraDeviceType), type, nameof(type));
265             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
266
267             Type = type;
268             Device = device;
269             Name = name ?? throw new ArgumentNullException(nameof(name), "name is null");
270             Id = id ?? throw new ArgumentNullException(nameof(id), "id is null");
271             NumberOfExtraStream = numberOfExtraStream;
272
273             Log.Debug(CameraLog.Tag, this.ToString());
274         }
275
276         /// <summary>
277         /// Gets the camera device type.
278         /// </summary>
279         /// <value><see cref="CameraDeviceType"/></value>
280         /// <since_tizen> 9 </since_tizen>
281         [EditorBrowsable(EditorBrowsableState.Never)]
282         public CameraDeviceType Type { get; }
283
284         /// <summary>
285         /// Gets the <see cref="CameraDevice"/>.
286         /// </summary>
287         /// <value><see cref="CameraDevice"/></value>
288         /// <since_tizen> 9 </since_tizen>
289         [EditorBrowsable(EditorBrowsableState.Never)]
290         public CameraDevice Device { get; }
291
292         /// <summary>
293         /// Gets the camera device name.
294         /// </summary>
295         /// <value>The camera device name</value>
296         /// <since_tizen> 9 </since_tizen>
297         [EditorBrowsable(EditorBrowsableState.Never)]
298         public string Name { get; }
299
300         /// <summary>
301         /// Gets the camera device Id.
302         /// </summary>
303         /// <value>The camera device id.</value>
304         /// <since_tizen> 9 </since_tizen>
305         [EditorBrowsable(EditorBrowsableState.Never)]
306         public string Id { get; }
307
308         /// <summary>
309         /// Gets the number of extra stream.
310         /// </summary>
311         /// <value>The number of extra stream.</value>
312         /// <since_tizen> 9 </since_tizen>
313         [EditorBrowsable(EditorBrowsableState.Never)]
314         public int NumberOfExtraStream { get; }
315
316         /// <summary>
317         /// Returns a string that represents the current object.
318         /// </summary>
319         /// <returns>A string that represents the current object.</returns>
320         /// <since_tizen> 9 </since_tizen>
321         [EditorBrowsable(EditorBrowsableState.Never)]
322         public override string ToString() =>
323             $"Type:{Type.ToString()}, Device:{Device.ToString()}, Name:{Name}, Id:{Id}, NumberOfExtraStream:{NumberOfExtraStream}";
324     }
325 }