Started adding js voice guidance

This commit is contained in:
PaulStets 2018-07-27 16:30:45 +03:00
parent 78d78036d5
commit 638f487eda
9 changed files with 396 additions and 3 deletions

View file

@ -2913,4 +2913,6 @@
<string name="wiki_article_search_text">Searching for the corresponding wiki article</string>
<string name="wiki_article_not_found">Article not found</string>
<string name="how_to_open_wiki_title">How to open Wikipedia articles?</string>
<string name="use_js_voice_guidance">Use JS voice guidance</string>
<string name="use_js_voice_guidance_description">Use new voice guidance logic based on JavaScript</string>
</resources>

View file

@ -46,6 +46,7 @@ import net.osmand.plus.search.QuickSearchHelper;
import net.osmand.plus.views.corenative.NativeCoreContext;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.plus.voice.CommandPlayerException;
import net.osmand.plus.voice.JSTTSCommandPlayerImpl;
import net.osmand.plus.voice.MediaCommandPlayerImpl;
import net.osmand.plus.voice.TTSCommandPlayerImpl;
import net.osmand.plus.wikivoyage.data.TravelDbHelper;
@ -577,7 +578,9 @@ public class AppInitializer implements IProgress {
if (!voiceDir.exists()) {
throw new CommandPlayerException(ctx.getString(R.string.voice_data_unavailable));
}
if (app.getSettings().USE_JS_VOICE_GUIDANCE.get()) {
return new JSTTSCommandPlayerImpl(osmandApplication, applicationMode, osmandApplication.getRoutingHelper().getVoiceRouter(), voiceProvider);
}
if (MediaCommandPlayerImpl.isMyData(voiceDir)) {
return new MediaCommandPlayerImpl(osmandApplication, applicationMode, osmandApplication.getRoutingHelper().getVoiceRouter(), voiceProvider);
} else if (TTSCommandPlayerImpl.isMyData(voiceDir)) {

View file

@ -1340,6 +1340,8 @@ public class OsmandSettings {
public final OsmandPreference<Boolean> ANIMATE_MY_LOCATION = new BooleanPreference("animate_my_location", true).makeGlobal().cache();
public final OsmandPreference<Boolean> USE_JS_VOICE_GUIDANCE = new BooleanPreference("use_js_voice_guidance", false);
public final OsmandPreference<Boolean> ROUTE_MAP_MARKERS_START_MY_LOC = new BooleanPreference("route_map_markers_start_my_loc", false).makeGlobal().cache();
public final OsmandPreference<Boolean> ROUTE_MAP_MARKERS_ROUND_TRIP = new BooleanPreference("route_map_markers_round_trip", false).makeGlobal().cache();

View file

@ -63,6 +63,9 @@ public class SettingsDevelopmentActivity extends SettingsBaseActivity {
R.string.animate_my_location,
R.string.animate_my_location_desc));
cat.addPreference(createCheckBoxPreference(settings.USE_JS_VOICE_GUIDANCE, getString(R.string.use_js_voice_guidance),
getString(R.string.use_js_voice_guidance_description)));
final Preference firstRunPreference = new Preference(this);
firstRunPreference.setTitle(R.string.simulate_initial_startup);
firstRunPreference.setSummary(R.string.simulate_initial_startup_descr);

View file

@ -69,6 +69,8 @@ public class VoiceRouter {
private static RouteDirectionInfo nextRouteDirection;
private Term empty;
private boolean useJS;
public interface VoiceMessageListener {
void onVoiceMessage();
}
@ -78,6 +80,7 @@ public class VoiceRouter {
public VoiceRouter(RoutingHelper router, final OsmandSettings settings) {
this.router = router;
this.settings = settings;
useJS = settings.USE_JS_VOICE_GUIDANCE.get();
this.mute = settings.VOICE_MUTE.get();
empty = new Struct("");
voiceMessageListeners = new ConcurrentHashMap<VoiceRouter.VoiceMessageListener, Integer>();

View file

@ -0,0 +1,54 @@
package net.osmand.plus.voice;
import java.util.List;
import alice.tuprolog.Struct;
public class AbstractJSCommandPlayer implements CommandPlayer {
@Override
public String getCurrentVoice() {
return null;
}
@Override
public CommandBuilder newCommandBuilder() {
JSCommandBuilder commandBuilder = new JSCommandBuilder(this);
commandBuilder.setParameters("km-m", true);
return commandBuilder;
}
@Override
public void playCommands(CommandBuilder builder) {
}
@Override
public void clear() {
}
@Override
public List<String> execute(List<Struct> listStruct) {
return null;
}
@Override
public void updateAudioStream(int streamType) {
}
@Override
public String getLanguage() {
return null;
}
@Override
public boolean supportsStructuredStreetNames() {
return true;
}
@Override
public void stop() {
}
}

View file

@ -53,8 +53,8 @@ public class CommandBuilder {
/**
*
*/
private final CommandPlayer commandPlayer;
private boolean alreadyExecuted = false;
protected final CommandPlayer commandPlayer;
protected boolean alreadyExecuted = false;
private List<Struct> listStruct = new ArrayList<Struct>();
public CommandBuilder(CommandPlayer commandPlayer){

View file

@ -0,0 +1,220 @@
package net.osmand.plus.voice;
import net.osmand.PlatformUtil;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JSCommandBuilder extends CommandBuilder {
private static final Log log = PlatformUtil.getLog(JSCommandBuilder.class);
protected static final String C_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
protected static final String C_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
protected static final String C_PREPARE_MAKE_UT = "prepare_make_ut"; //$NON-NLS-1$
protected static final String C_ROUNDABOUT = "roundabout"; //$NON-NLS-1$
protected static final String C_GO_AHEAD = "go_ahead"; //$NON-NLS-1$
protected static final String C_TURN = "turn"; //$NON-NLS-1$
protected static final String C_MAKE_UT = "make_ut"; //$NON-NLS-1$
protected static final String C_MAKE_UTWP = "make_ut_wp"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_DESTINATION = "and_arrive_destination"; //$NON-NLS-1$
protected static final String C_REACHED_DESTINATION = "reached_destination"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_INTERMEDIATE = "and_arrive_intermediate"; //$NON-NLS-1$
protected static final String C_REACHED_INTERMEDIATE = "reached_intermediate"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_WAYPOINT = "and_arrive_waypoint"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_FAVORITE = "and_arrive_favorite"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_POI_WAYPOINT = "and_arrive_poi"; //$NON-NLS-1$
protected static final String C_REACHED_WAYPOINT = "reached_waypoint"; //$NON-NLS-1$
protected static final String C_REACHED_FAVORITE = "reached_favorite"; //$NON-NLS-1$
protected static final String C_REACHED_POI = "reached_poi"; //$NON-NLS-1$
protected static final String C_THEN = "then"; //$NON-NLS-1$
protected static final String C_SPEAD_ALARM = "speed_alarm"; //$NON-NLS-1$
protected static final String C_ATTENTION = "attention"; //$NON-NLS-1$
protected static final String C_OFF_ROUTE = "off_route"; //$NON-NLS-1$
protected static final String C_BACK_ON_ROUTE ="back_on_route"; //$NON-NLS-1$
protected static final String C_BEAR_LEFT = "bear_left"; //$NON-NLS-1$
protected static final String C_BEAR_RIGHT = "bear_right"; //$NON-NLS-1$
protected static final String C_ROUTE_RECALC = "route_recalc"; //$NON-NLS-1$
protected static final String C_ROUTE_NEW_CALC = "route_new_calc"; //$NON-NLS-1$
protected static final String C_LOCATION_LOST = "location_lost"; //$NON-NLS-1$
protected static final String C_LOCATION_RECOVERED = "location_recovered"; //$NON-NLS-1$
private List<String> listStruct = new ArrayList<>();
public JSCommandBuilder(CommandPlayer commandPlayer) {
super(commandPlayer);
}
public void setParameters(String metricCons, boolean tts) {
// TODO Set the parameters to js context
}
private JSCommandBuilder addCommand(String name, Object... args){
// TODO add JSCore
listStruct.add(name);
return this;
}
public JSCommandBuilder goAhead(){
return goAhead(-1, new HashMap<String, String>());
}
public JSCommandBuilder goAhead(double dist, Map<String, String> streetName){
return addCommand(C_GO_AHEAD, dist, streetName);
}
public JSCommandBuilder makeUTwp(){
return makeUT(new HashMap<String, String>());
}
public JSCommandBuilder makeUT(Map<String, String> streetName){
return addCommand(C_MAKE_UT, streetName);
}
@Override
public JSCommandBuilder speedAlarm(int maxSpeed, float speed){
return addCommand(C_SPEAD_ALARM, maxSpeed, speed);
}
@Override
public JSCommandBuilder attention(String type){
return addCommand(C_ATTENTION, type);
}
@Override
public JSCommandBuilder offRoute(double dist){
return addCommand(C_OFF_ROUTE, dist);
}
@Override
public CommandBuilder backOnRoute(){
return addCommand(C_BACK_ON_ROUTE);
}
public JSCommandBuilder makeUT(double dist, Map<String,String> streetName){
return addCommand(C_MAKE_UT, dist, streetName);
}
public JSCommandBuilder prepareMakeUT(double dist, Map<String, String> streetName){
return addCommand(C_PREPARE_MAKE_UT, dist, streetName);
}
public JSCommandBuilder turn(String param, Map<String, String> streetName) {
return addCommand(C_TURN, param, streetName);
}
public JSCommandBuilder turn(String param, double dist, Map<String, String> streetName){
return addCommand(C_TURN, param, dist, streetName);
}
/**
*
* @param param A_LEFT, A_RIGHT, ...
* @param dist
* @return
*/
public JSCommandBuilder prepareTurn(String param, double dist, Map<String, String> streetName){
return addCommand(C_PREPARE_TURN, param, dist, streetName);
}
public JSCommandBuilder prepareRoundAbout(double dist, int exit, Map<String, String> streetName){
return addCommand(C_PREPARE_ROUNDABOUT, dist, exit, streetName);
}
public JSCommandBuilder roundAbout(double dist, double angle, int exit, Map<String, String> streetName){
return addCommand(C_ROUNDABOUT, dist, angle, exit, streetName);
}
public JSCommandBuilder roundAbout(double angle, int exit, Map<String, String> streetName) {
return roundAbout(-1, angle, exit, streetName);
}
@Override
public JSCommandBuilder andArriveAtDestination(String name){
return addCommand(C_AND_ARRIVE_DESTINATION, name);
}
@Override
public JSCommandBuilder arrivedAtDestination(String name){
return addCommand(C_REACHED_DESTINATION, name);
}
@Override
public JSCommandBuilder andArriveAtIntermediatePoint(String name){
return addCommand(C_AND_ARRIVE_INTERMEDIATE, name);
}
@Override
public JSCommandBuilder arrivedAtIntermediatePoint(String name) {
return addCommand(C_REACHED_INTERMEDIATE, name);
}
@Override
public JSCommandBuilder andArriveAtWayPoint(String name){
return addCommand(C_AND_ARRIVE_WAYPOINT, name);
}
@Override
public JSCommandBuilder arrivedAtWayPoint(String name) {
return addCommand(C_REACHED_WAYPOINT, name);
}
@Override
public JSCommandBuilder andArriveAtFavorite(String name) {
return addCommand(C_AND_ARRIVE_FAVORITE, name);
}
@Override
public JSCommandBuilder arrivedAtFavorite(String name) {
return addCommand(C_REACHED_FAVORITE, name);
}
@Override
public JSCommandBuilder andArriveAtPoi(String name) {
return addCommand(C_AND_ARRIVE_POI_WAYPOINT, name);
}
@Override
public JSCommandBuilder arrivedAtPoi(String name) {
return addCommand(C_REACHED_POI, name);
}
public JSCommandBuilder bearLeft(Map<String,String> streetName){
return addCommand(C_BEAR_LEFT, streetName);
}
public JSCommandBuilder bearRight(Map<String, String> streetName){
return addCommand(C_BEAR_RIGHT, streetName);
}
@Override
public JSCommandBuilder then(){
return addCommand(C_THEN);
}
@Override
public JSCommandBuilder gpsLocationLost() {
return addCommand(C_LOCATION_LOST);
}
@Override
public JSCommandBuilder gpsLocationRecover() {
return addCommand(C_LOCATION_RECOVERED);
}
@Override
public JSCommandBuilder newRouteCalculated(double dist, int time){
return addCommand(C_ROUTE_NEW_CALC, dist, time);
}
@Override
public JSCommandBuilder routeRecalculated(double dist, int time){
return addCommand(C_ROUTE_RECALC, dist, time);
}
@Override
public void play(){
this.commandPlayer.playCommands(this);
}
@Override
protected List<String> execute(){
alreadyExecuted = true;
return listStruct;
}
}

View file

@ -0,0 +1,106 @@
package net.osmand.plus.voice;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.speech.tts.TextToSpeech;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.routing.VoiceRouter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class JSTTSCommandPlayerImpl extends AbstractJSCommandPlayer {
private static final String TAG = JSTTSCommandPlayerImpl.class.getSimpleName();
private static TextToSpeech mTts;
private OsmandApplication app;
private ApplicationMode appMode;
private VoiceRouter vrt;
private String voiceProvider;
private HashMap<String, String> params = new HashMap<String, String>();
private static int ttsRequests = 0;
public JSTTSCommandPlayerImpl(OsmandApplication ctx, ApplicationMode applicationMode, VoiceRouter vrt, String voiceProvider) {
this.app = ctx;
this.appMode = applicationMode;
this.vrt = vrt;
this.voiceProvider = voiceProvider;
mTts = new TextToSpeech(ctx, null);
}
@Override
public String getCurrentVoice() {
return null;
}
@Override
public JSCommandBuilder newCommandBuilder() {
JSCommandBuilder commandBuilder = new JSCommandBuilder(this);
commandBuilder.setParameters(app.getSettings().METRIC_SYSTEM.get().toHumanString(app), true);
return commandBuilder;
}
@Override
public void playCommands(CommandBuilder builder) {
final List<String> execute = builder.execute(); //list of strings, the speech text, play it
StringBuilder bld = new StringBuilder();
for (String s : execute) {
bld.append(s).append(' ');
}
if (mTts != null && !vrt.isMute()) {
if (ttsRequests++ == 0) {
// Delay first prompt of each batch to allow BT SCO connection being established
if (app.getSettings().AUDIO_STREAM_GUIDANCE.getModeValue(appMode) == 0) {
ttsRequests++;
if (android.os.Build.VERSION.SDK_INT < 21) {
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,""+System.currentTimeMillis());
mTts.playSilence(app.getSettings().BT_SCO_DELAY.get(), TextToSpeech.QUEUE_ADD, params);
} else {
mTts.playSilentUtterance(app.getSettings().BT_SCO_DELAY.get(), TextToSpeech.QUEUE_ADD, ""+System.currentTimeMillis());
}
}
}
Log.d(TAG, "ttsRequests= "+ttsRequests);
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,""+System.currentTimeMillis());
mTts.speak(bld.toString(), TextToSpeech.QUEUE_ADD, params);
// Audio focus will be released when onUtteranceCompleted() completed is called by the TTS engine.
} else if (app != null && vrt.isMute()) {
// sendAlertToAndroidWear(ctx, bld.toString());
}
}
@Override
public void clear() {
}
@Override
public void updateAudioStream(int streamType) {
}
@Override
public String getLanguage() {
return null;
}
@Override
public boolean supportsStructuredStreetNames() {
return false;
}
@Override
public void stop() {
}
}