Add null annotations to org.openhab.core.voice (#2255)

Allows for using null annotations with the voice TTS add-ons.

Signed-off-by: Wouter Born <github@maindrain.net>
pull/2254/head
Wouter Born 2021-03-25 20:19:11 +01:00 committed by GitHub
parent 07b95ca668
commit db11cfda51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 134 additions and 42 deletions

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} starts hearing audio.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class AudioStartEvent implements STTEvent {
}

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} stops hearing audio.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class AudioStopEvent implements STTEvent {
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link KSEvent} fired when the {@link KSService} encounters an error.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class KSErrorEvent implements KSEvent {
/**
* The message describing the error

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A tagging interface for keyword spotting events.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface KSEvent {
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* General purpose keyword spotting exception
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class KSException extends Exception {
private static final long serialVersionUID = 1L;

View File

@ -12,6 +12,8 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The listener interface for receiving {@link KSEvent} events.
*
@ -22,6 +24,7 @@ package org.openhab.core.voice;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface KSListener {
/**
* Invoked when a {@link KSEvent} event occurs during keyword spotting.

View File

@ -15,6 +15,8 @@ package org.openhab.core.voice;
import java.util.Locale;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
@ -24,6 +26,7 @@ import org.openhab.core.audio.AudioStream;
* @author Kelly Davis - Initial contribution
* @author Kai Kreuzer - Refactored to use AudioStream
*/
@NonNullByDefault
public interface KSService {
/**
@ -39,7 +42,7 @@ public interface KSService {
* @param locale the locale to provide the label for
* @return a localized string to be used in UIs
*/
public String getLabel(Locale locale);
public String getLabel(@Nullable Locale locale);
/**
* Obtain the Locales available from this KSService

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* An handle to a {@link KSService}
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface KSServiceHandle {
/**
* Aborts keyword spotting in the associated {@link KSService}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link KSEvent} fired when the {@link KSService} spots a keyword.
*
* @author Kelly Davis - Initial contribution
* @author Yannick Schaus - Removed AudioSource information
*/
@NonNullByDefault
public class KSpottedEvent implements KSEvent {
}

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} starts recognition.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class RecognitionStartEvent implements STTEvent {
}

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} stops recognition.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class RecognitionStopEvent implements STTEvent {
}

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A tagging interface for speech-to-text events.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface STTEvent {
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* General purpose STT exception
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class STTException extends Exception {
private static final long serialVersionUID = 1L;

View File

@ -12,6 +12,8 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The listener interface for receiving {@link STTEvent} events.
*
@ -22,6 +24,7 @@ package org.openhab.core.voice;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface STTListener {
/**

View File

@ -15,6 +15,8 @@ package org.openhab.core.voice;
import java.util.Locale;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
@ -23,6 +25,7 @@ import org.openhab.core.audio.AudioStream;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface STTService {
/**
@ -38,7 +41,7 @@ public interface STTService {
* @param locale the locale to provide the label for
* @return a localized string to be used in UIs
*/
public String getLabel(Locale locale);
public String getLabel(@Nullable Locale locale);
/**
* Obtain the Locales available from this STTService

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* An handle to a {@link STTService}
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface STTServiceHandle {
/**
* Aborts recognition in the associated {@link STTService}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} encounters an error.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class SpeechRecognitionErrorEvent implements STTEvent {
/**
* The message describing the error

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} recognizes speech.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class SpeechRecognitionEvent implements STTEvent {
/**
* Confidence of recognized speech

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} starts hearing speech.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class SpeechStartEvent implements STTEvent {
}

View File

@ -12,10 +12,13 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A {@link STTEvent} fired when the {@link STTService} stops hearing speech.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class SpeechStopEvent implements STTEvent {
}

View File

@ -12,11 +12,14 @@
*/
package org.openhab.core.voice;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* General purpose TTS exception
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class TTSException extends Exception {
private static final long serialVersionUID = 1L;

View File

@ -15,6 +15,8 @@ package org.openhab.core.voice;
import java.util.Locale;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
@ -24,6 +26,7 @@ import org.openhab.core.audio.AudioStream;
* @author Kelly Davis - Initial contribution
* @author Kai Kreuzer - Refactored to use AudioStreams
*/
@NonNullByDefault
public interface TTSService {
/**
@ -39,7 +42,7 @@ public interface TTSService {
* @param locale the locale to provide the label for
* @return a localized string to be used in UIs
*/
public String getLabel(Locale locale);
public String getLabel(@Nullable Locale locale);
/**
* Obtain the voices available from this TTSService

View File

@ -14,11 +14,14 @@ package org.openhab.core.voice;
import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* This is the interface that a text-to-speech voice has to implement.
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public interface Voice {
/**

View File

@ -12,8 +12,11 @@
*/
package org.openhab.core.voice.internal;
import static org.openhab.core.voice.internal.VoiceManagerImpl.getBestMatch;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.openhab.core.audio.AudioException;
import org.openhab.core.audio.AudioFormat;
@ -104,7 +107,7 @@ public class DialogProcessor implements KSListener, STTListener {
public void start() {
try {
ks.spot(this, source.getInputStream(format), locale, this.keyword);
ks.spot(this, source.getInputStream(format), locale, keyword);
} catch (KSException e) {
logger.error("Encountered error calling spot: {}", e.getMessage());
} catch (AudioException e) {
@ -113,10 +116,10 @@ public class DialogProcessor implements KSListener, STTListener {
}
private void toggleProcessing(boolean value) {
if (this.processing == value) {
if (processing == value) {
return;
}
this.processing = value;
processing = value;
if (listeningItem != null && ItemUtil.isValidItemName(listeningItem)) {
OnOffType command = (value) ? OnOffType.ON : OnOffType.OFF;
eventPublisher.post(ItemEventFactory.createCommandEvent(listeningItem, command));
@ -126,13 +129,12 @@ public class DialogProcessor implements KSListener, STTListener {
@Override
public void ksEventReceived(KSEvent ksEvent) {
if (!processing) {
this.isSTTServerAborting = false;
isSTTServerAborting = false;
if (ksEvent instanceof KSpottedEvent) {
toggleProcessing(true);
if (stt != null) {
try {
this.sttServiceHandle = stt.recognize(this, source.getInputStream(format), this.locale,
new HashSet<>());
sttServiceHandle = stt.recognize(this, source.getInputStream(format), locale, new HashSet<>());
} catch (STTException e) {
say("Error during recognition: " + e.getMessage());
} catch (AudioException e) {
@ -149,14 +151,14 @@ public class DialogProcessor implements KSListener, STTListener {
@Override
public synchronized void sttEventReceived(STTEvent sttEvent) {
if (sttEvent instanceof SpeechRecognitionEvent) {
if (!this.isSTTServerAborting) {
this.sttServiceHandle.abort();
this.isSTTServerAborting = true;
if (!isSTTServerAborting) {
sttServiceHandle.abort();
isSTTServerAborting = true;
SpeechRecognitionEvent sre = (SpeechRecognitionEvent) sttEvent;
String question = sre.getTranscript();
try {
toggleProcessing(false);
String answer = hli.interpret(this.locale, question);
String answer = hli.interpret(locale, question);
if (answer != null) {
say(answer);
}
@ -167,9 +169,9 @@ public class DialogProcessor implements KSListener, STTListener {
} else if (sttEvent instanceof RecognitionStopEvent) {
toggleProcessing(false);
} else if (sttEvent instanceof SpeechRecognitionErrorEvent) {
if (!this.isSTTServerAborting) {
this.sttServiceHandle.abort();
this.isSTTServerAborting = true;
if (!isSTTServerAborting) {
sttServiceHandle.abort();
isSTTServerAborting = true;
toggleProcessing(false);
SpeechRecognitionErrorEvent sre = (SpeechRecognitionErrorEvent) sttEvent;
say("Encountered error: " + sre.getMessage());
@ -186,15 +188,23 @@ public class DialogProcessor implements KSListener, STTListener {
try {
Voice voice = null;
for (Voice currentVoice : tts.getAvailableVoices()) {
if (this.locale.getLanguage().equals(currentVoice.getLocale().getLanguage())) {
if (locale.getLanguage().equals(currentVoice.getLocale().getLanguage())) {
voice = currentVoice;
break;
}
}
if (null == voice) {
if (voice == null) {
throw new TTSException("Unable to find a suitable voice");
}
AudioStream audioStream = tts.synthesize(text, voice, null);
Set<AudioFormat> audioFormats = tts.getSupportedFormats();
AudioFormat audioFormat = getBestMatch(audioFormats, sink.getSupportedFormats());
if (audioFormat == null) {
throw new TTSException("No compatible audio format found for TTS '" + tts.getId() + "' and sink '"
+ sink.getId() + "'");
}
AudioStream audioStream = tts.synthesize(text, voice, audioFormat);
if (sink.getSupportedStreams().stream().anyMatch(clazz -> clazz.isInstance(audioStream))) {
try {

View File

@ -14,6 +14,7 @@ package org.openhab.core.voice;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
/**
@ -21,6 +22,7 @@ import org.junit.jupiter.api.Test;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class STTExceptionTest {
/**

View File

@ -14,6 +14,7 @@ package org.openhab.core.voice;
import static org.junit.jupiter.api.Assertions.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
/**
@ -21,6 +22,7 @@ import org.junit.jupiter.api.Test;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class SpeechRecognitionErrorEventTest {
/**

View File

@ -14,6 +14,7 @@ package org.openhab.core.voice;
import static org.junit.jupiter.api.Assertions.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
/**
@ -21,6 +22,7 @@ import org.junit.jupiter.api.Test;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class SpeechRecognitionEventTest {
/**

View File

@ -14,6 +14,7 @@ package org.openhab.core.voice;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
/**
@ -21,6 +22,7 @@ import org.junit.jupiter.api.Test;
*
* @author Kelly Davis - Initial contribution
*/
@NonNullByDefault
public class TTSExceptionTest {
/**

View File

@ -54,7 +54,7 @@ public class KSServiceStub implements KSService {
@Override
public Set<Locale> getSupportedLocales() {
return null;
return Set.of();
}
@Override

View File

@ -15,6 +15,8 @@ package org.openhab.core.voice.internal;
import java.util.Locale;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.voice.STTException;
@ -28,6 +30,7 @@ import org.openhab.core.voice.STTServiceHandle;
* @author Mihaela Memova - Initial contribution
* @author Velin Yordanov - migrated from groovy to java
*/
@NonNullByDefault
public class STTServiceStub implements STTService {
private static final Set<AudioFormat> SUPPORTED_FORMATS = Set.of(AudioFormat.MP3, AudioFormat.WAV);
@ -41,13 +44,13 @@ public class STTServiceStub implements STTService {
}
@Override
public String getLabel(Locale locale) {
public String getLabel(@Nullable Locale locale) {
return STTSERVICE_STUB_LABEL;
}
@Override
public Set<Locale> getSupportedLocales() {
return null;
return Set.of();
}
@Override

View File

@ -14,10 +14,12 @@ package org.openhab.core.voice.internal;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.voice.TTSException;
@ -33,6 +35,7 @@ import org.osgi.framework.ServiceReference;
* @author Mihaela Memova - Initial contribution
* @author Velin Yordanov - migrated from groovy to java
*/
@NonNullByDefault
public class TTSServiceStub implements TTSService {
private static final Set<AudioFormat> SUPPORTED_FORMATS = Set.of(AudioFormat.MP3, AudioFormat.WAV);
@ -40,45 +43,42 @@ public class TTSServiceStub implements TTSService {
private static final String TTS_SERVICE_STUB_ID = "ttsServiceStubID";
private static final String TTS_SERVICE_STUB_LABEL = "ttsServiceStubLabel";
private Set<Voice> availableVoices;
private BundleContext context;
private @Nullable BundleContext context;
public TTSServiceStub() {
}
public TTSServiceStub(BundleContext context) {
this.context = context;
}
public TTSServiceStub() {
}
@Override
public String getId() {
return TTS_SERVICE_STUB_ID;
}
@Override
public String getLabel(Locale locale) {
public String getLabel(@Nullable Locale locale) {
return TTS_SERVICE_STUB_LABEL;
}
@Override
public Set<Voice> getAvailableVoices() {
availableVoices = new HashSet<>();
Collection<ServiceReference<Voice>> refs;
BundleContext bundleContext = this.context;
if (bundleContext == null) {
return Set.of();
}
try {
refs = context.getServiceReferences(Voice.class, null);
if (refs != null) {
for (ServiceReference<Voice> ref : refs) {
Voice service = context.getService(ref);
if (service.getUID().startsWith(getId())) {
availableVoices.add(service);
}
}
}
Collection<ServiceReference<Voice>> refs = bundleContext.getServiceReferences(Voice.class, null);
return refs.stream() //
.map(ref -> bundleContext.getService(ref)) //
.filter(service -> service.getUID().startsWith(getId())) //
.collect(Collectors.toSet());
} catch (InvalidSyntaxException e) {
// If the specified filter contains an invalid filter expression that cannot be parsed.
return null;
return Set.of();
}
return availableVoices;
}
@Override

View File

@ -14,6 +14,7 @@ package org.openhab.core.voice.internal;
import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.voice.Voice;
/**
@ -22,6 +23,7 @@ import org.openhab.core.voice.Voice;
* @author Mihaela Memova - Initial contribution
* @author Velin Yordanov - migrated from groovy to java
*/
@NonNullByDefault
public class VoiceStub implements Voice {
private TTSServiceStub ttsService = new TTSServiceStub();