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 final 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}