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 AudioMarker recentlyPlayedMarker = null;
026    public double syncOffset;
027    public boolean timeFromAudio = false; // 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.png", parentLayer, time, offset);
031        this.audioUrl = audioUrl;
032        this.syncOffset = 0.0;
033        this.timeFromAudio = false;
034    }
035
036    @Override public void actionPerformed(ActionEvent ev) {
037        play();
038    }
039
040    public static AudioMarker recentlyPlayedMarker() {
041        return recentlyPlayedMarker;
042    }
043
044    public URL url() {
045        return audioUrl;
046    }
047
048    /**
049     * Starts playing the audio associated with the marker offset by the given amount
050     * @param after : seconds after marker where playing should start
051     */
052    public void play(double after) {
053        try {
054            // first enable tracing the audio along the track
055            Main.map.mapView.playHeadMarker.animate();
056
057            AudioPlayer.play(audioUrl, offset + syncOffset + after);
058            recentlyPlayedMarker = this;
059        } catch (Exception e) {
060            AudioPlayer.audioMalfunction(e);
061        }
062    }
063
064    /**
065     * Starts playing the audio associated with the marker: used in response to pressing
066     * the marker as well as indirectly
067     *
068     */
069    public void play() { play(0.0); }
070
071    public void adjustOffset(double adjustment) {
072        syncOffset = adjustment; // added to offset may turn out negative, but that's ok
073    }
074
075    public double syncOffset() {
076        return syncOffset;
077    }
078
079    @Override
080    protected TemplateEntryProperty getTextTemplate() {
081        return TemplateEntryProperty.forAudioMarker(parentLayer.getName());
082    }
083
084    @Override
085    public WayPoint convertToWayPoint() {
086        WayPoint wpt = super.convertToWayPoint();
087        GpxLink link = new GpxLink(audioUrl.toString());
088        link.type = "audio";
089        wpt.put(GpxConstants.META_LINKS, Collections.singleton(link));
090        wpt.addExtension("offset", Double.toString(offset));
091        wpt.addExtension("sync-offset", Double.toString(syncOffset));
092        return wpt;
093    }
094}