bbc / peaks.js

JavaScript UI component for interacting with audio waveforms
https://waveform.prototyping.bbc.co.uk
GNU Lesser General Public License v3.0
3.16k stars 277 forks source link

Pause event not emitted after using setSource #442

Closed benjaminhouy closed 2 years ago

benjaminhouy commented 2 years ago

Hi,

I load the following code on page load:

let setSegments = this.setSegments

        const options = {
            overview: {
                container: document.getElementById('overview-container'),
                waveformColor: 'blue',
            },
            mediaElement: document.querySelector('audio'),
            dataUri: {
                arraybuffer: document.getElementById('normal-audio-button').dataset.waveform
            },
            emitCueEvents: true,
        };

        // Initialize Peaks instance
        Peaks.init(options, function (err, peaks) {
            window.instance = peaks;
            window.speed = "normal";

            // Event listener adding HTML focus to French phrase matching currently-played segment
            instance.on('segments.enter', function (segment) {
                const segmentCard = document.getElementById(segment.id)
                segmentCard.focus({preventScroll: true})
                // Define current segment for the rewind method
                window.currentSegment = segment
            });
            setSegments()
        });
    }

Then I have a button users can click to load a different audio file. It triggers this function:

// Load normal speed audio and matching waveform
    loadNormal() {
        speed = "normal"
        const normalAudio = document.getElementById('normal-audio-button').dataset.mp3;
        const normalAudioWebm = document.getElementById('normal-audio-button').dataset.webm;
        const normalWaveform = document.getElementById('normal-audio-button').dataset.waveform;
        const explanation = document.getElementById('explanation');
        const audioElement = document.getElementById('audio');

        const audioSources = [
            {src: normalAudioWebm, type: 'audio/webm; codecs="opus"'},
            {src: normalAudio, type: 'audio/mpeg'}
        ];

        const normalAudioSource = this.getAudioSource(audioSources, audioElement)

        const options = {
            mediaUrl: normalAudioSource,
            dataUri: {
                arraybuffer: normalWaveform
            }
        };

        instance.setSource(options, function () {
            const view = instance.views.getView('overview');
            view.setWaveformColor('blue');
        });
        this.setSegments()
    }

Finally, I have a play pause button linked to the following function:

togglePlay() {
        instance.player.isPlaying() ? instance.player.pause() : instance.player.play();
    }

The issue I have is that if a user starts playing the audio and then clicks on the loadNormal() button, the audio pauses but instance.player.isPlaying() still returns true even if I then fire instance.player.pause().

One workaround I have found is adding this at the end of loadNormal which then makes instance.player.isPlaying() return false as expected:

instance.player.play()
instance.player.pause()

I'm not quite sure whether this is a bug and the pause event doesn't get emitted properly when using setSource or whether I'm using setSource wrong.

Thanks

chrisn commented 2 years ago

Thank you for reporting this. It is a bug, there's an internal isPlaying flag that's not reset after you call setSource. I don't think the flag is actually needed. I'll do some tests and post a fix soon.

benjaminhouy commented 2 years ago

Perfect, thank you.

I didn't realize there was a paused property for the HTML audio element. I switched to that and it works :)

togglePlay() {
        this.audioElement.paused ? instance.player.play() : instance.player.pause();
    }
chrisn commented 2 years ago

Excellent, thanks!

chrisn commented 2 years ago

v0.28.1 is now available in npm with this fix.

benjaminhouy commented 2 years ago

Thanks for the quick fix! :)