Search code examples
javahtmlaudiovaadin

Catch timeupdate event of an audio tag in vaadin


I use the audio tag in a component as propsed here: https://cookbook.vaadin.com/embed-audio

Now I want to fire an event when the audio plays. I found out that the audio tag provides the timeupdate event. I can catch it and it workes well. But now I want to get the current time of the audio playing. I read that the audio element has an attribute currentTime. But when I want to get that attribute from the audio element, it is not existing.

I printed all attributes of audio and everyting a get is src and style. Hope you can point me in the right direction here, since this does absolutely not make sense to me.

Edit: When I query the attribute via executeJs like:

UI.getCurrent().getPage().executeJs("return $0.currentTime", audio.getElement());

... , I get the value I'm looking for but then, the event listener does not work synchrnously anymore.

My class looks like that:

@Tag("audio")
public class Audio extends Component implements HasSize {

    private static final long serialVersionUID = 1L;

    private static final PropertyDescriptor<String, String> srcDescriptor = PropertyDescriptors
            .attributeWithDefault("src", "");

    public Audio() {
        super();
        getElement().setProperty("controls", true);
    }

    public Audio(String src) {
        setSrc(src);
        getElement().setProperty("controls", true);
    }

    public String getSrc() {
        return get(srcDescriptor);
    }

    public void setSrc(String src) {
        set(srcDescriptor, src);
    }

    public void setSrc(final AbstractStreamResource resource) {
        getElement().setAttribute("src", resource);
    }

    public void play() {
        getElement().callJsFunction("play");
    }

    public void stop() {
        getElement().callJsFunction("stop");
    }

    @DomEvent("timeupdate")
    public static class TimeUpdateEvent extends ComponentEvent<Audio> {

        private final int progress;

        public TimeUpdateEvent(Audio audio, boolean fromClient) {
            super(audio, fromClient);
            String currentTime = audio.getElement().getAttribute("currentTime");
            this.progress = Integer.valueOf(currentTime);
        }

        public Audio getAudio() {
            return (Audio) this.source;
        }

        public int getProgress() {
            return this.progress;
        }
    }

    public Registration addTimeUpdateListener(ComponentEventListener<Audio.TimeUpdateEvent> listener) {
        return addListener(Audio.TimeUpdateEvent.class, listener);
    }
}

Solution

  • Okay, I found a way using property chance listeners. I'm observice the javascript property currentTime and react to the timeupdate event. This does not emit a ComponentEvent but I can live with that.

    public Audio() {
        super();
        this.getElement().addPropertyChangeListener("currentTime", "timeupdate", e -> {
            currentTime = Float.parseFloat(e.getValue().toString());
        });
        getElement().setProperty("controls", true);
    }