How i can read javascript function in ASP.NET Core Blazor and Camera

Viewed 1192

How I can read javascript function in ASP.NET Core Blazor. I try to read script form javascript to show a picture from camera. I know I can use the API or use the Angular but I want keep easy

I add more file what I build

 @page "/"
@inject IJSRuntime IJR

<h1>Hello, world!</h1>
<div id="container">
    <div class="select">
        <label for="audioSource">Audio input source: </label><select id="audioSource"></select>
    </div>

    <div class="select">
        <label for="audioOutput">Audio output destination: </label><select id="audioOutput"></select>
    </div>

    <div class="select">
        <label for="videoSource">Video source: </label><select id="videoSource"></select>
    </div>

    <video id="video" playsinline autoplay></video>
    <video id="@audo" playsinline autoplay></video>

</div>

@code
{


    public object audo;

    protected override void OnInitialized()
    {
        
        audo = IJR.InvokeAsync<Object>("test.start");

    }

}

This is the javascript

'use strict';

const videoElement = document.querySelector('video');
const audioInputSelect = document.querySelector('select#audioSource');
const audioOutputSelect = document.querySelector('select#audioOutput');
const videoSelect = document.querySelector('select#videoSource');
const selectors = [audioInputSelect, audioOutputSelect, videoSelect];

audioOutputSelect.disabled = !('sinkId' in HTMLMediaElement.prototype);

function gotDevices(deviceInfos) {
  // Handles being called several times to update labels. Preserve values.
  const values = selectors.map(select => select.value);
  selectors.forEach(select => {
    while (select.firstChild) {
      select.removeChild(select.firstChild);
    }
  });
  for (let i = 0; i !== deviceInfos.length; ++i) {
    const deviceInfo = deviceInfos[i];
    const option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'audioinput') {
      option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
      audioInputSelect.appendChild(option);
    } else if (deviceInfo.kind === 'audiooutput') {
      option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
      audioOutputSelect.appendChild(option);
    } else if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
      videoSelect.appendChild(option);
    } else {
      console.log('Some other kind of source/device: ', deviceInfo);
    }
  }
  selectors.forEach((select, selectorIndex) => {
    if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
      select.value = values[selectorIndex];
    }
  });
}

navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);

// Attach audio output device to video element using device/sink ID.
function attachSinkId(element, sinkId) {
  if (typeof element.sinkId !== 'undefined') {
    element.setSinkId(sinkId)
        .then(() => {
          console.log(`Success, audio output device attached: ${sinkId}`);
        })
        .catch(error => {
          let errorMessage = error;
          if (error.name === 'SecurityError') {
            errorMessage = `You need to use HTTPS for selecting audio output device: ${error}`;
          }
          console.error(errorMessage);
          // Jump back to first output device in the list as it's the default.
          audioOutputSelect.selectedIndex = 0;
        });
  } else {
    console.warn('Browser does not support output device selection.');
  }
}

function changeAudioDestination() {
  const audioDestination = audioOutputSelect.value;
  attachSinkId(videoElement, audioDestination);
}

function gotStream(stream) {
  window.stream = stream; // make stream available to console
  videoElement.srcObject = stream;
  // Refresh button list in case labels have become available
  return navigator.mediaDevices.enumerateDevices();
}

function handleError(error) {
  console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);
}

windows.test = {
    start:function{
  if (window.stream) {
    window.stream.getTracks().forEach(track => {
      track.stop();
    });
  }
  const audioSource = audioInputSelect.value;
  const videoSource = videoSelect.value;
  const constraints = {
    audio: {deviceId: audioSource ? {exact: audioSource} : undefined},
    video: {deviceId: videoSource ? {exact: videoSource} : undefined}
  };
  navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
}
};
audioInputSelect.onchange = start;
audioOutputSelect.onchange = changeAudioDestination;

videoSelect.onchange = start;

start();

What is wrong it show any data?

This is the file what use WebRTC and I want us this for capture date

2 Answers

JSInterop in Blazor requires the javascript functions to be declared on the global scope (window). For this to work you should move your JS into it's own file in the web root (e.g. myJsFunctions.js) and declare the function on window:

window.myJsFunctions = {
  start: function() {
    if (window.stream) {
      window.stream.getTracks().forEach(track => {
        track.stop();
      });
    }
    const audioSource = audioInputSelect.value;
    const videoSource = videoSelect.value;
    const constraints = {
      audio: {deviceId: audioSource ? {exact: audioSource} : undefined},
      video: {deviceId: videoSource ? {exact: videoSource} : undefined}
    };
    navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
  }
};

And then load this script in the entry point inside the element of wwwroot/index.html (Blazor WebAssembly) or Pages/_Host.cshtml` (Blazor Server):

<script src="myJsFunctions.js"></script>

And then specify the full path to the function when invoking in your component:

audo = await JSRuntime.InvokeAsync<Object>("myJsFunctions.start");

Also, your start function doesn't appear to return anything. If that's the case, you should call InvokeVoidAsync:

await JSRuntime.InvokeVoidAsync("myJsFunctions.start");

See the docs for more.

Here I'm posting the working code.

Blazor Server App

_Host.cshtml

@page "/"
@namespace WebRtcBlazorApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = null;
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebRtcBlazorApp</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss"></a>
    </div>

    <script src="_framework/blazor.server.js"></script>

    <script src="~/js/JsFunctionText.js"></script>
    <script src="~/js/WebRtc.js"></script>
</body>
</html>

Index.razor

@page "/"

<h1 id="myHeader">Welcome To WebRTC Blazor</h1>

<div id="container">
    <div class="select">
        <label for="audioSource">Audio input source: </label><select id="audioSource"></select>
    </div>

    <div class="select">
        <label for="audioOutput">Audio output destination: </label><select id="audioOutput"></select>
    </div>

    <div class="select">
        <label for="videoSource">Video source: </label><select id="videoSource"></select>
    </div>

    <video id="video" playsinline autoplay></video>
</div>


@code{

    [Inject]
    IJSRuntime JSRuntime { get; set; }

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("test.start");

            StateHasChanged();
        }
    }
}

WebRtc.js ("wwwroot/js/WebRtc.js")

'use strict'


let videoElement;
let audioInputSelect;
let audioOutputSelect;
let videoSelect;
let selectors;
let dummySelect;

function pageReady() {
    videoElement = document.querySelector('video');
    audioInputSelect = document.querySelector('select#audioSource');
    audioOutputSelect = document.querySelector('select#audioOutput');
    videoSelect = document.querySelector('select#videoSource');
    selectors = [audioInputSelect, audioOutputSelect, videoSelect];

    dummySelect = document.querySelector('select#dummy');

    audioOutputSelect.disabled = !('sinkId' in HTMLMediaElement.prototype);

    audioInputSelect.onchange = window.test.start;
    audioOutputSelect.onchange = changeAudioDestination;

    videoSelect.onchange = window.test.start;
}

function gotDevices(deviceInfos) {
    // Handles being called several times to update labels. Preserve values.
    const values = selectors.map(select => select.value);
    selectors.forEach(select => {
        while (select.firstChild) {
            select.removeChild(select.firstChild);
        }
    });
    for (let i = 0; i !== deviceInfos.length; ++i) {
        const deviceInfo = deviceInfos[i];
        const option = document.createElement('option');
        option.value = deviceInfo.deviceId;
        if (deviceInfo.kind === 'audioinput') {
            option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
            audioInputSelect.appendChild(option);
        } else if (deviceInfo.kind === 'audiooutput') {
            option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
            audioOutputSelect.appendChild(option);
        } else if (deviceInfo.kind === 'videoinput') {
            option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
            videoSelect.appendChild(option);
        } else {
            console.log('Some other kind of source/device: ', deviceInfo);
        }
    }
    selectors.forEach((select, selectorIndex) => {
        if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
            select.value = values[selectorIndex];
        }
    });
}

navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);

// Attach audio output device to video element using device/sink ID.
function attachSinkId(element, sinkId) {
    if (typeof element.sinkId !== 'undefined') {
        element.setSinkId(sinkId)
            .then(() => {
                console.log(`Success, audio output device attached: ${sinkId}`);
            })
            .catch(error => {
                let errorMessage = error;
                if (error.name === 'SecurityError') {
                    errorMessage = `You need to use HTTPS for selecting audio output device: ${error}`;
                }
                console.error(errorMessage);
                // Jump back to first output device in the list as it's the default.
                audioOutputSelect.selectedIndex = 0;
            });
    } else {
        console.warn('Browser does not support output device selection.');
    }
}

function changeAudioDestination() {
    const audioDestination = audioOutputSelect.value;
    attachSinkId(videoElement, audioDestination);
}

function gotStream(stream) {
    window.stream = stream; // make stream available to console
    videoElement.srcObject = stream;
    // Refresh button list in case labels have become available
    return navigator.mediaDevices.enumerateDevices();
}

function handleError(error) {
    console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);
}

window.test = {
    start: function () {

        pageReady();

        if (window.stream) {
            window.stream.getTracks().forEach(track => {
                track.stop();
            });
        }
        const audioSource = audioInputSelect.value;
        const videoSource = videoSelect.value;
        const constraints = {
            audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
            video: { deviceId: videoSource ? { exact: videoSource } : undefined }
        };

        
        navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
    }
};

Screen shot attached

Related