upstream version 1.2.2
[debian/freetts] / demo / freetts / ClientServer / Client.java
1 /**
2  * Copyright 2001 Sun Microsystems, Inc.
3  * 
4  * See the file "license.terms" for information on usage and
5  * redistribution of this file, and for a DISCLAIMER OF ALL 
6  * WARRANTIES.
7  */
8
9
10 import com.sun.speech.freetts.audio.AudioPlayer;
11 import com.sun.speech.freetts.audio.JavaStreamingAudioPlayer;
12 import com.sun.speech.freetts.util.Utilities;
13
14 import java.io.BufferedReader;
15 import java.io.DataInputStream;
16 import java.io.InputStreamReader;
17 import java.io.IOException;
18 import java.io.PrintWriter;
19
20 import java.net.Socket;
21
22 import javax.sound.sampled.AudioFormat;
23
24
25 /**
26  * Implements a Java Client for the Client/Server demo. For details about
27  * the protocol between client and server, consult the file
28  * <code>Protocol.txt</code>.
29  */
30 public class Client {
31
32     private String serverAddress = Utilities.getProperty("server", "localhost");
33     private int serverPort = Utilities.getInteger("port", 5555).intValue();
34
35     private static final int AUDIO_BUFFER_SIZE = 256;
36
37     private boolean debug = Utilities.getBoolean("debug");
38
39     private BufferedReader systemInReader;  // for reading user input text
40     private BufferedReader reader;
41     private DataInputStream dataReader;     // for reading raw bytes
42     private PrintWriter writer;
43     private AudioPlayer audioPlayer;
44     private int sampleRate = Utilities.getInteger("sampleRate", 16000).intValue();
45     private int sampleSize = 16;            // in bits
46     private byte[] socketBuffer = new byte[AUDIO_BUFFER_SIZE];
47
48
49     private boolean metrics = Boolean.getBoolean("metrics");
50     private long sendTime;             // time the text is sent to server
51     private long receiveTime;          // time the first byte is received
52     private long firstSoundTime;       // time the first play to audio
53     private boolean firstByteReceived = false;
54
55
56     private static final String FIRST_SENTENCE =
57         "Type in what you want me to say.";
58
59
60     /**
61      * Constructs a default Client. It connects to the speech server, and
62      * constructs an AudioPlayer.
63      */
64     public Client() {
65         if (!connect()) {
66             System.out.println("Error connecting to " + serverAddress +
67                                " at " + serverPort);
68             System.exit(1);
69         }
70         this.audioPlayer = new JavaStreamingAudioPlayer();
71         this.audioPlayer.setAudioFormat
72             (new AudioFormat(sampleRate, sampleSize, 1, true, true));
73     }
74
75
76     /**
77      * Connects this client to the server.
78      *
79      * @return  <code>true</code>  if successfully connected
80      *          <code>false</code>  if failed to connect
81      */
82     private boolean connect() {
83         try {
84             Socket socket = new Socket(serverAddress, serverPort);
85             dataReader = new DataInputStream(socket.getInputStream());
86             systemInReader = new BufferedReader
87                 (new InputStreamReader(System.in));
88             writer = new PrintWriter(socket.getOutputStream(), true);
89             return true;
90         } catch (IOException ioe) {
91             ioe.printStackTrace();
92             return false;
93         }
94     }
95
96
97     /**
98      * Reads a line of text from the Socket.
99      *
100      * @return a line of text without the end of line character
101      */
102     private String readLine() throws IOException {
103         int i;
104         char c;
105         StringBuffer buffer = new StringBuffer();
106
107         while ((c = (char) dataReader.readByte()) != '\n') {
108             if (debug) {
109                 System.out.println(c);
110             }
111             buffer.append(c);
112         }
113
114         int lastCharIndex = buffer.length() - 1;
115         
116         // remove trailing ^M for Windows-based machines
117         byte lastByte = (byte) buffer.charAt(lastCharIndex);
118         if (lastByte == 13) {
119             return buffer.substring(0, lastCharIndex);
120         } else {
121             return buffer.toString();
122         }
123     }
124
125
126     /**
127      * Sends the given line of text to the Socket, appending an end of
128      * line character to the end.
129      *
130      * @param the line of text to send
131      */
132     private void sendLine(String line) {
133         if (debug) {
134             System.out.println(line);
135         }
136         line = line.trim();
137         if (line.length() > 0) {
138             writer.print(line);
139             writer.print('\n');
140             writer.flush();
141         }
142     }
143
144
145     /**
146      * Run the TTS protocol.
147      */
148     public void runTTSProtocol() {
149         try {
150             String readyLine = readLine();
151             if (readyLine.equals("READY")) {
152                 if (!sendTTSRequest(FIRST_SENTENCE)) {
153                     return;
154                 }
155                 System.out.print("Say       : ");
156                 String input;
157                 while ((input = systemInReader.readLine()) != null) {
158                     if (input.length() > 0 && !sendTTSRequest(input)) {
159                         return;
160                     }
161                     System.out.print("Say       : ");
162                 }
163             }
164             sendLine("DONE");
165
166             audioPlayer.drain();
167             audioPlayer.close();
168
169             System.out.println("ALL DONE");
170
171         } catch (Exception e) {
172             e.printStackTrace();
173         }
174     }
175
176
177     /**
178      * Sends a TTS request on the given text.
179      *
180      * @param text the text to do TTS on
181      *
182      * @return <code>true</code> if the TTS transaction was successful
183      *         <code>false</code> if an error occurred
184      */
185     private boolean sendTTSRequest(String text) {
186
187         if (metrics) {
188             sendTime = System.currentTimeMillis();
189             firstByteReceived = false;
190         }
191
192         // send TTS request to server
193         sendLine("TTS\n" +
194                  String.valueOf(sampleRate) + "\n" +
195                  text + "\n");
196
197         // get response
198         String numberSamplesStr = null;
199         int numberSamples = 0;
200
201         do {
202             try {
203                 numberSamplesStr = readLine();
204                 numberSamples = Integer.parseInt(numberSamplesStr);
205                                 
206                 if (numberSamples == -2) { // error
207                     System.err.println("Client.sendTTSRequest(): error!");
208                     return false;
209                 }                   
210                 if (numberSamples > 0) {
211                     System.out.println
212                         ("Receiving : " + numberSamples + " samples");
213                     receiveAndPlay(numberSamples);
214                 }
215             } catch (IOException ioe) {
216                 ioe.printStackTrace();
217             }
218         }
219         while (numberSamples > 0);
220
221         if (metrics) {
222             System.out.println("FirstByte : " +
223                                (receiveTime - sendTime) + " ms");
224         }
225
226         return true;
227     }
228
229
230     /**
231      * Reads the given number of bytes from the socket, and plays them
232      * with the AudioPlayer.
233      *
234      * @param numberSamples the number of bytes to read from the socket
235      */
236     private void receiveAndPlay(int numberSamples) {
237
238         int bytesToRead;
239         int bytesRemaining;
240
241         bytesRemaining = numberSamples;
242
243         audioPlayer.begin(0);
244
245         while (bytesRemaining > 0) {
246             
247             // how many more bytes do we have to read?
248             if (bytesRemaining >= AUDIO_BUFFER_SIZE) {
249                 bytesToRead = AUDIO_BUFFER_SIZE;
250             } else {
251                 bytesToRead = bytesRemaining;
252             }
253             
254             try {
255                 // we want to fill the socketBuffer completely before playing
256                 int nRead = 0;
257                 do {
258                     int read = dataReader.read
259                         (socketBuffer, nRead, bytesToRead);
260
261                     if (metrics && !firstByteReceived) {
262                         receiveTime = System.currentTimeMillis();
263                     }
264                     nRead += read;
265                     bytesToRead -= read;
266                 }
267                 while (bytesToRead > 0);
268                
269                 if (nRead < 0) {
270                     System.err.println("error reading samples");
271                 } else {
272                     bytesRemaining -= nRead;
273                     
274                     if (metrics && !firstByteReceived) {
275                         firstSoundTime = System.currentTimeMillis();
276                         firstByteReceived = true;
277                     }
278                     audioPlayer.write(socketBuffer, 0, nRead);
279                 }
280             } catch (IOException ioe) {
281                 ioe.printStackTrace();
282             }
283             
284             if (debug) {
285                 System.out.println("BytesRemaining: " + bytesRemaining);
286             }
287         }
288
289         audioPlayer.end();
290
291         if (debug) {
292             System.out.println("finished");
293         }
294     }
295
296
297     /**
298      * Main program to run the client.
299      */    
300     public static void main(String[] argv) {
301         Client client = new Client();
302         client.runTTSProtocol();
303         System.exit(0);
304     }
305 }