Search code examples
javascripthtmlaudiohtml5-audiovideo.js

videojs multiple audio languages


how can I add switchable audio tracks within videojs , I was trying by doing this :

 <video id="l2e-video" muted class="video-js vjs-default-skin vjs-big-play-centered" controls width="640" height="264" data-setup="" mediagroup="lang_tracks">
                <source src="http://localhost/1.mp4" type="video/mp4" >
                <track src="http://localhost/1.mp3" kind="descriptions" type="audio/mp3" srclang="en" label="English">
                <track src="http://localhost/1.mp3" kind="descriptions" type="audio/mp3" srclang="ar" label="Arabic">

        </video>

but when I'm trying to load it , it errors :

Text Track parsing errors for http://localhost/1.mp3

{name: "ParsingError", code: 0, message: "Malformed WebVTT signature."}

I have no clue how it says Text track when am explicitly setting the type to audio , how would I achieve having a video with multiple languages?!


Solution

  • So what I have ended up doing is , having one <video> without any sound/voice, and multiple <audio> with different languages , and I sync the video with the audio, here is an implementation using Angular it can be ported to any other framework easily :-

    HTML:

      <div class="video-container">
                                <video id="l2e-video" class="video-js vjs-default-skin vjs-big-play-centered" controls data-setup="" mediagroup="lang_tracks">
                                </video>
                                <audio id="l2e-audio" class="video-js vjs-default-skin" style="display:none"></audio>
        </div>
    

    TypeScript/Javascript:

    import { Video } from './../../models/video';
    import { Point } from './../../models/point';
    import { Audio } from "./../../models/audio";
    import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
    
    
    
    /*NOTES: add overlay for the markers*/
    
    @Component({
        selector: 'videojs',
        templateUrl: './videojs.component.html',
        styleUrls: ['./videojs.component.scss']
    })
    export class VideojsComponent implements OnInit, AfterViewInit, OnDestroy {
    
        video: any = videojs;
        audio: any = videojs;
        prevButton: any = {};
    
        qualities: Array<Video> = [];
        audioLangs: Array<Audio> = [];
    
    
        constructor() {
        }
    
    
        ngOnInit(): void {
            this.qualities = [
                { src: "http://localhost/1.mp4", type: "video/mp4", label: "SD" },
                { src: "http://localhost/1.mp4", type: "video/mp4", label: "HD" },
            ];
            this.audioLangs = [
                { src: 'http://localhost/en.m4a', type: 'audio/mp3', label: "English" },
                { src: 'http://localhost/ar.m4a', type: 'audio/mp3', label: "Arabic" }
            ];
            
        }
    
        ngAfterViewInit(): void {
            this.audio = videojs('l2e-audio', {});
    
            //TODO:: save video lang ,
            this.audio.src(this.audioLangs[0]); //to be changed dynamic
    
            this.video = videojs('l2e-video', {
                fluid: true,
                plugins: {
                
                    videoJsResolutionSwitcher: {
                        default: 'HD',
                        dynamicLabel: true
                    }
                }
            });
    
            this.video.updateSrc(this.qualities);
    
    
            this.Sync(this.video, this.audio);
        }
    
        ngOnDestroy(): void {
            this.video.dispose();
        }
    
    
    
    
        ChangeLang(index) {
            this.audio.src(this.audioLangs[index]);
            this.audio.play();
            this.audio.currentTime(this.video.currentTime());
        }
    
        private Sync(video, audio) {
    
            this.video.on('timeupdate', () => {
                if (!this.video.paused())
                    return;
                this.audio.trigger('timeupdate');
            });
            this.video.on('seeking', () => {
                this.audio.currentTime(this.video.currentTime());
            });
            this.video.on('volumechange', () => {
                if (this.video.muted()) {
                    this.audio.muted(true);
                } else {
                    this.audio.muted(false);
                }
    
                this.audio.volume(this.video.volume());
            });
            this.video.on('play', () => {
                this.audio.play();
            });
            this.video.on('pause', () => {
                this.audio.pause();
            });
        }
    
    }