/*
* 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
}
}