collab-project / videojs-wavesurfer

video.js plugin that adds a navigable waveform for audio and video files
https://collab-project.github.io/videojs-wavesurfer
MIT License
365 stars 54 forks source link

change src (player.src()) bug that duplicate event fire #151

Open kjw3898 opened 2 years ago

kjw3898 commented 2 years ago

Description

I use this plugin on react, and it's nice project. thanks when I change the src the player, it looks good work.

this.player.src({src: '../media/hal.wav', type: 'audio/wav'});

but it fire event twice. if change the src once more, it fire event 3times

so I tried to find problem from my project, I found weird console message when init page ( first src load)

video.min.js:12 VIDEOJS: Using video.js 7.15.4 with videojs-wavesurfer 3.8.0 and wavesurfer.js 5.2.0
webaudio.js:76 
value @ webaudio.js:76
video.min.js:12 VIDEOJS: Using wavesurfer.js MediaElement backend.
video.min.js:12 VIDEOJS: Loading element: [object HTMLAudioElement]
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!

when change src

VIDEOJS: Loading element: [object HTMLAudioElement]   // first load
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!                   
video.min.js:12 VIDEOJS: Loading element: [object HTMLAudioElement] // change src
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready   <-- duplicated ready event fire
index.js:29 waveform: ready!

when change src again

VIDEOJS: Loading element: [object HTMLAudioElement]   // first load
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Loading element: [object HTMLAudioElement]  // change src
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready    <-- duplicated ready event fire
index.js:29 waveform: ready!
VIDEOJS: Loading element: [object HTMLAudioElement]  // change src again
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready    <-- duplicated ready event fire
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready    <-- duplicated ready event fire
index.js:29 waveform: ready!

if you use other event , that also duplicated . eg. playbackFinish

I tried to some workaround for this problem but not work this.player.wavesurfer().load(item.path) // this code just change src of waveform. not audio(video.js src not changed)

Steps to reproduce

I can reproduce on react example in this repo with little change change the index.js ( /examples/react/index.js) to below code

/**
 * React example.
 */

class VideojsWavesurferPlayer extends React.Component {
    constructor() {
        super();
        this.clickevt = this.clickevt.bind(this);
    }

    clickevt(){
        this.player.src({src: '../media/hal.wav', type: 'audio/wav'});
    }
    componentDidMount() {
        // instantiate Video.js
        this.player = videojs(this.audioNode, this.props, () => {
            // print version information at startup
            var version_info = 'Using video.js ' + videojs.VERSION +
                ' with videojs-wavesurfer ' + videojs.getPluginVersion('wavesurfer') +
                ' and wavesurfer.js ' + WaveSurfer.VERSION;
            videojs.log(version_info);

            // load file
            this.player.src({src: '../media/hal.wav', type: 'audio/wav'});
        });

        this.player.on('waveReady', (event) => {
            console.log('waveform: ready!');
        });

        this.player.on('playbackFinish', (event) => {
            console.log('playback finished.');
        });

        // error handling
        this.player.on('error', (element, error) => {
            console.warn(error);
        });
    }

    // destroy player on unmount
    componentWillUnmount() {
        if (this.player) {
            this.player.dispose();
        }
    }

    // wrap the player in a div with a `data-vjs-player` attribute
    // so videojs won't create additional wrapper in the DOM
    // see https://github.com/videojs/video.js/pull/3856
    render() {
        return (<div>
            <div data-vjs-player>
                <audio id="myAudio" ref={ node => this.audioNode = node } className="video-js vjs-default-skin"></audio>
            </div>
            <button onClick = {this.clickevt}> click!</button></div>
        )
    }
}

const videoJsOptions = {
    controls: true,
    autoplay: false,
    loop: false,
    muted: false,
    fluid: false,
    width: 600,
    height: 300,
    bigPlayButton: false,
    plugins: {
        wavesurfer: {
            backend: 'MediaElement',
            displayMilliseconds: true,
            debug: true,
            waveColor: 'white',
            progressColor: 'black',
            cursorColor: 'black',
            hideScrollbar: true
        }
    }
};

ReactDOM.render(<VideojsWavesurferPlayer { ...videoJsOptions } />, document.getElementById('root'));

and, open dev tool on web browser, click the button that title is click! then watch to console log

you'll see the result like this

VIDEOJS: Using wavesurfer.js MediaElement backend.
video.min.js:12 VIDEOJS: Loading element: [object HTMLAudioElement]
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Loading element: [object HTMLAudioElement]
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Loading element: [object HTMLAudioElement]
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!
video.min.js:12 VIDEOJS: Waveform is ready
index.js:29 waveform: ready!

Results

Expected

not duplicate event fire

Actual

duplicated event fire

Versions

Make sure to include the following versions:

videojs/wavesurfer

what version of video.js, videojs-wavesurfer and wavesurfer.js does this occur with? i checked this issue on VIDEOJS: Using video.js 7.15.4 with videojs-wavesurfer 3.8.0 and wavesurfer.js 5.2.0 <- example code version VIDEOJS: Using video.js 7.15.4 with videojs-wavesurfer 3.8.0, wavesurfer.js 5.2.0 and React 17.0.2 <- my project

Browsers OSes

I found this error on windows chrome, edge, and electron. other OS and browser not checked

thijstriemstra commented 2 years ago

Thanks for the detailed feedback. I was able to reproduce this without react as well, simply call player.src() at some point, e.g:

player.src({src: 'media/hal.wav', type: 'audio/wav'});

and it triggers the waveReady and playbackFinish events twice. Calling player.src() again results in those events being called three times so there I suspect there is something that doesn't clean up the event listeners properly..

Tested with video.js 7.17.0 with videojs-wavesurfer 3.8.0 and wavesurfer.js 5.2.0 on Firefox 94.0.2, macOS 12.0.1

Looks like it's related to this video.js issue? https://github.com/videojs/video.js/issues/4677