/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Diagnostics; using System.Linq; using NativeHandle = Interop.StreamRecorderHandle; using Native = Interop.StreamRecorder; namespace Tizen.Multimedia { /// /// Provides the ability to record user buffer from application. /// /// [Obsolete("Deprecated in API10; Will be removed in API12")] public partial class StreamRecorder : IDisposable { private NativeHandle _handle; private bool _disposed = false; private bool _audioEnabled; private bool _videoEnabled; private StreamRecorderVideoFormat _sourceFormat; private const string Feature = "http://tizen.org/feature/multimedia.stream_recorder"; private static bool IsSupported() { return System.Information.TryGetValue(Feature, out bool isSupported) && isSupported; } /// /// Initialize a new instance of the class. /// /// The feature is not supported. /// 3 /// http://tizen.org/feature/multimedia.stream_recorder [Obsolete("Deprecated in API10; Will be removed in API12")] public StreamRecorder() { if (IsSupported() == false) { throw new NotSupportedException( $"The feature({Feature}) is not supported on the current device."); } try { Native.Create(out _handle).ThrowIfError("Failed to create stream recorder."); } catch (TypeLoadException) { throw new NotSupportedException("StreamRecorder is not supported."); } LoadCapabilities(); RegisterStreamRecorderNotifiedEvent(); RegisterBufferConsumedEvent(); RegisterRecordingStatusChangedEvent(); RegisterRecordingErrorOccurredEvent(); RegisterRecordingLimitReachedEvent(); } internal NativeHandle Handle { get { if (_disposed) { throw new ObjectDisposedException(nameof(StreamRecorder)); } return _handle; } } /// /// Gets the current state of the stream recorder. /// /// The has already been disposed. /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public RecorderState State { get { Native.GetState(Handle, out var val).ThrowIfError("Failed to get the stream recorder state."); return val; } } private void ValidateState(params RecorderState[] required) { Debug.Assert(required.Length > 0); var curState = State; if (!required.Contains(curState)) { throw new InvalidOperationException($"The stream recorder is not in a valid state. " + $"Current State : { curState }, Valid State : { string.Join(", ", required) }."); } } #region Operation methods /// /// Prepares the stream recorder with the specified options. /// /// The recorder must be . /// The options for recording. /// The recorder is not in the valid state. /// Both and /// are null. /// /// contains a value which is not supported. /// The has already been disposed. /// /// /// /// /// /// 4 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Prepare(StreamRecorderOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } ValidateState(RecorderState.Idle); options.Apply(this); Native.Prepare(Handle).ThrowIfError("Failed to prepare stream recorder."); _audioEnabled = options.Audio != null; _videoEnabled = options.Video != null; if (options.Video != null) { _sourceFormat = options.Video.SourceFormat; } } /// /// Unprepares the stream recorder. /// /// /// The recorder state must be state by /// , and .
/// The recorder state will be .
///
/// It has no effect if the recorder is already in the state. ///
/// The recorder is not in the valid state. /// The has already been disposed. /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Unprepare() { if (State == RecorderState.Idle) { return; } ValidateState(RecorderState.Ready); Native.Unprepare(Handle).ThrowIfError("Failed to reset the stream recorder."); } /// /// Starts recording. /// /// /// The recorder state must be state by /// or /// state by .
///
/// It has no effect if the recorder is already in the state. ///
/// The recorder is not in the valid state. /// The access of the resources can not be granted. /// The has already been disposed. /// /// /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Start() { if (State == RecorderState.Recording) { return; } ValidateState(RecorderState.Ready, RecorderState.Paused); Native.Start(Handle).ThrowIfError("Failed to start the stream recorder."); } /// /// Pauses recording. /// /// /// Recording can be resumed with .
///
/// The recorder state must be state by .
///
/// It has no effect if the recorder is already in the state. ///
/// The recorder is not in the valid state. /// The has already been disposed. /// /// /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Pause() { if (State == RecorderState.Paused) { return; } ValidateState(RecorderState.Recording); Native.Pause(Handle).ThrowIfError("Failed to pause the stream recorder."); } /// /// Stops recording and saves the result. /// /// /// The recorder state must be state by or /// state by .
///
/// The recorder state will be after commit. /// /// http://tizen.org/privilege/mediastorage is needed if the save path are relevant to media storage. /// http://tizen.org/privilege/externalstorage is needed if the save path are relevant to external storage. /// ///
/// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The recorder is not in the valid state. /// The access to the resources can not be granted. /// The has already been disposed. /// /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Commit() { ValidateState(RecorderState.Paused, RecorderState.Recording); Native.Commit(Handle).ThrowIfError("Failed to commit."); } /// /// Cancels recording. /// The recording data is discarded and not written. /// /// /// The recorder state must be state by or /// state by . /// /// The recorder is not in the valid state. /// The has already been disposed. /// /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Cancel() { ValidateState(RecorderState.Paused, RecorderState.Recording); Native.Cancel(Handle).ThrowIfError("Failed to cancel recording."); } private static bool AreVideoTypesMatched(StreamRecorderVideoFormat videoFormat, MediaFormatVideoMimeType mimeType) { return (videoFormat == StreamRecorderVideoFormat.Nv12 && mimeType == MediaFormatVideoMimeType.NV12) || (videoFormat == StreamRecorderVideoFormat.Nv21 && mimeType == MediaFormatVideoMimeType.NV21) || (videoFormat == StreamRecorderVideoFormat.I420 && mimeType == MediaFormatVideoMimeType.I420); } /// /// Pushes a packet as recording raw data. /// /// An audio or video packet to record. /// /// The recorder state must be state by . /// /// /// The recorder is not in the valid state.
/// -or-
/// is an audio packet but audio recording is not enabled(See ).
/// -or-
/// is a video packet but video recording is not enabled(See ).
/// -or-
/// is a video packet but the does not match the video source format.
/// -or-
/// An internal error occurs. ///
/// The has already been disposed. /// /// /// /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void PushBuffer(MediaPacket packet) { if (packet == null) { throw new ArgumentNullException(nameof(packet)); } ValidateState(RecorderState.Recording); switch (packet.Format.Type) { case MediaFormatType.Audio: if (_audioEnabled == false) { throw new InvalidOperationException("Audio option is not set."); } break; case MediaFormatType.Video: if (_videoEnabled == false) { throw new InvalidOperationException("Video option is not set."); } if (AreVideoTypesMatched(_sourceFormat, (packet.Format as VideoMediaFormat).MimeType) == false) { throw new InvalidOperationException("Video format does not match."); } break; default: throw new ArgumentException("Packet is not valid."); } Native.PushStreamBuffer(Handle, MediaPacket.Lock.Get(packet).GetHandle()) .ThrowIfError("Failed to push buffer."); } #endregion #region Dispose support /// /// Release any unmanaged resources used by this object. /// /// 3 [Obsolete("Deprecated in API10; Will be removed in API12")] public void Dispose() { Dispose(true); } /// /// Releases the resources used by the StreamRecorder. /// /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. /// /// 3 protected virtual void Dispose(bool disposing) { if (!_disposed) { _handle?.Dispose(); _disposed = true; } } #endregion } }