Angular implementation - Storm JavaScript Player

Below you’ll find a short tutorial on how to implement Storm Player using your own custom component in Angular.

Requirements

  • Node: 16.14+
  • Angular: 16.0.0+

Installation

  1. NPM
                                    
    npm install @stormstreaming/stormplayer
                                
  2. Yarn
                                    
    yarn add @stormstreaming/stormplayer
                                

Sample code

                        
import {
    StormPlayer as StormPlayerClass,
    StormPlayerConfig,
    StormStreamConfig,
    StormPlayerEvent
} from "@stormstreaming/stormplayer";
import {
    Component,
    ElementRef,
    Input,
    OnDestroy,
    OnInit,
    ViewChild
} from '@angular/core';

@Component({
    selector: 'app-storm-player',
    template: ``
})

export class StormPlayer implements OnInit, OnDestroy {

    @ViewChild('target', {
        static: true
    }) target: ElementRef | undefined;

    // @ts-ignore
    @Input() streamData: {
        serverURL: string;
        applicationName: string;
        streamKey: string;
    };

    // @ts-ignore
    @Input() playerSettings: {
        width: number;
        height: number;
        title: string;
        subtitle: string;
    };

    /**
     * Player ID
     */
    containerID: string = "stormContainer_" + Math.round(Math.random() * 1000);

    /**
     * Storm Player Configuration Object
     */
    playerConfig ? : StormPlayerConfig;

    /**
     * Storm Library Configuration Object
     */
    streamConfig ? : StormStreamConfig;

    /**
     * Player itself
     */
    player ? : StormPlayerClass;

    constructor(
        private elementRef: ElementRef,
    ) {}

    ngOnInit() {

        if (!this.elementRef?.nativeElement.hasAttribute("id"))
            this.elementRef.nativeElement.setAttribute("id", this.containerID);
        else
            this.containerID = this.elementRef.nativeElement.getAttribute("id");

        this.streamConfig = {
            configurationType: "embedded",
            stream: {
                serverList: [{
                        host: this.streamData.serverURL,
                        application: this.streamData.applicationName,
                        port: 443,
                        ssl: true
                    } // this is where our storm server url goes
                ],
                sourceList: [{
                    protocol: "storm",
                    streamKey: this.streamData.streamKey,
                }, ],
            },
            settings: {
                autoStart: true,
                debug: {
                    console: {
                        enabled: true,
                        logTypes: ["INFO", "ERROR", "TRACE", "WARNING", "SUCCESS"],
                        monoColor: false,
                    },
                },
            },
        };

        this.playerConfig = {
            containerID: this.containerID,
            width: this.playerSettings.width,
            height: this.playerSettings.height,
            title: this.playerSettings.title,
            subtitle: this.playerSettings.subtitle,
        }

        // start StormPlayer
        this.player = new StormPlayerClass(this.playerConfig, this.streamConfig, true);
        this.player.addEventListener("playbackProgress", this.onPlaybackProgress)
        this.player.initialize();

    }

    onPlaybackProgress(event: StormPlayerEvent["playbackProgress"]) {
        console.log(`Player ID: ${event.ref.getInstanceID()} - Playback Progress Update`);
        console.log(`-- >: streamStartTime (source): ${event.streamStartTime}`);
        console.log(`-- >: streamDuration (source): ${event.streamDuration}`);
        console.log(`-- >: playbackStartTime (this stream): ${event.playbackStartTime}`);
        console.log(`-- >: playbackDuration (this stream): ${event.playbackDuration}`);
    };

    ngOnDestroy() {
        // destroy StormPlayer
        if (this.player) {
            this.player.removeEventListener("playbackProgress", this.onPlaybackProgress);
            this.player.destroy();
        }
    }
}
                    

Code explanation

  1. Imports
                                    
    import {
        StormPlayer as StormPlayerClass,
        StormPlayerConfig,
        StormStreamConfig,
        StormPlayerEvent
    } from "@stormstreaming/stormplayer";
    import {
        Component,
        ElementRef,
        Input,
        OnDestroy,
        OnInit,
        ViewChild
    } from '@angular/core';
                                

    These are the required imports that include Storm Player into your class, along with the required Angular classes.

  2. Player & Stream Input Objects
                                    
    / @ts-ignore
    @Input() streamData: {
        serverURL: string;
        applicationName: string;
        streamKey: string;
    };
    
    // @ts-ignore
    @Input() playerSettings: {
        width: number;
        height: number;
        title: string;
        subtitle: string;
    };
                                

    These simplified parameters will be used to provide all required data to the player. Most settings will remain in this class however.

  3. Assigning id to the parent container
                                    
    if (!this.elementRef?.nativeElement.hasAttribute("id"))
        this.elementRef.nativeElement.setAttribute("id", this.containerID);
    else
        this.containerID = this.elementRef.nativeElement.getAttribute("id");
                                

    For the Storm Player to work properly a parent container must have an id attribute. We can either attach such ID to it, or use an existing one.

  4. Player & Stream Config Objects
                                    
    this.streamConfig = {
        configurationType: "embedded",
        stream: {
            serverList: [{
                    host: this.streamData.serverURL,
                    application: this.streamData.applicationName,
                    port: 443,
                    ssl: true
                } // this is where our storm server url goes
            ],
            sourceList: [{
                protocol: "storm",
                streamKey: this.streamData.streamKey,
            }, ],
        },
        settings: {
            autoStart: true,
            debug: {
                console: {
                    enabled: true,
                },
            },
        },
    };
    
    this.playerConfig = {
        containerID: this.containerID,
        width: this.playerSettings.width,
        height: this.playerSettings.height,
        title: this.playerSettings.title,
        subtitle: this.playerSettings.subtitle,
    };
                                

    These are core Storm Player & Storm Stream configuration objects. You can learn more about configuring this section from the Storm Library - Embedded Configuration and Storm Library - Gateway Configuration (for Storm Cloud).

  5. Player object creation, event registration & initialization
                                    
    // start StormPlayer
    this.player = new StormPlayerClass(this.playerConfig, this.streamConfig, true);
    this.player.addEventListener("playbackProgress", this.onPlaybackProgress)
    this.player.initialize();
                                

    In the first line we create new player instance. The last parameter forces the player to wait for “initialize()” method before starting its code. Between those two methods we can register events to interact with the player. The lists of supported events can be found in the Player Events and Playback Events sections. For a comprehensive description of the API, please refer to the API Methods section.

  6. Sample event-listener callback method
                                    
    onPlaybackProgress(event: StormPlayerEvent["playbackProgress"]) {
        console.log(`Player ID: ${event.ref.getInstanceID()} - Playback Progress Update`);
        console.log(`-- >: streamStartTime (source): ${event.streamStartTime}`);
        console.log(`-- >: streamDuration (source): ${event.streamDuration}`);
        console.log(`-- >: playbackStartTime (this stream): ${event.playbackStartTime}`);
        console.log(`-- >: playbackDuration (this stream): ${event.playbackDuration}`);
    };
                                

    A sample callback method for playbackProgress event.

Embedding player

In order to embed our component in Angular, we need register our component within our module declarations section.

                                
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import {StormPlayer} from "./StormPlayer";

@NgModule({
  ...
  declarations: [
    ...
    StormPlayer
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }
}
                            

One that part is done, we can use the following code to inject player into a page:

                                
<app-storm-player
    [streamData]="{serverURL: 'localhost', applicationName: 'live', streamKey:'test'}"
    [playerSettings]="{ title:'Title goes here', subtitle:'Subtitle', width:640, height:320}"
>
</app-storm-player>