/* * Copyright (c) 2021 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.Collections.Generic; using System.Diagnostics; using System.Linq; using static Interop; namespace Tizen.Multimedia.Remoting { /// /// Represents a media packet source. /// /// /// /// 9 public sealed class MediaPacketSource : MediaSource { private readonly MediaFormat _audioMediaFormat; private readonly MediaFormat _videoMediaFormat; private static List _supportedAudioFormats; private static List _supportedVideoFormats; /// /// Gets all supported audio types. /// /// 9 public static IEnumerable SupportedAudioTypes { get { GetSupportedTypes(); return _supportedAudioFormats.AsReadOnly(); } } /// /// Gets all supported video types. /// /// 9 public static IEnumerable SupportedVideoTypes { get { GetSupportedTypes(); return _supportedVideoFormats.AsReadOnly(); } } private static void GetSupportedTypes() { if (_supportedAudioFormats != null || _supportedVideoFormats != null) { return; } // Currentely, supported formats are fixed in native fw but I'll keep this for future use. _supportedAudioFormats = new List() { MediaFormatAudioMimeType.Vorbis, MediaFormatAudioMimeType.Opus, MediaFormatAudioMimeType.Pcm }; _supportedVideoFormats = new List() { MediaFormatVideoMimeType.H264SP, MediaFormatVideoMimeType.H264MP, MediaFormatVideoMimeType.H264HP, MediaFormatVideoMimeType.MJpeg, MediaFormatVideoMimeType.Vp8, MediaFormatVideoMimeType.Vp9, MediaFormatVideoMimeType.I420, MediaFormatVideoMimeType.NV12 }; } private MediaPacketSourceConfiguration CreateAudioConfiguration(AudioMediaFormat format) { if (format == null) { return null; } if (!SupportedAudioTypes.Contains(format.MimeType)) { throw new ArgumentException($"The audio format is not supported, Type : {format.MimeType}."); } return new MediaPacketSourceConfiguration(this); } private MediaPacketSourceConfiguration CreateVideoConfiguration(VideoMediaFormat format) { if (format == null) { return null; } if (!SupportedVideoTypes.Contains(format.MimeType)) { throw new ArgumentException($"The video format is not supported, Type : {format.MimeType}."); } return new MediaPacketSourceConfiguration(this); } /// /// Initializes a new instance of the MediaPacketSource class with the specified . /// /// The for this source. /// is null. /// is not supported. /// /// 9 public MediaPacketSource(AudioMediaFormat audioMediaFormat) : base(MediaType.Audio) { _audioMediaFormat = audioMediaFormat ?? throw new ArgumentNullException(nameof(audioMediaFormat)); AudioConfiguration = CreateAudioConfiguration(audioMediaFormat); } /// /// Initializes a new instance of the MediaPacketSource class with the specified . /// /// The for this source. /// is null. /// is not supported. /// /// 9 public MediaPacketSource(VideoMediaFormat videoMediaFormat) : base(MediaType.Video) { _videoMediaFormat = videoMediaFormat ?? throw new ArgumentNullException(nameof(videoMediaFormat)); VideoConfiguration = CreateVideoConfiguration(videoMediaFormat); } /// /// Gets the audio configuration, or null if no AudioMediaFormat is specified in the constructor. /// /// 9 public MediaPacketSourceConfiguration AudioConfiguration { get; } /// /// Gets the video configuration, or null if no VideoMediaFormat is specified in the constructor. /// /// 9 public MediaPacketSourceConfiguration VideoConfiguration { get; } /// /// Pushes elementary stream to decode audio or video. /// /// /// This source must be set as a source to a WebRTC and the WebRTC must be in the /// or state /// /// The to decode. /// /// This source is not set as a source to a WebRTC.
/// -or-
/// The WebRTC is not in the valid state. ///
/// is null. /// has been disposed. /// /// is neither video nor audio type.
/// -or-
/// The format of packet is not matched with the specified format in the constructor. ///
/// /// /// /// 9 public void Push(MediaPacket packet) { if (WebRtc == null) { Log.Error(WebRTCLog.Tag, "The source is not set as a source to a WebRTC yet."); throw new InvalidOperationException("The source is not set as a source to a WebRTC yet."); } if (packet == null) { Log.Error(WebRTCLog.Tag, "packet is null"); throw new ArgumentNullException(nameof(packet)); } if (packet.IsDisposed) { Log.Error(WebRTCLog.Tag, "packet is disposed"); throw new ObjectDisposedException(nameof(packet)); } if (packet.Format.Type == MediaFormatType.Text || packet.Format.Type == MediaFormatType.Container) { Log.Error(WebRTCLog.Tag, "The format of the packet is invalid : " + packet.Format.Type); throw new ArgumentException($"The format of the packet is invalid : {packet.Format.Type}."); } if (!packet.Format.Equals(_audioMediaFormat) && !packet.Format.Equals(_videoMediaFormat)) { Log.Error(WebRTCLog.Tag, "The format of the packet is invalid : Unmatched format."); throw new ArgumentException("The format of the packet is invalid : Unmatched format."); } if (packet.Format.Type == MediaFormatType.Video && _videoMediaFormat == null) { Log.Error(WebRTCLog.Tag, "Video is not configured with the current source."); throw new ArgumentException("Video is not configured with the current source."); } if (packet.Format.Type == MediaFormatType.Audio && _audioMediaFormat == null) { Log.Error(WebRTCLog.Tag, "Audio is not configured with the current source."); throw new ArgumentException("Audio is not configured with the current source."); } NativeWebRTC.PushMediaPacket(WebRtc.Handle, SourceId.Value, packet.GetHandle()). ThrowIfFailed("Failed to push the packet to the WebRTC"); } private void SetMediaStreamInfo(MediaFormat mediaFormat) { if (mediaFormat == null) { return; } IntPtr ptr = IntPtr.Zero; try { ptr = mediaFormat.AsNativeHandle(); NativeWebRTC.SetMediaPacketSourceInfo(WebRtc.Handle, SourceId.Value, ptr). ThrowIfFailed("Failed to set the media stream info"); } finally { MediaFormat.ReleaseNativeHandle(ptr); } } internal override void OnAttached(WebRTC webRtc) { Debug.Assert(webRtc != null); if (WebRtc != null) { Log.Error(WebRTCLog.Tag, "The source is has already been assigned to another WebRTC."); throw new InvalidOperationException("The source is has already been assigned to another WebRTC."); } NativeWebRTC.AddMediaSource(webRtc.Handle, MediaSourceType.MediaPacket, out uint sourceId). ThrowIfFailed("Failed to add MediaPacketSource."); WebRtc = webRtc; SourceId = sourceId; AudioConfiguration?.OnWebRTCSet(); VideoConfiguration?.OnWebRTCSet(); SetMediaStreamInfo(_audioMediaFormat); SetMediaStreamInfo(_videoMediaFormat); } internal override void OnDetached(WebRTC webRtc) { NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value). ThrowIfFailed("Failed to remove MediaPacketSource."); AudioConfiguration?.OnWebRTCUnset(); VideoConfiguration?.OnWebRTCUnset(); WebRtc = null; } } }