Author: fdesbois Date: 2012-09-04 18:05:15 +0200 (Tue, 04 Sep 2012) New Revision: 517 Url: http://forge.codelutin.com/repositories/revision/sammoa/517 Log: refs #1197 : add configuration for audio + improve FlightController behavior with devices Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioConfig.java Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/SammoaConfig.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/DeviceManagerProvider.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioReaderMock.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorder.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderDefault.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderMock.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/SammoaAudioRecorder.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java trunk/sammoa-application/src/main/resources/i18n/sammoa-application_en_GB.properties trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java trunk/sammoa-ui-swing/pom.xml trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java trunk/sammoa-ui-swing/src/main/resources/i18n/sammoa-ui-swing_en_GB.properties Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/SammoaConfig.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/SammoaConfig.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/SammoaConfig.java 2012-09-04 16:05:15 UTC (rev 517) @@ -27,6 +27,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.base.Throwables; +import fr.ulr.sammoa.application.device.audio.AudioConfig; import fr.ulr.sammoa.application.device.gps.GpsConfig; import fr.ulr.sammoa.persistence.AutoSaveListener; import org.apache.commons.io.FileUtils; @@ -89,6 +90,8 @@ protected GpsConfig gpsConfig; + protected AudioConfig audioConfig; + public SammoaConfig(String file, String... args) { applicationConfig = new ApplicationConfig(); @@ -106,6 +109,7 @@ } gpsConfig = new GpsConfig(applicationConfig); + audioConfig = new AudioConfig(applicationConfig); try { prepareDirectories(); @@ -147,6 +151,10 @@ return gpsConfig; } + public AudioConfig getAudioConfig() { + return audioConfig; + } + public void save() { applicationConfig.saveForUser(); } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/DeviceManagerProvider.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/DeviceManagerProvider.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/DeviceManagerProvider.java 2012-09-04 16:05:15 UTC (rev 517) @@ -28,6 +28,7 @@ import com.google.common.base.Throwables; import com.google.common.collect.Sets; import fr.ulr.sammoa.application.SammoaServiceSupport; +import fr.ulr.sammoa.application.device.audio.AudioConfig; import fr.ulr.sammoa.application.device.audio.AudioReader; import fr.ulr.sammoa.application.device.audio.AudioReaderMock; import fr.ulr.sammoa.application.device.audio.AudioRecorder; @@ -53,20 +54,23 @@ deviceManagers = Sets.newHashSet(); } - public <T extends DeviceManager> T openDeviceManager(Class<T> deviceManagerClass, boolean autoStart) { + public <T extends DeviceManager> T openDeviceManager(Class<T> deviceManagerClass, + boolean autoStart) { T result; if (GpsHandler.class.isAssignableFrom(deviceManagerClass)) { result = (T) openGpsDevice(context.getConfig().getGpsConfig()); } else if (AudioRecorder.class.isAssignableFrom(deviceManagerClass)) { - result = (T) openAudioRecorderDevice(); + result = (T) openAudioRecorderDevice(context.getConfig().getAudioConfig()); } else if (AudioReader.class.isAssignableFrom(deviceManagerClass)) { - result = (T) openAudioReaderDevice(); + result = (T) openAudioReaderDevice(context.getConfig().getAudioConfig()); } else { - throw new IllegalArgumentException("The deviceManager class " + deviceManagerClass.getName() + " is not supported"); + throw new IllegalArgumentException("The deviceManager class " + + deviceManagerClass.getName() + + " is not supported"); } if (autoStart) { @@ -87,7 +91,8 @@ return null; } - public GpsHandler openGpsDevice(final GpsConfig config) throws DeviceTechnicalException { + public GpsHandler openGpsDevice(final GpsConfig config) + throws DeviceTechnicalException { GpsHandler oldInstance = getDeviceManager(GpsHandler.class); @@ -137,7 +142,8 @@ return result; } - public AudioRecorder openAudioRecorderDevice() throws DeviceTechnicalException { + public AudioRecorder openAudioRecorderDevice(final AudioConfig config) + throws DeviceTechnicalException { AudioRecorder oldInstance = getDeviceManager(AudioRecorder.class); @@ -146,13 +152,14 @@ @Override public AudioRecorder get() { // return new AudioRecorderDefault(); - return new SammoaAudioRecorder(44100, 16); + return new SammoaAudioRecorder(config); } }); return result; } - public AudioReader openAudioReaderDevice() throws DeviceTechnicalException { + public AudioReader openAudioReaderDevice(final AudioConfig config) + throws DeviceTechnicalException { AudioReader oldInstance = getDeviceManager(AudioReader.class); @@ -160,7 +167,7 @@ @Override public AudioReader get() { - return new AudioReaderMock(); + return new AudioReaderMock(config); } }); return result; Added: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioConfig.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioConfig.java (rev 0) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioConfig.java 2012-09-04 16:05:15 UTC (rev 517) @@ -0,0 +1,171 @@ +package fr.ulr.sammoa.application.device.audio; +/* + * #%L + * SAMMOA :: Application + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2012 UMS 3462, Code Lutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import org.nuiton.util.ApplicationConfig; + +import static org.nuiton.i18n.I18n.n_; + +/** + * Created: 18/06/12 + * + * @author fdesbois <desbois@codelutin.com> + */ +public class AudioConfig { + + protected ApplicationConfig applicationConfig; + + public AudioConfig(ApplicationConfig applicationConfig) { + this.applicationConfig = applicationConfig; + this.applicationConfig.loadDefaultOptions(AudioConfigOption.values()); + } + + /** @return {@link AudioConfigOption#SAMPLE_RATE} value */ + public float getSampleRate() { + float result = applicationConfig.getOptionAsFloat(AudioConfigOption.SAMPLE_RATE.key); + return result; + } + + /** @return {@link AudioConfigOption#SAMPLE_SIZE_IN_BITS} value */ + public int getSampleSizeInBits() { + int result = applicationConfig.getOptionAsInt(AudioConfigOption.SAMPLE_SIZE_IN_BITS.key); + return result; + } + + /** @return {@link AudioConfigOption#RECORD_DELAY_IN_SECONDS} value */ + public int getRecordDelayInSeconds() { + int result = applicationConfig.getOptionAsInt(AudioConfigOption.RECORD_DELAY_IN_SECONDS.key); + return result; + } + + public enum AudioConfigOption implements ApplicationConfig.OptionDef { + + /** Sampel rate to record audio */ + SAMPLE_RATE( + "sammoa.audio.sampleRate", + n_("sammoa.config.audio.sampleRate"), + "8000", + Float.class + ), + /** Period time in seconds for each check of the gps to update location */ + SAMPLE_SIZE_IN_BITS( + "sammoa.audio.sampleSizeInBits", + n_("sammoa.config.audio.sampleSizeInBits"), + "8", + Integer.class + ), + /** Time in seconds between each record, this will record in multiple files */ + RECORD_DELAY_IN_SECONDS( + "sammoa.audio.recordDelayInSeconds", + n_("sammoa.config.audio.recordDelayInSeconds"), + "0", + Integer.class + ); + + /** Configuration key. */ + private final String key; + + /** I18n key of option description */ + private final String description; + + /** Type of option */ + private final Class<?> type; + + /** Default value of option. */ + private String defaultValue; + + /** Flag to not keep option value on disk */ + private boolean isTransient; + + /** Flag to not allow option value modification */ + private boolean isFinal; + + AudioConfigOption(String key, + String description, + String defaultValue, + Class<?> type, + boolean isTransient, + boolean isFinal) { + this.key = key; + this.description = description; + this.defaultValue = defaultValue; + this.type = type; + this.isTransient = isTransient; + this.isFinal = isFinal; + } + + AudioConfigOption(String key, + String description, + String defaultValue, + Class<?> type) { + this(key, description, defaultValue, type, false, false); + } + + @Override + public String getKey() { + return key; + } + + @Override + public Class<?> getType() { + return type; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getDefaultValue() { + return defaultValue; + } + + @Override + public boolean isTransient() { + return isTransient; + } + + @Override + public boolean isFinal() { + return isFinal; + } + + @Override + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public void setTransient(boolean newValue) { + // not used + } + + @Override + public void setFinal(boolean newValue) { + // not used + } + } +} Property changes on: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioConfig.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioReaderMock.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioReaderMock.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioReaderMock.java 2012-09-04 16:05:15 UTC (rev 517) @@ -41,12 +41,18 @@ */ public class AudioReaderMock implements AudioReader { + protected AudioConfig config; + protected long position; protected DeviceState state = DeviceState.UNAVAILABLE; protected Set<DeviceStateListener> listeners = Sets.newHashSet(); + public AudioReaderMock(AudioConfig config) { + this.config = config; + } + @Override public AudioFileFormat.Type getOutputType() { return AudioFileFormat.Type.WAVE; Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorder.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorder.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorder.java 2012-09-04 16:05:15 UTC (rev 517) @@ -43,18 +43,16 @@ /** * Record the audio line and save the data in given {@code outputFile}. The - * previous recording will be stopped in {@code delaySeconds}. The delay is + * previous recording will be stopped after some delay depends + * on {@link AudioConfig#getRecordDelayInSeconds()}. The delay is * useful to avoid recording lost or too quick between two files. * * @param outputFile File to record - * @param delaySeconds Delay for previous recording */ - void record(File outputFile, long delaySeconds); + void record(File outputFile); /** - * Stop the current recording after {@code delaySeconds}. - * - * @param delaySeconds Delay for current recording + * Stop the current recording. */ - void stopRecord(long delaySeconds); + void stopRecord(); } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderDefault.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderDefault.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderDefault.java 2012-09-04 16:05:15 UTC (rev 517) @@ -81,6 +81,8 @@ private static final AudioFileFormat.Type DEFAULT_OUTPUT_TYPE = AudioFileFormat.Type.WAVE; + protected AudioConfig config; + protected AudioFormat audioFormat; protected AudioFileFormat.Type outputType; @@ -102,11 +104,11 @@ protected Set<DeviceStateListener> listeners; - public AudioRecorderDefault() { + public AudioRecorderDefault(AudioConfig config) { this(new AudioFormat( DEFAULT_ENCODING, - DEFAULT_SAMPLE_RATE, - DEFAULT_SAMPLE_SIZE_IN_BITS, + config.getSampleRate(), + config.getSampleSizeInBits(), DEFAULT_CHANNELS, DEFAULT_FRAME_SIZE, DEFAULT_FRAME_RATE, @@ -216,7 +218,7 @@ } @Override - public void record(File outputFile, long delaySeconds) { + public void record(File outputFile) { if (DeviceState.UNAVAILABLE == state) { if (logger.isWarnEnabled()) { @@ -243,7 +245,7 @@ } else if (currentRecorder == recorder1) { if (recorder1.isRecording()) { - recorder1.stop(delaySeconds); + recorder1.stop(config.getRecordDelayInSeconds()); } if (recorder2 != null && recorder2.isRecording()) { @@ -256,7 +258,7 @@ } else if (currentRecorder == recorder2) { if (recorder2.isRecording()) { - recorder2.stop(delaySeconds); + recorder2.stop(config.getRecordDelayInSeconds()); } if (recorder1.isRecording()) { @@ -276,9 +278,9 @@ } @Override - public void stopRecord(long delaySeconds) { + public void stopRecord() { if (currentRecorder != null) { - currentRecorder.stop(delaySeconds); + currentRecorder.stop(config.getRecordDelayInSeconds()); } } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderMock.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderMock.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/AudioRecorderMock.java 2012-09-04 16:05:15 UTC (rev 517) @@ -41,6 +41,12 @@ */ public class AudioRecorderMock implements AudioRecorder { + protected AudioConfig config; + + public AudioRecorderMock(AudioConfig config) { + this.config = config; + } + @Override public DeviceState getState() { return DeviceState.UNAVAILABLE; @@ -62,12 +68,12 @@ } @Override - public void record(File outputFile, long delaySeconds) { + public void record(File outputFile) { // do nothing } @Override - public void stopRecord(long delaySeconds) { + public void stopRecord() { // do nothing } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/SammoaAudioRecorder.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/SammoaAudioRecorder.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/device/audio/SammoaAudioRecorder.java 2012-09-04 16:05:15 UTC (rev 517) @@ -55,6 +55,8 @@ private static final Logger logger = LoggerFactory.getLogger(SammoaAudioRecorder.class); + protected AudioConfig config; + protected AudioFormat audioFormat; protected AudioFileFormat.Type outputType; @@ -65,16 +67,16 @@ protected AudioRecorderThread currentRecorder; - public SammoaAudioRecorder(float sampleRate, // 8000,11025,16000,22050,44100 - int sampleSizeInBits) { // 8,16 + public SammoaAudioRecorder(AudioConfig config) { + this.config = config; int channels = 1; // 1,2 boolean signed = true; // true,false boolean bigEndian = false; // true,false audioFormat = new AudioFormat( - sampleRate, - sampleSizeInBits, + config.getSampleRate(), + config.getSampleSizeInBits(), channels, signed, bigEndian); @@ -131,7 +133,7 @@ } @Override - public void record(File outputFile, long delaySeconds) { + public void record(File outputFile) { Preconditions.checkNotNull(outputFile); try { @@ -139,7 +141,7 @@ stop(); // start new recorder thread currentRecorder = new AudioRecorderThread( - audioFormat, outputType, outputFile, delaySeconds, this); + audioFormat, outputType, outputFile, config.getRecordDelayInSeconds(), this); currentRecorder.start(); setState(DeviceState.RUNNING, null); @@ -156,7 +158,7 @@ } @Override - public void stopRecord(long delaySeconds) { + public void stopRecord() { stop(); } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/BaseFlightController.java 2012-09-04 16:05:15 UTC (rev 517) @@ -67,10 +67,6 @@ private static final TimeLog timeLog = new TimeLog(BaseFlightController.class, 500, 1000); protected FlightService service; -// -// protected AudioRecorder audioRecorder; -// -// protected GpsHandler gpsHandler; protected boolean initialized; @@ -292,6 +288,8 @@ currentRoute = newCurrentRoute; + TransectFlight lastTransectOldValue = lastTransect; + if (currentRoute == null) { if (flight.getEndDate() == null) { @@ -337,7 +335,7 @@ if (fireChanges) { onStateChanged(state); - onLastTransectChanged(lastTransect); + onLastTransectChanged(lastTransectOldValue, lastTransect); onNextTransectChanged(nextTransect); onCurrentRouteChanged(currentRoute); } @@ -368,6 +366,7 @@ Date currentDate = geoPoint.getRecordTime(); // The next transect becomes the last one (or current in this case) + TransectFlight lastTransectOldValue = lastTransect; lastTransect = nextTransect; // Create new LEG route @@ -388,7 +387,7 @@ // Fire events after commit onRouteAdded(previousRoute, currentRoute); - onLastTransectChanged(lastTransect); + onLastTransectChanged(lastTransectOldValue, lastTransect); onNextTransectChanged(nextTransect); onStateChanged(state); @@ -581,6 +580,7 @@ Date currentDate = geoPoint.getRecordTime(); + TransectFlight lastTransectOldValue = lastTransect; lastTransect = null; // Create new TRANSIT route @@ -596,7 +596,7 @@ // Fire events after commit onRouteAdded(previousRoute, currentRoute); - onLastTransectChanged(lastTransect); + onLastTransectChanged(lastTransectOldValue, lastTransect); onNextTransectChanged(nextTransect); onStateChanged(state); @@ -771,7 +771,7 @@ } } - protected void onLastTransectChanged(TransectFlight lastTransect) { + protected void onLastTransectChanged(TransectFlight oldValue, TransectFlight newValue) { // no fire by default } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerOnBoard.java 2012-09-04 16:05:15 UTC (rev 517) @@ -23,6 +23,7 @@ * #L% */ +import com.google.common.base.Objects; import com.google.common.base.Preconditions; import fr.ulr.sammoa.application.device.DeviceManager; import fr.ulr.sammoa.application.device.audio.AudioRecorder; @@ -47,10 +48,6 @@ */ public class FlightControllerOnBoard extends BaseFlightController implements GpsLocationListener { - protected GpsHandler gpsHandler; - - protected AudioRecorder audioRecorder; - @Override public <T extends DeviceManager> void openDeviceManager(Class<T> deviceManager) { boolean autoStart = initialized && isRunning(); @@ -59,16 +56,19 @@ if (result instanceof GpsHandler) { ((GpsHandler) result).addGpsLocationListener(this); + + } else if (autoStart && result instanceof AudioRecorder) { + restartAudio((AudioRecorder) result); } } @Override public void init(Flight flight) { - gpsHandler = getDeviceManager(GpsHandler.class); + GpsHandler gpsHandler = getGpsHandler(); Preconditions.checkNotNull(gpsHandler, "You must open the gpsHandler device before init"); - audioRecorder = getDeviceManager(AudioRecorder.class); + AudioRecorder audioRecorder = getAudioRecorder(); Preconditions.checkNotNull(audioRecorder, "You must open the audioRecorder device before init"); super.init(flight); @@ -81,23 +81,16 @@ audioRecorder.start(); - // Restart recording audio if onEffort or circleBack (recovery mode) - if (state == FlightState.ON_EFFORT - || currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { - - File audioFile = flightStorage.getAudioFile( - lastTransect, audioRecorder.getOutputType().getExtension()); - audioRecorder.record(audioFile, 3); - } + restartAudio(audioRecorder); } } @Override public void start() { - gpsHandler.start(); + getGpsHandler().start(); - audioRecorder.start(); + getAudioRecorder().start(); super.start(); } @@ -107,9 +100,9 @@ super.stop(); - audioRecorder.stop(); + getAudioRecorder().stop(); - gpsHandler.stop(); + getGpsHandler().stop(); } @Override @@ -123,7 +116,7 @@ @Override protected GeoPoint getLocation(TopiaContext tx) throws TopiaException { - GeoPoint result = gpsHandler.getCurrentLocation(); + GeoPoint result = getGpsHandler().getCurrentLocation(); result.setFlight(flight); if (result.getTopiaId() == null) { SammoaDAOHelper.getGeoPointDAO(tx).create(result); @@ -132,17 +125,43 @@ } @Override - protected void onLastTransectChanged(TransectFlight lastTransect) { + protected void onLastTransectChanged(TransectFlight oldValue, + TransectFlight newValue) { - if (lastTransect == null) { - audioRecorder.stopRecord(3); + // Record audio for the lastTransect (also current one in case of LEG) - } else { + if (!Objects.equal(oldValue, newValue)) { + + AudioRecorder audioRecorder = getAudioRecorder(); + + if (newValue == null) { + audioRecorder.stopRecord(); + + } else { + File audioFile = flightStorage.getAudioFile( + newValue, audioRecorder.getOutputType().getExtension()); + audioRecorder.record(audioFile); + } + } + + super.onLastTransectChanged(oldValue, newValue); + } + + protected void restartAudio(AudioRecorder audioRecorder) { + if (state == FlightState.ON_EFFORT + || currentRoute.getRouteType() == RouteType.CIRCLE_BACK) { + File audioFile = flightStorage.getAudioFile( lastTransect, audioRecorder.getOutputType().getExtension()); - audioRecorder.record(audioFile, 3); + audioRecorder.record(audioFile); } + } - super.onLastTransectChanged(lastTransect); + protected GpsHandler getGpsHandler() { + return getDeviceManager(GpsHandler.class); } + + protected AudioRecorder getAudioRecorder() { + return getDeviceManager(AudioRecorder.class); + } } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/flightController/FlightControllerValidation.java 2012-09-04 16:05:15 UTC (rev 517) @@ -54,8 +54,6 @@ private static final Logger logger = LoggerFactory.getLogger(FlightControllerValidation.class); - protected AudioReader audioReader; - protected List<GeoPoint> geoPoints; protected List<Route> routes; @@ -68,7 +66,7 @@ @Override public void init(Flight flight) { - audioReader = getDeviceManager(AudioReader.class); + AudioReader audioReader = getAudioReader(); Preconditions.checkNotNull(audioReader, "You must open the audioReader device before init"); super.init(flight); @@ -95,7 +93,7 @@ ); } - long position = audioReader.getPosition(); + long position = getAudioReader().getPosition(); DateTime newTime; if (position > 0) { @@ -162,16 +160,20 @@ } @Override - protected void onLastTransectChanged(TransectFlight transectFlight) { + protected void onLastTransectChanged(TransectFlight oldValue, + TransectFlight newValue) { - // Only change audio if lastTransect isn't the same - if (!Objects.equal(lastTransect, transectFlight)) { + // Read audio for the lastTransect (also current one in case of LEG) + if (!Objects.equal(oldValue, newValue)) { + + AudioReader audioReader = getAudioReader(); + audioReader.unload(); - if (transectFlight != null) { + if (newValue != null) { File file = flightStorage.getAudioFile( - transectFlight, audioReader.getOutputType().getExtension()); + newValue, audioReader.getOutputType().getExtension()); if (file.exists()) { audioReader.load(file); @@ -179,6 +181,10 @@ } } - super.onLastTransectChanged(transectFlight); + super.onLastTransectChanged(oldValue, newValue); } + + protected AudioReader getAudioReader() { + return getDeviceManager(AudioReader.class); + } } Modified: trunk/sammoa-application/src/main/resources/i18n/sammoa-application_en_GB.properties =================================================================== --- trunk/sammoa-application/src/main/resources/i18n/sammoa-application_en_GB.properties 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-application/src/main/resources/i18n/sammoa-application_en_GB.properties 2012-09-04 16:05:15 UTC (rev 517) @@ -1,6 +1,9 @@ sammoa.config.admin.email=Administrator's email sammoa.config.application.site.url=Website URL of the application sammoa.config.application.version=Version of the application +sammoa.config.audio.recordDelayInSeconds=Delay in seconds between each audio record. This will record multiple files at the same time to avoid too sudden stops. (Warning \: this is not supported by all sound systems) +sammoa.config.audio.sampleRate=Rate for the audio sampling (possible values \: 8000, 11025, 16000, 22050, 44100) +sammoa.config.audio.sampleSizeInBits=Size of bits for the audio sampling (possible values \: 8, 16) sammoa.config.background.shape.file=Location of the Background shape file sammoa.config.backup.directory=BAckup directory where to sotre all data backup sammoa.config.campaign.directory=Directory where are stored campaign data (maps, flight audio files,...) Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java 2012-09-04 16:05:15 UTC (rev 517) @@ -53,6 +53,10 @@ // static class do not have instanciation } + public static boolean isAnyMatchTransectFlight(Iterable<Route> routes, TransectFlight transectFlight) { + return Iterables.any(routes, withTransectFlight(transectFlight)); + } + public static boolean isRouteLeg(Route route) { return route != null && RouteType.LEG == route.getRouteType(); } Modified: trunk/sammoa-ui-swing/pom.xml =================================================================== --- trunk/sammoa-ui-swing/pom.xml 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-ui-swing/pom.xml 2012-09-04 16:05:15 UTC (rev 517) @@ -13,6 +13,8 @@ </parent> <artifactId>sammoa-ui-swing</artifactId> + <inceptionYear>2012</inceptionYear> + <url>http://forge.codelutin.com/projects/sammoa</url> <name>SAMMOA :: UI Swing</name> <description>Swing interface using Jaxx</description> Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/MainUIHandler.java 2012-09-04 16:05:15 UTC (rev 517) @@ -26,7 +26,11 @@ import fr.ulr.sammoa.application.SammoaConfig; import fr.ulr.sammoa.application.SammoaContext; +import fr.ulr.sammoa.application.device.DeviceManager; import fr.ulr.sammoa.application.device.DeviceTechnicalException; +import fr.ulr.sammoa.application.device.audio.AudioConfig; +import fr.ulr.sammoa.application.device.audio.AudioReader; +import fr.ulr.sammoa.application.device.audio.AudioRecorder; import fr.ulr.sammoa.application.device.gps.GpsConfig; import fr.ulr.sammoa.application.device.gps.GpsHandler; import fr.ulr.sammoa.application.flightController.FlightController; @@ -255,8 +259,7 @@ ConfigUIHelper helper = new ConfigUIHelper(config); helper.registerCallBack( - "ui", - n_("sammoa.action.reload.ui"), + "ui", n_("sammoa.action.reload.ui"), SwingUtil.createActionIcon("reload-ui"), new Runnable() { @@ -264,143 +267,186 @@ public void run() { reloadSammoa(); } - }); - helper.registerCallBack( - "home", - n_("sammoa.action.reload.home"), - SwingUtil.createActionIcon("config"), - new Runnable() { + } + ); - @Override - public void run() { - if (SammoaScreen.HOME == ui.getScreen()) { - HomeUI homeUI = (HomeUI) currentBody; - homeUI.getHandler().selectCampaign(); + // APPLICATION + { + helper.addCategory(n_("sammoa.config.category.applications"), + n_("sammoa.config.category.applications.description")); + helper.registerCallBack( + "home", n_("sammoa.action.reload.home"), + SwingUtil.createActionIcon("config"), + new Runnable() { + + @Override + public void run() { + if (SammoaScreen.HOME == ui.getScreen()) { + HomeUI homeUI = (HomeUI) currentBody; + homeUI.getHandler().selectCampaign(); + } } } - }); + ); + helper.addOption(SammoaConfig.SammoaConfigOption.SYSTEM_ID); + helper.setOptionCallBack("home"); + helper.addOption(SammoaConfig.SammoaConfigOption.DATA_DIRECTORY); + helper.setOptionCallBack("ui"); + helper.addOption(SammoaConfig.SammoaConfigOption.FLIGHT_NUMBER); + helper.addOption(SammoaConfig.SammoaConfigOption.BACKGROUND_SHAPE_FILE); + helper.setOptionCallBack("ui"); + helper.addOption(SammoaConfig.SammoaConfigOption.AUTO_COMMIT_DELAY); // milliseconds + helper.setOptionCallBack("ui"); + } - // categorie applications - helper.addCategory(n_("sammoa.config.category.applications"), - n_("sammoa.config.category.applications.description")); + // SHORTCUT + { + helper.addCategory(n_("sammoa.config.category.shortcuts"), + n_("sammoa.config.category.shortcuts.description")); + helper.registerCallBack( + "actions", n_("sammoa.action.reload.actions"), + SwingUtil.createActionIcon("config"), + new Runnable() { - helper.addOption(SammoaConfig.SammoaConfigOption.SYSTEM_ID); - helper.setOptionCallBack("home"); - helper.addOption(SammoaConfig.SammoaConfigOption.DATA_DIRECTORY); - helper.setOptionCallBack("ui"); -// helper.addOption(SammoaConfig.SammoaConfigOption.CAMPAIGN_DIRECTORY); -// helper.setOptionCallBack("ui"); - helper.addOption(SammoaConfig.SammoaConfigOption.FLIGHT_NUMBER); - helper.addOption(SammoaConfig.SammoaConfigOption.BACKGROUND_SHAPE_FILE); - helper.setOptionCallBack("ui"); - // milliseconds - helper.addOption(SammoaConfig.SammoaConfigOption.AUTO_COMMIT_DELAY); - helper.setOptionCallBack("ui"); + @Override + public void run() { -// helper.addOption(SammoaConfig.SammoaConfigOption.STRATE_SHAPE_FILE); -// helper.setOptionCallBack("ui"); -// helper.addOption(SammoaConfig.SammoaConfigOption.TRANSECT_SHAPE_FILE); -// helper.setOptionCallBack("ui"); + if (SammoaScreen.FLIGHT == ui.getScreen() + || SammoaScreen.VALIDATION == ui.getScreen()) { - helper.registerCallBack("actions", - n_("sammoa.action.reload.actions"), - SwingUtil.createActionIcon("config"), - new Runnable() { + FlightUI flightUI = (FlightUI) currentBody; + flightUI.getHandler().initActions(); + } + } + } + ); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_START); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_STOP); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_BEGIN); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_END); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_NEXT); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_ADD); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_LEFT_OBSERVATION); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_CENTER_OBSERVATION); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_RIGHT_OBSERVATION); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_CIRCLE_BACK); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_VALID_TRANSECT); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_VALID_OBSERVATION); + helper.setOptionCallBack("actions"); + helper.addOption(SammoaConfig.SammoaConfigOption.KEY_VALID_ROUTE); + helper.setOptionCallBack("actions"); + } - @Override - public void run() { + // GPS + { + helper.addCategory(n_("sammoa.config.category.gps"), + n_("sammoa.config.category.gps.description")); + helper.registerCallBack( + "gps", n_("sammoa.action.reload.gps"), + SwingUtil.createActionIcon("config"), + new Runnable() { - if (SammoaScreen.FLIGHT == ui.getScreen() - || SammoaScreen.VALIDATION == ui.getScreen()) { + @Override + public void run() { - FlightUI flightUI = (FlightUI) currentBody; - flightUI.getHandler().initActions(); - } - } - }); - // categorie raccourcis - helper.addCategory(n_("sammoa.config.category.shortcuts"), - n_("sammoa.config.category.shortcuts.description")); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_START); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_STOP); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_BEGIN); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_END); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_NEXT); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_ADD); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_LEFT_OBSERVATION); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_CENTER_OBSERVATION); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_RIGHT_OBSERVATION); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_CIRCLE_BACK); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_VALID_TRANSECT); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_VALID_OBSERVATION); - helper.setOptionCallBack("actions"); - helper.addOption(SammoaConfig.SammoaConfigOption.KEY_VALID_ROUTE); - helper.setOptionCallBack("actions"); + if (SammoaScreen.FLIGHT == ui.getScreen()) { - // gps - helper.registerCallBack("gps", - n_("sammoa.action.reload.gps"), - SwingUtil.createActionIcon("config"), - new Runnable() { + reloadDevice((FlightUI) currentBody, GpsHandler.class); + } + } + } + ); + helper.addOption(GpsConfig.GpsConfigOption.GPS_HANDLER, + SammoaConfig.PROPERTY_GPS_CONFIG + "." + GpsConfig.PROPERTY_GPS_HNALDER_CLASS); + helper.setOptionCallBack("gps"); + helper.addOption(GpsConfig.GpsConfigOption.GPS_DEVICE); + helper.setOptionCallBack("gps"); + helper.addOption(GpsConfig.GpsConfigOption.GPS_SPEED); + helper.setOptionCallBack("gps"); + helper.addOption(GpsConfig.GpsConfigOption.GPS_CHECK_PERIOD); + helper.setOptionCallBack("gps"); + helper.addOption(GpsConfig.GpsConfigOption.GPS_TIMEOUT); + helper.setOptionCallBack("gps"); + } - @Override - public void run() { + // AUDIO + { + helper.addCategory(n_("sammoa.config.category.audio"), + n_("sammoa.config.category.audio.description")); + helper.registerCallBack( + "audio", n_("sammoa.action.reload.audio"), + SwingUtil.createActionIcon("config"), + new Runnable() { - if (SammoaScreen.FLIGHT == ui.getScreen()) { + @Override + public void run() { - FlightUI flightUI = (FlightUI) currentBody; + if (SammoaScreen.FLIGHT == ui.getScreen()) { - try { - FlightController flightController = flightUI.getHandler().getFlightController(); - flightController.openDeviceManager(GpsHandler.class); - } catch (DeviceTechnicalException ex) { - logger.error("Error on new GpsHandler", ex); - SammoaUtil.showErrorMessage(ui, ex.getMessageWithCause()); - } - } - } - }); - helper.addCategory(n_("sammoa.config.category.gps"), - n_("sammoa.config.category.gps.description")); - helper.addOption(GpsConfig.GpsConfigOption.GPS_HANDLER, - SammoaConfig.PROPERTY_GPS_CONFIG + "." + GpsConfig.PROPERTY_GPS_HNALDER_CLASS); - helper.setOptionCallBack("gps"); - helper.addOption(GpsConfig.GpsConfigOption.GPS_DEVICE); - helper.setOptionCallBack("gps"); - helper.addOption(GpsConfig.GpsConfigOption.GPS_SPEED); - helper.setOptionCallBack("gps"); - helper.addOption(GpsConfig.GpsConfigOption.GPS_CHECK_PERIOD); - helper.setOptionCallBack("gps"); - helper.addOption(GpsConfig.GpsConfigOption.GPS_TIMEOUT); - helper.setOptionCallBack("gps"); + reloadDevice((FlightUI) currentBody, AudioRecorder.class); - // others - helper.addCategory(n_("sammoa.config.category.other"), - n_("sammoa.config.category.other.description")); + } else if (SammoaScreen.VALIDATION == ui.getScreen()) { - helper.addOption(SammoaConfig.SammoaConfigOption.LOCALE); - helper.setOptionCallBack("ui"); + reloadDevice((FlightUI) currentBody, AudioReader.class); + } + } + } + ); + helper.addOption(AudioConfig.AudioConfigOption.SAMPLE_RATE); + helper.setOptionCallBack("audio"); + helper.addOption(AudioConfig.AudioConfigOption.SAMPLE_SIZE_IN_BITS); + helper.setOptionCallBack("audio"); + helper.addOption(AudioConfig.AudioConfigOption.RECORD_DELAY_IN_SECONDS); + helper.setOptionCallBack("audio"); + } - helper.addOption(SammoaConfig.SammoaConfigOption.SITE_URL); - helper.addOption(SammoaConfig.SammoaConfigOption.UI_CONFIG_FILE); - helper.setOptionCallBack("ui"); + // OTHER + { + helper.addCategory(n_("sammoa.config.category.other"), + n_("sammoa.config.category.other.description")); + helper.addOption(SammoaConfig.SammoaConfigOption.LOCALE); + helper.setOptionCallBack("ui"); + helper.addOption(SammoaConfig.SammoaConfigOption.SITE_URL); + helper.addOption(SammoaConfig.SammoaConfigOption.UI_CONFIG_FILE); + helper.setOptionCallBack("ui"); + } helper.buildUI(ui, "sammoa.config.category.applications"); helper.displayUI(ui, false); } + /** + * Reload the given device identified by its {@code deviceManagerClass} for + * {@code ui}. + * + * @param ui FlightUI contains the controller that manage devices + * @param deviceManagerClass Class of the device to reload + * @param <T> Type of {@link DeviceManager} + * @see FlightController#openDeviceManager(Class) + */ + protected <T extends DeviceManager> void reloadDevice(FlightUI ui, + Class<T> deviceManagerClass) { + try { + FlightController flightController = ui.getHandler().getFlightController(); + flightController.openDeviceManager(deviceManagerClass); + } catch (DeviceTechnicalException ex) { + logger.error("Error on new " + deviceManagerClass.getSimpleName(), ex); + SammoaUtil.showErrorMessage(ui, ex.getMessageWithCause()); + } + } + public void showHome() { if (checkCurrentFlight(_("sammoa.confirmDialog.flightInProgress.message.showHome"))) { setScreen(SammoaScreen.HOME); Modified: trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java =================================================================== --- trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-ui-swing/src/main/java/fr/ulr/sammoa/ui/swing/flight/FlightUIHandler.java 2012-09-04 16:05:15 UTC (rev 517) @@ -569,10 +569,10 @@ ((TransectFlightModel) input).getSource(); // Enabled only if no route match the transectFlight - // Note : the deleted route case is too complex, the user must delete routes before transect - boolean result = FluentIterable - .from(getModel().getRoutes()) - .anyMatch(Routes.withTransectFlight(transectFlight)); + // Note : the deleted route case is too complex, + // the user must delete routes before transect + boolean result = Routes.isAnyMatchTransectFlight( + getModel().getRoutes(), transectFlight); return !result; } }); @@ -600,7 +600,16 @@ @Override public boolean apply(Object input) { - return !((TransectFlightModel) input).isDeleted(); + TransectFlight transectFlight = + ((TransectFlightModel) input).getSource(); + + // Enabled only if no route match the transectFlight + // Note : the deleted route case is too complex, + // the user must create a new transectFlight to + // use it as next one + boolean result = Routes.isAnyMatchTransectFlight( + getModel().getRoutes(), transectFlight); + return !result; } }); Modified: trunk/sammoa-ui-swing/src/main/resources/i18n/sammoa-ui-swing_en_GB.properties =================================================================== --- trunk/sammoa-ui-swing/src/main/resources/i18n/sammoa-ui-swing_en_GB.properties 2012-09-04 16:04:55 UTC (rev 516) +++ trunk/sammoa-ui-swing/src/main/resources/i18n/sammoa-ui-swing_en_GB.properties 2012-09-04 16:05:15 UTC (rev 517) @@ -37,7 +37,8 @@ sammoa.action.quitExportMaps=Quit sammoa.action.quitImportApplication=Quit sammoa.action.reload.actions=Reload actions -sammoa.action.reload.gps=Reload GPS +sammoa.action.reload.audio=Relad Audio device +sammoa.action.reload.gps=Reload GPS device sammoa.action.reload.home=Reload home screen sammoa.action.reload.ui=Reload sammoa ui sammoa.action.right.tip=RIGHT \: create a new Observation for the observer on the right side @@ -56,9 +57,10 @@ sammoa.action.validTransect=Transect sammoa.action.validTransect.tip=Validate the selected transect and all its routes and observations sammoa.action.validation=Validation -sammoa.askQuestion.deleteTransect.message= sammoa.config.category.applications=Application sammoa.config.category.applications.description=Application +sammoa.config.category.audio=Audio +sammoa.config.category.audio.description=Audio configuration sammoa.config.category.gps=GPS sammoa.config.category.gps.description=GPS configuration sammoa.config.category.other=Other