Lit: reference a HTML video element from typescript code

How do I reference a HTML video element from the typescript class, as shown below:

File src/main/frontend/src/eyevinn-webrtc-player.ts is:

import { html, LitElement } from 'lit';
import { WebRTCPlayer } from '@eyevinn/webrtc-player';

class EyevinnWebRTCPlayer extends LitElement {
  render() {
    return html`
       <video id="webrtc-player" controls=true autoplay=false></video>
    `;
  }

  play(channelUrl: string) {

    const video = document.getElementById('webrtc-player') as HTMLVideoElement;

    const player = new WebRTCPlayer({
      video: video,
      type: 'whep',
      statsTypeFilter: '^candidate-*|^inbound-rtp'
    });
    player.load(new URL(channelUrl));
    player.unmute();
  }
}

customElements.define('eyevinn-webrtc-player', EyevinnWebRTCPlayer);

The issue is in the following line:

const video = document.getElementById('webrtc-player') as HTMLVideoElement;

which results in null value assigned to video variable.

The corresponding Java class is:

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.littemplate.LitTemplate;

@Tag("eyevinn-webrtc-player")
@NpmPackage(value = "@eyevinn/webrtc-player", version = "^0.13.0")
@JsModule("./src/eyevinn-webrtc-player.ts")
public class EyevinnWebrtcPlayer extends LitTemplate {

    private final String whepUrl;

    /**
     * Construct new Eyevinn WebRTC player component.
     *
     * @param whepUrl       the full URL to the video source, e.g. http://localhost:8889/cam1/whep
     */
    public EyevinnWebrtcPlayer(final String whepUrl) {
        super();

        this.whepUrl = whepUrl;

    }


    /**
     * Display the WebRTC Video player element on the web page.
     */
    public void play() {

        getElement ().executeJs (
                    String.format("return this.play('%s');", this.whepUrl));
        
    }
}

Any idea how to invoke the play() properly and start the WebRTC stream ?

Hi,

Take a look at Working with Shadow DOM – Lit

1 Like

Thanks @Artur.

Here’s the working example:

The eyevinn-webrtc-player.ts contains:

import { LitElement, html} from 'lit';
import { WebRTCPlayer } from '@eyevinn/webrtc-player';

class EyevinnWebRTCPlayer extends LitElement {

  private player: WebRTCPlayer | null = null;

  constructor() {
    super();

    console.log('EyevinnWebRTCPlayer instance created.');
  }

  render() {

    console.log('EyevinnWebRTCPlayer rendering HTML Video element with id=webrtc-player.');

    return html`
       <video id="webrtc-player" controls=true autoplay=false></video>
    `;
  }

  firstUpdated() {

    console.log('EyevinnWebRTCPlayer, firstUpdated() invoked.');

    const video = this._webrtcPlayer as HTMLVideoElement;

    this.player = new WebRTCPlayer({
      video: video,
      type: 'whep',
      statsTypeFilter: '^candidate-*|^inbound-rtp'
    });
  }

  get _webrtcPlayer(): HTMLVideoElement | null {

    console.log('EyevinnWebRTCPlayer, getting webrtc-player element.');

    return this.renderRoot?.querySelector('#webrtc-player') ?? null;
  }

  play(channelUrl: string) {

    console.log('EyevinnWebRTCPlayer, play() invoked.');

    if (!this.player) {
        console.log('EyevinnWebRTCPlayer, play() method, this.player is null !');

        return;
    }

    this.player.load(new URL(channelUrl));
    this.player.unmute();
  }

  stop() {

    console.log('EyevinnWebRTCPlayer, stop() invoked.');

    if (!this.player) {
        console.log('EyevinnWebRTCPlayer, stop() method, this.player is null !');

        return;
    }

    this.player.unload();
  }
}

customElements.define('eyevinn-webrtc-player', EyevinnWebRTCPlayer);

And the Java code, EyevinnWebrtcPlayer.java is:

import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.littemplate.LitTemplate;

@Tag("eyevinn-webrtc-player")
@NpmPackage(value = "@eyevinn/webrtc-player", version = "^0.13.0")
@JsModule("./src/eyevinn-webrtc-player.ts")
public class EyevinnWebrtcPlayer extends LitTemplate {

    private final String whepUrl;

    /**
     * Construct new Eyevinn WebRTC player component.
     *
     * @param whepUrl       the full URL to the video source, e.g. http://localhost:8889/cam1/whep
     */
    public EyevinnWebrtcPlayer(final String whepUrl) {
        super();

        this.whepUrl = whepUrl;
    }

    /**
     * Display the WebRTC Video player element on the web page.
     *
     * @param opened    if true, the WebRTC session will open,
     *                  if false it will close the WebRTC session
     */
    public void play(boolean opened) {

        if (opened == true) {

            getElement ().executeJs (
                    String.format("return this.play('%s');", this.whepUrl));
        }
        else {

            stop ();
        }
    }

    /**
     * Close the WebRTC session.
     * You might invoke the {@link #play(boolean)} method with argument <i>opened</i> set to <i>false</i>.
     */
    public void stop() {
        getElement ().executeJs ("return this.stop();");
    }
}

**NOTE: ** In this example, WebRTC player will use WHEP protocol to initiate webrtc connection towards media server or a proxy. I’ve tested with MediaMTX, and the WHEP protocol works (e.g. H.264 stream).

For more information about the @eyevinn/webrtc-player, visit Eyevinn webrtc-player GitHub page.