]> git.basschouten.com Git - openhab-addons.git/blob
681e033362d094598df6bc31d496ab26167734de
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.voice.picotts.internal;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileNotFoundException;
18 import java.io.IOException;
19 import java.io.InputStream;
20
21 import org.openhab.core.audio.AudioException;
22 import org.openhab.core.audio.AudioFormat;
23 import org.openhab.core.audio.AudioStream;
24 import org.openhab.core.audio.FixedLengthAudioStream;
25 import org.openhab.core.voice.Voice;
26
27 /**
28  * Implementation of {@link AudioStream} for {@link PicoTTSService}
29  *
30  * @author Florian Schmidt - Initial Contribution
31  */
32 class PicoTTSAudioStream extends FixedLengthAudioStream {
33     private final Voice voice;
34     private final String text;
35     private final AudioFormat audioFormat;
36     private final InputStream inputStream;
37
38     private long length;
39     private File file;
40
41     public PicoTTSAudioStream(String text, Voice voice, AudioFormat audioFormat) throws AudioException {
42         this.text = text;
43         this.voice = voice;
44         this.audioFormat = audioFormat;
45         this.inputStream = createInputStream();
46     }
47
48     @Override
49     public AudioFormat getFormat() {
50         return audioFormat;
51     }
52
53     private InputStream createInputStream() throws AudioException {
54         String outputFile = generateOutputFilename();
55         String[] command = getCommand(outputFile);
56
57         try {
58             Process process = Runtime.getRuntime().exec(command);
59             process.waitFor();
60             file = new File(outputFile);
61             this.length = file.length();
62             return getFileInputStream(file);
63         } catch (IOException e) {
64             throw new AudioException("Error while executing '" + command + "'", e);
65         } catch (InterruptedException e) {
66             throw new AudioException("The '" + command + "' has been interrupted", e);
67         }
68     }
69
70     private InputStream getFileInputStream(File file) throws AudioException {
71         if (file == null) {
72             throw new IllegalArgumentException("file must not be null");
73         }
74         if (file.exists()) {
75             try {
76                 return new FileInputStream(file);
77             } catch (FileNotFoundException e) {
78                 throw new AudioException("Cannot open temporary audio file '" + file.getName() + ".");
79             }
80         } else {
81             throw new AudioException("Temporary file '" + file.getName() + "' not found!");
82         }
83     }
84
85     /**
86      * Generates a unique, absolute output filename
87      *
88      * @return Unique, absolute output filename
89      */
90     private String generateOutputFilename() throws AudioException {
91         try {
92             File tempFile = File.createTempFile(Integer.toString(text.hashCode()), ".wav");
93             tempFile.deleteOnExit();
94             return tempFile.getAbsolutePath();
95         } catch (IOException e) {
96             throw new AudioException("Unable to create temp file.", e);
97         }
98     }
99
100     /**
101      * Gets the command used to generate an audio file {@code outputFile}
102      *
103      * @param outputFile The absolute filename of the command's output
104      * @return The command used to generate the audio file {@code outputFile}
105      */
106     private String[] getCommand(String outputFile) {
107         return new String[] { "pico2wave", "-l=" + this.voice.getLabel(), "-w=" + outputFile, this.text };
108     }
109
110     @Override
111     public int read() throws IOException {
112         return inputStream.read();
113     }
114
115     @Override
116     public long length() {
117         return length;
118     }
119
120     @Override
121     public InputStream getClonedStream() throws AudioException {
122         if (file != null) {
123             return getFileInputStream(file);
124         } else {
125             throw new AudioException("No temporary audio file available.");
126         }
127     }
128 }