adapted Audio action to new ESH TTS interfaces (#53)

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer 2016-08-20 20:49:39 +02:00 committed by GitHub
parent 795aab9b19
commit 33b6032405
9 changed files with 37 additions and 242 deletions

View File

@ -22,6 +22,8 @@ Import-Package: com.google.common.base,
org.eclipse.emf.common.util, org.eclipse.emf.common.util,
org.eclipse.emf.ecore, org.eclipse.emf.ecore,
org.eclipse.emf.ecore.resource, org.eclipse.emf.ecore.resource,
org.eclipse.smarthome.config.core,
org.eclipse.smarthome.core.audio,
org.eclipse.smarthome.core.autoupdate, org.eclipse.smarthome.core.autoupdate,
org.eclipse.smarthome.core.common.registry, org.eclipse.smarthome.core.common.registry,
org.eclipse.smarthome.core.events, org.eclipse.smarthome.core.events,
@ -32,7 +34,7 @@ Import-Package: com.google.common.base,
org.eclipse.smarthome.core.persistence, org.eclipse.smarthome.core.persistence,
org.eclipse.smarthome.core.transform, org.eclipse.smarthome.core.transform,
org.eclipse.smarthome.core.types, org.eclipse.smarthome.core.types,
org.eclipse.smarthome.io.voice.tts, org.eclipse.smarthome.core.voice,
org.eclipse.smarthome.model.item, org.eclipse.smarthome.model.item,
org.eclipse.smarthome.model.persistence, org.eclipse.smarthome.model.persistence,
org.eclipse.smarthome.model.script.engine, org.eclipse.smarthome.model.script.engine,
@ -89,7 +91,6 @@ Export-Package: org.codehaus.jackson,
org.openhab.core.types, org.openhab.core.types,
org.openhab.io.console, org.openhab.io.console,
org.openhab.io.multimedia.actions, org.openhab.io.multimedia.actions,
org.openhab.io.multimedia.tts,
org.openhab.io.net.actions, org.openhab.io.net.actions,
org.openhab.io.net.exec, org.openhab.io.net.exec,
org.openhab.io.net.http, org.openhab.io.net.http,
@ -104,3 +105,4 @@ Bundle-ClassPath: lib/jl1.0.1.jar,
lib/jackson-core-asl-1.9.2.jar, lib/jackson-core-asl-1.9.2.jar,
lib/jackson-mapper-asl-1.9.2.jar lib/jackson-mapper-asl-1.9.2.jar
Service-Component: OSGI-INF/*.xml Service-Component: OSGI-INF/*.xml
Bundle-ActivationPolicy: lazy

View File

@ -9,9 +9,10 @@
http://www.eclipse.org/legal/epl-v10.html http://www.eclipse.org/legal/epl-v10.html
--> -->
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.openhab.action.audio"> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.openhab.action.audio">
<implementation class="org.openhab.io.multimedia.actions.AudioActionService"/> <implementation class="org.openhab.io.multimedia.actions.AudioActionService"/>
<service> <service>
<provide interface="org.openhab.core.scriptengine.action.ActionService"/> <provide interface="org.openhab.core.scriptengine.action.ActionService"/>
</service> </service>
<reference bind="setVoiceManager" cardinality="1..1" interface="org.eclipse.smarthome.core.voice.VoiceManager" name="VoiceManager" policy="static" unbind="unsetVoiceManager"/>
</scr:component> </scr:component>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015-2016 by the respective copyright holders.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="org.openhab.core.compat1x.ttsservicefactory">
<implementation class="org.openhab.io.multimedia.tts.internal.TTSServiceFactory"/>
<reference bind="addTTSService" cardinality="0..n" interface="org.openhab.io.multimedia.tts.TTSService" name="TTSService" policy="dynamic" unbind="removeTTSService"/>
</scr:component>

View File

@ -3,14 +3,6 @@ bin.includes = META-INF/,\
.,\ .,\
lib/,\ lib/,\
OSGI-INF/,\ OSGI-INF/,\
OSGI-INF/autoupdateproviderdelegate.xml,\
OSGI-INF/eventbridge.xml,\
OSGI-INF/eventpublisherdelegate.xml,\
OSGI-INF/bindingconfigreaderfactory.xml,\
OSGI-INF/actionservicefactory.xml,\
OSGI-INF/itemuiregistry.xml,\
OSGI-INF/chartproviderfactory.xml,\
OSGI-INF/ttsservicefactory.xml,\
lib/jackson-core-asl-1.9.2.jar,\ lib/jackson-core-asl-1.9.2.jar,\
lib/jackson-mapper-asl-1.9.2.jar lib/jackson-mapper-asl-1.9.2.jar
source.. = src/main/java/ source.. = src/main/java/

View File

@ -18,7 +18,6 @@ import java.net.MalformedURLException;
import java.net.Socket; import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.Collection;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -33,15 +32,10 @@ import javax.sound.sampled.UnsupportedAudioFileException;
import org.apache.commons.collections.Closure; import org.apache.commons.collections.Closure;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils; import org.eclipse.smarthome.config.core.ConfigConstants;
import org.eclipse.smarthome.io.voice.tts.TTSService;
import org.openhab.core.compat1x.internal.CompatibilityActivator;
import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.PercentType;
import org.openhab.core.scriptengine.action.ActionDoc; import org.openhab.core.scriptengine.action.ActionDoc;
import org.openhab.core.scriptengine.action.ParamDoc; import org.openhab.core.scriptengine.action.ParamDoc;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -50,7 +44,6 @@ import javazoom.jl.player.Player;
public class Audio { public class Audio {
private static final String RUNTIME_DIR = "runtime";
private static final String SOUND_DIR = "sounds"; private static final String SOUND_DIR = "sounds";
private static final Logger logger = LoggerFactory.getLogger(Audio.class); private static final Logger logger = LoggerFactory.getLogger(Audio.class);
@ -65,7 +58,8 @@ public class Audio {
@ActionDoc(text = "plays a sound from the sounds folder") @ActionDoc(text = "plays a sound from the sounds folder")
static public void playSound(@ParamDoc(name = "filename", text = "the filename with extension") String filename) { static public void playSound(@ParamDoc(name = "filename", text = "the filename with extension") String filename) {
try { try {
InputStream is = new FileInputStream(RUNTIME_DIR + File.separator + SOUND_DIR + File.separator + filename); InputStream is = new FileInputStream(
ConfigConstants.getConfigFolder() + File.separator + SOUND_DIR + File.separator + filename);
if (filename.toLowerCase().endsWith(".mp3")) { if (filename.toLowerCase().endsWith(".mp3")) {
Player player = new Player(is); Player player = new Player(is);
playInThread(player); playInThread(player);
@ -168,7 +162,7 @@ public class Audio {
*/ */
@ActionDoc(text = "says a given text through the default TTS service") @ActionDoc(text = "says a given text through the default TTS service")
static public void say(@ParamDoc(name = "text") Object text) { static public void say(@ParamDoc(name = "text") Object text) {
say(text.toString(), null); AudioActionService.voiceManager.say(text.toString());
} }
/** /**
@ -185,7 +179,7 @@ public class Audio {
*/ */
@ActionDoc(text = "says a given text through the default TTS service with a given voice") @ActionDoc(text = "says a given text through the default TTS service with a given voice")
static public void say(@ParamDoc(name = "text") Object text, @ParamDoc(name = "voice") String voice) { static public void say(@ParamDoc(name = "text") Object text, @ParamDoc(name = "voice") String voice) {
say(text, voice, null); AudioActionService.voiceManager.say(text.toString(), voice);
} }
/** /**
@ -204,18 +198,8 @@ public class Audio {
*/ */
@ActionDoc(text = "says a given text through the default TTS service with a given voice") @ActionDoc(text = "says a given text through the default TTS service with a given voice")
static public void say(@ParamDoc(name = "text") Object text, @ParamDoc(name = "voice") String voice, static public void say(@ParamDoc(name = "text") Object text, @ParamDoc(name = "voice") String voice,
@ParamDoc(name = "device") String device) { @ParamDoc(name = "sink") String sink) {
if (StringUtils.isNotBlank(text.toString())) { AudioActionService.voiceManager.say(text.toString(), voice, sink);
TTSService ttsService = getTTSService(CompatibilityActivator.getContext(), System.getProperty("osgi.os"));
if (ttsService == null) {
ttsService = getTTSService(CompatibilityActivator.getContext(), "any");
}
if (ttsService != null) {
ttsService.say(text.toString(), voice, device);
} else {
logger.error("No TTS service available - tried to say: {}", text);
}
}
} }
@ActionDoc(text = "sets the master volume of the host") @ActionDoc(text = "sets the master volume of the host")
@ -387,31 +371,6 @@ public class Audio {
}.start(); }.start();
} }
/**
* Queries the OSGi service registry for a service that provides a TTS implementation
* for a given platform.
*
* @param context the bundle context to access the OSGi service registry
* @param os a valid osgi.os string value or "any" if service should be platform-independent
* @return a service instance or null, if none could be found
*/
static private TTSService getTTSService(BundleContext context, String os) {
if (context != null) {
String filter = os != null ? "(os=" + os + ")" : null;
try {
Collection<ServiceReference<TTSService>> refs = context.getServiceReferences(TTSService.class, filter);
if (refs != null && refs.size() > 0) {
return context.getService(refs.iterator().next());
} else {
return null;
}
} catch (InvalidSyntaxException e) {
// this should never happen
}
}
return null;
}
private static boolean isMacOSX() { private static boolean isMacOSX() {
return System.getProperty("osgi.os").equals("macosx"); return System.getProperty("osgi.os").equals("macosx");
} }

View File

@ -8,10 +8,13 @@
*/ */
package org.openhab.io.multimedia.actions; package org.openhab.io.multimedia.actions;
import org.eclipse.smarthome.core.voice.VoiceManager;
import org.openhab.core.scriptengine.action.ActionService; import org.openhab.core.scriptengine.action.ActionService;
public class AudioActionService implements ActionService { public class AudioActionService implements ActionService {
public static VoiceManager voiceManager;
@Override @Override
public String getActionClassName() { public String getActionClassName() {
return Audio.class.getCanonicalName(); return Audio.class.getCanonicalName();
@ -22,5 +25,11 @@ public class AudioActionService implements ActionService {
return Audio.class; return Audio.class;
} }
protected void setVoiceManager(VoiceManager voiceManager) {
AudioActionService.voiceManager = voiceManager;
} }
protected void unsetVoiceManager(VoiceManager voiceManager) {
AudioActionService.voiceManager = null;
}
}

View File

@ -1,33 +0,0 @@
/**
* Copyright (c) 2015-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.io.multimedia.tts;
/**
* This is the interface that a text-to-speech service has to implement.
*
* @author Kai Kreuzer - Initial contribution and API
*
*/
public interface TTSService {
/**
* Speaks the text with a given voice
*
* @param text
* the text to speak
* @param voice
* the name of the voice to use or null, if the default voice
* should be used
* @param device
* the name of audio device to be used to play the audio or null,
* if the default output device should be used
*/
void say(String text, String voice, String outputDevice);
}

View File

@ -1,33 +0,0 @@
/**
* Copyright (c) 2015-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.io.multimedia.tts.internal;
import org.eclipse.smarthome.io.voice.tts.TTSService;
/**
* This class serves as a mapping from the "old" org.openhab namespace to the
* new org.eclipse.smarthome namespace for the action service. It wraps an
* instance with the old interface into a class with the new interface.
*
* @author Tobias Bräutigam - Initial contribution and API
*/
public class TTSServiceDelegate implements TTSService {
private org.openhab.io.multimedia.tts.TTSService service;
public TTSServiceDelegate(org.openhab.io.multimedia.tts.TTSService service) {
this.service = service;
}
@Override
public void say(String text, String voice, String outputDevice) {
service.say(text, voice, outputDevice);
}
}

View File

@ -1,87 +0,0 @@
/**
* Copyright (c) 2015-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.io.multimedia.tts.internal;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.openhab.io.multimedia.tts.TTSService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class listens for services that implement the old tts service interface
* and registers an according service for each under the new interface.
*
* @author Tobias Bräutigam - Initial contribution and API (copied from
* ActionServiceFactory)
*/
public class TTSServiceFactory {
private static final Logger logger = LoggerFactory.getLogger(TTSServiceFactory.class);
private Map<String, ServiceRegistration<org.eclipse.smarthome.io.voice.tts.TTSService>> delegates = new HashMap<>();
private BundleContext context;
private Map<TTSService, Map> ttsServices = new HashMap<>();
public void activate(BundleContext context) {
this.context = context;
for (TTSService service : ttsServices.keySet()) {
registerDelegateService(service, ttsServices.get(service));
}
}
public void deactivate() {
for (ServiceRegistration<org.eclipse.smarthome.io.voice.tts.TTSService> serviceReg : delegates.values()) {
serviceReg.unregister();
}
delegates.clear();
this.context = null;
}
public void addTTSService(TTSService service, Map prop) {
if (context != null) {
registerDelegateService(service, prop);
} else {
ttsServices.put(service, prop);
}
}
public void removeTTSService(TTSService service) {
if (context != null) {
unregisterDelegateService(service);
}
}
private void registerDelegateService(TTSService ttsService, Map properties) {
if (!delegates.containsKey(ttsService.getClass().getName())) {
TTSServiceDelegate service = new TTSServiceDelegate(ttsService);
Dictionary<String, Object> props = new Hashtable<String, Object>();
if (properties != null && properties.containsKey("os")) {
props.put("os", properties.get("os"));
}
ServiceRegistration<org.eclipse.smarthome.io.voice.tts.TTSService> serviceReg = context
.registerService(org.eclipse.smarthome.io.voice.tts.TTSService.class, service, props);
delegates.put(ttsService.getClass().getName(), serviceReg);
}
}
private void unregisterDelegateService(TTSService service) {
if (delegates.containsKey(service.getClass().getName())) {
ServiceRegistration<org.eclipse.smarthome.io.voice.tts.TTSService> serviceReg = delegates
.get(service.getClass().getName());
delegates.remove(service.getClass().getName());
serviceReg.unregister();
}
}
}