/**
* Copyright (c) 2014-2017 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.eclipse.smarthome.voice.mactts.internal;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.eclipse.smarthome.core.audio.AudioException;
import org.eclipse.smarthome.core.audio.AudioFormat;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.voice.TTSException;
import org.eclipse.smarthome.core.voice.TTSService;
import org.eclipse.smarthome.core.voice.Voice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a TTS service implementation for Mac OS, which simply uses the "say" command from the OS.
*
* @author Kai Kreuzer - Initial contribution and API
* @author Pauli Antilla
* @author Kelly Davis
*/
public class MacTTSService implements TTSService {
private final Logger logger = LoggerFactory.getLogger(MacTTSService.class);
/**
* Set of supported voices
*/
private final Set<Voice> voices = initVoices();
/**
* Set of supported audio formats
*/
private final Set<AudioFormat> audioFormats = initAudioFormats();
@Override
public Set<Voice> getAvailableVoices() {
return this.voices;
}
@Override
public Set<AudioFormat> getSupportedFormats() {
return this.audioFormats;
}
@Override
public AudioStream synthesize(String text, Voice voice, AudioFormat requestedFormat) throws TTSException {
// Validate arguments
if ((null == text) || text.isEmpty()) {
throw new TTSException("The passed text is null or empty");
}
if (!this.voices.contains(voice)) {
throw new TTSException("The passed voice is unsupported");
}
boolean isAudioFormatSupported = false;
for (AudioFormat currentAudioFormat : this.audioFormats) {
if (currentAudioFormat.isCompatible(requestedFormat)) {
isAudioFormatSupported = true;
break;
}
}
if (!isAudioFormatSupported) {
throw new TTSException("The passed AudioFormat is unsupported");
}
try {
return new MacTTSAudioStream(text, voice, requestedFormat);
} catch (AudioException e) {
throw new TTSException(e);
}
}
/**
* Initializes this.voices
*
* @return The voices of this instance
*/
private final Set<Voice> initVoices() {
Set<Voice> voices = new HashSet<Voice>();
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
Process process = Runtime.getRuntime().exec("say -v ?");
inputStreamReader = new InputStreamReader(process.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
String nextLine;
while ((nextLine = bufferedReader.readLine()) != null) {
voices.add(new MacTTSVoice(nextLine));
}
} catch (IOException e) {
logger.error("Error while executing the 'say -v ?' command: " + e.getMessage());
} finally {
IOUtils.closeQuietly(bufferedReader);
}
return voices;
}
/**
* Initializes this.audioFormats
*
* @return The audio formats of this instance
*/
private final Set<AudioFormat> initAudioFormats() {
AudioFormat audioFormat = new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, false, 16,
null, (long) 44100);
return Collections.singleton(audioFormat);
}
@Override
public String getId() {
return "mactts";
}
@Override
public String getLabel(Locale locale) {
return "MacOS TTS";
}
}