[mactts] Add LRU cache (#15109)

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2023-07-01 10:59:30 +02:00 committed by GitHub
parent d12693419c
commit dd913e5245
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 7 deletions

View File

@ -54,3 +54,7 @@ org.openhab.voice:defaultVoice=mactts:Alex
## Supported Audio Formats
The MacTTS service produces audio streams using WAV containers and PCM (signed) codec with 16bit depth and 44.1kHz frequency.
## Caching
The macOS TTS service uses the openHAB TTS cache to cache audio files produced from the most recent queries in order to reduce traffic, improve performance and reduce number of requests.

View File

@ -22,6 +22,7 @@ import org.openhab.core.audio.AudioException;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.audio.FixedLengthAudioStream;
import org.openhab.core.common.Disposable;
import org.openhab.core.voice.Voice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -31,8 +32,9 @@ import org.slf4j.LoggerFactory;
*
* @author Kelly Davis - Initial contribution and API
* @author Kai Kreuzer - Refactored to use AudioStream and fixed audio format to produce
* @author Laurent Garnier - Add dispose method to delete the temporary file
*/
class MacTTSAudioStream extends FixedLengthAudioStream {
class MacTTSAudioStream extends FixedLengthAudioStream implements Disposable {
private final Logger logger = LoggerFactory.getLogger(MacTTSAudioStream.class);
@ -175,4 +177,17 @@ class MacTTSAudioStream extends FixedLengthAudioStream {
throw new AudioException("No temporary audio file available.");
}
}
@Override
public void dispose() throws IOException {
if (file != null && file.exists()) {
try {
if (!file.delete()) {
logger.warn("Failed to delete the file {}", file.getAbsolutePath());
}
} catch (SecurityException e) {
logger.warn("Failed to delete the file {}: {}", file.getAbsolutePath(), e.getMessage());
}
}
}
}

View File

@ -24,10 +24,14 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioException;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.voice.AbstractCachedTTSService;
import org.openhab.core.voice.TTSCache;
import org.openhab.core.voice.TTSException;
import org.openhab.core.voice.TTSService;
import org.openhab.core.voice.Voice;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -37,13 +41,19 @@ import org.slf4j.LoggerFactory;
* @author Kai Kreuzer - Initial contribution and API
* @author Pauli Antilla
* @author Kelly Davis
* @author Laurent Garnier : Implement TTS LRU cache
*/
@Component
@Component(service = TTSService.class)
@NonNullByDefault
public class MacTTSService implements TTSService {
public class MacTTSService extends AbstractCachedTTSService {
private final Logger logger = LoggerFactory.getLogger(MacTTSService.class);
@Activate
public MacTTSService(final @Reference TTSCache ttsCache) {
super(ttsCache);
}
/**
* Set of supported voices
*/
@ -66,7 +76,7 @@ public class MacTTSService implements TTSService {
}
@Override
public AudioStream synthesize(String text, Voice voice, AudioFormat requestedFormat) throws TTSException {
public AudioStream synthesizeForCache(String text, Voice voice, AudioFormat requestedFormat) throws TTSException {
// Validate arguments
if (text.isEmpty()) {
throw new TTSException("The passed text is null or empty");

View File

@ -16,13 +16,17 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.storage.StorageService;
import org.openhab.core.voice.TTSException;
import org.openhab.core.voice.Voice;
import org.openhab.core.voice.internal.cache.TTSLRUCacheImpl;
/**
* Test TTSServiceMacOS
@ -31,6 +35,8 @@ import org.openhab.core.voice.Voice;
*/
public class TTSServiceMacOSTest {
private StorageService storageService;
/**
* Test TTSServiceMacOS.getAvailableVoices()
*/
@ -38,7 +44,10 @@ public class TTSServiceMacOSTest {
public void getAvailableVoicesTest() {
assumeTrue("Mac OS X".equals(System.getProperty("os.name")));
MacTTSService ttsServiceMacOS = new MacTTSService();
Map<String, Object> config = new HashMap<>();
config.put("enableCacheTTS", false);
TTSLRUCacheImpl voiceLRUCache = new TTSLRUCacheImpl(storageService, config);
MacTTSService ttsServiceMacOS = new MacTTSService(voiceLRUCache);
assertFalse(ttsServiceMacOS.getAvailableVoices().isEmpty());
}
@ -49,7 +58,10 @@ public class TTSServiceMacOSTest {
public void getSupportedFormatsTest() {
assumeTrue("Mac OS X".equals(System.getProperty("os.name")));
MacTTSService ttsServiceMacOS = new MacTTSService();
Map<String, Object> config = new HashMap<>();
config.put("enableCacheTTS", false);
TTSLRUCacheImpl voiceLRUCache = new TTSLRUCacheImpl(storageService, config);
MacTTSService ttsServiceMacOS = new MacTTSService(voiceLRUCache);
assertFalse(ttsServiceMacOS.getSupportedFormats().isEmpty());
}
@ -60,7 +72,10 @@ public class TTSServiceMacOSTest {
public void synthesizeTest() throws IOException, TTSException {
assumeTrue("Mac OS X".equals(System.getProperty("os.name")));
MacTTSService ttsServiceMacOS = new MacTTSService();
Map<String, Object> config = new HashMap<>();
config.put("enableCacheTTS", false);
TTSLRUCacheImpl voiceLRUCache = new TTSLRUCacheImpl(storageService, config);
MacTTSService ttsServiceMacOS = new MacTTSService(voiceLRUCache);
Set<Voice> voices = ttsServiceMacOS.getAvailableVoices();
Set<AudioFormat> audioFormats = ttsServiceMacOS.getSupportedFormats();
try (AudioStream audioStream = ttsServiceMacOS.synthesize("Hello", voices.iterator().next(),