WebRTC 2.0 Architecture
C:\Program Files (x86)\Medialooks\MPlatform SDK\Samples WebRTC\C#\WebRTC 2.0
C:\Program Files (x86)\Medialooks\MFormats SDK\Samples WebRTC\C#\WebRTC 2.0
WebRTC 2.0 Delphi Duplex Sample:
https://drive.medialooks.com/index.php/s/gErKF9EYifxHBM8
The main logic for establishing connections is based on channels:
- IMCChannelSGN – used to control and communicate with the signaling server. It allows enumeration of current active channels and access to channel metadata.
- IMCChannel – represents the actual media communication channel, which we previously referred to as a room in WebRTC 1.0.
MConnectClass - used for creating the IMChannel and IMCChannelSGN, connecting to existing channels.
Overview of WebRTCHelper
The WebRTCHelper class used in the samples encapsulates the logic required to manage bi-directional video communication using the Medialooks MConnectClass (IMConnect), IMCChannel, and IMCChannelSGN.
Samples channel establishment logic
To create an IMCChannelSGN instance, call Enum_Create on the MConnectClass. You can then enumerate existing channels. If the required channel doesn't exist, create one using Channel_Create(). If it does, use Channel_Connect() to join it.
As an example of the logic for connecting to a signaling server and joining or creating a channel, you can refer to the samples in WebRTCHelper.Connect method.
public void Connect(string URL)
{
server.Enum_Create(URL + "_enum", "username=test_user password=12345", " ", null, out server_manager);
channel_url = URL;
var members = GetRoomMembers();
if (members.Count <= 0)
{
current_channel = CreateChannel(channel_url);
current_channel.OnEventSafe += new IMEventsEvent_OnEventSafeEventHandler(Current_channel_OnEventSafe);
mode = PeerMode.server;
}
else
{
current_channel = ConnectToChannel(channel_url);
mode = PeerMode.client;
}
}This logic determines the role (server/client) dynamically based on whether the channel already exists.
Sample Authentication and Security
The OnEventSafe channel event handler is triggered when a remote_offer is received, meaning a remote peer is attempting to connect and the channel was created with secured = "true":
Channel_Create(_url, "secured=true", " ", callback, out var channel);You can use OnEventSafe for different scenarios. In our samples, we use a ProtectionForm class to validate incoming peer credentials, but you can implement your own authentication logic. ProtectionForm is provided only as a simple example auth module.
If authorisation fails, the peer is rejected using IMAttributes.AttributesStringSet to set. succeded=false.
void Current_channel_OnEventSafe(string bsChannelID, string bsEventName, string bsEventParam, object pEventObject)
{
if (bsEventName == "remote_offer")
{
try
{
// Cast to IMAttrinutes
MPLATFORMLib.IMAttributes attributes = (pEventObject as MPLATFORMLib.IMAttributes);
if (attributes != null)
{
string all_props;
attributes.AttributesSave(out all_props);
// If connection secured (see CreateChannel params - "secured=true"),
// guest_login, guest_password should be specified in props
// If not secured - only 'name' in props
string guest_login;
attributes.AttributesStringGet("guest_login", out guest_login);
string guest_password;
attributes.AttributesStringGet("guest_password", out guest_password);
if (!secure.IsValid(guest_login, guest_password))
{
attributes.AttributesStringSet("succeded", "false");
attributes.AttributesStringSet("reason", "not_authorized");
}
else
{
attributes.AttributesStringSet("succeded", "true");
}
}
}
catch (Exception ex)
{
}
}
}Sample Peer Enumeration and Metadata
GetRoomMembers() uses VTSG_EnumGetCount and VTSG_EnumGetByIndex to retrieve metadata about connected peers via the IMCChannelSGN interface.
We intentionally skip peers of type "enum", since these peers do not send or receive any video. They are used only for channel enumeration purposes.
public List<IMAttributes> GetRoomMembers()
{
lstChannelsAttributes.Clear();
server_manager.VTSG_EnumGetCount(null, out var count, null);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
server_manager.VTSG_EnumGetByIndex("", i, out var channel, out var channel_props);
channel_props.AttributesStringGet("mode", out var mode);
channel_props.AttributesStringGet("id", out var id);
//skip peers that are enums i.e. for example server.Enum_Create(URL, "username=test_user password=12345", "", null, out server_manager); WebRTCHelper.cs
if (!mode.Equals("enum") && !id.Equals(current_id))
{
lstChannelsAttributes.Add(channel_props);
}
}
}
return lstChannelsAttributes;
}Sample Channel Status Monitoring
GetChannelInfoDetails() retrieves runtime metrics using ChannelInfoGet:
- eDataState: data stream state
- eChannelMode: mode of the channel (enum reference)
- eSGNState: signaling server state (enum reference)
public string GetChannelInfoDetails()
{
current_channel.ChannelInfoGet(out var info);
return
$"eDataState: {info.eDataState}\n" +
$"eChannelMode: {info.eChannelMode}\n" +
$"eSGNState: {info.eSGNState}\n" +
$"nChannelsConnected: {info.nChannelsConnected}\n" +
$"cbDataSend: {info.cbDataSend}\n" +
$"cbDataReceived: {info.cbDataReceived}\n" +
$"dblRcvBandwidth: {info.dblRcvBandwidth}\n" +
$"dblSendBandwidth: {info.dblSendBandwidth}";
}Sample Sending and Receiving Media
-
SendToChannel(MFFrame)– sends a video frame to the channel usingChannelSend. -
ReceiverFrameChannel()– receives frames usingChannelReceive. Ifmix_on_serveris true, it collects and composites frames from all peers.
public MFrame ReceiverFrameChannel()
{
try
{
object frame = null;
// Server. Receive the frames from all connected peers
if (mode == PeerMode.server)
{
//mix all remote peers to one frame
if (mix_on_server)
{
List<MFrame> frames_from_remote_peers = new List<MFrame>();
foreach (string id in peersID)
{
current_channel.ChannelReceive(0, -1, id, out frame, "");
if (frame != null)
frames_from_remote_peers.Add((MFrame)frame);
}
frame = mixFrames(frames_from_remote_peers.ToArray());
}
else
{
current_channel.ChannelReceive(0, -1, show_remote_peer, out frame, "");
}
}
else
{
// Receiver. Just receive the signal from server we can use the empty peer id
current_channel.ChannelReceive(0, -1, "", out frame, "");
}
return (MFrame)frame;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return null;
}The mixFrames() method arranges up to 4 frames into a 2x2 grid on a 1920×1080 canvas using:
-
MFFactoryClass.MFFrameCreateFromMem– to allocate the background frame. -
IMFFrame.MFConvert– to resize incoming frames. -
MFOverlay– to place each frame on the canvas.
Connected Peers List
GetConnectedPeers() retrieves the IDs of peers currently connected using indexed property access (connected[i]::remote::id) from the channel.
public async Task<string[]> GetConnectedPeers()
{
if (current_channel != null)
{
current_channel.ChannelInfoGet(out var info);
int connected_count = info.nChannelsConnected;
if (mode == PeerMode.server)
{
var newpeersID = new ConcurrentBag<string>();
Volatile.Write(ref peersID, newpeersID);
for (int i = 0; i < connected_count; i++)
{
try
{
current_channel.PropsGetCount($"connected[{i}]::remote", out var stat);
current_channel.PropsGet($"connected[{i}]::remote::id", out var connected_id);
peersID.Add(connected_id);
}
catch { }
;
}
}
}
return peersID.ToArray();
}Documentation References
- MConnectClass
- IMConnect
- MCChannelClass
- IMCChannel
- IMCChannelSGN
- eVTSG_State
- eChannelMode
- eMC_ChannelState
This helper class provides a full abstraction for WebRTC 2.0 peer setup and media transmission in duplex or one-way mode using the Medialooks SDK, supporting secure connections and multi-peer mixing.