[Multimedia] Deprecate constructors related to ElmSharp (#4540)
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Remoting / WebRTC / MediaPacketSource.cs
1 /*
2  * Copyright (c) 2021 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 static Interop;
22
23 namespace Tizen.Multimedia.Remoting
24 {
25     /// <summary>
26     /// Represents a media packet source.
27     /// </summary>
28     /// <seealso cref="WebRTC.AddSource"/>
29     /// <seealso cref="WebRTC.AddSources"/>
30     /// <since_tizen> 9 </since_tizen>
31     public sealed class MediaPacketSource : MediaSource
32     {
33         private readonly MediaFormat _audioMediaFormat;
34         private readonly MediaFormat _videoMediaFormat;
35         private static List<MediaFormatAudioMimeType> _supportedAudioFormats;
36         private static List<MediaFormatVideoMimeType> _supportedVideoFormats;
37
38         /// <summary>
39         /// Gets all supported audio types.
40         /// </summary>
41         /// <since_tizen> 9 </since_tizen>
42         public static IEnumerable<MediaFormatAudioMimeType> SupportedAudioTypes
43         {
44             get
45             {
46                 GetSupportedTypes();
47                 return _supportedAudioFormats.AsReadOnly();
48             }
49         }
50
51         /// <summary>
52         /// Gets all supported video types.
53         /// </summary>
54         /// <since_tizen> 9 </since_tizen>
55         public static IEnumerable<MediaFormatVideoMimeType> SupportedVideoTypes
56         {
57             get
58             {
59                 GetSupportedTypes();
60                 return _supportedVideoFormats.AsReadOnly();
61             }
62         }
63
64         private static void GetSupportedTypes()
65         {
66             if (_supportedAudioFormats != null || _supportedVideoFormats != null)
67             {
68                 return;
69             }
70
71             // Currentely, supported formats are fixed in native fw but I'll keep this for future use.
72             _supportedAudioFormats = new List<MediaFormatAudioMimeType>()
73             {
74                 MediaFormatAudioMimeType.Vorbis,
75                 MediaFormatAudioMimeType.Opus,
76                 MediaFormatAudioMimeType.Pcm
77             };
78             _supportedVideoFormats = new List<MediaFormatVideoMimeType>()
79             {
80                 MediaFormatVideoMimeType.H264SP,
81                 MediaFormatVideoMimeType.H264MP,
82                 MediaFormatVideoMimeType.H264HP,
83                 MediaFormatVideoMimeType.MJpeg,
84                 MediaFormatVideoMimeType.Vp8,
85                 MediaFormatVideoMimeType.Vp9,
86                 MediaFormatVideoMimeType.I420,
87                 MediaFormatVideoMimeType.NV12
88             };
89         }
90
91         private MediaPacketSourceConfiguration CreateAudioConfiguration(AudioMediaFormat format)
92         {
93             if (format == null)
94             {
95                 return null;
96             }
97
98             if (!SupportedAudioTypes.Contains<MediaFormatAudioMimeType>(format.MimeType))
99             {
100                 throw new ArgumentException($"The audio format is not supported, Type : {format.MimeType}.");
101             }
102
103             return new MediaPacketSourceConfiguration(this);
104         }
105
106         private MediaPacketSourceConfiguration CreateVideoConfiguration(VideoMediaFormat format)
107         {
108             if (format == null)
109             {
110                 return null;
111             }
112
113             if (!SupportedVideoTypes.Contains(format.MimeType))
114             {
115                 throw new ArgumentException($"The video format is not supported, Type : {format.MimeType}.");
116             }
117             return new MediaPacketSourceConfiguration(this);
118         }
119
120         /// <summary>
121         /// Initializes a new instance of the MediaPacketSource class with the specified <see cref="AudioMediaFormat"/>.
122         /// </summary>
123         /// <param name="audioMediaFormat">The <see cref="AudioMediaFormat"/> for this source.</param>
124         /// <exception cref="ArgumentNullException"><paramref name="audioMediaFormat"/> is null.</exception>
125         /// <exception cref="ArgumentException"><paramref name="audioMediaFormat"/> is not supported.</exception>
126         /// <seealso cref="SupportedAudioTypes"/>
127         /// <since_tizen> 9 </since_tizen>
128         public MediaPacketSource(AudioMediaFormat audioMediaFormat) : base(MediaType.Audio)
129         {
130             _audioMediaFormat = audioMediaFormat ?? throw new ArgumentNullException(nameof(audioMediaFormat));
131             AudioConfiguration = CreateAudioConfiguration(audioMediaFormat);
132         }
133
134         /// <summary>
135         /// Initializes a new instance of the MediaPacketSource class with the specified <see cref="VideoMediaFormat"/>.
136         /// </summary>
137         /// <param name="videoMediaFormat">The <see cref="VideoMediaFormat"/> for this source.</param>
138         /// <exception cref="ArgumentNullException"><paramref name="videoMediaFormat"/> is null.</exception>
139         /// <exception cref="ArgumentException"><paramref name="videoMediaFormat"/> is not supported.</exception>
140         /// <seealso cref="SupportedVideoTypes"/>
141         /// <since_tizen> 9 </since_tizen>
142         public MediaPacketSource(VideoMediaFormat videoMediaFormat) : base(MediaType.Video)
143         {
144             _videoMediaFormat = videoMediaFormat ?? throw new ArgumentNullException(nameof(videoMediaFormat));
145             VideoConfiguration = CreateVideoConfiguration(videoMediaFormat);
146         }
147
148         /// <summary>
149         /// Gets the audio configuration, or null if no AudioMediaFormat is specified in the constructor.
150         /// </summary>
151         /// <since_tizen> 9 </since_tizen>
152         public MediaPacketSourceConfiguration AudioConfiguration { get; }
153
154         /// <summary>
155         /// Gets the video configuration, or null if no VideoMediaFormat is specified in the constructor.
156         /// </summary>
157         /// <since_tizen> 9 </since_tizen>
158         public MediaPacketSourceConfiguration VideoConfiguration { get; }
159
160         /// <summary>
161         /// Pushes elementary stream to decode audio or video.
162         /// </summary>
163         /// <remarks>
164         /// This source must be set as a source to a WebRTC and the WebRTC must be in the
165         /// <see cref="WebRTCState.Negotiating"/> or <see cref="WebRTCState.Playing"/> state
166         /// </remarks>
167         /// <param name="packet">The <see cref="MediaPacket"/> to decode.</param>
168         /// <exception cref="InvalidOperationException">
169         ///     This source is not set as a source to a WebRTC.<br/>
170         ///     -or-<br/>
171         ///     The WebRTC is not in the valid state.
172         /// </exception>
173         /// <exception cref="ArgumentNullException"><paramref name="packet"/> is null.</exception>
174         /// <exception cref="ObjectDisposedException"><paramref name="packet"/> has been disposed.</exception>
175         /// <exception cref="ArgumentException">
176         ///     <paramref name="packet"/> is neither video nor audio type.<br/>
177         ///     -or-<br/>
178         ///     The format of packet is not matched with the specified format in the constructor.
179         /// </exception>
180         /// <seealso cref="WebRTC.AddSource"/>
181         /// <seealso cref="WebRTC.AddSources"/>
182         /// <seealso cref="MediaPacket"/>
183         /// <since_tizen> 9 </since_tizen>
184         public void Push(MediaPacket packet)
185         {
186             if (WebRtc == null)
187             {
188                 Log.Error(WebRTCLog.Tag, "The source is not set as a source to a WebRTC yet.");
189                 throw new InvalidOperationException("The source is not set as a source to a WebRTC yet.");
190             }
191
192             if (packet == null)
193             {
194                 Log.Error(WebRTCLog.Tag, "packet is null");
195                 throw new ArgumentNullException(nameof(packet));
196             }
197
198             if (packet.IsDisposed)
199             {
200                 Log.Error(WebRTCLog.Tag, "packet is disposed");
201                 throw new ObjectDisposedException(nameof(packet));
202             }
203
204             if (packet.Format.Type == MediaFormatType.Text || packet.Format.Type == MediaFormatType.Container)
205             {
206                 Log.Error(WebRTCLog.Tag, "The format of the packet is invalid : " + packet.Format.Type);
207                 throw new ArgumentException($"The format of the packet is invalid : {packet.Format.Type}.");
208             }
209
210             if (!packet.Format.Equals(_audioMediaFormat) && !packet.Format.Equals(_videoMediaFormat))
211             {
212                 Log.Error(WebRTCLog.Tag, "The format of the packet is invalid : Unmatched format.");
213                 throw new ArgumentException("The format of the packet is invalid : Unmatched format.");
214             }
215
216             if (packet.Format.Type == MediaFormatType.Video && _videoMediaFormat == null)
217             {
218                 Log.Error(WebRTCLog.Tag, "Video is not configured with the current source.");
219                 throw new ArgumentException("Video is not configured with the current source.");
220             }
221
222             if (packet.Format.Type == MediaFormatType.Audio && _audioMediaFormat == null)
223             {
224                 Log.Error(WebRTCLog.Tag, "Audio is not configured with the current source.");
225                 throw new ArgumentException("Audio is not configured with the current source.");
226             }
227
228             NativeWebRTC.PushMediaPacket(WebRtc.Handle, SourceId.Value, packet.GetHandle()).
229                 ThrowIfFailed("Failed to push the packet to the WebRTC");
230         }
231
232         private void SetMediaStreamInfo(MediaFormat mediaFormat)
233         {
234             if (mediaFormat == null)
235             {
236                 return;
237             }
238
239             IntPtr ptr = IntPtr.Zero;
240
241             try
242             {
243                 ptr = mediaFormat.AsNativeHandle();
244                 NativeWebRTC.SetMediaPacketSourceInfo(WebRtc.Handle, SourceId.Value, ptr).
245                     ThrowIfFailed("Failed to set the media stream info");
246             }
247             finally
248             {
249                 MediaFormat.ReleaseNativeHandle(ptr);
250             }
251         }
252
253         internal override void OnAttached(WebRTC webRtc)
254         {
255             Debug.Assert(webRtc != null);
256
257             if (WebRtc != null)
258             {
259                 Log.Error(WebRTCLog.Tag, "The source is has already been assigned to another WebRTC.");
260                 throw new InvalidOperationException("The source is has already been assigned to another WebRTC.");
261             }
262
263             NativeWebRTC.AddMediaSource(webRtc.Handle, MediaSourceType.MediaPacket, out uint sourceId).
264                 ThrowIfFailed("Failed to add MediaPacketSource.");
265
266             WebRtc = webRtc;
267             SourceId = sourceId;
268
269             AudioConfiguration?.OnWebRTCSet();
270             VideoConfiguration?.OnWebRTCSet();
271
272             SetMediaStreamInfo(_audioMediaFormat);
273             SetMediaStreamInfo(_videoMediaFormat);
274         }
275
276         internal override void OnDetached(WebRTC webRtc)
277         {
278             NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
279                 ThrowIfFailed("Failed to remove MediaPacketSource.");
280
281             AudioConfiguration?.OnWebRTCUnset();
282             VideoConfiguration?.OnWebRTCUnset();
283
284             WebRtc = null;
285         }
286     }
287 }