/* * 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 System.Threading.Tasks; using static Interop; namespace Tizen.Multimedia.Remoting { /// /// Provides the ability to control WebRTCSignalingServer. /// [EditorBrowsable(EditorBrowsableState.Never)] public class WebRTCSignalingServer : IDisposable { private readonly IntPtr _handle; private bool _disposed; /// /// Initializes a new instance of the class. /// /// The server port. [EditorBrowsable(EditorBrowsableState.Never)] public WebRTCSignalingServer(int port) { SignalingServer.Create(port, out _handle). ThrowIfFailed("Failed to create signaling"); Debug.Assert(true); } /// /// Starts the signaling server. /// [EditorBrowsable(EditorBrowsableState.Never)] public void Start() { ValidateNotDisposed(); SignalingServer.Start(_handle). ThrowIfFailed("Failed to start signaling server"); } /// /// Stops the signaling server. /// [EditorBrowsable(EditorBrowsableState.Never)] public void Stop() { ValidateNotDisposed(); SignalingServer.Stop(_handle). ThrowIfFailed("Failed to stop signaling server"); } #region dispose support internal bool IsDisposed => _disposed; /// /// Releases all resources used by the current instance. /// /// The WebRTCSignalingServer has already been disposed. public void Dispose() { Dispose(true); GC.SuppressFinalize((object)this); } /// /// Releases the unmanaged resources used by the . /// /// /// true to release both managed and unmanaged resources; /// false to release only unmanaged resources. /// [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 } /// /// Provides the ability to control WebRTCSignalingClient. /// [EditorBrowsable(EditorBrowsableState.Never)] public class WebRTCSignalingClient : IDisposable { private IntPtr _handle; private bool _isConnected; private (string serverIp, int port) _serverInfo; private SignalingClient.SignalingMessageCallback _signalingMessageCallback; private bool _disposed; /// /// Initializes a new instance of the class. /// /// The server IP. /// The server port. /// [EditorBrowsable(EditorBrowsableState.Never)] public WebRTCSignalingClient(string serverIp, int port) { ValidationUtil.ValidateIsNullOrEmpty(serverIp, nameof(serverIp)); if (port < 0) { throw new ArgumentException("port should be greater than zero."); } _serverInfo.serverIp = serverIp; _serverInfo.port = port; } /// /// Occurs when a message to be handled is sent from the remote peer or the signaling server. /// [EditorBrowsable(EditorBrowsableState.Never)] public event EventHandler SignalingMessage; /// /// Connect to signaling server and return client id. /// /// The signaling client ID. /// The WebRTCSignalingClient has already been disposed. [EditorBrowsable(EditorBrowsableState.Never)] public async Task Connect() { ValidateNotDisposed(); var tcsConnected = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _signalingMessageCallback = (type, message, _) => { Log.Info(WebRTCLog.Tag, $"type:{type}, message:{message}"); if (!_isConnected && type == SignalingMessageType.Connected) { _isConnected = true; SignalingClient.GetID(_handle, out int id).ThrowIfFailed("Failed to get signaling client ID"); Log.Info(WebRTCLog.Tag, $"Client ID[{id}]"); tcsConnected.TrySetResult(id); } SignalingMessage?.Invoke(this, new WebRTCSignalingEventArgs(type, message)); }; SignalingClient.Connect(_serverInfo.serverIp, _serverInfo.port, _signalingMessageCallback, IntPtr.Zero, out _handle). ThrowIfFailed("Failed to connect to server"); return await tcsConnected.Task; } /// /// Requests session with peer ID. /// /// The ID of remote peer. /// The WebRTCSignalingClient has already been disposed. /// [EditorBrowsable(EditorBrowsableState.Never)] public void RequestSession(int peerId) { ValidateNotDisposed(); SignalingClient.RequestSession(_handle, peerId). ThrowIfFailed("Failed to request session to peer"); } /// /// Sends the signaling message to remote peer. /// /// /// The WebRTCSignalingClient has already been disposed. [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; /// /// Releases all resources used by the current instance. /// /// The WebRTCSignalingClient has already been disposed. public void Dispose() { Dispose(true); GC.SuppressFinalize((object)this); } /// /// Releases the unmanaged resources used by the . /// /// /// true to release both managed and unmanaged resources; /// false to release only unmanaged resources. /// [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 } }