[TCSACR-37][Camera/Recorder] Modify camera, recorder privilege for some APIs
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Camera / Camera / Camera.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.Collections.Generic;
19 using System.Diagnostics;
20 using System.Linq;
21 using System.Runtime.InteropServices;
22 using System.Threading;
23 using static Interop;
24 using Native = Interop.Camera;
25
26 namespace Tizen.Multimedia
27 {
28     static internal class CameraLog
29     {
30         internal const string Tag = "Tizen.Multimedia.Camera";
31         internal const string Enter = "[Enter]";
32         internal const string Leave = "[Leave]";
33     }
34
35     /// <summary>
36     /// The camera class provides methods to capture photos and support setting up notifications
37     /// for state changes of capturing, previewing, focusing, information about resolution and binary format
38     /// and functions for picture manipulations like sepia negative and many more.
39     /// It also notifies you when a significant picture parameter changes e.g. focus.
40     /// </summary>
41     public class Camera : IDisposable, IDisplayable<CameraError>
42     {
43         private IntPtr _handle = IntPtr.Zero;
44         private bool _disposed = false;
45         private CameraState _state = CameraState.None;
46         private static Dictionary<object, int> _callbackIdInfo = new Dictionary<object, int>();
47
48         /// <summary>
49         /// Initializes a new instance of the <see cref="Camera"/> Class.
50         /// </summary>
51         /// <param name="device">The camera device to access</param>
52         public Camera(CameraDevice device)
53         {
54             CameraErrorFactory.ThrowIfError(Native.Create((int)device, out _handle),
55                 "Failed to create camera instance");
56
57             Feature = new CameraFeatures(this);
58             Setting = new CameraSettings(this);
59             DisplaySettings = new CameraDisplaySettings(this);
60
61             RegisterCallbacks();
62
63             SetState(CameraState.Created);
64         }
65
66         /// <summary>
67         /// Destructor of the camera class.
68         /// </summary>
69         ~Camera()
70         {
71             Dispose(false);
72         }
73
74         public IntPtr Handle => GetHandle();
75
76         internal IntPtr GetHandle()
77         {
78             ValidateNotDisposed();
79             return _handle;
80         }
81
82 #region Dispose support
83         /// <summary>
84         /// Release any unmanaged resources used by this object.
85         /// </summary>
86         public void Dispose()
87         {
88             Dispose(true);
89             GC.SuppressFinalize(this);
90         }
91
92         protected virtual void Dispose(bool disposing)
93         {
94             if (!_disposed)
95             {
96                 if (disposing)
97                 {
98                     // to be used if there are any other disposable objects
99                 }
100
101                 if (_handle != IntPtr.Zero)
102                 {
103                     Native.Destroy(_handle);
104                     _handle = IntPtr.Zero;
105                 }
106
107                 _disposed = true;
108             }
109         }
110
111         internal void ValidateNotDisposed()
112         {
113             if (_disposed)
114             {
115                 Log.Error(CameraLog.Tag, "Camera handle is disposed.");
116                 throw new ObjectDisposedException(nameof(Camera));
117             }
118         }
119 #endregion Dispose support
120
121 #region Check camera state
122         internal void ValidateState(params CameraState[] required)
123         {
124             ValidateNotDisposed();
125
126             Debug.Assert(required.Length > 0);
127
128             var curState = _state;
129             if (!required.Contains(curState))
130             {
131                 throw new InvalidOperationException($"The camera is not in a valid state. " +
132                     $"Current State : { curState }, Valid State : { string.Join(", ", required) }.");
133             }
134         }
135
136         internal void SetState(CameraState state)
137         {
138             _state = state;
139         }
140 #endregion Check camera state
141
142 #region EventHandlers
143         /// <summary>
144         /// Event that occurs when an camera is interrupted by policy.
145         /// </summary>
146         public event EventHandler<CameraInterruptedEventArgs> Interrupted;
147         private Native.InterruptedCallback _interruptedCallback;
148
149         /// <summary>
150         /// Event that occurs when there is an asynchronous error.
151         /// </summary>
152         public event EventHandler<CameraErrorOccurredEventArgs> ErrorOccurred;
153         private Native.ErrorCallback _errorCallback;
154
155         /// <summary>
156         /// Event that occurs when the auto focus state is changed.
157         /// </summary>
158         public event EventHandler<CameraFocusStateChangedEventArgs> FocusStateChanged;
159         private Native.FocusStateChangedCallback _focusStateChangedCallback;
160
161         /// <summary>
162         /// Event that occurs when a face is detected in preview frame.
163         /// </summary>
164         public event EventHandler<FaceDetectedEventArgs> FaceDetected;
165         private Native.FaceDetectedCallback _faceDetectedCallback;
166
167         /// <summary>
168         /// Event that occurs during capture of image.
169         /// </summary>
170         public event EventHandler<CameraCapturingEventArgs> Capturing;
171         private Native.CapturingCallback _capturingCallback;
172
173         /// <summary>
174         /// Event that occurs after the capture of the image.
175         /// </summary>
176         public event EventHandler<EventArgs> CaptureCompleted;
177         private Native.CaptureCompletedCallback _captureCompletedCallback;
178
179         /// <summary>
180         /// Event that occurs when there is change in HDR capture progress.
181         /// Check whether HdrCapture feature is supported or not before add this EventHandler.
182         /// </summary>
183         public event EventHandler<HdrCaptureProgressEventArgs> HdrCaptureProgress;
184         private Native.HdrCaptureProgressCallback _hdrCaptureProgressCallback;
185
186         /// <summary>
187         /// Event that occurs when camera state is changed.
188         /// </summary>
189         public event EventHandler<CameraStateChangedEventArgs> StateChanged;
190         private Native.StateChangedCallback _stateChangedCallback;
191
192     #region DeviceStateChanged callback
193         internal static Native.DeviceStateChangedCallback _deviceStateChangedCallback;
194         private static event EventHandler<CameraDeviceStateChangedEventArgs> _deviceStateChanged;
195         private static object _deviceStateChangedEventLock = new object();
196
197         /// <summary>
198         /// Set the DeviceStateChanged Callback.
199         /// User doesn't need to create camera instance.
200         /// This static EventHandler calls platform function every time because each callback function have to remain its own callbackId.
201         /// </summary>
202         /// <param name="callback">Callback of type <see cref="Native.DeviceStateChangedCallback"/>.</param>
203         /// <param name="callbackId">The Id of registered callback.</param>
204         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
205         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
206         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
207         public static event EventHandler<CameraDeviceStateChangedEventArgs> DeviceStateChanged
208         {
209             add
210             {
211                 lock (_deviceStateChangedEventLock)
212                 {
213                     int callbackId = 0;
214
215                     _deviceStateChangedCallback = (CameraDevice device, CameraDeviceState state, IntPtr userData) =>
216                     {
217                         _deviceStateChanged?.Invoke(null, new CameraDeviceStateChangedEventArgs(device, state));
218                     };
219                     CameraErrorFactory.ThrowIfError(Native.SetDeviceStateChangedCallback(_deviceStateChangedCallback, IntPtr.Zero, out callbackId),
220                         "Failed to set interrupt callback");
221
222                     // Keep current callbackId and EventHandler pair to remove EventHandler later.
223                     _callbackIdInfo.Add(value, callbackId);
224                     Log.Info(CameraLog.Tag, "add callbackId " + callbackId.ToString());
225
226                     _deviceStateChanged += value;
227                 }
228             }
229
230             remove
231             {
232                 lock (_deviceStateChangedEventLock)
233                 {
234                     _deviceStateChanged -= value;
235
236                     int callbackId = 0;
237                     _callbackIdInfo.TryGetValue(value, out callbackId);
238                     Log.Info(CameraLog.Tag, "remove callbackId " + callbackId.ToString());
239
240                     CameraErrorFactory.ThrowIfError(Native.UnsetDeviceStateChangedCallback(callbackId),
241                             "Unsetting media packet preview callback failed");
242
243                     _callbackIdInfo.Remove(value);
244
245                     if (_deviceStateChanged == null)
246                     {
247                         _deviceStateChangedCallback = null;
248                     }
249                 }
250             }
251         }
252         #endregion DeviceStateChanged callback
253
254     #region Preview EventHandler
255         private Native.PreviewCallback _previewCallback;
256         private event EventHandler<PreviewEventArgs> _preview;
257         private object _previewEventLock = new object();
258         /// <summary>
259         /// Event that occurs once per frame when previewing.
260         /// Preview callback is registered when user add callback explicitly to avoid useless P/Invoke.
261         /// </summary>
262         public event EventHandler<PreviewEventArgs> Preview
263         {
264             add
265             {
266                 lock (_previewEventLock)
267                 {
268                     if (_preview == null)
269                     {
270                         RegisterPreviewCallback();
271                     }
272
273                     _preview += value;
274                 }
275             }
276
277             remove
278             {
279                 lock (_previewEventLock)
280                 {
281                     _preview -= value;
282
283                     if (_preview == null)
284                     {
285                         CameraErrorFactory.ThrowIfError(Native.UnsetPreviewCallback(_handle),
286                             "Unsetting preview callback failed");
287                         _previewCallback = null;
288                     }
289                 }
290             }
291         }
292     #endregion Preview EventHandler
293
294     #region MediaPacketPreview EventHandler
295         private Native.MediaPacketPreviewCallback _mediaPacketPreviewCallback;
296         private EventHandler<MediaPacketPreviewEventArgs> _mediaPacketPreview;
297         private object _mediaPacketPreviewEventLock = new object();
298
299         /// <summary>
300         /// Event that occurs once per frame when previewing.
301         /// Preview callback is registered when user add callback explicitly to avoid useless P/Invoke.
302         /// </summary>
303         public event EventHandler<MediaPacketPreviewEventArgs> MediaPacketPreview
304         {
305             add
306             {
307                 lock (_mediaPacketPreviewEventLock)
308                 {
309                     if (_mediaPacketPreview == null)
310                     {
311                         RegisterMediaPacketPreviewCallback();
312                     }
313
314                     _mediaPacketPreview += value;
315                 }
316             }
317
318             remove
319             {
320                 lock (_mediaPacketPreviewEventLock)
321                 {
322                     _mediaPacketPreview -= value;
323
324                     if (_mediaPacketPreview == null)
325                     {
326                         CameraErrorFactory.ThrowIfError(Native.UnsetMediaPacketPreviewCallback(_handle),
327                             "Unsetting media packet preview callback failed");
328                         _mediaPacketPreviewCallback = null;
329                     }
330                 }
331             }
332         }
333     #endregion MediaPacketPreview EventHandler
334
335 #endregion EventHandlers
336
337 #region Properties
338         /// <summary>
339         /// Get/Set the various camera settings.
340         /// </summary>
341         public CameraSettings Setting { get; }
342
343         /// <summary>
344         /// Gets the various camera features.
345         /// </summary>
346         public CameraFeatures Feature { get; }
347
348         /// <summary>
349         /// Get/set various camera display properties.
350         /// </summary>
351         public CameraDisplaySettings DisplaySettings{ get; }
352
353         private Display _display;
354
355         private CameraError SetDisplay(Display display)
356         {
357             if (display == null)
358             {
359                 return CameraDisplay.SetTarget(GetHandle(), DisplayType.None, IntPtr.Zero);
360             }
361
362             return display.ApplyTo(this);
363         }
364
365         private void ReplaceDisplay(Display newDisplay)
366         {
367             if (_display != null)
368             {
369                 _display.Owner = null;
370             }
371             _display = newDisplay;
372             if (_display != null)
373             {
374                 _display.Owner = this;
375             }
376         }
377
378         /// <summary>
379         /// Sets or gets the display type and handle to show preview images.
380         /// The camera must be in the <see cref="CameraState.Created"/> state.
381         /// </summary>
382         /// <remarks>
383         /// This must be set before StartPreview() method.
384         /// In Custom ROI display mode, DisplayRoiArea property must be set before calling this method.
385         /// </remarks>
386         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
387         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
388         /// <exception cref="ObjectDisposedException" > The camera already has been disposed.</exception>
389         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
390         public Display Display
391         {
392             get
393             {
394                 return _display;
395             }
396             set
397             {
398                 ValidateState(CameraState.Created);
399
400                 if (value != null && value.Owner != null)
401                 {
402                     if (ReferenceEquals(this, value.Owner))
403                     {
404                         return;
405                     }
406                     else
407                     {
408                         throw new ArgumentException("The display has already been assigned to another.");
409                     }
410                 }
411                 CameraErrorFactory.ThrowIfError(SetDisplay(value), "Failed to set the camera display");
412
413                 ReplaceDisplay(value);
414             }
415         }
416
417         CameraError IDisplayable<CameraError>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
418         {
419             Debug.Assert(_disposed == false);
420
421             Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
422
423             return CameraDisplay.SetTarget(GetHandle(), type, evasObject);
424         }
425
426         /// <summary>
427         /// Gets the state of the camera.
428         /// </summary>
429         /// <value> None, Created, Preview, Capturing, Captured </value>
430         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
431         public CameraState State
432         {
433             get
434             {
435                 ValidateNotDisposed();
436
437                 CameraState val = CameraState.None;
438                 CameraErrorFactory.ThrowIfError(Native.GetState(_handle, out val),
439                     "Failed to get camera state");
440
441                 return val;
442             }
443         }
444
445         /// <summary>
446         /// The hint for display reuse.
447         /// If the hint is set to true, the display will be reused when the camera device is changed with
448         /// ChangeDevice method.
449         /// </summary>
450         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
451         /// <exception cref="InvalidOperationException">Invalid state.</exception>
452         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
453         public bool DisplayReuseHint
454         {
455             get
456             {
457                 ValidateNotDisposed();
458
459                 bool val = false;
460
461                 CameraErrorFactory.ThrowIfError(Native.GetDisplayReuseHint(_handle, out val),
462                     "Failed to get camera display reuse hint");
463
464                 return val;
465             }
466
467             set
468             {
469                 ValidateState(CameraState.Preview);
470
471                 CameraErrorFactory.ThrowIfError(Native.SetDisplayReuseHint(_handle, value),
472                     "Failed to set display reuse hint.");
473             }
474         }
475
476         /// <summary>
477         /// Gets the facing direction of camera module.
478         /// </summary>
479         /// <value>A <see cref="CameraFacingDirection"/> that specifies the facing direction of camera device.</value>
480         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
481         public CameraFacingDirection Direction
482         {
483             get
484             {
485                 ValidateNotDisposed();
486
487                 CameraFacingDirection val = 0;
488
489                 CameraErrorFactory.ThrowIfError(Native.GetFacingDirection(_handle, out val),
490                     "Failed to get camera direction");
491
492                 return val;
493             }
494         }
495
496         /// <summary>
497         /// Gets the camera device count.
498         /// </summary>
499         /// <value>This returns 2, if the device supports primary and secondary cameras.
500         /// Otherwise 1, if the device only supports primary camera.</value>
501         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
502         public int CameraCount
503         {
504             get
505             {
506                 ValidateNotDisposed();
507
508                 int val = 0;
509
510                 CameraErrorFactory.ThrowIfError(Native.GetDeviceCount(_handle, out val),
511                     "Failed to get camera device count");
512
513                 return val;
514             }
515         }
516         #endregion Properties
517
518         #region Methods
519         /// <summary>
520         /// Changes the camera device.
521         /// </summary>
522         /// <param name="device">The hardware camera to access.</param>
523         /// <remarks>
524         /// If display reuse is set using <see cref="DisplayReuseHint"/>
525         /// before stopping the preview, the display will be reused and last frame on the display
526         /// can be kept even though camera device is changed.
527         /// The camera must be in the <see cref="CameraState.Created"/> or <see cref="CameraState.Preview"/> state.
528         /// </remarks>
529         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
530         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
531         /// <exception cref="NotSupportedException">In case of ChangeDevice feature is not supported.</exception>
532         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
533         public void ChangeDevice(CameraDevice device)
534         {
535             ValidateState(CameraState.Created, CameraState.Preview);
536
537             CameraErrorFactory.ThrowIfError(Native.ChangeDevice(_handle, (int)device),
538                 "Failed to change the camera device");
539         }
540
541         /// <summary>
542         /// Gets the device state.
543         /// </summary>
544         /// <param name="device">The device to get state.</param>
545         /// <returns>Returns the state of camera device</returns>
546         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
547         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
548         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
549         public CameraDeviceState GetDeviceState(CameraDevice device)
550         {
551             int val = 0;
552
553             CameraErrorFactory.ThrowIfError(Native.GetDeviceState(device, out val),
554                 "Failed to get the camera device state.");
555
556             return (CameraDeviceState)val;
557         }
558
559         /// <summary>
560         /// Gets the flash state.
561         /// </summary>
562         /// <param name="device">The device to get state.</param>
563         /// <returns>Returns the flash state of camera device</returns>
564         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
565         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
566         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
567         public static CameraFlashState GetFlashState(CameraDevice device)
568         {
569             CameraFlashState val = CameraFlashState.NotUsed;
570
571             CameraErrorFactory.ThrowIfError(Native.GetFlashState(device, out val),
572                 "Failed to get camera flash state");
573
574             return val;
575         }
576
577         /// <summary>
578         /// Starts capturing and drawing preview frames on the screen.
579         /// The display handle must be set using <see cref="CameraDisplaySettings.SetInfo"/>
580         /// before using this method.
581         /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
582         /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
583         /// before using this method.
584         /// The camera must be in the <see cref="CameraState.Created"/> or <see cref="CameraState.Captured"/> state.
585         /// </summary>
586         /// <privilege>
587         /// http://tizen.org/privilege/camera
588         /// </privilege>
589         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
590         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
591         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
592         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
593         public void StartPreview()
594         {
595             ValidateState(CameraState.Created, CameraState.Captured);
596
597             CameraErrorFactory.ThrowIfError(Native.StartPreview(_handle),
598                 "Failed to start the camera preview.");
599
600             // Update by StateChangedCallback can be delayed for dozens of milliseconds.
601             SetState(CameraState.Preview);
602         }
603
604         /// <summary>
605         /// Stops capturing and drawing preview frames on the screen.
606         /// The camera must be in the <see cref="CameraState.Preview"/> state.
607         /// </summary>
608         /// <privilege>
609         /// http://tizen.org/privilege/camera
610         /// </privilege>
611         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
612         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
613         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
614         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
615         public void StopPreview()
616         {
617             ValidateState(CameraState.Preview);
618
619             CameraErrorFactory.ThrowIfError(Native.StopPreview(_handle),
620                 "Failed to stop the camera preview.");
621
622             SetState(CameraState.Created);
623         }
624
625         /// <summary>
626         /// Starts capturing of still images.
627         /// EventHandler must be set for capturing using <see cref="Capturing"/>
628         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
629         /// The camera must be in the <see cref="CameraState.Preview"/> state.
630         /// </summary>
631         /// <privilege>
632         /// http://tizen.org/privilege/camera
633         /// </privilege>
634         /// <remarks>
635         /// This function causes the transition of the camera state from Capturing to Captured
636         /// automatically and the corresponding EventHandlers will be invoked.
637         /// The preview should be restarted by calling <see cref="StartPreview"/> method after capture is completed.
638         /// </remarks>
639         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
640         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
641         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
642         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
643         public void StartCapture()
644         {
645             ValidateState(CameraState.Preview);
646
647             CameraErrorFactory.ThrowIfError(Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero),
648                 "Failed to start the camera capture.");
649
650             SetState(CameraState.Capturing);
651         }
652
653         /// <summary>
654         /// Starts continuously capturing still images.
655         /// EventHandler must be set for capturing using <see cref="Capturing"/>
656         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
657         /// The camera must be in the <see cref="CameraState.Preview"/> state.
658         /// </summary>
659         /// <privilege>
660         /// http://tizen.org/privilege/camera
661         /// </privilege>
662         /// <param name="count">The number of still images.</param>
663         /// <param name="interval">The interval of the capture(milliseconds).</param>
664         /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
665         /// <seealso cref="System.Threading.CancellationToken"/>
666         /// <remarks>
667         /// If this is not supported zero shutter lag occurs. The capture resolution could be
668         /// changed to the preview resolution. This function causes the transition of the camera state
669         /// from Capturing to Captured automatically and the corresponding Eventhandlers will be invoked.
670         /// Each captured image will be delivered through Eventhandler set using <see cref="Capturing"/> event.
671         /// The preview should be restarted by calling <see cref="StartPreview"/> method after capture is completed.
672         /// </remarks>
673         /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
674         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
675         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
676         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
677         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
678         public void StartCapture(int count, int interval, CancellationToken cancellationToken)
679         {
680             ValidateState(CameraState.Preview);
681
682             if (count < 2)
683             {
684                 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
685             }
686
687             if (interval < 0)
688             {
689                 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
690             }
691
692             //Handle CancellationToken
693             if (cancellationToken != CancellationToken.None)
694             {
695                 cancellationToken.Register(() =>
696                 {
697                     CameraErrorFactory.ThrowIfError(Native.StopContinuousCapture(_handle),
698                         "Failed to cancel the continuous capture");
699                     SetState(CameraState.Captured);
700                 });
701             }
702
703             CameraErrorFactory.ThrowIfError(Native.StartContinuousCapture(_handle, count, interval,
704                 _capturingCallback, _captureCompletedCallback, IntPtr.Zero), "Failed to start the continuous capture.");
705
706             SetState(CameraState.Capturing);
707         }
708
709         /// <summary>
710         /// Starts camera auto-focusing, asynchronously.
711         /// The camera must be in the <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/> state.
712         /// </summary>
713         /// <param name="continuous">Continuous auto focus</param>
714         /// <privilege>
715         /// http://tizen.org/privilege/camera
716         /// </privilege>
717         /// <remarks>
718         /// If continuous status is true, the camera continuously tries to focus.
719         /// </remarks>
720         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
721         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
722         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
723         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
724         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
725         public void StartFocusing(bool continuous)
726         {
727             ValidateState(CameraState.Preview, CameraState.Captured);
728
729             CameraErrorFactory.ThrowIfError(Native.StartFocusing(_handle, continuous),
730                 "Failed to cancel the camera focus.");
731         }
732
733         /// <summary>
734         /// Stops camera auto focusing.
735         /// The camera must be in the <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/> state.
736         /// </summary>
737         /// <privilege>
738         /// http://tizen.org/privilege/camera
739         /// </privilege>
740         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
741         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
742         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
743         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
744         public void StopFocusing()
745         {
746             ValidateState(CameraState.Preview, CameraState.Captured);
747
748             CameraErrorFactory.ThrowIfError(Native.CancelFocusing(_handle),
749                 "Failed to cancel the camera focus.");
750         }
751
752         /// <summary>
753         /// Starts face detection.
754         /// The camera must be in the <see cref="CameraState.Preview"/> state.
755         /// </summary>
756         /// <privilege>
757         /// http://tizen.org/privilege/camera
758         /// </privilege>
759         /// <remarks>
760         /// This should be called after <see cref="StartPreview"/> is started.
761         /// The Eventhandler set using <see cref="FaceDetected"/> invoked when the face is detected in preview frame.
762         /// Internally it starts continuous focus and focusing on the detected face.
763         /// </remarks>
764         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
765         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
766         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
767         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
768         public void StartFaceDetection()
769         {
770             ValidateState(CameraState.Preview);
771
772             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
773             {
774                 var result = new List<FaceDetectionData>();
775                 IntPtr current = faces;
776
777                 for (int i = 0; i < count; i++)
778                 {
779                     result.Add(new FaceDetectionData(current));
780                     current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
781                 }
782
783                 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
784             };
785             CameraErrorFactory.ThrowIfError(Native.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero),
786                 "Failed to start face detection");
787         }
788
789         /// <summary>
790         /// Stops face detection.
791         /// </summary>
792         /// <privilege>
793         /// http://tizen.org/privilege/camera
794         /// </privilege>
795         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
796         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
797         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
798         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
799         public void StopFaceDetection()
800         {
801             if (_faceDetectedCallback == null)
802             {
803                 throw new InvalidOperationException("The face detection is not started.");
804             }
805
806             CameraErrorFactory.ThrowIfError(Native.StopFaceDetection(_handle),
807                 "Failed to stop the face detection.");
808
809             _faceDetectedCallback = null;
810         }
811 #endregion Methods
812
813 #region Callback registrations
814         private void RegisterCallbacks()
815         {
816             RegisterErrorCallback();
817             RegisterFocusStateChanged();
818             RegisterHdrCaptureProgress();
819             RegisterInterruptedCallback();
820             RegisterStateChangedCallback();
821
822             //Define capturing callback
823             _capturingCallback = (IntPtr image, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
824             {
825                 Capturing?.Invoke(this, new CameraCapturingEventArgs(new ImageData(image),
826                     postview == IntPtr.Zero ? null : new ImageData(postview),
827                     thumbnail == IntPtr.Zero ? null : new ImageData(thumbnail)));
828             };
829
830             //Define captureCompleted callback
831             _captureCompletedCallback = _ =>
832             {
833                 SetState(CameraState.Captured);
834                 CaptureCompleted?.Invoke(this, EventArgs.Empty);
835             };
836         }
837
838         private void RegisterInterruptedCallback()
839         {
840             _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
841             {
842                 Interrupted?.Invoke(this, new CameraInterruptedEventArgs(policy, previous, current));
843             };
844             CameraErrorFactory.ThrowIfError(Native.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero),
845                 "Failed to set interrupt callback");
846         }
847
848         private void RegisterErrorCallback()
849         {
850             _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
851             {
852                 ErrorOccurred?.Invoke(this, new CameraErrorOccurredEventArgs(error, current));
853             };
854             CameraErrorFactory.ThrowIfError(Native.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero),
855                 "Setting error callback failed");
856         }
857
858         private void RegisterStateChangedCallback()
859         {
860             _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr _) =>
861             {
862                 SetState(current);
863                 Log.Info(CameraLog.Tag, "Camera state changed " + previous.ToString() + " -> " + current.ToString());
864                 StateChanged?.Invoke(this, new CameraStateChangedEventArgs(previous, current, byPolicy));
865             };
866             CameraErrorFactory.ThrowIfError(Native.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero),
867                 "Setting state changed callback failed");
868         }
869
870         private void RegisterFocusStateChanged()
871         {
872             _focusStateChangedCallback = (CameraFocusState state, IntPtr userData) =>
873             {
874                 FocusStateChanged?.Invoke(this, new CameraFocusStateChangedEventArgs(state));
875             };
876             CameraErrorFactory.ThrowIfError(Native.SetFocusStateChangedCallback(_handle, _focusStateChangedCallback, IntPtr.Zero),
877                 "Setting focus changed callback failed");
878         }
879
880         private void RegisterHdrCaptureProgress()
881         {
882             //Hdr Capture can not be supported.
883             if (Feature.IsHdrCaptureSupported)
884             {
885                 _hdrCaptureProgressCallback = (int percent, IntPtr userData) =>
886                 {
887                     HdrCaptureProgress?.Invoke(this, new HdrCaptureProgressEventArgs(percent));
888                 };
889                 CameraErrorFactory.ThrowIfError(Native.SetHdrCaptureProgressCallback(_handle, _hdrCaptureProgressCallback, IntPtr.Zero),
890                     "Setting Hdr capture progress callback failed");
891             }
892         }
893
894         private void RegisterPreviewCallback()
895         {
896             _previewCallback = (IntPtr frame, IntPtr userData) =>
897             {
898                 _preview?.Invoke(this, new PreviewEventArgs(new PreviewData(frame)));
899             };
900             CameraErrorFactory.ThrowIfError(Native.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero),
901                 "Setting preview callback failed");
902         }
903
904         private void RegisterMediaPacketPreviewCallback()
905         {
906             _mediaPacketPreviewCallback = (IntPtr mediaPacket, IntPtr userData) =>
907             {
908                 MediaPacket packet = MediaPacket.From(mediaPacket);
909                 var eventHandler = _mediaPacketPreview;
910
911                 if (eventHandler != null)
912                 {
913                     eventHandler.Invoke(this, new MediaPacketPreviewEventArgs(packet));
914                 }
915                 else
916                 {
917                     packet.Dispose();
918                 }
919             };
920             CameraErrorFactory.ThrowIfError(Native.SetMediaPacketPreviewCallback(_handle, _mediaPacketPreviewCallback, IntPtr.Zero),
921                 "Setting media packet preview callback failed");
922         }
923 #endregion Callback registrations
924     }
925 }
926