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.attr.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}