|
2 | 2 |
|
3 | 3 | import java.io.IOException;
|
4 | 4 | import java.io.InputStream;
|
| 5 | +import java.io.SequenceInputStream; |
5 | 6 | import java.net.URL;
|
6 | 7 | import java.net.URLConnection;
|
7 | 8 | import java.net.URLEncoder;
|
8 | 9 | import java.util.ArrayList;
|
| 10 | +import java.util.Collections; |
| 11 | +import java.util.LinkedHashSet; |
9 | 12 | import java.util.List;
|
| 13 | +import java.util.Set; |
| 14 | +import java.util.concurrent.Callable; |
| 15 | +import java.util.concurrent.ExecutionException; |
| 16 | +import java.util.concurrent.ExecutorService; |
| 17 | +import java.util.concurrent.Executors; |
| 18 | +import java.util.concurrent.Future; |
10 | 19 |
|
11 | 20 | import com.darkprograms.speech.translator.GoogleTranslate;
|
12 | 21 |
|
@@ -127,11 +136,29 @@ public InputStream getMP3Data(String synthText) throws IOException{
|
127 | 136 | * @throws IOException Throws exception if it cannot complete the request
|
128 | 137 | */
|
129 | 138 | public InputStream getMP3Data(List<String> synthText) throws IOException{
|
130 |
| - InputStream complete = getMP3Data(synthText.remove(0)); |
131 |
| - for(String part: synthText){ |
132 |
| - complete = new java.io.SequenceInputStream(complete, getMP3Data(part));//Concatenate with new MP3 Data |
| 139 | + //Uses an executor service pool for concurrency |
| 140 | + ExecutorService pool = Executors.newFixedThreadPool(synthText.size()); |
| 141 | + //Stores the Future (Data that will be returned in the future) |
| 142 | + Set<Future<InputStream>> set = new LinkedHashSet<Future<InputStream>>(); |
| 143 | + for(String part: synthText){ //Iterates through the list |
| 144 | + Callable<InputStream> callable = new MP3DataFetcher(part);//Creates Callable |
| 145 | + Future<InputStream> future = pool.submit(callable);//Begins to run Callable |
| 146 | + set.add(future);//Adds the response that will be returned to a set. |
133 | 147 | }
|
134 |
| - return complete; |
| 148 | + List<InputStream> inputStreams = new ArrayList<InputStream>(set.size()); |
| 149 | + for(Future<InputStream> future: set){ |
| 150 | + try { |
| 151 | + inputStreams.add(future.get());//Gets the returned data from the future. |
| 152 | + } catch (ExecutionException e) {//Thrown if the MP3DataFetcher encountered an error. |
| 153 | + Throwable ex = e.getCause(); |
| 154 | + if(ex instanceof IOException){ |
| 155 | + throw (IOException)ex;//Downcasts and rethrows it. |
| 156 | + } |
| 157 | + } catch (InterruptedException e){//Will probably never be called, but just in case... |
| 158 | + Thread.currentThread().interrupt();//Interrupts the thread since something went wrong. |
| 159 | + } |
| 160 | + } |
| 161 | + return new SequenceInputStream(Collections.enumeration(inputStreams));//Sequences the stream. |
135 | 162 | }
|
136 | 163 |
|
137 | 164 | /**
|
@@ -211,5 +238,24 @@ private boolean isEndingPunctuation(char input){
|
211 | 238 | public String detectLanguage(String text) throws IOException{
|
212 | 239 | return GoogleTranslate.detectLanguage(text);
|
213 | 240 | }
|
| 241 | + |
| 242 | + /** |
| 243 | + * This class is a callable. |
| 244 | + * A callable is like a runnable except that it can return data and throw exceptions. |
| 245 | + * Useful when using futures. Dramatically improves the speed of execution. |
| 246 | + * @author Aaron Gokaslan (Skylion) |
| 247 | + */ |
| 248 | + private class MP3DataFetcher implements Callable<InputStream>{ |
| 249 | + private String synthText; |
| 250 | + |
| 251 | + public MP3DataFetcher(String synthText){ |
| 252 | + this.synthText = synthText; |
| 253 | + } |
| 254 | + |
| 255 | + public InputStream call() throws IOException{ |
| 256 | + return getMP3Data(synthText); |
| 257 | + } |
| 258 | + } |
| 259 | + |
214 | 260 | }
|
215 | 261 |
|
0 commit comments