001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer.markerlayer;
003
004import java.awt.event.ActionEvent;
005import java.net.URL;
006import java.util.Collections;
007
008import org.openstreetmap.josm.Main;
009import org.openstreetmap.josm.data.coor.LatLon;
010import org.openstreetmap.josm.data.gpx.GpxConstants;
011import org.openstreetmap.josm.data.gpx.GpxLink;
012import org.openstreetmap.josm.data.gpx.WayPoint;
013import org.openstreetmap.josm.tools.AudioPlayer;
014import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
015
016/**
017 * Marker class with audio playback capability.
018 *
019 * @author Frederik Ramm
020 *
021 */
022public class AudioMarker extends ButtonMarker {
023
024    private URL audioUrl;
025    private static volatile AudioMarker recentlyPlayedMarker;
026    public double syncOffset;
027    public boolean timeFromAudio; // as opposed to from the GPX track
028
029    public AudioMarker(LatLon ll, TemplateEngineDataProvider dataProvider, URL audioUrl, MarkerLayer parentLayer, double time, double offset) {
030        super(ll, dataProvider, "speech", parentLayer, time, offset);
031        this.audioUrl = audioUrl;
032        this.syncOffset = 0.0;
033        this.timeFromAudio = false;
034    }
035
036    @Override
037    public void actionPerformed(ActionEvent ev) {
038        play();
039    }
040
041    public static AudioMarker recentlyPlayedMarker() {
042        return recentlyPlayedMarker;
043    }
044
045    public URL url() {
046        return audioUrl;
047    }
048
049    /**
050     * Starts playing the audio associated with the marker offset by the given amount
051     * @param after : seconds after marker where playing should start
052     */
053    public void play(double after) {
054        try {
055            // first enable tracing the audio along the track
056            Main.map.mapView.playHeadMarker.animate();
057
058            AudioPlayer.play(audioUrl, offset + syncOffset + after);
059            recentlyPlayedMarker = this;
060        } catch (Exception e) {
061            AudioPlayer.audioMalfunction(e);
062        }
063    }
064
065    /**
066     * Starts playing the audio associated with the marker: used in response to pressing
067     * the marker as well as indirectly
068     *
069     */
070    public void play() {
071        play(0.0);
072    }
073
074    public void adjustOffset(double adjustment) {
075        syncOffset = adjustment; // added to offset may turn out negative, but that's ok
076    }
077
078    public double syncOffset() {
079        return syncOffset;
080    }
081
082    @Override
083    protected TemplateEntryProperty getTextTemplate() {
084        return TemplateEntryProperty.forAudioMarker(parentLayer.getName());
085    }
086
087    @Override
088    public WayPoint convertToWayPoint() {
089        WayPoint wpt = super.convertToWayPoint();
090        GpxLink link = new GpxLink(audioUrl.toString());
091        link.type = "audio";
092        wpt.put(GpxConstants.META_LINKS, Collections.singleton(link));
093        wpt.addExtension("offset", Double.toString(offset));
094        wpt.addExtension("sync-offset", Double.toString(syncOffset));
095        return wpt;
096    }
097}