Exemple #1
0
        /// <summary>
        /// Initialize a new instance of the <see cref="StreamRecorder"/> class.
        /// </summary>
        /// <exception cref="NotSupportedException">The feature is not supported.</exception>
        /// <since_tizen> 3 </since_tizen>
        /// <feature> http://tizen.org/feature/multimedia.stream_recorder </feature>
        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();
        }
 private void RegisterRecordingStatusChangedEvent()
 {
     _recordingStatusCallback = (elapsedTime, fileSize, _) =>
     {
         RecordingStatusChanged?.Invoke(this, new RecordingStatusChangedEventArgs((long)elapsedTime, (long)fileSize));
     };
     Native.SetStatusChangedCallback(_handle, _recordingStatusCallback).
     ThrowIfError("Failed to initialize status changed event.");
 }
        private void RegisterRecordingLimitReachedEvent()
        {
            _recordingLimitReachedCallback = (type, _) =>
            {
                RecordingLimitReached?.Invoke(this, new RecordingLimitReachedEventArgs(type));
            };

            Native.SetLimitReachedCallback(_handle, _recordingLimitReachedCallback).
            ThrowIfError("Failed to initialize limit reached event.");
        }
 private void RegisterRecordingErrorOccurredEvent()
 {
     _recorderErrorCallback = (error, currentState, _) =>
     {
         ErrorOccurred?.Invoke(this, new StreamRecorderErrorOccurredEventArgs(
                                   error == StreamRecorderErrorCode.OutOfStorage ?
                                   StreamRecorderError.OutOfStorage : StreamRecorderError.InternalError, currentState));
     };
     Native.SetErrorCallback(_handle, _recorderErrorCallback).
     ThrowIfError("Failed to set error callback");
 }
Exemple #5
0
        /// <summary>
        /// Pauses recording.
        /// </summary>
        /// <remarks>
        /// Recording can be resumed with <see cref="Start"/>.<br/>
        /// <br/>
        /// The recorder state must be <see cref="RecorderState.Recording"/> state by <see cref="Start"/>.<br/>
        /// <br/>
        /// It has no effect if the recorder is already in the <see cref="RecorderState.Paused"/> state.
        /// </remarks>
        /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <seealso cref="Start"/>
        /// <seealso cref="Commit"/>
        /// <seealso cref="Cancel"/>
        /// <since_tizen> 3 </since_tizen>
        public void Pause()
        {
            if (State == RecorderState.Paused)
            {
                return;
            }

            ValidateState(RecorderState.Recording);

            Native.Pause(Handle).ThrowIfError("Failed to pause the stream recorder.");
        }
Exemple #6
0
        /// <summary>
        /// Starts recording.
        /// </summary>
        /// <remarks>
        /// The recorder state must be <see cref="RecorderState.Ready"/> state by
        /// <see cref="Prepare(StreamRecorderOptions)"/> or
        /// <see cref="RecorderState.Paused"/> state by <see cref="Pause"/>.<br/>
        /// <br/>
        /// It has no effect if the recorder is already in the <see cref="RecorderState.Recording"/> state.
        /// </remarks>
        /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
        /// <exception cref="UnauthorizedAccessException">The access of the resources can not be granted.</exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <seealso cref="Pause"/>
        /// <seealso cref="Commit"/>
        /// <seealso cref="Cancel"/>
        /// <since_tizen> 3 </since_tizen>
        public void Start()
        {
            if (State == RecorderState.Recording)
            {
                return;
            }

            ValidateState(RecorderState.Ready, RecorderState.Paused);

            Native.Start(Handle).ThrowIfError("Failed to start the stream recorder.");
        }
Exemple #7
0
        /// <summary>
        /// Unprepares the stream recorder.
        /// </summary>
        /// <remarks>
        /// The recorder state must be <see cref="RecorderState.Ready"/> state by
        /// <see cref="Prepare(StreamRecorderOptions)"/>, <see cref="Cancel"/> and <see cref="Commit"/>.<br/>
        /// The recorder state will be <see cref="RecorderState.Idle"/>.<br/>
        /// <br/>
        /// It has no effect if the recorder is already in the <see cref="RecorderState.Idle"/> state.
        /// </remarks>
        /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <seealso cref="Prepare"/>
        /// <since_tizen> 3 </since_tizen>
        public void Unprepare()
        {
            if (State == RecorderState.Idle)
            {
                return;
            }

            ValidateState(RecorderState.Ready);

            Native.Unprepare(Handle).ThrowIfError("Failed to reset the stream recorder.");
        }
        private static IEnumerable <RecorderAudioCodec> LoadAudioCodecs(StreamRecorder recorder)
        {
            var result = new List <RecorderAudioCodec>();

            Native.AudioEncoders(recorder.Handle, (codec, _) =>
            {
                result.Add(codec.ToRecorderEnum());
                return(true);
            }).ThrowIfError("Failed to get the supported audio codecs.");

            return(result.AsReadOnly());
        }
        private static IEnumerable <RecorderFileFormat> LoadFileFormats(StreamRecorder recorder)
        {
            var result = new List <RecorderFileFormat>();

            Native.FileFormats(recorder.Handle, (fileFormat, _) =>
            {
                result.Add(fileFormat.ToRecorderEnum());
                return(true);
            }).ThrowIfError("Failed to get the supported file formats.");

            return(result.AsReadOnly());
        }
        private static IEnumerable <RecorderVideoCodec> LoadVideoCodecs(StreamRecorder recorder)
        {
            var result = new List <RecorderVideoCodec>();

            Native.VideoEncoderCallback callback = (codec, _) =>
            {
                result.Add(codec.ToRecorderEnum());
                return(true);
            };

            Native.VideoEncoders(recorder.Handle, callback).ThrowIfError("Failed to get the supported video codecs.");

            return(result.AsReadOnly());
        }
        private static IEnumerable <Size> LoadResolutions(StreamRecorder recorder)
        {
            List <Size> result = new List <Size>();

            Native.VideoResolutionCallback callback = (width, height, _) =>
            {
                result.Add(new Size(width, height));
                return(true);
            };

            Native.VideoResolution(recorder.Handle, callback).
            ThrowIfError("Failed to get the supported video resolutions.");

            return(result.AsReadOnly());
        }
        private void RegisterStreamRecorderNotifiedEvent()
        {
            _notifiedCallback = (previous, current, notify, _) =>
            {
                if (previous == 0)
                {
                    return;
                }

                StateChanged?.Invoke(this, new StreamRecorderStateChangedEventArgs(
                                         (RecorderState)previous, (RecorderState)current));
            };

            Native.SetNotifiedCallback(_handle, _notifiedCallback).
            ThrowIfError("Failed to initialize state changed event.");
        }
Exemple #13
0
        /// <summary>
        /// Prepares the stream recorder with the specified options.
        /// </summary>
        /// <remarks>The recorder must be <see cref="RecorderState.Idle"/>.</remarks>
        /// <param name="options">The options for recording.</param>
        /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
        /// <exception cref="ArgumentException">Both <see cref="StreamRecorderOptions.Audio"/> and
        ///     <see cref="StreamRecorderOptions.Video"/> are null.
        /// </exception>
        /// <exception cref="NotSupportedException"><paramref name="options"/> contains a value which is not supported.</exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <seealso cref="Unprepare"/>
        /// <seealso cref="Start"/>
        /// <seealso cref="StreamRecorderOptions"/>
        /// <seealso cref="StreamRecorderAudioOptions"/>
        /// <seealso cref="StreamRecorderVideoOptions"/>
        /// <since_tizen> 4 </since_tizen>
        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;
            }
        }
        private void RegisterBufferConsumedEvent()
        {
            _bufferConsumedCallback = (lockedPacketHandle, _) =>
            {
                MediaPacket packet = null;

                // Lock must be disposed here, note that the packet won't be disposed.
                using (MediaPacket.Lock packetLock =
                           MediaPacket.Lock.FromHandle(lockedPacketHandle))
                {
                    Debug.Assert(packetLock != null);

                    packet = packetLock.MediaPacket;
                }

                BufferConsumed?.Invoke(this, new StreamRecorderBufferConsumedEventArgs(packet));
            };

            Native.SetBufferConsumedCallback(_handle, _bufferConsumedCallback).
            ThrowIfError("Failed to initialize buffer consumed event.");
        }
Exemple #15
0
        /// <summary>
        /// Pushes a packet as recording raw data.
        /// </summary>
        /// <param name="packet">An audio or video packet to record.</param>
        /// <remarks>
        /// The recorder state must be <see cref="RecorderState.Recording"/> state by <see cref="Start"/>.
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        ///     The recorder is not in the valid state.<br/>
        ///     -or-<br/>
        ///     <paramref name="packet"/> is an audio packet but audio recording is not enabled(See <see cref="StreamRecorderOptions.Audio"/>).<br/>
        ///     -or-<br/>
        ///     <paramref name="packet"/> is a video packet but video recording is not enabled(See <see cref="StreamRecorderOptions.Video"/>).<br/>
        ///     -or-<br/>
        ///     <paramref name="packet"/> is a video packet but the <see cref="VideoMediaFormat.MimeType"/> does not match the video source format.<br/>
        ///     -or-<br/>
        ///     An internal error occurs.
        /// </exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <see cref="Prepare(StreamRecorderOptions)"/>
        /// <seealso cref="StreamRecorderOptions.Audio"/>
        /// <seealso cref="StreamRecorderOptions.Video"/>
        /// <seealso cref="StreamRecorderVideoOptions.SourceFormat"/>
        /// <since_tizen> 3 </since_tizen>
        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.");
        }
Exemple #16
0
        /// <summary>
        /// Stops recording and saves the result.
        /// </summary>
        /// <remarks>
        /// The recorder state must be <see cref="RecorderState.Recording"/> state by <see cref="Start"/> or
        /// <see cref="RecorderState.Paused"/> state by <see cref="Pause"/>.<br/>
        /// <br/>
        /// The recorder state will be <see cref="RecorderState.Ready"/> after commit.
        /// <para>
        /// 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.
        /// </para>
        /// </remarks>
        /// <privilege>http://tizen.org/privilege/mediastorage</privilege>
        /// <privilege>http://tizen.org/privilege/externalstorage</privilege>
        /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
        /// <exception cref="UnauthorizedAccessException">The access to the resources can not be granted.</exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <seealso cref="Start"/>
        /// <seealso cref="Pause"/>
        /// <since_tizen> 3 </since_tizen>
        public void Commit()
        {
            ValidateState(RecorderState.Paused, RecorderState.Recording);

            Native.Commit(Handle).ThrowIfError("Failed to commit.");
        }
Exemple #17
0
        /// <summary>
        /// Cancels recording.
        /// The recording data is discarded and not written.
        /// </summary>
        /// <remarks>
        /// The recorder state must be <see cref="RecorderState.Recording"/> state by <see cref="Start"/> or
        /// <see cref="RecorderState.Paused"/> state by <see cref="Pause"/>.
        /// </remarks>
        /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
        /// <exception cref="ObjectDisposedException">The <see cref="StreamRecorder"/> has already been disposed.</exception>
        /// <seealso cref="Start"/>
        /// <seealso cref="Pause"/>
        /// <since_tizen> 3 </since_tizen>
        public void Cancel()
        {
            ValidateState(RecorderState.Paused, RecorderState.Recording);

            Native.Cancel(Handle).ThrowIfError("Failed to cancel recording.");
        }