{
public const string ScreenMirroring = "libcapi-media-screen-mirroring.so.0";
public const string MediaController = "libcapi-media-controller.so.0";
+ public const string WebRTC = "libcapi-media-webrtc.so.0";
}
}
--- /dev/null
+/*
+ * 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.Runtime.InteropServices;
+using Tizen.Applications;
+using Tizen.Multimedia.Remoting;
+
+internal static partial class Interop
+{
+ internal static partial class NativeDataChannel
+ {
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void CreatedCallback(IntPtr handle, IntPtr dataChanndelHandle, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void OpenedCallback(IntPtr dataChannelHandle, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void MessageReceivedCallback(IntPtr dataChannelHandle, DataChannelType type, IntPtr message, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void ErrorOccurredCallback(IntPtr dataChanndelHandle, WebRTCErrorCode error, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void ClosedCallback(IntPtr dataChanndelHandle, IntPtr userData);
+
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_create_data_channel")]
+ internal static extern WebRTCErrorCode Create(IntPtr handle, string label, SafeBundleHandle bundle, out IntPtr dataChanndelHandle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_destroy_data_channel")]
+ internal static extern WebRTCErrorCode Destroy(IntPtr dataChanndelHandle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_send_string")]
+ internal static extern WebRTCErrorCode SendString(IntPtr dataChanndelHandle, string data);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_send_bytes")]
+ internal static extern WebRTCErrorCode SendBytes(IntPtr dataChanndelHandle, byte[] data, uint size);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_get_label")]
+ internal static extern WebRTCErrorCode GetLabel(IntPtr dataChanndelHandle, out string label);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_data")]
+ internal static extern WebRTCErrorCode GetData(IntPtr byteDataHandle, out IntPtr data, out ulong size);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_data_channel_cb")]
+ internal static extern WebRTCErrorCode SetCreatedByPeerCb(IntPtr handle, CreatedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_data_channel_cb")]
+ internal static extern WebRTCErrorCode UnsetCreatedByPeerCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_set_open_cb")]
+ internal static extern WebRTCErrorCode SetOpenedCb(IntPtr dataChanndelHandle, OpenedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_unset_open_cb")]
+ internal static extern WebRTCErrorCode UnsetOpenedCb(IntPtr dataChanndelHandle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_set_message_cb")]
+ internal static extern WebRTCErrorCode SetMessageReceivedCb(IntPtr dataChanndelHandle, MessageReceivedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_unset_message_cb")]
+ internal static extern WebRTCErrorCode UnsetMessageReceivedCb(IntPtr dataChanndelHandle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_set_error_cb")]
+ internal static extern WebRTCErrorCode SetErrorOccurredCb(IntPtr dataChanndelHandle, ErrorOccurredCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_unset_error_cb")]
+ internal static extern WebRTCErrorCode UnsetErrorOccurredCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_set_close_cb")]
+ internal static extern WebRTCErrorCode SetClosedCb(IntPtr dataChanndelHandle, ClosedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_data_channel_unset_close_cb")]
+ internal static extern WebRTCErrorCode UnsetClosedCb(IntPtr handle);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.Runtime.InteropServices;
+using Tizen.Multimedia.Remoting;
+
+internal static partial class Interop
+{
+ internal static class SignalingServer
+ {
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_server_create")]
+ internal static extern WebRTCErrorCode Create(int port, out IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_server_destroy")]
+ internal static extern WebRTCErrorCode Destroy(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_server_start")]
+ internal static extern WebRTCErrorCode Start(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_server_stop")]
+ internal static extern WebRTCErrorCode Stop(IntPtr handle);
+ }
+
+ internal static class SignalingClient
+ {
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_connect")]
+ internal static extern WebRTCErrorCode Connect(string serverIp, int port, SignalingMessageCallback callback, IntPtr userData, out IntPtr clientHandle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_disconnect")]
+ internal static extern WebRTCErrorCode Disconnect(IntPtr clientHandle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_request_session")]
+ internal static extern WebRTCErrorCode RequestSession(IntPtr clientHandle, int peerId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_send_message")]
+ internal static extern WebRTCErrorCode SendMessage(IntPtr clientHandle, string message);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_signaling_get_id")]
+ internal static extern WebRTCErrorCode GetID(IntPtr clientHandle, out int id);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void SignalingMessageCallback(SignalingMessageType type, string message, IntPtr userData);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.Runtime.InteropServices;
+using Tizen;
+using Tizen.Applications;
+using Tizen.Multimedia;
+using Tizen.Multimedia.Remoting;
+
+internal static partial class Interop
+{
+ internal static partial class NativeWebRTC
+ {
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void ErrorOccurredCallback(IntPtr handle, WebRTCErrorCode error, WebRTCState state, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void StateChangedCallback(IntPtr handle, WebRTCState previous, WebRTCState current, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void IceGatheringStateChangedCallback(IntPtr handle, WebRTCIceGatheringState state, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void SignalingStateChangedCallback(IntPtr handle, WebRTCSignalingState state, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void PeerConnectionStateChangedCallback(IntPtr handle, WebRTCPeerConnectionState state, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void IceConnectionStateChangedCallback(IntPtr handle, WebRTCIceConnectionState state, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void MediaPacketBufferStatusCallback(uint sourceId, MediaPacketBufferStatus status, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void NegotiationNeededCallback(IntPtr handle, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void IceCandidateCallback(IntPtr handle, string candidate, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void TrackAddedCallback(IntPtr handle, MediaType type, uint id, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void FrameEncodedCallback(IntPtr handle, MediaType type, uint trackId, IntPtr packetHandle, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate bool SupportedMediaFormatCallback(int format, IntPtr userData);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate bool RetrieveTurnServerCallback(string server, IntPtr userData);
+
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_create")]
+ internal static extern WebRTCErrorCode Create(out WebRTCHandle handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_destroy")]
+ internal static extern WebRTCErrorCode Destroy(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_start")]
+ internal static extern WebRTCErrorCode Start(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_stop")]
+ internal static extern WebRTCErrorCode Stop(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_state")]
+ internal static extern WebRTCErrorCode GetState(IntPtr handle, out WebRTCState state);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_ice_gathering_state")]
+ internal static extern WebRTCErrorCode GetIceGatheringState(IntPtr handle, out WebRTCIceGatheringState state);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_signaling_state")]
+ internal static extern WebRTCErrorCode GetSignalingState(IntPtr handle, out WebRTCSignalingState state);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_peer_connection_state")]
+ internal static extern WebRTCErrorCode GetPeerConnectionState(IntPtr handle, out WebRTCPeerConnectionState state);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_ice_connection_state")]
+ internal static extern WebRTCErrorCode GetIceConnectionState(IntPtr handle, out WebRTCIceConnectionState state);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_add_media_source")]
+ internal static extern WebRTCErrorCode AddMediaSource(IntPtr handle, MediaSourceType type, out uint sourceId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_add_media_source_internal")]
+ internal static extern WebRTCErrorCode AddCustomMediaSource(IntPtr handle, CustomMediaSourceType type, out uint sourceId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_remove_media_source")]
+ internal static extern WebRTCErrorCode RemoveMediaSource(IntPtr handle, uint sourceId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_packet_source_set_format")]
+ internal static extern WebRTCErrorCode SetMediaPacketSourceInfo(IntPtr handle, uint sourceId, IntPtr packet);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_packet_source_push_packet")]
+ internal static extern WebRTCErrorCode PushMediaPacket(IntPtr handle, uint sourceId, IntPtr packet);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_file_source_set_path")]
+ internal static extern WebRTCErrorCode SetFileSourcePath(IntPtr handle, uint sourceId, string path);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_get_transceiver_direction")]
+ internal static extern WebRTCErrorCode GetTransceiverDirection(IntPtr handle, uint sourceId, MediaType type, out TransceiverDirection mode);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_transceiver_direction")]
+ internal static extern WebRTCErrorCode SetTransceiverDirection(IntPtr handle, uint sourceId, MediaType type, TransceiverDirection mode);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_pause")]
+ internal static extern WebRTCErrorCode SetPause(IntPtr handle, uint sourceId, MediaType type, bool pause);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_get_pause")]
+ internal static extern WebRTCErrorCode GetPause(IntPtr handle, uint sourceId, MediaType type, out bool isPaused);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_mute")]
+ internal static extern WebRTCErrorCode SetMute(IntPtr handle, uint sourceId, MediaType type, bool mute);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_get_mute")]
+ internal static extern WebRTCErrorCode GetMute(IntPtr handle, uint sourceId, MediaType type, out bool mute);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_video_resolution")]
+ internal static extern WebRTCErrorCode SetVideoResolution(IntPtr handle, uint sourceId, int width, int height);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_get_video_resolution")]
+ internal static extern WebRTCErrorCode GetVideoResolution(IntPtr handle, uint sourceId, out int width, out int height);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_audio_loopback")]
+ internal static extern WebRTCErrorCode SetAudioLoopback(IntPtr handle, uint sourceId, AudioStreamPolicyHandle streamInfo, out uint trackId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_video_loopback")]
+ internal static extern WebRTCErrorCode SetVideoLoopback(IntPtr handle, uint sourceId, WebRTCDisplayType type, IntPtr display, out uint trackId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_source_set_video_loopback_to_ecore_wl")]
+ internal static extern WebRTCErrorCode SetEcoreVideoLoopback(IntPtr handle, uint sourceId, IntPtr display, out uint trackId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_mic_source_set_sound_stream_info")]
+ internal static extern WebRTCErrorCode SetAudioStreamPolicyToMicrophoneSource(IntPtr handle, uint sourceId, AudioStreamPolicyHandle streamInfo);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_sound_stream_info")]
+ internal static extern WebRTCErrorCode SetAudioStreamPolicy(IntPtr handle, uint trackId, AudioStreamPolicyHandle streamInfo);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_display")]
+ internal static extern WebRTCErrorCode SetDisplay(IntPtr handle, uint trackId, WebRTCDisplayType type, IntPtr display);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_ecore_wl_display")]
+ internal static extern WebRTCErrorCode SetEcoreDisplay(IntPtr handle, uint trackId, IntPtr display);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_display_mode")]
+ internal static extern WebRTCErrorCode SetDisplayMode(IntPtr handle, uint trackId, WebRTCDisplayMode mode);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_display_mode")]
+ internal static extern WebRTCErrorCode GetDisplayMode(IntPtr handle, uint trackId, out WebRTCDisplayMode mode);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_display_visible")]
+ internal static extern WebRTCErrorCode SetDisplayVisible(IntPtr handle, uint trackId, bool isVisible);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_display_visible")]
+ internal static extern WebRTCErrorCode GetDisplayVisible(IntPtr handle, uint trackId, out bool isVisible);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_stun_server")]
+ internal static extern WebRTCErrorCode GetStunServer(IntPtr handle, out string server);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_stun_server")]
+ internal static extern WebRTCErrorCode SetStunServer(IntPtr handle, string server);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_add_turn_server")]
+ internal static extern WebRTCErrorCode AddTurnServer(IntPtr handle, string server);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_foreach_turn_server")]
+ internal static extern WebRTCErrorCode ForeachTurnServer(IntPtr handle, RetrieveTurnServerCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_ice_transport_policy")]
+ internal static extern WebRTCErrorCode SetIceTransportPolicy(IntPtr handle, IceTransportPolicy policy);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_get_ice_transport_policy")]
+ internal static extern WebRTCErrorCode GetIceTransportPolicy(IntPtr handle, out IceTransportPolicy policy);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_create_offer")]
+ internal static extern WebRTCErrorCode CreateSDPOffer(IntPtr handle, SafeBundleHandle bundle, out string offer);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_create_answer")]
+ internal static extern WebRTCErrorCode CreateSDPAnswer(IntPtr handle, SafeBundleHandle bundle, out string offer);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_local_description")]
+ internal static extern WebRTCErrorCode SetLocalDescription(IntPtr handle, string description);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_remote_description")]
+ internal static extern WebRTCErrorCode SetRemoteDescription(IntPtr handle, string description);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_add_ice_candidate")]
+ internal static extern WebRTCErrorCode AddIceCandidate(IntPtr handle, string candidate);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_foreach_media_source_supported_format")]
+ internal static extern WebRTCErrorCode SupportedMediaSourceFormat(IntPtr handle, SupportedMediaFormatCallback callback, IntPtr userData);
+
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_error_cb")]
+ internal static extern WebRTCErrorCode SetErrorOccurredCb(IntPtr handle, ErrorOccurredCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_error_cb")]
+ internal static extern WebRTCErrorCode UnsetErrorOccurredCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_state_changed_cb")]
+ internal static extern WebRTCErrorCode SetStateChangedCb(IntPtr handle, StateChangedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_state_changed_cb")]
+ internal static extern WebRTCErrorCode UnsetStateChangedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_ice_gathering_state_change_cb")]
+ internal static extern WebRTCErrorCode SetIceGatheringStateChangedCb(IntPtr handle, IceGatheringStateChangedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_ice_gathering_state_change_cb")]
+ internal static extern WebRTCErrorCode UnsetIceGatheringStateChangedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_signaling_state_change_cb")]
+ internal static extern WebRTCErrorCode SetSignalingStateChangedCb(IntPtr handle, SignalingStateChangedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_signaling_state_change_cb")]
+ internal static extern WebRTCErrorCode UnsetSignalingStateChangedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_peer_connection_state_change_cb")]
+ internal static extern WebRTCErrorCode SetPeerConnectionStateChangedCb(IntPtr handle, PeerConnectionStateChangedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_peer_connection_state_change_cb")]
+ internal static extern WebRTCErrorCode UnsetPeerConnectionStateChangedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_ice_connection_state_change_cb")]
+ internal static extern WebRTCErrorCode SetIceConnectionStateChangedCb(IntPtr handle, IceConnectionStateChangedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_ice_connection_state_change_cb")]
+ internal static extern WebRTCErrorCode UnsetIceConnectionStateChangedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_packet_source_set_buffer_state_changed_cb")]
+ internal static extern WebRTCErrorCode SetBufferStateChangedCb(IntPtr handle, uint sourceId, MediaPacketBufferStatusCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_media_packet_source_unset_buffer_state_changed_cb")]
+ internal static extern WebRTCErrorCode UnsetBufferStateChangedCb(IntPtr handle, uint sourceId);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_negotiation_needed_cb")]
+ internal static extern WebRTCErrorCode SetNegotiationNeededCb(IntPtr handle, NegotiationNeededCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_negotiation_needed_cb")]
+ internal static extern WebRTCErrorCode UnsetNegotiationNeededCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_ice_candidate_cb")]
+ internal static extern WebRTCErrorCode SetIceCandidateCb(IntPtr handle, IceCandidateCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_ice_candidate_cb")]
+ internal static extern WebRTCErrorCode UnsetIceCandidateCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_track_added_cb")]
+ internal static extern WebRTCErrorCode SetTrackAddedCb(IntPtr handle, TrackAddedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_track_added_cb")]
+ internal static extern WebRTCErrorCode UnsetTrackAddedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_encoded_audio_frame_cb")]
+ internal static extern WebRTCErrorCode SetAudioFrameEncodedCb(IntPtr handle, FrameEncodedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_encoded_audio_frame_cb")]
+ internal static extern WebRTCErrorCode UnsetAudioFrameEncodedCb(IntPtr handle);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_set_encoded_video_frame_cb")]
+ internal static extern WebRTCErrorCode SetVideoFrameEncodedCb(IntPtr handle, FrameEncodedCallback callback, IntPtr userData = default);
+
+ [DllImport(Libraries.WebRTC, EntryPoint = "webrtc_unset_encoded_video_frame_cb")]
+ internal static extern WebRTCErrorCode UnsetVideoFrameEncodedCb(IntPtr handle);
+ }
+
+ internal class WebRTCHandle : SafeHandle
+ {
+ protected WebRTCHandle()
+ : base(IntPtr.Zero, true)
+ {
+ }
+
+ public override bool IsInvalid => handle == IntPtr.Zero;
+
+ protected override bool ReleaseHandle()
+ {
+ var ret = NativeWebRTC.Destroy(handle);
+ if (ret != WebRTCErrorCode.None)
+ {
+ return true;
+ }
+
+ Log.Debug(GetType().FullName, $"Failed to release native {GetType().Name}");
+ return false;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.Diagnostics;
+using NativeWebRTC = Interop.NativeWebRTC;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Represents a camera source.
+ /// </summary>
+ /// <remarks>The camera privilege(http://tizen.org/privilege/camera) is required.</remarks>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaCameraSource : MediaSource
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaCameraSource"/> class.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaCameraSource() : base(MediaType.Video) {}
+
+ internal override void OnAttached(WebRTC webRtc)
+ {
+ Debug.Assert(webRtc != null);
+
+ if (WebRtc != null)
+ {
+ throw new InvalidOperationException("The source is has already been assigned to another WebRTC.");
+ }
+
+ NativeWebRTC.AddMediaSource(webRtc.Handle, MediaSourceType.Camera, out uint sourceId).
+ ThrowIfFailed("Failed to add MediaCameraSource.");
+
+ WebRtc = webRtc;
+ SourceId = sourceId;
+ }
+
+ internal override void OnDetached(WebRTC webRtc)
+ {
+ NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
+ ThrowIfFailed("Failed to remove MediaCameraSource.");
+
+ WebRtc = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.ComponentModel;
+using System.Diagnostics;
+using NativeWebRTC = Interop.NativeWebRTC;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Represents a audio, video custom source.
+ /// </summary>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public sealed class MediaCustomSource : MediaSource
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaCustomSource"/> class.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public MediaCustomSource(MediaType type) : base(type) {}
+
+ internal override void OnAttached(WebRTC webRtc)
+ {
+ Debug.Assert(webRtc != null);
+
+ if (WebRtc != null)
+ {
+ throw new InvalidOperationException("The source is has already been assigned to another WebRTC.");
+ }
+
+ var type = MediaType == MediaType.Video ? CustomMediaSourceType.Video : CustomMediaSourceType.Audio;
+
+ NativeWebRTC.AddCustomMediaSource(webRtc.Handle, type, out uint sourceId).
+ ThrowIfFailed($"Failed to add {MediaType.ToString()} MediaCustomSource.");
+
+ WebRtc = webRtc;
+ SourceId = sourceId;
+ }
+
+ internal override void OnDetached(WebRTC webRtc)
+ {
+ NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
+ ThrowIfFailed($"Failed to remove {MediaType.ToString()} MediaCustomSource.");
+
+ WebRtc = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.Diagnostics;
+using NativeWebRTC = Interop.NativeWebRTC;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Represents a file source.
+ /// </summary>
+ /// <remarks>
+ /// The media storage privilege(http://tizen.org/privilege/mediastorage) is required.<br/>
+ /// The external storage privilege(http://tizen.org/privilege/externalstorage) is required.
+ /// </remarks>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaFileSource : MediaSource
+ {
+ private string _path;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaFileSource"/> class.
+ /// </summary>
+ /// <param name="type">The <see cref="MediaType"/> of file source.</param>
+ /// <param name="path">The file path.</param>
+ /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaFileSource(MediaType type, string path) : base(type)
+ {
+ _path = path ?? throw new ArgumentNullException(nameof(path), "path is null");
+ }
+
+ internal override void OnAttached(WebRTC webRtc)
+ {
+ Debug.Assert(webRtc != null);
+
+ if (WebRtc != null)
+ {
+ throw new InvalidOperationException("The source is has already been assigned to another WebRTC.");
+ }
+
+ NativeWebRTC.AddMediaSource(webRtc.Handle, MediaSourceType.File, out uint sourceId).
+ ThrowIfFailed("Failed to add MediaFileSource.");
+
+ NativeWebRTC.SetFileSourcePath(webRtc.Handle, sourceId, _path).
+ ThrowIfFailed("Failed to set path for MediaFileSource.");
+
+ WebRtc = webRtc;
+ SourceId = sourceId;
+ }
+
+ internal override void OnDetached(WebRTC webRtc)
+ {
+ NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
+ ThrowIfFailed("Failed to remove MediaFileSource.");
+
+ WebRtc = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.Diagnostics;
+using NativeWebRTC = Interop.NativeWebRTC;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Represents a microphone source.
+ /// </summary>
+ /// <remarks>The recorder privilege(http://tizen.org/privilege/recorder) is required.</remarks>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaMicrophoneSource : MediaSource
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaMicrophoneSource"/> class.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaMicrophoneSource() : base(MediaType.Audio) {}
+
+ 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.Microphone, out uint sourceId).
+ ThrowIfFailed("Failed to add MediaMicrophoneSource.");
+
+ WebRtc = webRtc;
+ SourceId = sourceId;
+ }
+
+ internal override void OnDetached(WebRTC webRtc)
+ {
+ NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
+ ThrowIfFailed("Failed to remove MediaMicrophoneSource.");
+
+ WebRtc = (WebRTC)null;
+ }
+
+ /// <summary>
+ /// Applies the audio stream policy to <see cref="MediaMicrophoneSource"/>.
+ /// </summary>
+ /// <param name="policy">The <see cref="AudioStreamPolicy"/> to apply.</param>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/> state.<br/>
+ /// <br/>
+ /// <see cref="WebRTC"/> does not support all <see cref="AudioStreamType"/>.<br/>
+ /// Supported types are <see cref="AudioStreamType.Media"/>, <see cref="AudioStreamType.VoiceRecognition"/>,
+ /// <see cref="AudioStreamType.Voip"/>, <see cref="AudioStreamType.MediaExternalOnly"/>.
+ /// </remarks>
+ /// <exception cref="ObjectDisposedException">
+ /// The WebRTC has already been disposed.<br/>
+ /// -or-<br/>
+ /// <paramref name="policy"/> has already been disposed.
+ /// </exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ArgumentNullException"><paramref name="policy"/> is null.</exception>
+ /// <exception cref="NotSupportedException">
+ /// <see cref="AudioStreamType"/> of <paramref name="policy"/> is not supported on the current platform.
+ /// </exception>
+ /// <seealso cref="AudioStreamPolicy"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void ApplyAudioStreamPolicy(AudioStreamPolicy policy)
+ {
+ if (policy == null)
+ {
+ throw new ArgumentNullException(nameof(policy), "policy is null");
+ }
+
+ WebRtc.ValidateWebRTCState(WebRTCState.Idle);
+
+ var ret = NativeWebRTC.SetAudioStreamPolicyToMicrophoneSource(WebRtc.Handle, SourceId.Value, policy.Handle);
+
+ if (ret == WebRTCErrorCode.InvalidArgument)
+ {
+ throw new NotSupportedException("The specified policy is not supported on the current system.");
+ }
+
+ ret.ThrowIfFailed("Failed to set the audio stream policy to the WebRTC");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="MediaPacketSourceConfiguration.BufferStatusChanged"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class MediaPacketBufferStatusChangedEventArgs : EventArgs
+ {
+ internal MediaPacketBufferStatusChangedEventArgs(uint sourceId, MediaPacketBufferStatus status)
+ {
+ SourceId = sourceId;
+ Status = status;
+ }
+
+ /// <summary>
+ /// Gets the source ID.
+ /// </summary>
+ /// <value>The source ID.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public uint SourceId { get; }
+
+ /// <summary>
+ /// Gets the media packet buffer status.
+ /// </summary>
+ /// <value>The media packet buffer status.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaPacketBufferStatus Status { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"Source ID={SourceId}, Buffer status={Status}";
+ }
+}
--- /dev/null
+/*
+ * 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
+{
+ /// <summary>
+ /// Represents a media packet source.
+ /// </summary>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaPacketSource : MediaSource
+ {
+ private readonly MediaFormat _audioMediaFormat;
+ private readonly MediaFormat _videoMediaFormat;
+ private static List<MediaFormatAudioMimeType> _supportedAudioFormats;
+ private static List<MediaFormatVideoMimeType> _supportedVideoFormats;
+
+ /// <summary>
+ /// Gets all supported audio types.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public static IEnumerable<MediaFormatAudioMimeType> SupportedAudioTypes
+ {
+ get
+ {
+ GetSupportedTypes();
+ return _supportedAudioFormats.AsReadOnly();
+ }
+ }
+
+ /// <summary>
+ /// Gets all supported video types.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public static IEnumerable<MediaFormatVideoMimeType> 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>()
+ {
+ MediaFormatAudioMimeType.Vorbis,
+ MediaFormatAudioMimeType.Opus,
+ MediaFormatAudioMimeType.Pcm
+ };
+ _supportedVideoFormats = new List<MediaFormatVideoMimeType>()
+ {
+ 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<MediaFormatAudioMimeType>(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);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the MediaPacketSource class with the specified <see cref="AudioMediaFormat"/>.
+ /// </summary>
+ /// <param name="audioMediaFormat">The <see cref="AudioMediaFormat"/> for this source.</param>
+ /// <exception cref="ArgumentNullException"><paramref name="audioMediaFormat"/> is null.</exception>
+ /// <exception cref="ArgumentException"><paramref name="audioMediaFormat"/> is not supported.</exception>
+ /// <seealso cref="SupportedAudioTypes"/>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaPacketSource(AudioMediaFormat audioMediaFormat) : base(MediaType.Audio)
+ {
+ _audioMediaFormat = audioMediaFormat ?? throw new ArgumentNullException(nameof(audioMediaFormat));
+ AudioConfiguration = CreateAudioConfiguration(audioMediaFormat);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the MediaPacketSource class with the specified <see cref="VideoMediaFormat"/>.
+ /// </summary>
+ /// <param name="videoMediaFormat">The <see cref="VideoMediaFormat"/> for this source.</param>
+ /// <exception cref="ArgumentNullException"><paramref name="videoMediaFormat"/> is null.</exception>
+ /// <exception cref="ArgumentException"><paramref name="videoMediaFormat"/> is not supported.</exception>
+ /// <seealso cref="SupportedVideoTypes"/>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaPacketSource(VideoMediaFormat videoMediaFormat) : base(MediaType.Video)
+ {
+ _videoMediaFormat = videoMediaFormat ?? throw new ArgumentNullException(nameof(videoMediaFormat));
+ VideoConfiguration = CreateVideoConfiguration(videoMediaFormat);
+ }
+
+ /// <summary>
+ /// Gets the audio configuration, or null if no AudioMediaFormat is specified in the constructor.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaPacketSourceConfiguration AudioConfiguration { get; }
+
+ /// <summary>
+ /// Gets the video configuration, or null if no VideoMediaFormat is specified in the constructor.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaPacketSourceConfiguration VideoConfiguration { get; }
+
+ /// <summary>
+ /// Pushes elementary stream to decode audio or video.
+ /// </summary>
+ /// <remarks>
+ /// This source must be set as a source to a WebRTC and the WebRTC must be in the
+ /// <see cref="WebRTCState.Negotiating"/> or <see cref="WebRTCState.Playing"/> state
+ /// </remarks>
+ /// <param name="packet">The <see cref="MediaPacket"/> to decode.</param>
+ /// <exception cref="InvalidOperationException">
+ /// This source is not set as a source to a WebRTC.<br/>
+ /// -or-<br/>
+ /// The WebRTC is not in the valid state.
+ /// </exception>
+ /// <exception cref="ArgumentNullException"><paramref name="packet"/> is null.</exception>
+ /// <exception cref="ObjectDisposedException"><paramref name="packet"/> has been disposed.</exception>
+ /// <exception cref="ArgumentException">
+ /// <paramref name="packet"/> is neither video nor audio type.<br/>
+ /// -or-<br/>
+ /// The format of packet is not matched with the specified format in the constructor.
+ /// </exception>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <seealso cref="MediaPacket"/>
+ /// <since_tizen> 9 </since_tizen>
+ 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.");
+ }
+
+ WebRtc.ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing);
+
+ 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)
+ {
+ Log.Warn(WebRTCLog.Tag, "invalid media format");
+ }
+ else
+ {
+ 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides means to configure properties and handle events for <see cref="MediaPacketSource"/>.
+ /// </summary>
+ /// <seealso cref="MediaPacketSource"/>
+ /// <since_tizen> 9 </since_tizen>
+ public class MediaPacketSourceConfiguration
+ {
+ private readonly MediaPacketSource _owner;
+ NativeWebRTC.MediaPacketBufferStatusCallback _mediaPacketBufferStatusChangedCallback;
+
+ internal MediaPacketSourceConfiguration(MediaPacketSource owner)
+ {
+ _owner = owner;
+ }
+
+ /// <summary>
+ /// Occurs when the buffer underruns or overflows.
+ /// </summary>
+ /// <remarks>The event handler will be executed on an internal thread.</remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<MediaPacketBufferStatusChangedEventArgs> BufferStatusChanged;
+
+ private IntPtr Handle => _owner.WebRtc.Handle;
+
+ private uint SourceId => _owner.SourceId.Value;
+
+ internal void OnWebRTCSet()
+ {
+ if (_mediaPacketBufferStatusChangedCallback == null)
+ {
+ RegisterBufferStatusChangedCallback();
+ }
+ }
+
+ internal void OnWebRTCUnset()
+ {
+ if (_mediaPacketBufferStatusChangedCallback != null)
+ {
+ UnregisterBufferStatusChangedCallback();
+ }
+ }
+
+ private void RegisterBufferStatusChangedCallback()
+ {
+ _mediaPacketBufferStatusChangedCallback = (sourceId_, state, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"sourceId:{sourceId_}, state:{state}");
+
+ BufferStatusChanged?.Invoke(this, new MediaPacketBufferStatusChangedEventArgs(sourceId_, state));
+ };
+
+ NativeWebRTC.SetBufferStateChangedCb(Handle, SourceId, _mediaPacketBufferStatusChangedCallback, IntPtr.Zero).
+ ThrowIfFailed("Failed to set buffer status changed callback.");
+ }
+
+ private void UnregisterBufferStatusChangedCallback()
+ {
+ NativeWebRTC.UnsetBufferStateChangedCb(Handle, SourceId).
+ ThrowIfFailed("Failed to unset buffer status changed callback.");
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.Diagnostics;
+using NativeWebRTC = Interop.NativeWebRTC;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Represents a screen source.
+ /// </summary>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaScreenSource : MediaSource
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaScreenSource"/> class.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaScreenSource() : base(MediaType.Video) {}
+
+ internal override void OnAttached(WebRTC webRtc)
+ {
+ Debug.Assert(webRtc != null);
+
+ if (WebRtc != null)
+ {
+ throw new InvalidOperationException("The source is has already been assigned to another WebRTC.");
+ }
+
+ NativeWebRTC.AddMediaSource(webRtc.Handle, MediaSourceType.Screen, out uint sourceId).
+ ThrowIfFailed("Failed to add MediaScreenSource.");
+
+ WebRtc = webRtc;
+ SourceId = sourceId;
+ }
+
+ internal override void OnDetached(WebRTC webRtc)
+ {
+ NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
+ ThrowIfFailed("Failed to remove MediaScreenSource.");
+
+ WebRtc = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 ElmSharp;
+using System;
+using System.Diagnostics;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// MediaSource is a base class for <see cref="WebRTC"/> sources.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public abstract class MediaSource : IDisplayable<uint>
+ {
+ internal WebRTC WebRtc { get; set; }
+ internal uint? SourceId { get; set; }
+ private Display _display;
+
+ /// <summary>
+ /// Gets the type of MediaSource.
+ /// </summary>
+ /// <value><see cref="MediaType"/></value>
+ /// <since_tizen> 9 </since_tizen>
+ protected MediaType MediaType { get; }
+
+ private bool IsDetached {get; set;} = false;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaSource"/> class.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ protected MediaSource(MediaType mediaType)
+ {
+ MediaType = mediaType;
+ }
+
+ internal void AttachTo(WebRTC webRtc)
+ {
+ if (IsDetached)
+ {
+ throw new InvalidOperationException("MediaSource was already detached.");
+ }
+
+ OnAttached(webRtc);
+ }
+
+ internal void DetachFrom(WebRTC webRtc)
+ {
+ OnDetached(webRtc);
+ IsDetached = true;
+ }
+
+ internal abstract void OnAttached(WebRTC webRtc);
+
+ internal abstract void OnDetached(WebRTC webRtc);
+
+ /// <summary>
+ /// Gets or sets the transceiver direction of current media source.
+ /// </summary>
+ /// <value>A <see cref="TransceiverDirection"/> that specifies the transceiver direction.</value>
+ /// <exception cref="InvalidOperationException">MediaSource is not attached yet.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public TransceiverDirection TransceiverDirection
+ {
+ get
+ {
+ if (!SourceId.HasValue)
+ {
+ throw new InvalidOperationException("MediaSource is not attached yet. Call SetSource() first.");
+ }
+
+ NativeWebRTC.GetTransceiverDirection(WebRtc.Handle, SourceId.Value, MediaType, out TransceiverDirection mode).
+ ThrowIfFailed("Failed to get transceiver direction.");
+
+ return mode;
+ }
+ set
+ {
+ if (!SourceId.HasValue)
+ {
+ throw new InvalidOperationException("MediaSource is not attached yet. Call SetSource() first.");
+ }
+
+ NativeWebRTC.SetTransceiverDirection(WebRtc.Handle, SourceId.Value, MediaType, value).
+ ThrowIfFailed("Failed to get transceiver direction.");
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the pause status of current media source.
+ /// </summary>
+ /// <value>A value that specifies the pause status.</value>
+ /// <exception cref="InvalidOperationException">MediaSource is not attached yet.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public bool Pause
+ {
+ get
+ {
+ NativeWebRTC.GetPause(WebRtc.Handle, SourceId.Value, MediaType, out bool isPaused).
+ ThrowIfFailed("Failed to get pause");
+
+ return isPaused;
+ }
+ set
+ {
+ NativeWebRTC.SetPause(WebRtc.Handle, SourceId.Value, MediaType, value).
+ ThrowIfFailed("Failed to set pause");
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the mute status of the current media source.
+ /// </summary>
+ /// <value>A value that specifies the mute status.</value>
+ /// <exception cref="InvalidOperationException">MediaSource is not attached yet.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public bool Mute
+ {
+ get
+ {
+ NativeWebRTC.GetMute(WebRtc.Handle, SourceId.Value, MediaType, out bool isMuted).
+ ThrowIfFailed("Failed to get mute");
+
+ return isMuted;
+ }
+ set
+ {
+ NativeWebRTC.SetMute(WebRtc.Handle, SourceId.Value, MediaType, value).
+ ThrowIfFailed("Failed to set mute");
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the video resolution of the current media source.
+ /// </summary>
+ /// <value>A value that specifies the mute status.</value>
+ /// <exception cref="ArgumentException">This source is not video source.</exception>
+ /// <exception cref="InvalidOperationException">MediaSource is not attached yet.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public Size VideoResolution
+ {
+ get
+ {
+ if (MediaType != MediaType.Video)
+ {
+ throw new ArgumentException("This property is only for video.");
+ }
+
+ NativeWebRTC.GetVideoResolution(WebRtc.Handle, SourceId.Value, out int width, out int height).
+ ThrowIfFailed("Failed to get video resolution");
+
+ return new Size(width, height);
+ }
+ set
+ {
+ if (MediaType != MediaType.Video)
+ {
+ throw new ArgumentException("This property is only for video.");
+ }
+
+ NativeWebRTC.SetVideoResolution(WebRtc.Handle, SourceId.Value, value.Width, value.Height).
+ ThrowIfFailed("Failed to set video resolution");
+ }
+ }
+
+ /// <summary>
+ /// Enables the audio loopback. The local audio will be played with <paramref name="policy"/>.
+ /// </summary>
+ /// <param name="policy">The <see cref="AudioStreamPolicy"/> to apply.</param>
+ /// <remarks>
+ /// <see cref="MediaSource"/> does not support all <see cref="AudioStreamType"/>.<br/>
+ /// Supported types are <see cref="AudioStreamType.Media"/>, <see cref="AudioStreamType.Voip"/>,
+ /// <see cref="AudioStreamType.MediaExternalOnly"/>.<br/>
+ /// </remarks>
+ /// <exception cref="ArgumentNullException"><paramref name="policy"/> is null.</exception>
+ /// <exception cref="InvalidOperationException">This MediaSource is not Audio</exception>
+ /// <exception cref="NotSupportedException">
+ /// <see cref="AudioStreamType"/> of <paramref name="policy"/> is not supported on the current platform.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// <paramref name="policy"/> or WebRTC has already been disposed.
+ /// </exception>
+ /// <returns><see cref="MediaStreamTrack"/></returns>
+ public MediaStreamTrack EnableAudioLoopback(AudioStreamPolicy policy)
+ {
+ if (policy == null)
+ {
+ throw new ArgumentNullException(nameof(policy));
+ }
+
+ if (MediaType != MediaType.Audio)
+ {
+ throw new InvalidOperationException("AudioLoopback is only for Audio MediaSource");
+ }
+
+ var ret = NativeWebRTC.SetAudioLoopback(WebRtc.Handle, SourceId.Value, policy.Handle, out uint trackId);
+
+ if (ret == WebRTCErrorCode.InvalidArgument)
+ {
+ throw new NotSupportedException("The specified policy is not supported on the current system.");
+ }
+
+ ret.ThrowIfFailed("Failed to set the audio stream policy to the WebRTC");
+
+ return new MediaStreamTrack(WebRtc, MediaType, trackId);
+ }
+
+ private uint SetDisplay(Display display)
+ => display.ApplyTo(this);
+
+ private void ReplaceDisplay(Display newDisplay)
+ {
+ _display?.SetOwner(null);
+ _display = newDisplay;
+ _display?.SetOwner(this);
+ }
+
+ /// <summary>
+ /// Enables the video loopback. The local video will be diaplayed in <paramref name="display"/>.
+ /// </summary>
+ /// <param name="display">The <see cref="Display"/> to apply.</param>
+ /// <exception cref="ArgumentException">The display has already been assigned to another.</exception>
+ /// <exception cref="ArgumentNullException"><paramref name="display"/> is null.</exception>
+ /// <exception cref="InvalidOperationException">This MediaSource is not Video</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <returns><see cref="MediaStreamTrack"/></returns>
+ public MediaStreamTrack EnableVideoLoopback(Display display)
+ {
+ uint trackId = 0;
+
+ if (display == null)
+ {
+ throw new ArgumentNullException(nameof(display), "Display cannot be null.");
+ }
+
+ if (MediaType != MediaType.Video)
+ {
+ throw new InvalidOperationException("VideoLoopback is only for Video MediaSource");
+ }
+
+ if (display?.Owner != null)
+ {
+ if (ReferenceEquals(this, display.Owner))
+ {
+ throw new ArgumentException("The display has already been assigned to another.");
+ }
+ }
+ else
+ {
+ trackId = SetDisplay(display);
+ ReplaceDisplay(display);
+ }
+
+ return new MediaStreamTrack(WebRtc, MediaType, trackId);
+ }
+
+ uint IDisplayable<uint>.ApplyEvasDisplay(DisplayType type, EvasObject evasObject)
+ {
+ Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
+ Debug.Assert(type != DisplayType.None);
+
+ NativeWebRTC.SetVideoLoopback(WebRtc.Handle, SourceId.Value,
+ type == DisplayType.Overlay ? WebRTCDisplayType.Overlay : WebRTCDisplayType.Evas, evasObject,
+ out uint trackId).ThrowIfFailed("Failed to set video loopback");
+
+ return trackId;
+ }
+
+ uint IDisplayable<uint>.ApplyEcoreWindow(IntPtr windowHandle)
+ {
+ NativeWebRTC.SetEcoreVideoLoopback(WebRtc.Handle, SourceId.Value, windowHandle, out uint trackId).
+ ThrowIfFailed("Failed to set ecore video loopback");
+
+ return trackId;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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 ElmSharp;
+using System;
+using System.Diagnostics;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides the ability to control audio/video track.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaStreamTrack : IDisplayable<WebRTCErrorCode>
+ {
+ private WebRTC _webRtc;
+ private uint _trackId;
+ private Display _display;
+
+ internal MediaStreamTrack(WebRTC webRtc, MediaType type, uint trackId)
+ {
+ _webRtc = webRtc;
+ _trackId = trackId;
+ Type = type;
+ }
+
+ /// <summary>
+ /// Gets the the of media stream track.
+ /// </summary>
+ /// <value><see cref="MediaType"/></value>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaType Type { get; }
+
+ private WebRTCErrorCode SetDisplay(Display display)
+ => display.ApplyTo(this);
+
+ private void ReplaceDisplay(Display newDisplay)
+ {
+ _display?.SetOwner(null);
+ _display = newDisplay;
+ _display?.SetOwner(this);
+ }
+
+ /// <summary>
+ /// Gets or sets the display to show remote video.
+ /// </summary>
+ /// <value>A <see cref="Multimedia.Display"/> that specifies the display.</value>
+ /// <remarks>
+ /// If user set video source with <see cref="TransceiverDirection.SendRecv"/>, <see cref="Display"/> must be set.<br/>
+ /// If not, the received video will fill entire screen.<br/>
+ /// If remote track, <see cref="Display"/> must be set in <see cref="WebRTC.TrackAdded"/> event.<br/>
+ /// The display is created with <see cref="MediaView"/>.
+ /// </remarks>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed of.</exception>
+ /// <exception cref="ArgumentException">The value has already been assigned to another WebRTC.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not called in <see cref="WebRTC.TrackAdded"/> event.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public Display Display
+ {
+ get => _display;
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value), "Display cannot be null.");
+ }
+
+ if (value?.Owner != null)
+ {
+ if (ReferenceEquals(this, value.Owner))
+ {
+ throw new ArgumentException("The display has already been assigned to another.");
+ }
+ }
+ else
+ {
+ SetDisplay(value).ThrowIfFailed("Failed to configure display of the MediaStreamTrack");
+ ReplaceDisplay(value);
+ }
+ }
+ }
+
+ WebRTCErrorCode IDisplayable<WebRTCErrorCode>.ApplyEvasDisplay(DisplayType type, EvasObject evasObject)
+ {
+ Debug.Assert(Enum.IsDefined(typeof(DisplayType), type));
+ Debug.Assert(type != DisplayType.None);
+
+ return NativeWebRTC.SetDisplay(_webRtc.Handle, _trackId,
+ type == DisplayType.Overlay ? WebRTCDisplayType.Overlay : WebRTCDisplayType.Evas, evasObject);
+ }
+
+ WebRTCErrorCode IDisplayable<WebRTCErrorCode>.ApplyEcoreWindow(IntPtr windowHandle)
+ {
+ return NativeWebRTC.SetEcoreDisplay(_webRtc.Handle, _trackId, windowHandle);
+ }
+
+ /// <summary>
+ /// Gets or sets the display mode.
+ /// </summary>
+ /// <remarks>
+ /// This property is meaningful only in overlay or EVAS surface display type.
+ /// </remarks>
+ /// <value>A <see cref="WebRTCDisplayMode"/> that specifies the display mode.</value>
+ /// <exception cref="ArgumentException">Display mode type is incorrect.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCDisplayMode DisplayMode
+ {
+ get
+ {
+ NativeWebRTC.GetDisplayMode(_webRtc.Handle, _trackId, out var val).
+ ThrowIfFailed("Failed to get WebRTC display mode");
+
+ return val;
+ }
+ set
+ {
+ ValidationUtil.ValidateEnum(typeof(WebRTCDisplayMode), value, nameof(value));
+
+ NativeWebRTC.SetDisplayMode(_webRtc.Handle, _trackId, value).
+ ThrowIfFailed("Failed to set WebRTC display mode.");
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the display visibility.
+ /// </summary>
+ /// <value>true if WebRTC display is visible, otherwise false.</value>
+ /// <remarks>
+ /// This property is meaningful only in overlay or EVAS surface display type.
+ /// </remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public bool DisplayVisible
+ {
+ get
+ {
+ NativeWebRTC.GetDisplayVisible(_webRtc.Handle, _trackId,out bool val).
+ ThrowIfFailed("Failed to get visible status");
+
+ return val;
+ }
+ set
+ {
+ NativeWebRTC.SetDisplayVisible(_webRtc.Handle, _trackId, value).
+ ThrowIfFailed("Failed to set display status.");
+ }
+ }
+
+ /// <summary>
+ /// Applies the audio stream policy to remote track.
+ /// </summary>
+ /// <param name="policy">The <see cref="AudioStreamPolicy"/> to apply.</param>
+ /// <remarks>
+ /// This must be called in <see cref="WebRTC.TrackAdded"/> event.<br/>
+ /// <br/>
+ /// <see cref="WebRTC"/> does not support all <see cref="AudioStreamType"/>.<br/>
+ /// Supported types are <see cref="AudioStreamType.Media"/>, <see cref="AudioStreamType.Voip"/>,
+ /// <see cref="AudioStreamType.MediaExternalOnly"/>.
+ /// </remarks>
+ /// <exception cref="ArgumentNullException"><paramref name="policy"/> is null.</exception>
+ /// <exception cref="InvalidOperationException">
+ /// <see cref="WebRTC.AudioFrameEncoded"/> was set.<br/>
+ /// -or-<br/>
+ /// This method was not called in <see cref="WebRTC.TrackAdded"/> event.
+ /// </exception>
+ /// <exception cref="NotSupportedException">
+ /// <see cref="AudioStreamType"/> of <paramref name="policy"/> is not supported on the current platform.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// The WebRTC has already been disposed.<br/>
+ /// -or-<br/>
+ /// <paramref name="policy"/> has already been disposed.
+ /// </exception>
+ /// <seealso cref="AudioStreamPolicy"/>
+ /// <seealso cref="WebRTC.TrackAdded"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void ApplyAudioStreamPolicy(AudioStreamPolicy policy)
+ {
+ if (policy == null)
+ {
+ throw new ArgumentNullException(nameof(policy));
+ }
+
+ if (Type != MediaType.Audio)
+ {
+ throw new InvalidOperationException("Should be applied in Audio");
+ }
+
+ var ret = NativeWebRTC.SetAudioStreamPolicy(_webRtc.Handle, _trackId, policy.Handle);
+
+ if (ret == WebRTCErrorCode.InvalidArgument)
+ {
+ throw new NotSupportedException("The specified policy is not supported on the current system.");
+ }
+
+ ret.ThrowIfFailed("Failed to set the audio stream policy to the WebRTC");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.Diagnostics;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Represents an audio or a video test source.
+ /// </summary>
+ /// <seealso cref="WebRTC.AddSource"/>
+ /// <seealso cref="WebRTC.AddSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public sealed class MediaTestSource : MediaSource
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaTestSource"/> class.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaTestSource(MediaType type) : base(type) {}
+ internal override void OnAttached(WebRTC webRtc)
+ {
+ Debug.Assert(webRtc != null);
+
+ if (WebRtc != null)
+ {
+ throw new InvalidOperationException("The source is has already been assigned to another WebRTC.");
+ }
+
+ var type = MediaType == MediaType.Video ? MediaSourceType.VideoTest : MediaSourceType.AudioTest;
+
+ NativeWebRTC.AddMediaSource(webRtc.Handle, type, out uint sourceId).
+ ThrowIfFailed($"Failed to add {MediaType.ToString()} MediaTestSource.");
+
+ WebRtc = webRtc;
+ SourceId = sourceId;
+ }
+
+ internal override void OnDetached(WebRTC webRtc)
+ {
+ NativeWebRTC.RemoveMediaSource(webRtc.Handle, SourceId.Value).
+ ThrowIfFailed($"Failed to remove {MediaType.ToString()} MediaTestSource.");
+
+ WebRtc = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides the ability to control WebRTC.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public partial class WebRTC
+ {
+ private NativeWebRTC.ErrorOccurredCallback _webRtcErrorOccurredCallback;
+ private NativeWebRTC.StateChangedCallback _webRtcStateChangedCallback;
+ private NativeWebRTC.IceGatheringStateChangedCallback _webRtcIceGatheringStateChangedCallback;
+ private NativeWebRTC.SignalingStateChangedCallback _webRtcSignalingStateChangedCallback;
+ private NativeWebRTC.PeerConnectionStateChangedCallback _webRtcPeerConnectionStateChangedCallback;
+ private NativeWebRTC.IceConnectionStateChangedCallback _webRtcIceConnectionStateChangedCallback;
+ private NativeWebRTC.NegotiationNeededCallback _webRtcNegotiationNeededCallback;
+ private NativeWebRTC.IceCandidateCallback _webRtcIceCandidateCallback;
+ private NativeWebRTC.TrackAddedCallback _webRtcTrackAddedCallback;
+ private NativeWebRTC.FrameEncodedCallback _webRtcAudioFrameEncodedCallback;
+ private NativeWebRTC.FrameEncodedCallback _webRtcVideoFrameEncodedCallback;
+ private NativeDataChannel.CreatedCallback _webRtcDataChannelCreatedCallback;
+
+ /// <summary>
+ /// Occurs when any error occurs.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCErrorOccurredEventArgs> ErrorOccurred;
+
+ /// <summary>
+ /// Occurs when WebRTC state is changed.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCStateChangedEventArgs> StateChanged;
+
+ /// <summary>
+ /// Occurs when the WebRTC ICE gathering state is changed.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCIceGatheringStateChangedEventArgs> IceGatheringStateChanged;
+
+ /// <summary>
+ /// Occurs when the WebRTC signaling state is changed.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCSignalingStateChangedEventArgs> SignalingStateChanged;
+
+ /// <summary>
+ /// Occurs when the WebRTC peer connection state is changed.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCPeerConnectionStateChangedEventArgs> PeerConnectionStateChanged;
+
+ /// <summary>
+ /// Occurs when the WebRTC ICE connection state is changed.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCIceConnectionStateChangedEventArgs> IceConnectionStateChanged;
+
+ /// <summary>
+ /// Occurs when negotiation is needed.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<EventArgs> NegotiationNeeded;
+
+ /// <summary>
+ /// Occurs when the WebRTC needs to send the ICE candidate message to the remote peer.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCIceCandidateEventArgs> IceCandidate;
+
+ /// <summary>
+ /// Occurs when a new track has been added to the WebRTC.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCTrackAddedEventArgs> TrackAdded;
+
+ private event EventHandler<WebRTCFrameEncodedEventArgs> _audioFrameEncoded;
+
+ /// <summary>
+ /// Occurs when each audio frame is ready to render.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCFrameEncodedEventArgs> AudioFrameEncoded
+ {
+ add
+ {
+ if (_audioFrameEncoded == null)
+ {
+ RegisterAudioFrameEncodedCallback();
+ }
+
+ _audioFrameEncoded += value;
+ }
+ remove
+ {
+ _audioFrameEncoded -= value;
+
+ if (_audioFrameEncoded == null)
+ {
+ UnregisterAudioFrameEncodedCallback();
+ }
+ }
+ }
+
+ private event EventHandler<WebRTCFrameEncodedEventArgs> _videoFrameEncoded;
+
+ /// <summary>
+ /// Occurs when each video frame is ready to render.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCFrameEncodedEventArgs> VideoFrameEncoded
+ {
+ add
+ {
+ if (_videoFrameEncoded == null)
+ {
+ RegisterVideoFrameEncodedCallback();
+ }
+
+ _videoFrameEncoded += value;
+ }
+ remove
+ {
+ _videoFrameEncoded -= value;
+
+ if (_videoFrameEncoded == null)
+ {
+ UnregisterVideoFrameEncodedCallback();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Occurs when the data channel is created to the connection by the remote peer.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCDataChannelEventArgs> DataChannel;
+
+ private void RegisterEvents()
+ {
+ RegisterErrorOccurredCallback();
+ RegisterStateChangedCallback();
+ RegisterIceGatheringStateChangedCallback();
+ RegisterSignalingStateChangedCallback();
+ RegisterPeerConnectionStateChangedCallback();
+ RegisterIceConnectionStateChangedCallback();
+ RegisterNegotiationNeededCallback();
+ RegisterIceCandidateCallback();
+ RegisterTrackAddedCallback();
+ RegisterDataChannelCreatedCallback();
+ }
+
+ private void RegisterErrorOccurredCallback()
+ {
+ _webRtcErrorOccurredCallback = (handle, error, state, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"{error}, {state}");
+
+ ErrorOccurred?.Invoke(this, new WebRTCErrorOccurredEventArgs((WebRTCError)error, state));
+ };
+
+ NativeWebRTC.SetErrorOccurredCb(Handle, _webRtcErrorOccurredCallback).
+ ThrowIfFailed("Failed to set error occurred callback.");
+ }
+
+ private void RegisterStateChangedCallback()
+ {
+ _webRtcStateChangedCallback = (handle, previous, current, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"{previous}, {current}");
+
+ StateChanged?.Invoke(this, new WebRTCStateChangedEventArgs(previous, current));
+ };
+
+ NativeWebRTC.SetStateChangedCb(Handle, _webRtcStateChangedCallback).
+ ThrowIfFailed("Failed to set state changed callback.");
+ }
+
+ private void RegisterIceGatheringStateChangedCallback()
+ {
+ _webRtcIceGatheringStateChangedCallback = (handle, state, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Ice gathering state : {state}");
+
+ IceGatheringStateChanged?.Invoke(this, new WebRTCIceGatheringStateChangedEventArgs(state));
+ };
+
+ NativeWebRTC.SetIceGatheringStateChangedCb(Handle, _webRtcIceGatheringStateChangedCallback).
+ ThrowIfFailed("Failed to set Ice gathering state changed callback.");
+ }
+
+ private void RegisterSignalingStateChangedCallback()
+ {
+ _webRtcSignalingStateChangedCallback = (handle, state, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Signaling state : {state}");
+
+ SignalingStateChanged?.Invoke(this, new WebRTCSignalingStateChangedEventArgs(state));
+ };
+
+ NativeWebRTC.SetSignalingStateChangedCb(Handle, _webRtcSignalingStateChangedCallback).
+ ThrowIfFailed("Failed to set signaling state changed callback.");
+ }
+
+ private void RegisterPeerConnectionStateChangedCallback()
+ {
+ _webRtcPeerConnectionStateChangedCallback = (handle, state, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Peer connection state : {state}");
+
+ PeerConnectionStateChanged?.Invoke(this, new WebRTCPeerConnectionStateChangedEventArgs(state));
+ };
+
+ NativeWebRTC.SetPeerConnectionStateChangedCb(Handle, _webRtcPeerConnectionStateChangedCallback).
+ ThrowIfFailed("Failed to set peer connection state changed callback.");
+ }
+
+ private void RegisterIceConnectionStateChangedCallback()
+ {
+ _webRtcIceConnectionStateChangedCallback = (handle, state, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Ice connection state : {state}");
+
+ IceConnectionStateChanged?.Invoke(this, new WebRTCIceConnectionStateChangedEventArgs(state));
+ };
+
+ NativeWebRTC.SetIceConnectionStateChangedCb(Handle, _webRtcIceConnectionStateChangedCallback).
+ ThrowIfFailed("Failed to set ICE connection state changed callback.");
+ }
+
+ private void RegisterNegotiationNeededCallback()
+ {
+ _webRtcNegotiationNeededCallback = (handle, _) =>
+ {
+ NegotiationNeeded?.Invoke(this, new EventArgs());
+ };
+
+ NativeWebRTC.SetNegotiationNeededCb(Handle, _webRtcNegotiationNeededCallback).
+ ThrowIfFailed("Failed to set negotiation needed callback.");
+ }
+
+ private void RegisterIceCandidateCallback()
+ {
+ _webRtcIceCandidateCallback = (handle, candidate, _) =>
+ {
+ IceCandidate?.Invoke(this, new WebRTCIceCandidateEventArgs(candidate));
+ };
+
+ NativeWebRTC.SetIceCandidateCb(Handle, _webRtcIceCandidateCallback).
+ ThrowIfFailed("Failed to set ice candidate callback.");
+ }
+
+ private void RegisterTrackAddedCallback()
+ {
+ _webRtcTrackAddedCallback = (handle, type, id, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Track type[{type}], id[{id}]");
+
+ TrackAdded?.Invoke(this, new WebRTCTrackAddedEventArgs(new MediaStreamTrack(this, type, id)));
+ };
+
+ NativeWebRTC.SetTrackAddedCb(Handle, _webRtcTrackAddedCallback).
+ ThrowIfFailed("Failed to set track added callback.");
+ }
+
+ private void RegisterAudioFrameEncodedCallback()
+ {
+ _webRtcAudioFrameEncodedCallback = (handle, type, id, packet, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Track type[{type}], id[{id}]");
+
+ _audioFrameEncoded?.Invoke(this,
+ new WebRTCFrameEncodedEventArgs(new MediaStreamTrack(this, type, id), MediaPacket.From(packet)));
+ };
+
+ NativeWebRTC.SetAudioFrameEncodedCb(Handle, _webRtcAudioFrameEncodedCallback).
+ ThrowIfFailed("Failed to set audio frame encoded callback.");
+ }
+
+ private void UnregisterAudioFrameEncodedCallback()
+ {
+ NativeWebRTC.UnsetAudioFrameEncodedCb(Handle).
+ ThrowIfFailed("Failed to unset audio frame encoded callback.");
+ }
+
+ private void RegisterVideoFrameEncodedCallback()
+ {
+ _webRtcVideoFrameEncodedCallback = (handle, type, id, packet, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"Track type[{type}], id[{id}]");
+
+ _videoFrameEncoded?.Invoke(this,
+ new WebRTCFrameEncodedEventArgs(new MediaStreamTrack(this, type, id), MediaPacket.From(packet)));
+ };
+
+ NativeWebRTC.SetVideoFrameEncodedCb(Handle, _webRtcVideoFrameEncodedCallback).
+ ThrowIfFailed("Failed to set video frame encoded callback.");
+ }
+
+ private void UnregisterVideoFrameEncodedCallback()
+ {
+ NativeWebRTC.UnsetVideoFrameEncodedCb(Handle).
+ ThrowIfFailed("Failed to unset video frame encoded callback.");
+ }
+
+ private void RegisterDataChannelCreatedCallback()
+ {
+ _webRtcDataChannelCreatedCallback = (handle, dataChannelHandle, _) =>
+ {
+ Log.Debug(WebRTCLog.Tag, "Invoked");
+
+ DataChannel?.Invoke(this, new WebRTCDataChannelEventArgs(dataChannelHandle));
+ };
+
+ NativeDataChannel.SetCreatedByPeerCb(Handle, _webRtcDataChannelCreatedCallback).
+ ThrowIfFailed("Failed to set data channel created callback.");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 ElmSharp;
+using System;
+using System.Diagnostics;
+using static Interop;
+using NativeWebRTC = Interop.NativeWebRTC;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides the ability to control WebRTC.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public partial class WebRTC
+ {
+ internal IntPtr Handle
+ {
+ get
+ {
+ ValidateNotDisposed();
+ return _handle.DangerousGetHandle();
+ }
+ }
+
+ /// <summary>
+ /// Gets the state of the WebRTC.
+ /// </summary>
+ /// <value>The current state of the WebRTC.</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCState State
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetState(Handle, out WebRTCState state).
+ ThrowIfFailed("Failed to retrieve the state of the WebRTC");
+
+ Debug.Assert(Enum.IsDefined(typeof(WebRTCState), state));
+
+ return state;
+ }
+ }
+
+ /// <summary>
+ /// Gets the Ice gathering state of the WebRTC.
+ /// </summary>
+ /// <value>The current Ice gathering state of the WebRTC.</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCIceGatheringState IceGatheringState
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetIceGatheringState(Handle, out WebRTCIceGatheringState state).
+ ThrowIfFailed("Failed to retrieve the state of the WebRTC");
+
+ Debug.Assert(Enum.IsDefined(typeof(WebRTCIceGatheringState), state));
+
+ return state;
+ }
+ }
+
+ /// <summary>
+ /// Gets the signaling state of the WebRTC.
+ /// </summary>
+ /// <value>The current signaling state of the WebRTC.</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCSignalingState SignalingState
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetSignalingState(Handle, out WebRTCSignalingState state).
+ ThrowIfFailed("Failed to retrieve the state of the WebRTC");
+
+ Debug.Assert(Enum.IsDefined(typeof(WebRTCSignalingState), state));
+
+ return state;
+ }
+ }
+
+ /// <summary>
+ /// Gets the peer connection state of the WebRTC.
+ /// </summary>
+ /// <value>The current peer connection state of the WebRTC.</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCPeerConnectionState PeerConnectionState
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetPeerConnectionState(Handle, out WebRTCPeerConnectionState state).
+ ThrowIfFailed("Failed to retrieve the state of the WebRTC");
+
+ Debug.Assert(Enum.IsDefined(typeof(WebRTCPeerConnectionState), state));
+
+ return state;
+ }
+ }
+
+ /// <summary>
+ /// Gets the ICE connection state of the WebRTC.
+ /// </summary>
+ /// <value>The current ICE connection state of the WebRTC.</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCIceConnectionState IceConnectionState
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetIceConnectionState(Handle, out WebRTCIceConnectionState state).
+ ThrowIfFailed("Failed to retrieve the state of the WebRTC");
+
+ Debug.Assert(Enum.IsDefined(typeof(WebRTCIceConnectionState), state));
+
+ return state;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the STUN server url.
+ /// </summary>
+ /// <value>The STUN server url</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public string StunServer
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetStunServer(Handle, out string server).
+ ThrowIfFailed("Failed to get stun server name");
+
+ return server;
+ }
+ set
+ {
+ ValidateNotDisposed();
+
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value), "Stun server name is null.");
+ }
+
+ NativeWebRTC.SetStunServer(Handle, value).
+ ThrowIfFailed("Failed to set stun server name");
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the ICE transport policy.
+ /// </summary>
+ /// <value>The policy of ICE transport</value>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public IceTransportPolicy IceTransportPolicy
+ {
+ get
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.GetIceTransportPolicy(Handle, out IceTransportPolicy policy).
+ ThrowIfFailed("Failed to get ICE transport policy");
+
+ return policy;
+ }
+ set
+ {
+ ValidateNotDisposed();
+
+ NativeWebRTC.SetIceTransportPolicy(Handle, value).
+ ThrowIfFailed("Failed to set ICE transport policy");
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.Threading.Tasks;
+using System.Collections.ObjectModel;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using Tizen.Applications;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ internal static class WebRTCLog
+ {
+ internal const string Tag = "Tizen.Multimedia.WebRTC";
+ }
+
+ /// <summary>
+ /// Provides the ability to control WebRTC.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public partial class WebRTC : IDisposable
+ {
+ private readonly WebRTCHandle _handle;
+ private List<MediaSource> _source;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebRTC"/> class.
+ /// </summary>
+ /// <feature>http://tizen.org/feature/network.wifi</feature>
+ /// <feature>http://tizen.org/feature/network.telephony</feature>
+ /// <feature>http://tizen.org/feature/network.ethernet</feature>
+ /// <privilege>http://tizen.org/privilege/internet</privilege>
+ /// <exception cref="UnauthorizedAccessException">Thrown when the permission is denied.</exception>
+ /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTC()
+ {
+ if (!Features.IsSupported(WebRTCFeatures.Wifi) &&
+ !Features.IsSupported(WebRTCFeatures.Telephony) &&
+ !Features.IsSupported(WebRTCFeatures.Ethernet))
+ {
+ throw new NotSupportedException("Network features are not supported.");
+ }
+
+ NativeWebRTC.Create(out _handle).ThrowIfFailed("Failed to create webrtc");
+
+ Debug.Assert(_handle != null);
+
+ RegisterEvents();
+
+ _source = new List<MediaSource>();
+ }
+
+ internal void ValidateWebRTCState(params WebRTCState[] desiredStates)
+ {
+ Debug.Assert(desiredStates.Length > 0);
+
+ ValidateNotDisposed();
+
+ WebRTCState curState = State;
+ if (!curState.IsAnyOf(desiredStates))
+ {
+ throw new InvalidOperationException("The WebRTC is not in a valid state. " +
+ $"Current State : { curState }, Valid State : { string.Join(", ", desiredStates) }.");
+ }
+ }
+
+ #region Dispose support
+ private bool _disposed;
+
+ /// <summary>
+ /// Releases all resources used by the current instance.
+ /// </summary>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the <see cref="WebRTC"/>.
+ /// </summary>
+ /// <param name="disposing">
+ /// true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.
+ /// </param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed || !disposing)
+ return;
+
+ if (_source != null && _source.Count > 0)
+ {
+ try
+ {
+ foreach (var source in _source)
+ {
+ source.DetachFrom(this);
+ }
+ _source = null;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(WebRTCLog.Tag, ex.ToString());
+ }
+ }
+ if (_handle != null)
+ {
+ _handle.Dispose();
+ _disposed = true;
+ }
+ }
+
+ internal void ValidateNotDisposed()
+ {
+ if (_disposed)
+ {
+ Log.Warn(WebRTCLog.Tag, "WebRTC was disposed");
+ throw new ObjectDisposedException(nameof(WebRTC));
+ }
+ }
+
+ internal bool IsDisposed => _disposed;
+ #endregion
+
+ /// <summary>
+ /// Starts the WebRTC.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/> state.<br/>
+ /// The WebRTC state will be <see cref="WebRTCState.Negotiating"/> state.<br/>
+ /// <see cref="StateChanged"/> event will be invoked when the state is changed to <see cref="WebRTCState.Negotiating"/> internally.
+ /// </remarks>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <see also="WebRTCState"/>
+ /// <see also="StateChanged"/>
+ /// <see also="CreateOffer"/>
+ /// <see also="CreateSetOffer"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void Start()
+ {
+ ValidateWebRTCState(WebRTCState.Idle);
+
+ NativeWebRTC.Start(Handle).ThrowIfFailed("Failed to start the WebRTC");
+ }
+
+ /// <summary>
+ /// Starts the WebRTC.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/> state.<br/>
+ /// The WebRTC state will be <see cref="WebRTCState.Negotiating"/> state.<br/>
+ /// This ensures that <see cref="StateChanged" /> event will be invoked with <see cref="WebRTCState.Negotiating"/> state.
+ /// </remarks>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <see also="WebRTCState"/>
+ /// <see also="CreateOffer"/>
+ /// <see also="CreateSetOffer"/>
+ /// <since_tizen> 9 </since_tizen>
+ public async Task StartAsync()
+ {
+ ValidateWebRTCState(WebRTCState.Idle);
+
+ var tcs = new TaskCompletionSource<bool>();
+ EventHandler<WebRTCStateChangedEventArgs> stateChangedEventHandler = (s, e) =>
+ {
+ if (e.Current == WebRTCState.Negotiating)
+ {
+ tcs.TrySetResult(true);
+ }
+ };
+
+ try
+ {
+ StateChanged += stateChangedEventHandler;
+
+ NativeWebRTC.Start(Handle).ThrowIfFailed("Failed to start the WebRTC");
+
+ await tcs.Task;
+ }
+ finally
+ {
+ StateChanged -= stateChangedEventHandler;
+ }
+ }
+
+ /// <summary>
+ /// Stops the WebRTC.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Negotiating"/> or <see cref="WebRTCState.Playing"/> state.<br/>
+ /// The WebRTC state will be <see cref="WebRTCState.Idle"/> state.
+ /// </remarks>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void Stop()
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing);
+
+ NativeWebRTC.Stop(Handle).ThrowIfFailed("Failed to stop the WebRTC");
+ }
+
+ /// <summary>
+ /// Creates SDP offer to start a new WebRTC connection to a remote peer.
+ /// </summary>
+ /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Negotiating"/></remarks>
+ /// <returns>The SDP offer.</returns>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="CreateOffer(Bundle)"/>
+ /// <since_tizen> 9 </since_tizen>
+ public string CreateOffer() => CreateOffer(null);
+
+ /// <summary>
+ /// Creates SDP offer with option to start a new WebRTC connection to a remote peer.
+ /// </summary>
+ /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Negotiating"/></remarks>
+ /// <param name="bundle">Configuration options for the offer.</param>
+ /// <returns>The SDP offer.</returns>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="CreateOffer()"/>
+ /// <since_tizen> 9 </since_tizen>
+ public string CreateOffer(Bundle bundle)
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating);
+
+ var bundle_ = bundle?.SafeBundleHandle ?? new SafeBundleHandle();
+ NativeWebRTC.CreateSDPOffer(Handle, bundle_, out string offer).ThrowIfFailed("Failed to create offer");
+
+ return offer;
+ }
+
+ /// <summary>
+ /// Creates SDP answer to an offer received from a remote peer.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Negotiating"/>.<br/>
+ /// The SDP offer must be set by <see cref="SetRemoteDescription"/> before creating answer.
+ /// </remarks>
+ /// <returns>The SDP answer.</returns>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="CreateAnswer(Bundle)"/>
+ /// <seealso cref="SetRemoteDescription(string)"/>
+ /// <since_tizen> 9 </since_tizen>
+ public string CreateAnswer() => CreateAnswer(null);
+
+ /// <summary>
+ /// Creates SDP answer with option to an offer received from a remote peer.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Negotiating"/>.<br/>
+ /// The SDP offer must be set by <see cref="SetRemoteDescription"/> before creating answer.
+ /// </remarks>
+ /// <param name="bundle">Configuration options for the answer.</param>
+ /// <returns>The SDP answer.</returns>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="CreateAnswer()"/>
+ /// <seealso cref="SetRemoteDescription(string)"/>
+ /// <since_tizen> 9 </since_tizen>
+ public string CreateAnswer(Bundle bundle)
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating);
+
+ var bundle_ = bundle?.SafeBundleHandle ?? new SafeBundleHandle();
+
+ NativeWebRTC.CreateSDPAnswer(Handle, bundle_, out string answer).ThrowIfFailed("Failed to create answer");
+
+ return answer;
+ }
+
+ /// <summary>
+ /// Sets the session description for a local peer.
+ /// </summary>
+ /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Negotiating"/>.</remarks>
+ /// <param name="description">The local session description.</param>
+ /// <exception cref="ArgumentException">The description is empty string.</exception>
+ /// <exception cref="ArgumentNullException">The description is null.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="CreateOffer()"/>
+ /// <seealso cref="CreateAnswer()"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void SetLocalDescription(string description)
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating);
+
+ ValidationUtil.ValidateIsNullOrEmpty(description, nameof(description));
+
+ NativeWebRTC.SetLocalDescription(Handle, description).ThrowIfFailed("Failed to set description.");
+ }
+
+ /// <summary>
+ /// Sets the session description of the remote peer's current offer or answer.
+ /// </summary>
+ /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Negotiating"/>.</remarks>
+ /// <param name="description">The remote session description.</param>
+ /// <exception cref="ArgumentException">The description is empty string.</exception>
+ /// <exception cref="ArgumentNullException">The description is null.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="CreateOffer()"/>
+ /// <seealso cref="CreateAnswer()"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void SetRemoteDescription(string description)
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating);
+
+ ValidationUtil.ValidateIsNullOrEmpty(description, nameof(description));
+
+ NativeWebRTC.SetRemoteDescription(Handle, description).ThrowIfFailed("Failed to set description.");
+ }
+
+ /// <summary>
+ /// Adds a new ICE candidate from the remote peer over its signaling channel.
+ /// </summary>
+ /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Negotiating"/>.</remarks>
+ /// <param name="iceCandidate">The ICE candidate.</param>
+ /// <exception cref="ArgumentException">The ICE candidate is empty string.</exception>
+ /// <exception cref="ArgumentNullException">The ICE candidate is null.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void AddIceCandidate(string iceCandidate)
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating);
+
+ ValidationUtil.ValidateIsNullOrEmpty(iceCandidate, nameof(iceCandidate));
+
+ NativeWebRTC.AddIceCandidate(Handle, iceCandidate).ThrowIfFailed("Failed to set ICE candidate.");
+ }
+
+ /// <summary>
+ /// Adds new ICE candidates from the remote peer over its signaling channel.
+ /// </summary>
+ /// <remarks>The WebRTC must be in the <see cref="WebRTCState.Negotiating"/>.</remarks>
+ /// <param name="iceCandidates">The ICE candidates.</param>
+ /// <exception cref="ArgumentException">The ICE candidate is empty string.</exception>
+ /// <exception cref="ArgumentNullException">The ICE candidate is null.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void AddIceCandidates(IEnumerable<string> iceCandidates)
+ {
+ ValidateWebRTCState(WebRTCState.Negotiating);
+
+ ValidationUtil.ValidateIsAny(iceCandidates);
+
+ #pragma warning disable CA1062
+ foreach (string iceCandidate in iceCandidates)
+ {
+ AddIceCandidate(iceCandidate);
+ }
+ #pragma warning restore CA1062
+ }
+
+ /// <summary>
+ /// Adds media source.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/>.<br/>
+ /// Each MediaSource requires different feature or privilege.<br/>
+ /// <see cref="MediaCameraSource"/> needs camera feature and privilege.<br/>
+ /// <see cref="MediaFileSource"/> needs mediastorage or externalstorage privilege.<br/>
+ /// <see cref="MediaMicrophoneSource"/> needs microphone feature and recorder privilege.<br/>
+ /// </remarks>
+ /// <param name="source">The media sources to add.</param>
+ /// <feature>http://tizen.org/feature/camera</feature>
+ /// <feature>http://tizen.org/feature/microphone</feature>
+ /// <privilege>http://tizen.org/privilege/camera</privilege>
+ /// <privilege>http://tizen.org/privilege/mediastorage</privilege>
+ /// <privilege>http://tizen.org/privilege/externalstorage</privilege>
+ /// <privilege>http://tizen.org/privilege/recorder</privilege>
+ /// <exception cref="ArgumentNullException">The media source is null.</exception>
+ /// <exception cref="InvalidOperationException">
+ /// The WebRTC is not in the valid state.<br/>
+ /// - or -<br/>
+ /// All or one of <paramref name="source"/> was already detached.
+ /// </exception>
+ /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <exception cref="UnauthorizedAccessException">Thrown when the permission is denied.</exception>
+ /// <seealso cref="MediaCameraSource"/>
+ /// <seealso cref="MediaMicrophoneSource"/>
+ /// <seealso cref="MediaTestSource"/>
+ /// <seealso cref="MediaPacketSource"/>
+ /// <seealso cref="AddSources"/>
+ /// <seealso cref="RemoveSource"/>
+ /// <seealso cref="RemoveSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void AddSource(MediaSource source)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException(nameof(source), "source is null");
+ }
+
+ ValidateWebRTCState(WebRTCState.Idle);
+
+ source?.AttachTo(this);
+
+ _source.Add(source);
+ }
+
+ /// <summary>
+ /// Adds media sources.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/>.<br/>
+ /// Each MediaSource requires different feature or privilege.<br/>
+ /// <see cref="MediaCameraSource"/> needs camera feature and privilege.<br/>
+ /// <see cref="MediaFileSource"/> needs mediastorage or externalstorage privilege.<br/>
+ /// <see cref="MediaMicrophoneSource"/> needs microphone feature and recorder privilege.<br/>
+ /// </remarks>
+ /// <param name="sources">The media sources to add.</param>
+ /// <feature>http://tizen.org/feature/camera</feature>
+ /// <feature>http://tizen.org/feature/microphone</feature>
+ /// <privilege>http://tizen.org/privilege/camera</privilege>
+ /// <privilege>http://tizen.org/privilege/mediastorage</privilege>
+ /// <privilege>http://tizen.org/privilege/externalstorage</privilege>
+ /// <privilege>http://tizen.org/privilege/recorder</privilege>
+ /// <exception cref="ArgumentNullException">The media source is null.</exception>
+ /// <exception cref="InvalidOperationException">
+ /// The WebRTC is not in the valid state.<br/>
+ /// - or -<br/>
+ /// All or one of <paramref name="sources"/> was already detached.
+ /// </exception>
+ /// <exception cref="NotSupportedException">The required feature is not supported.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <exception cref="UnauthorizedAccessException">Thrown when the permission is denied.</exception>
+ /// <seealso cref="MediaCameraSource"/>
+ /// <seealso cref="MediaMicrophoneSource"/>
+ /// <seealso cref="MediaTestSource"/>
+ /// <seealso cref="MediaPacketSource"/>
+ /// <seealso cref="AddSource"/>
+ /// <seealso cref="RemoveSource"/>
+ /// <seealso cref="RemoveSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void AddSources(params MediaSource[] sources)
+ {
+ foreach (var source in sources)
+ {
+ AddSource(source);
+ }
+ }
+
+ /// <summary>
+ /// Removes media source.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/>.<br/>
+ /// If user want to use removed MediaSource again, user should create new instance for it.
+ /// </remarks>
+ /// <param name="source">The media source to remove.</param>
+ /// <exception cref="ArgumentNullException">The media source is null.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="MediaCameraSource"/>
+ /// <seealso cref="MediaMicrophoneSource"/>
+ /// <seealso cref="MediaTestSource"/>
+ /// <seealso cref="MediaPacketSource"/>
+ /// <seealso cref="AddSource"/>
+ /// <seealso cref="AddSources"/>
+ /// <seealso cref="RemoveSources"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void RemoveSource(MediaSource source)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException(nameof(source), "source is null");
+ }
+
+ ValidateWebRTCState(WebRTCState.Idle);
+
+ source?.DetachFrom(this);
+
+ _source.Remove(source);
+
+ source = null;
+ }
+
+ /// <summary>
+ /// Removes media sources.
+ /// </summary>
+ /// <remarks>
+ /// The WebRTC must be in the <see cref="WebRTCState.Idle"/>.<br/>
+ /// If user want to use removed MediaSource again, user should create new instance for it.
+ /// </remarks>
+ /// <param name="sources">The media source to remove.</param>
+ /// <exception cref="ArgumentNullException">The media source is null.</exception>
+ /// <exception cref="InvalidOperationException">The WebRTC is not in the valid state.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <seealso cref="MediaCameraSource"/>
+ /// <seealso cref="MediaMicrophoneSource"/>
+ /// <seealso cref="MediaTestSource"/>
+ /// <seealso cref="MediaPacketSource"/>
+ /// <seealso cref="AddSource"/>
+ /// <seealso cref="AddSources"/>
+ /// <seealso cref="RemoveSource"/>
+ /// <since_tizen> 9 </since_tizen>
+ public void RemoveSources(params MediaSource[] sources)
+ {
+ foreach (var source in sources)
+ {
+ RemoveSource(source);
+ }
+ }
+
+ /// <summary>
+ /// Sets a turn server.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">The <paramref name="turnServer"/> is null.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void SetTurnServer(string turnServer)
+ {
+ ValidateNotDisposed();
+
+ if (turnServer == null)
+ {
+ throw new ArgumentNullException(nameof(turnServer), "Turn server name is null.");
+ }
+
+ NativeWebRTC.AddTurnServer(Handle, turnServer).
+ ThrowIfFailed("Failed to add turn server");
+ }
+
+ /// <summary>
+ /// Sets turn servers.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">The one of <paramref name="turnServers"/> is null.</exception>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void SetTurnServers(params string[] turnServers)
+ {
+ ValidateNotDisposed();
+
+ foreach (var turnServer in turnServers)
+ {
+ SetTurnServer(turnServer);
+ }
+ }
+
+ /// <summary>
+ /// Gets all turn servers.
+ /// </summary>
+ /// <returns>The turn server list.</returns>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public ReadOnlyCollection<string> GetTurnServer()
+ {
+ ValidateNotDisposed();
+
+ var list = new List<string>();
+
+ NativeWebRTC.RetrieveTurnServerCallback callback = (server, _) =>
+ {
+ if (!string.IsNullOrWhiteSpace(server))
+ {
+ list.Add(server);
+ }
+
+ return true;
+ };
+
+ NativeWebRTC.ForeachTurnServer(Handle, callback).ThrowIfFailed("Failed to retrieve turn server");
+
+ return list.AsReadOnly();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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 static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides the ability to control WebRTC data channel.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public partial class WebRTCDataChannel
+ {
+ private NativeDataChannel.OpenedCallback _webRtcDataChannelOpenedCallback;
+ private NativeDataChannel.ClosedCallback _webRtcDataChannelClosedCallback;
+ private NativeDataChannel.MessageReceivedCallback _webRtcDataChannelMsgRecvCallback;
+ private NativeDataChannel.ErrorOccurredCallback _webRtcDataChannelErrorOccurredCallback;
+
+ /// <summary>
+ /// Occurs when the data channel's underlying data transport is established.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<EventArgs> Opened;
+
+ /// <summary>
+ /// Occurs when the data channel has closed down.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<EventArgs> Closed;
+
+ /// <summary>
+ /// Occurs when a message is received from the remote peer.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCDataChannelMessageReceivedEventArgs> MessageReceived;
+
+ /// <summary>
+ /// Occurs when an error occurs on the data channel.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public event EventHandler<WebRTCDataChannelErrorOccurredEventArgs> ErrorOccurred;
+
+ private void RegisterEvents()
+ {
+ RegisterDataChannelOpenedCallback();
+ RegisterDataChannelClosedCallback();
+ RegisterDataChannelMsgRecvCallback();
+ RegisterDataChannelErrorOccurredCallback();
+ }
+
+ private void RegisterDataChannelOpenedCallback()
+ {
+ _webRtcDataChannelOpenedCallback = (dataChannelHandle, _) =>
+ {
+ Opened?.Invoke(this, new EventArgs());
+ };
+
+ NativeDataChannel.SetOpenedCb(_handle, _webRtcDataChannelOpenedCallback).
+ ThrowIfFailed("Failed to set data channel opened callback.");
+ }
+
+ private void RegisterDataChannelMsgRecvCallback()
+ {
+ _webRtcDataChannelMsgRecvCallback = (dataChannelHandle, type, message, _) =>
+ {
+ MessageReceived?.Invoke(this, new WebRTCDataChannelMessageReceivedEventArgs(type, message));
+ };
+
+ NativeDataChannel.SetMessageReceivedCb(_handle, _webRtcDataChannelMsgRecvCallback).
+ ThrowIfFailed("Failed to set data channel message received callback.");
+ }
+
+ private void RegisterDataChannelErrorOccurredCallback()
+ {
+ _webRtcDataChannelErrorOccurredCallback = (dataChannelHandle, error, _) =>
+ {
+ ErrorOccurred?.Invoke(this, new WebRTCDataChannelErrorOccurredEventArgs((WebRTCError)error));
+ };
+
+ NativeDataChannel.SetErrorOccurredCb(_handle, _webRtcDataChannelErrorOccurredCallback).
+ ThrowIfFailed("Failed to set data channel error callback.");
+ }
+
+ private void RegisterDataChannelClosedCallback()
+ {
+ _webRtcDataChannelClosedCallback = (dataChannelHandle, _) =>
+ {
+ Closed?.Invoke(this, new EventArgs());
+ };
+
+ NativeDataChannel.SetClosedCb(_handle, _webRtcDataChannelClosedCallback).
+ ThrowIfFailed("Failed to set data channel closed callback.");
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.ComponentModel;
+using System.Diagnostics;
+using Tizen.Applications;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides the ability to control WebRTC data channel.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public partial class WebRTCDataChannel : IDisposable
+ {
+ private readonly IntPtr _handle;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebRTCDataChannel"/> class.
+ /// </summary>
+ /// <param name="webRtc">The owner of this WebRTCDataChannel.</param>
+ /// <param name="label">The name of this data channel.</param>
+ /// <exception cref="ArgumentNullException">The webRtc or label is null.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCDataChannel(WebRTC webRtc, string label)
+ : this(webRtc, label, null)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebRTCDataChannel"/> class.
+ /// </summary>
+ /// <remarks>
+ /// The bundle is similar format as the RTCDataChannelInit members outlined https://www.w3.org/TR/webrtc/#dom-rtcdatachannelinit.<br/>
+ /// The following attributes can be set to options by using <see cref="Bundle"/> API:<br/>
+ /// 'ordered' of type bool : Whether the channel will send data with guaranteed ordering. The default value is true.<br/>
+ /// 'max-packet-lifetime' of type int : The time in milliseconds to attempt transmitting unacknowledged data. -1 for unset. The default value is -1.<br/>
+ /// 'max-retransmits' of type int : The number of times data will be attempted to be transmitted without acknowledgement before dropping. The default value is -1.<br/>
+ /// 'protocol' of type string : The subprotocol used by this channel. The default value is NULL.<br/>
+ /// 'id' of type int : Override the default identifier selection of this channel. The default value is -1.<br/>
+ /// 'priority' of type int : The priority to use for this channel(1:very low, 2:low, 3:medium, 4:high). The default value is 2.<br/>
+ /// </remarks>
+ /// <param name="webRtc">The owner of this WebRTCDataChannel.</param>
+ /// <param name="label">The name of this data channel.</param>
+ /// <param name="bundle">The data channel option.</param>
+ /// <exception cref="ArgumentNullException">The webRtc or label is null.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCDataChannel(WebRTC webRtc, string label, Bundle bundle)
+ {
+ if (webRtc == null)
+ {
+ throw new ArgumentNullException(nameof(webRtc), "WebRTC is not created successfully.");
+ }
+
+ if (string.IsNullOrEmpty(label))
+ {
+ throw new ArgumentNullException(nameof(label), "label is null.");
+ }
+
+ var bundle_ = bundle?.SafeBundleHandle ?? new SafeBundleHandle();
+ NativeDataChannel.Create(webRtc.Handle, label, bundle_, out _handle).
+ ThrowIfFailed("Failed to create webrtc data channel");
+
+ Debug.Assert(_handle != null);
+
+ Label = label;
+
+ RegisterEvents();
+ }
+
+ internal WebRTCDataChannel(IntPtr dataChannelHandle)
+ {
+ if (dataChannelHandle == IntPtr.Zero)
+ {
+ throw new ArgumentNullException(nameof(dataChannelHandle),
+ "WebRTC is not created successfully in native");
+ }
+
+ _handle = dataChannelHandle;
+
+ NativeDataChannel.GetLabel(_handle, out string label).
+ ThrowIfFailed("Failed to get label");
+
+ Label = label;
+
+ Log.Info(WebRTCLog.Tag, "Register event");
+ RegisterEvents();
+ }
+
+ private IntPtr Handle
+ {
+ get
+ {
+ ValidateNotDisposed();
+ return _handle;
+ }
+ }
+
+ /// <summary>
+ /// Gets the label of this data channel.
+ /// </summary>
+ /// <value>The label.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public string Label { get; }
+
+ /// <summary>
+ /// Sends a string data across the data channel to the remote peer.
+ /// </summary>
+ /// <param name="data">The string data to send</param>
+ /// <since_tizen> 9 </since_tizen>
+ public void Send(string data)
+ {
+ ValidateNotDisposed();
+
+ NativeDataChannel.SendString(Handle, data).
+ ThrowIfFailed("Failed to send string data");
+ }
+
+ /// <summary>
+ /// Sends byte data across the data channel to the remote peer.
+ /// </summary>
+ /// <param name="data">The byte data to send</param>
+ /// <since_tizen> 9 </since_tizen>
+ public void Send(byte[] data)
+ {
+ ValidateNotDisposed();
+
+ if (data == null)
+ {
+ throw new ArgumentNullException(nameof(data), "data is null");
+ }
+
+ NativeDataChannel.SendBytes(Handle, data, (uint)data.Length).
+ ThrowIfFailed("Failed to send bytes data");
+ }
+
+ #region Dispose support
+ private bool _disposed;
+
+ /// <summary>
+ /// Releases all resources used by the current instance.
+ /// </summary>
+ /// <exception cref="ObjectDisposedException">The WebRTC has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the <see cref="WebRTCDataChannel"/>.
+ /// </summary>
+ /// <param name="disposing">
+ /// true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.
+ /// </param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed || !disposing)
+ {
+ return;
+ }
+
+ if (true)
+ {
+ NativeDataChannel.Destroy(_handle);
+ _disposed = true;
+ }
+ }
+
+ private void ValidateNotDisposed()
+ {
+ if (_disposed)
+ {
+ Log.Warn(WebRTCLog.Tag, "WebRTCDataChannel was disposed");
+ throw new ObjectDisposedException(nameof(WebRTCDataChannel));
+ }
+ }
+ #endregion Dispose support
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTCDataChannel.ErrorOccurred"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCDataChannelErrorOccurredEventArgs : EventArgs
+ {
+ internal WebRTCDataChannelErrorOccurredEventArgs(WebRTCError error)
+ {
+ Error = error;
+ }
+
+ /// <summary>
+ /// Gets the error.
+ /// </summary>
+ /// <value>The error.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCError Error { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"Error={Error}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.DataChannel"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCDataChannelEventArgs : EventArgs
+ {
+ internal WebRTCDataChannelEventArgs(IntPtr dataChannelHandle)
+ {
+ DataChannel = new WebRTCDataChannel(dataChannelHandle);
+ }
+
+ /// <summary>
+ /// Gets the created data channel instance.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCDataChannel DataChannel { get; }
+ }
+}
--- /dev/null
+/*
+ * 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.Runtime.InteropServices;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTCDataChannel.MessageReceived"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCDataChannelMessageReceivedEventArgs : EventArgs
+ {
+ internal WebRTCDataChannelMessageReceivedEventArgs(DataChannelType type, IntPtr message)
+ {
+ Type = type;
+
+ if (type == DataChannelType.Strings)
+ {
+ Message = Marshal.PtrToStringAnsi(message);
+ }
+ else
+ {
+ NativeDataChannel.GetData(message, out IntPtr data, out ulong size).
+ ThrowIfFailed("Failed to get data");
+
+ Data = new byte[(int)size];
+ Marshal.Copy(data, Data, 0, (int)size);
+ }
+ }
+
+ /// <summary>
+ /// Gets the data channel type.
+ /// </summary>
+ /// <value>The data channel type.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public DataChannelType Type { get; }
+
+ /// <summary>
+ /// Gets the string message from remote peer.
+ /// </summary>
+ /// <remarks>
+ /// If <see cref="WebRTCDataChannelMessageReceivedEventArgs.Type"/> is <see cref="DataChannelType.Bytes"/>, this property is null.
+ /// </remarks>
+ /// <value>The message.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public string Message { get; }
+
+ #pragma warning disable CA1819 // the purpose of this member is to pass received data to user, no need to protect it from changes
+ /// <summary>
+ /// Gets the byte data from remote peer.
+ /// </summary>
+ /// <remarks>
+ /// If <see cref="WebRTCDataChannelMessageReceivedEventArgs.Type"/> is <see cref="DataChannelType.Strings"/>, this property is null.
+ /// </remarks>
+ /// <value>The message.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public byte[] Data { get; }
+ #pragma warning restore CA1819
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"Channel type={Type}, Message={Message}";
+ }
+}
--- /dev/null
+/*
+ * 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.ComponentModel;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Specifies errors.
+ /// </summary>
+ /// <seealso cref="WebRTC.ErrorOccurred"/>
+ /// <seealso cref="WebRTCErrorOccurredEventArgs"/>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCError
+ {
+ /// <summary>
+ /// The connection failed.
+ /// </summary>
+ ConnectionFailed = WebRTCErrorCode.ConnectionFailed,
+
+ /// <summary>
+ /// The stream failed.
+ /// </summary>
+ StreamFailed = WebRTCErrorCode.StreamFailed,
+
+ /// <summary>
+ /// The resource failed.
+ /// </summary>
+ ResourceFailed = WebRTCErrorCode.ResourceFailed,
+
+ /// <summary>
+ /// The resource conflicted.
+ /// </summary>
+ ResourceConflict = WebRTCErrorCode.ResourceConflict,
+
+ /// <summary>
+ /// The invalid operation.
+ /// </summary>
+ InvalidOperation = WebRTCErrorCode.InvalidOperation
+ }
+
+ /// <summary>
+ /// Specifies states that a <see cref="WebRTC"/> can have.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCState
+ {
+ /// <summary>
+ /// The Initial state, create but not started.
+ /// </summary>
+ Idle,
+
+ /// <summary>
+ /// Started and negotiating.
+ /// </summary>
+ Negotiating,
+
+ /// <summary>
+ /// Negotiated and started all streams.
+ /// </summary>
+ Playing,
+ }
+
+ /// <summary>
+ /// Specifies ICE gathering states that a <see cref="WebRTC"/> can have.
+ /// </summary>
+ /// <seealso cref="WebRTC.IceCandidate"/>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCIceGatheringState
+ {
+ /// <summary>
+ /// The Initial state.
+ /// </summary>
+ New,
+
+ /// <summary>
+ /// Ice candidate is creating.
+ /// </summary>
+ Gathering,
+
+ /// <summary>
+ /// Ice gathering sequence has been completed.
+ /// </summary>
+ Completed,
+ }
+
+ /// <summary>
+ /// Specifies signaling states that a <see cref="WebRTC"/> can have.
+ /// </summary>
+ /// <remarks>This state is related in SDP offer/answer.</remarks>
+ /// <seealso cref="WebRTC.SetLocalDescription"/>
+ /// <seealso cref="WebRTC.SetRemoteDescription"/>
+ /// <seealso cref="WebRTC.CreateAnswer()"/>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCSignalingState
+ {
+ /// <summary>
+ /// The Initial state.
+ /// </summary>
+ Stable,
+
+ /// <summary>
+ /// The local SDP offer has been applied successfully.
+ /// </summary>
+ HaveLocalOffer,
+
+ /// <summary>
+ /// The remote SDP offer has been applied successfully.
+ /// </summary>
+ HaveRemoteOffer,
+
+ /// <summary>
+ /// The SDP offer sent by the remote peer has been applied and <br/>
+ /// an answer has been created and applied.
+ /// </summary>
+ HaveLocalPrAnswer,
+
+ /// <summary>
+ /// A provisional answer has been received and successfully applied in local.
+ /// </summary>
+ HaveRemotePrAnswer,
+
+ /// <summary>
+ /// The connection is closed.
+ /// </summary>
+ Closed
+ }
+
+ /// <summary>
+ /// Specifies peer connection states that a <see cref="WebRTC"/> can have.
+ /// </summary>
+ /// <remarks>This state is related in peer connection.</remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCPeerConnectionState
+ {
+ /// <summary>
+ /// The Initial state.
+ /// </summary>
+ New,
+
+ /// <summary>
+ /// Establishing a connection is in the process.
+ /// </summary>
+ Connecting,
+
+ /// <summary>
+ /// The remote SDP offer has been applied successfully.
+ /// </summary>
+ Connected,
+
+ /// <summary>
+ /// The SDP offer sent by the remote peer has been applied and an answer has been created and applied.
+ /// </summary>
+ Disconnected,
+
+ /// <summary>
+ /// A provisional answer has been received and successfully applied in local.
+ /// </summary>
+ Failed,
+
+ /// <summary>
+ /// The connection is closed.
+ /// </summary>
+ Closed
+ }
+
+ /// <summary>
+ /// Specifies ICE connection states that a <see cref="WebRTC"/> can have.
+ /// </summary>
+ /// <remarks>This state describe the current state of local and its connection to the ICE server(STUN or TURN).</remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCIceConnectionState
+ {
+ /// <summary>
+ /// The Initial state.
+ /// </summary>
+ New,
+
+ /// <summary>
+ /// Checking pairs of local and remote candidates against one another to try to find a compatible match.
+ /// </summary>
+ Checking,
+
+ /// <summary>
+ /// A usable pairing of local and remote candidates has been found for all components of the connection,<br/>
+ /// and the connection has been established.
+ /// </summary>
+ Connected,
+
+ /// <summary>
+ /// Gathering candidates has been finished and hecked all pairs against one another,<br/>
+ /// and has found a connection for all components.
+ /// </summary>
+ Completed,
+
+ /// <summary>
+ /// There's no compatible matches.
+ /// </summary>
+ Failed,
+
+ /// <summary>
+ /// This is a less stringent test than "Failed" and may trigger intermittently and resolve just as spontaneously on less reliable networks,<br/>
+ /// or during temporary disconnections. When the problem resolves, the connection may return to the "connected" state.
+ /// </summary>
+ Disconnected,
+
+ /// <summary>
+ /// Closed.
+ /// </summary>
+ Closed
+ }
+
+ internal static class WebRTCStateExtensions
+ {
+ internal static bool IsAnyOf<T>(this T thisState, params T[] states) =>
+ Array.IndexOf<T>(states, thisState) != -1;
+ }
+
+ /// <summary>
+ /// Specifies data type that transfers on data channel.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public enum DataChannelType
+ {
+ /// <summary>
+ /// The string data type.
+ /// </summary>
+ Strings,
+
+ /// <summary>
+ /// The byte data type.
+ /// </summary>
+ Bytes,
+ }
+
+ /// <summary>
+ /// Specifies the buffer state type of <see cref="MediaPacketSource"/>.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public enum MediaPacketBufferStatus
+ {
+ /// <summary>
+ /// The buffer underrun.
+ /// </summary>
+ Underrun,
+
+ /// <summary>
+ /// The buffer overflow.
+ /// </summary>
+ Overflow,
+ }
+
+ /// <summary>
+ /// Specifies the media type.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public enum MediaType
+ {
+ /// <summary>
+ /// The audio type.
+ /// </summary>
+ Audio,
+
+ /// <summary>
+ /// The video type.
+ /// </summary>
+ Video,
+ }
+
+ /// <summary>
+ /// Specifies the transceiver direction type.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public enum TransceiverDirection
+ {
+ /// <summary>
+ /// Send only.
+ /// </summary>
+ SendOnly,
+
+ /// <summary>
+ /// Receive only.
+ /// </summary>
+ RecvOnly,
+
+ /// <summary>
+ /// Send and receive.
+ /// </summary>
+ SendRecv,
+ }
+
+ /// <summary>
+ /// Specifies the policy of Ice transport.
+ /// </summary>
+ /// <remarks>
+ /// See also https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum
+ /// </remarks>
+ /// <since_tizen> 9 </since_tizen>
+ public enum IceTransportPolicy
+ {
+ /// <summary>
+ /// All.
+ /// </summary>
+ All,
+
+ /// <summary>
+ /// Relay.
+ /// </summary>
+ Relay
+ }
+
+ /// <summary>
+ /// Specifies the display type.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public enum WebRTCDisplayMode
+ {
+ /// <summary>
+ /// Letter box.
+ /// </summary>
+ LetterBox,
+
+ /// <summary>
+ /// Original size.
+ /// </summary>
+ OriginSize,
+
+ /// <summary>
+ /// Full screen.
+ /// </summary>
+ Full
+ }
+
+ /// <summary>
+ /// Specifies the signaling message type.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum SignalingMessageType
+ {
+ /// <summary>
+ /// Connected.
+ /// </summary>
+ Connected,
+
+ /// <summary>
+ /// Disconnected.
+ /// </summary>
+ Disconnected,
+
+ /// <summary>
+ /// Session established.
+ /// </summary>
+ SessionEstablished,
+
+ /// <summary>
+ /// Session closed.
+ /// </summary>
+ SessionClosed,
+
+ /// <summary>
+ /// SDP(Session Description Protocol).
+ /// </summary>
+ Sdp,
+
+ /// <summary>
+ /// ICE(Interactive Connectivity Establishment) candidate.
+ /// </summary>
+ IceCandidate,
+
+ /// <summary>
+ /// Error.
+ /// </summary>
+ Error,
+ }
+
+ internal enum MediaSourceType
+ {
+ AudioTest,
+
+ VideoTest,
+
+ Microphone,
+
+ Camera,
+
+ Screen,
+
+ File,
+
+ MediaPacket
+ }
+
+ internal enum CustomMediaSourceType
+ {
+ Audio = 7,
+
+ Video
+ }
+
+ internal enum WebRTCDisplayType
+ {
+ Overlay,
+
+ Evas,
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.IO;
+using Tizen.Internals.Errors;
+
+namespace Tizen.Multimedia.Remoting
+{
+ internal enum WebRTCErrorCode
+ {
+ None = ErrorCode.None,
+ FeatureNotSupported = ErrorCode.NotSupported,
+ PermissionDenied = ErrorCode.PermissionDenied,
+ InvalidArgument = ErrorCode.InvalidParameter,
+ InvalidOperation = ErrorCode.InvalidOperation,
+ TizenWebRTCError = -0x03000000,
+ InvalidState = TizenWebRTCError | 0x01,
+ ConnectionFailed = TizenWebRTCError | 0x02,
+ StreamFailed = TizenWebRTCError | 0x03,
+ ResourceFailed = TizenWebRTCError | 0x04,
+ ResourceConflict = TizenWebRTCError | 0x05
+ }
+
+ internal static class WebRTCErrorCodeExtensions
+ {
+ internal static void ThrowIfFailed(this WebRTCErrorCode errorCode, string message)
+ {
+ if (errorCode == WebRTCErrorCode.None)
+ return;
+
+ string errMessage = (message ?? "Operation failed") + " : " + errorCode.ToString() + ".";
+
+ switch (errorCode)
+ {
+ case WebRTCErrorCode.FeatureNotSupported:
+ throw new NotSupportedException(errMessage);
+ case WebRTCErrorCode.InvalidState:
+ case WebRTCErrorCode.ConnectionFailed:
+ case WebRTCErrorCode.StreamFailed:
+ case WebRTCErrorCode.ResourceFailed:
+ case WebRTCErrorCode.ResourceConflict:
+ case WebRTCErrorCode.InvalidOperation:
+ throw new InvalidOperationException(errMessage);
+ case WebRTCErrorCode.InvalidArgument:
+ throw new ArgumentException(errMessage);
+ case WebRTCErrorCode.PermissionDenied:
+ throw new UnauthorizedAccessException(errMessage);
+ }
+ }
+ }
+}
+
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.ErrorOccurred"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCErrorOccurredEventArgs : EventArgs
+ {
+ internal WebRTCErrorOccurredEventArgs(WebRTCError error, WebRTCState state)
+ {
+ Error = error;
+ State = state;
+ }
+
+ /// <summary>
+ /// Gets the error.
+ /// </summary>
+ /// <value>The error.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCError Error { get; }
+
+ /// <summary>
+ /// Gets the current state.
+ /// </summary>
+ /// <value>The state.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCState State { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"Error={Error}, State={State}";
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+namespace Tizen.Multimedia.Remoting
+{
+ internal static class WebRTCFeatures
+ {
+ internal const string Wifi = "http://tizen.org/feature/network.wifi";
+ internal const string Telephony = "http://tizen.org/feature/network.telephony";
+ internal const string Ethernet = "http://tizen.org/feature/network.ethernet";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.AudioFrameEncoded"/> or <see cref="WebRTC.VideoFrameEncoded"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCFrameEncodedEventArgs : EventArgs
+ {
+ internal WebRTCFrameEncodedEventArgs(MediaStreamTrack track, MediaPacket packet)
+ {
+ MediaStreamTrack = track;
+ Packet = packet;
+ }
+
+ /// <summary>
+ /// Gets the track information.
+ /// </summary>
+ /// <value>The media type.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaStreamTrack MediaStreamTrack { get; }
+
+ /// <summary>
+ /// Gets the media packet which has a frame data.
+ /// </summary>
+ /// <value>The media packet which has a frame data.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaPacket Packet { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"MediaType={MediaStreamTrack.Type}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.IceCandidate"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCIceCandidateEventArgs : EventArgs
+ {
+ internal WebRTCIceCandidateEventArgs(string iceCandidate)
+ {
+ ICECandidate = iceCandidate;
+ }
+
+ /// <summary>
+ /// Gets the ICE candidate.
+ /// </summary>
+ /// <value>The ICE candidate.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public string ICECandidate { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"ICE candidate={ICECandidate}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.IceConnectionStateChanged"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCIceConnectionStateChangedEventArgs : EventArgs
+ {
+ internal WebRTCIceConnectionStateChangedEventArgs(WebRTCIceConnectionState state)
+ {
+ State = state;
+ }
+
+ /// <summary>
+ /// The ICE connection state.
+ /// </summary>
+ /// <value>The ICE connection state</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCIceConnectionState State { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"State={State}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.IceGatheringStateChanged"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCIceGatheringStateChangedEventArgs : EventArgs
+ {
+ internal WebRTCIceGatheringStateChangedEventArgs(WebRTCIceGatheringState state)
+ {
+ State = state;
+ }
+
+ /// <summary>
+ /// The current ICE gathering state.
+ /// </summary>
+ /// <value>The ICE gathering state.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCIceGatheringState State { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"State={State}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.PeerConnectionStateChanged"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCPeerConnectionStateChangedEventArgs : EventArgs
+ {
+ internal WebRTCPeerConnectionStateChangedEventArgs(WebRTCPeerConnectionState state)
+ {
+ State = state;
+ }
+
+ /// <summary>
+ /// The peer connection state.
+ /// </summary>
+ /// <value>The peer connection state</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCPeerConnectionState State { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"State={State}";
+ }
+}
--- /dev/null
+/*
+ * 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.ComponentModel;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTCSignalingClient.SignalingMessage"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class WebRTCSignalingEventArgs : EventArgs
+ {
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal WebRTCSignalingEventArgs(SignalingMessageType type, string message)
+ {
+ MessageType = type;
+ Message = message;
+ }
+
+ /// <summary>
+ /// Gets the signaling message type.
+ /// </summary>
+ /// <value>The signaling message type.</value>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public SignalingMessageType MessageType { get; }
+
+ /// <summary>
+ /// Gets the message from remote peer.
+ /// </summary>
+ /// <value>The message.</value>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string Message { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override string ToString() => $"MessageType={MessageType}, Message={Message}";
+ }
+}
--- /dev/null
+/*
+ * 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.ComponentModel;
+using System.Diagnostics;
+using static Interop;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides the ability to control WebRTCSignalingServer.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class WebRTCSignalingServer : IDisposable
+ {
+ private readonly IntPtr _handle;
+ private bool _disposed;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebRTCSignalingServer"/> class.
+ /// </summary>
+ /// <param name="port">The server port.</param>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public WebRTCSignalingServer(int port)
+ {
+ SignalingServer.Create(port, out _handle).
+ ThrowIfFailed("Failed to create signaling");
+
+ Debug.Assert(true);
+ }
+
+ /// <summary>
+ /// Starts the signaling server.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Start()
+ {
+ ValidateNotDisposed();
+
+ SignalingServer.Start(_handle).
+ ThrowIfFailed("Failed to start signaling server");
+ }
+
+ /// <summary>
+ /// Stops the signaling server.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Stop()
+ {
+ ValidateNotDisposed();
+
+ SignalingServer.Stop(_handle).
+ ThrowIfFailed("Failed to stop signaling server");
+ }
+
+ #region dispose support
+ internal bool IsDisposed => _disposed;
+ /// <summary>
+ /// Releases all resources used by the current instance.
+ /// </summary>
+ /// <exception cref="ObjectDisposedException">The WebRTCSignalingServer has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize((object)this);
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the <see cref="WebRTCSignalingServer"/>.
+ /// </summary>
+ /// <param name="disposing">
+ /// true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.
+ /// </param>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed || !disposing)
+ {
+ return;
+ }
+
+ if (_handle != null)
+ {
+ SignalingServer.Destroy(_handle);
+ _disposed = true;
+ }
+ }
+
+ private void ValidateNotDisposed()
+ {
+ if (_disposed)
+ {
+ Log.Error(WebRTCLog.Tag, "WebRTCSignalingServer was disposed");
+ throw new ObjectDisposedException(nameof(WebRTCSignalingServer));
+ }
+ }
+ #endregion dispose support
+ }
+
+
+ /// <summary>
+ /// Provides the ability to control WebRTCSignalingClient.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class WebRTCSignalingClient : IDisposable
+ {
+ private readonly IntPtr _handle;
+ private bool _isConnected;
+ private SignalingClient.SignalingMessageCallback _signalingMessageCallback;
+ private bool _disposed;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebRTCSignalingClient"/> class.
+ /// </summary>
+ /// <param name="serverIp">The server IP.</param>
+ /// <param name="port">The server port.</param>
+ /// <seealso cref="GetID"/>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public WebRTCSignalingClient(string serverIp, int port)
+ {
+ IntPtr zero = IntPtr.Zero;
+
+ ValidationUtil.ValidateIsNullOrEmpty(serverIp, nameof(serverIp));
+
+ _signalingMessageCallback = (type, message, _) =>
+ {
+ Log.Info(WebRTCLog.Tag, $"type:{type}, message:{message}");
+
+ if (type == SignalingMessageType.Connected)
+ {
+ _isConnected = true;
+ }
+
+ SignalingMessage?.Invoke(this, new WebRTCSignalingEventArgs(type, message));
+ };
+
+ SignalingClient.Connect(serverIp, port, _signalingMessageCallback, zero, out _handle).
+ ThrowIfFailed("Failed to connect to server");
+ }
+
+ /// <summary>
+ /// Occurs when a message to be handled is sent from the remote peer or the signaling server.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event EventHandler<WebRTCSignalingEventArgs> SignalingMessage;
+
+ /// <summary>
+ /// Gets the state whether signaling client is connected to remote peer or not.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool IsConnected => _isConnected;
+
+ /// <summary>
+ /// Gets the signaling client ID.
+ /// </summary>
+ /// <remarks>
+ /// This method must be called after <see cref="SignalingMessage"/> event is occurred with <see cref="SignalingMessageType.Connected"/>.
+ /// </remarks>
+ /// <returns>The signaling client ID.</returns>
+ /// <exception cref="ObjectDisposedException">The WebRTCSignalingClient has already been disposed.</exception>
+ /// <exception cref="InvalidOperationException">The signaling client is not connected yet.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int GetID()
+ {
+ ValidateNotDisposed();
+
+ if (!IsConnected)
+ {
+ throw new InvalidOperationException("Client is not connected to server yet.");
+ }
+
+ SignalingClient.GetID(_handle, out int id).
+ ThrowIfFailed("Failed to get signaling client ID");
+
+ return id;
+ }
+
+ /// <summary>
+ /// Requests session with peer ID.
+ /// </summary>
+ /// <param name="peerId">The ID of remote peer.</param>
+ /// <exception cref="ObjectDisposedException">The WebRTCSignalingClient has already been disposed.</exception>
+ /// <see cref="SignalingMessageType.SessionEstablished"/>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RequestSession(int peerId)
+ {
+ ValidateNotDisposed();
+
+ SignalingClient.RequestSession(_handle, peerId).
+ ThrowIfFailed("Failed to request session to peer");
+ }
+
+ /// <summary>
+ /// Sends the signaling message to remote peer.
+ /// </summary>
+ /// <param name="message"></param>
+ /// <exception cref="ObjectDisposedException">The WebRTCSignalingClient has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SendMessage(string message)
+ {
+ ValidateNotDisposed();
+
+ SignalingClient.SendMessage(_handle, message).
+ ThrowIfFailed("Failed to send message to peer");
+ }
+
+ #region dispose support
+ internal bool IsDisposed => _disposed;
+ /// <summary>
+ /// Releases all resources used by the current instance.
+ /// </summary>
+ /// <exception cref="ObjectDisposedException">The WebRTCSignalingClient has already been disposed.</exception>
+ /// <since_tizen> 9 </since_tizen>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize((object)this);
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources used by the <see cref="WebRTCSignalingClient"/>.
+ /// </summary>
+ /// <param name="disposing">
+ /// true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.
+ /// </param>
+ /// <since_tizen> 9 </since_tizen>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed || !disposing)
+ {
+ return;
+ }
+
+ if (_handle != null)
+ {
+ SignalingClient.Disconnect(_handle);
+
+ _isConnected = false;
+ _disposed = true;
+ }
+ }
+
+ private void ValidateNotDisposed()
+ {
+ if (_disposed)
+ {
+ Log.Error(WebRTCLog.Tag, "WebRTCSignalingClient was disposed");
+ throw new ObjectDisposedException(nameof(WebRTCSignalingClient));
+ }
+ }
+ #endregion dispose support
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.SignalingStateChanged"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCSignalingStateChangedEventArgs : EventArgs
+ {
+ internal WebRTCSignalingStateChangedEventArgs(WebRTCSignalingState state)
+ {
+ State = state;
+ }
+
+ /// <summary>
+ /// The signaling state.
+ /// </summary>
+ /// <value>The signaling state</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCSignalingState State { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"State={State}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.StateChanged"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCStateChangedEventArgs : EventArgs
+ {
+ internal WebRTCStateChangedEventArgs(WebRTCState previous, WebRTCState current)
+ {
+ Previous = previous;
+ Current = current;
+ }
+
+ /// <summary>
+ /// The previous state.
+ /// </summary>
+ /// <value>The previous WebRTC state</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCState Previous { get; }
+
+ /// <summary>
+ /// The current state.
+ /// </summary>
+ /// <value>The current WebRTC state</value>
+ /// <since_tizen> 9 </since_tizen>
+ public WebRTCState Current { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"Previous state={Previous}, Current state={Current}";
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+namespace Tizen.Multimedia.Remoting
+{
+ /// <summary>
+ /// Provides data for the <see cref="WebRTC.TrackAdded"/> event.
+ /// </summary>
+ /// <since_tizen> 9 </since_tizen>
+ public class WebRTCTrackAddedEventArgs : EventArgs
+ {
+ internal WebRTCTrackAddedEventArgs(MediaStreamTrack track)
+ {
+ MediaStreamTrack = track;
+ }
+
+ /// <summary>
+ /// Gets the media type.
+ /// </summary>
+ /// <value>The media type.</value>
+ /// <since_tizen> 9 </since_tizen>
+ public MediaStreamTrack MediaStreamTrack { get; }
+
+ /// <summary>
+ /// Returns a string that represents the current object.
+ /// </summary>
+ /// <returns>A string that represents the current object.</returns>
+ /// <since_tizen> 9 </since_tizen>
+ public override string ToString() => $"MediaType={MediaStreamTrack.Type}";
+ }
+}