/// <summary> /// Receives data on <see cref="T:WebAssembly.Net.WebSockets.ClientWebSocket"/> as an asynchronous operation. /// </summary> /// <returns>The async.</returns> /// <param name="buffer">Buffer.</param> /// <param name="cancellationToken">Cancellation token.</param> public async Task <WebRtcReceiveResult> ReceiveAsync(ArraySegment <byte> buffer, CancellationToken cancellationToken) { ThrowIfDisposed(); var tcsReceive = new TaskCompletionSource <WebRtcReceiveResult>(); // Wrap the cancellationToken in a using so that it can be disposed of whether // we successfully receive or not. // Otherwise any timeout/cancellation would apply to the full session. using (cancellationToken.Register(() => tcsReceive.TrySetCanceled())) { if (bufferedPayload == null) { bufferedPayload = await receiveMessageQueue.DequeuePayloadAsync(cancellationToken); } var endOfMessage = bufferedPayload.BufferPayload(buffer, out WebRtcReceiveResult receiveResult); tcsReceive.SetResult(receiveResult); if (endOfMessage) { bufferedPayload = null; } return(await tcsReceive.Task); } }
public RTCDataChannel(JSObject ho) { cts = new CancellationTokenSource(); this.hostObject = ho; _ = Task.Run(Receive); onMessage = new Action <JSObject>((messageEvent) => { ThrowIfNotConnected(); using (messageEvent) { // get the events "data" var eventData = messageEvent.GetObjectProperty("data"); switch (eventData) { case ArrayBuffer buffer: using (buffer) { var mess = new ReceivePayload(buffer, WebSockets.WebSocketMessageType.Binary); receiveMessageQueue.BufferPayload(mess); } break; case JSObject blobData: using (blobData) { // TODO: Handle ArrayBuffer binary type but have only seen 'blob' so far without // changing the default websocket binary type manually. var dataType = hostObject.GetObjectProperty("binaryType").ToString(); if (dataType == "blob") { Action <JSObject> loadend = null; // Create a new "FileReader" object using (var reader = new HostObject("FileReader")) { loadend = new Action <JSObject>((loadEvent) => { using (var target = (JSObject)loadEvent.GetObjectProperty("target")) { if ((int)target.GetObjectProperty("readyState") == 2) { using (var binResult = (ArrayBuffer)target.GetObjectProperty("result")) { var mess = new ReceivePayload(binResult, WebSockets.WebSocketMessageType.Binary); receiveMessageQueue.BufferPayload(mess); //Runtime.FreeObject(loadend); } } } loadEvent.Dispose(); }); reader.Invoke("addEventListener", "loadend", loadend); //using (var blobData = (JSObject)messageEvent.GetObjectProperty("data")) // reader.Invoke("readAsArrayBuffer", blobData); } } else { throw new NotImplementedException($"WebSocket binary type '{hostObject.GetObjectProperty("binaryType").ToString()}' not supported."); } } break; case String message: { var mess = new ReceivePayload(Encoding.UTF8.GetBytes(message), WebSockets.WebSocketMessageType.Text); receiveMessageQueue.BufferPayload(mess); } break; } } }); // Attach the onMessage callaback hostObject.Invoke("addEventListener", "message", onMessage); onOpen = new Action <JSObject>((messageEvent) => { this.OnOpen?.Invoke(this, EventArgs.Empty); messageEvent.Dispose(); }); // Attach the onMessage callaback hostObject.SetObjectProperty("onopen", onOpen); onClose = new Action <JSObject>((messageEvent) => { this.OnClose?.Invoke(this, EventArgs.Empty); messageEvent.Dispose(); }); // Attach the onMessage callaback hostObject.SetObjectProperty("onclose", onClose); }