Skip to content

MicrophoneException, API Authentication Exception, Flac library #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions .classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="javaFlacEncoder-0.3.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Binary file added javaFlacEncoder-0.3.1.jar
Binary file not shown.
27 changes: 12 additions & 15 deletions src/com/darkprograms/speech/microphone/Microphone.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ public void setTargetDataLine(TargetDataLine targetDataLine) {
*
* @param fileType File type to save the audio in<br>
* Example, to save as WAVE use AudioFileFormat.Type.WAVE
* @throws MicrophoneException Is thrown if there was an error initializing the microphone
*/
public Microphone(AudioFileFormat.Type fileType) {
public Microphone(AudioFileFormat.Type fileType) throws MicrophoneException {
setState(CaptureState.CLOSED);
setFileType(fileType);
initTargetDataLine();
Expand All @@ -99,27 +100,24 @@ public Microphone(AudioFileFormat.Type fileType) {
/**
* Initializes the target data line.
*/
private void initTargetDataLine(){
private void initTargetDataLine() throws MicrophoneException{
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, getAudioFormat());
try {
setTargetDataLine((TargetDataLine) AudioSystem.getLine(dataLineInfo));
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
} catch (IllegalArgumentException | LineUnavailableException e) {
throw new MicrophoneException(e);
}

}


/**
* Captures audio from the microphone and saves it a file
*
* @param audioFile The File to save the audio to
* @throws LineUnavailableException
* @throws MicrophoneException Is thrown if there was an error initializing the microphone
* @throws Exception Throws an exception if something went wrong
*/
public void captureAudioToFile(File audioFile) throws LineUnavailableException {
public void captureAudioToFile(File audioFile) throws MicrophoneException {
setState(CaptureState.STARTING_CAPTURE);
setAudioFile(audioFile);

Expand All @@ -137,10 +135,10 @@ public void captureAudioToFile(File audioFile) throws LineUnavailableException {
* Captures audio from the microphone and saves it a file
*
* @param audioFile The fully path (String) to a file you want to save the audio in
* @throws LineUnavailableException
* @throws MicrophoneException Is thrown if there was an error initializing the microphone
* @throws Exception Throws an exception if something went wrong
*/
public void captureAudioToFile(String audioFile) throws LineUnavailableException {
public void captureAudioToFile(String audioFile) throws MicrophoneException {
File file = new File(audioFile);
captureAudioToFile(file);
}
Expand Down Expand Up @@ -168,8 +166,9 @@ public AudioFormat getAudioFormat() {
/**
* Opens the microphone, starting the targetDataLine.
* If it's already open, it does nothing.
* @throws MicrophoneException Is thrown if there was an error - the microphone
*/
public void open(){
public void open() throws MicrophoneException{
if(getTargetDataLine()==null){
initTargetDataLine();
}
Expand All @@ -179,9 +178,7 @@ public void open(){
getTargetDataLine().open(getAudioFormat());
getTargetDataLine().start();
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
throw new MicrophoneException(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ public class MicrophoneAnalyzer extends Microphone {
/**
* Constructor
* @param fileType The file type you want to save in. FLAC recommended.
* @throws MicrophoneException Is thrown if there was an error initializing the microphone
*/
public MicrophoneAnalyzer(AudioFileFormat.Type fileType){
public MicrophoneAnalyzer(AudioFileFormat.Type fileType) throws MicrophoneException{
super(fileType);
}

Expand Down
13 changes: 13 additions & 0 deletions src/com/darkprograms/speech/microphone/MicrophoneException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.darkprograms.speech.microphone;

/**
* @author Jeremy Treder
*
*/
public class MicrophoneException extends Exception
{
public MicrophoneException(Throwable cause)
{
super("Can not initialize microphone.", cause);
}
}
13 changes: 7 additions & 6 deletions src/com/darkprograms/speech/recognizer/FlacEncoder.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.darkprograms.speech.recognizer;

import javaFlacEncoder.FLACEncoder;
import javaFlacEncoder.FLACFileOutputStream;
import javaFlacEncoder.StreamConfiguration;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javaFlacEncoder.FLACEncoder;
import javaFlacEncoder.FLACFileOutputStream;
import javaFlacEncoder.StreamConfiguration;

/*************************************************************************************************************
* Class that contains methods to encode Wave files to FLAC files
Expand Down
57 changes: 44 additions & 13 deletions src/com/darkprograms/speech/recognizer/GSpeechDuplex.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javaFlacEncoder.FLACFileWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.net.ssl.HttpsURLConnection;
import javax.sound.sampled.AudioFormat;
Expand All @@ -22,6 +26,8 @@
import com.darkprograms.speech.util.ChunkedOutputStream;
import com.darkprograms.speech.util.StringUtil;

import javaFlacEncoder.FLACFileWriter;

/**
* A class for using Google's Duplex Speech API. Allows for continuous recognition. Requires an API-Key.
* A duplex API opens two connections. One to an upstream and one to a downstream. The system allows
Expand All @@ -30,6 +36,14 @@
* @author Skylion (Aaron Gokaslan), Robert Rowntree.
*/
public class GSpeechDuplex{
public interface Catchable{
/**
* Is called from a separate thread if something went wrong! It is maybe called just after a few
* seconds after stop capturing.
* @param throwable The exception occurred. One probable exception is{@link GoogleHTTPException}
*/
public void onException(Throwable throwable);
}

//TODO Cleanup Printlns

Expand Down Expand Up @@ -102,26 +116,28 @@ public void setLanguage(String language){
* @param flacFile The file you wish to upload.
* NOTE: Segment the file if duration is greater than 15 seconds.
* @param sampleRate The sample rate of the file.
* @param exceptionCallback If something went wrong on the HTTP downstream thread.
* @throws IOException If something has gone wrong with reading the file
*/
public void recognize(File flacFile, int sampleRate) throws IOException{
recognize(mapFileIn(flacFile), sampleRate);
public void recognize(File flacFile, int sampleRate, Catchable exceptionCallback) throws IOException{
recognize(mapFileIn(flacFile), sampleRate, exceptionCallback);
}

/**
* Send a byte[] to the URL with a specified sampleRate.
* NOTE: The byte[] should contain no more than 15 seconds of audio.
* Chunking is not fully implemented as of yet. Will not string data together for context yet.
* @param data The byte[] you want to send.
* @param exceptionCallback If something went wrong on the HTTP downstream thread.
* @param sampleRate The sample rate of aforementioned byte array.
*/
public void recognize(byte[] data, int sampleRate){
public void recognize(byte[] data, int sampleRate, Catchable exceptionCallback){

if(data.length >= MAX_SIZE){//Temporary Chunking. Does not allow for Google to gather context.
System.out.println("Chunking the audio into smaller parts...");
byte[][] dataArray = chunkAudio(data);
for(byte[]array: dataArray){
recognize(array, sampleRate);
recognize(array, sampleRate, exceptionCallback);
}
}

Expand All @@ -137,7 +153,7 @@ public void recognize(byte[] data, int sampleRate){
"&key=" + API_KEY ;

//Opens downChannel
this.downChannel(API_DOWN_URL);
this.downChannel(API_DOWN_URL, exceptionCallback);
//Opens upChannel
this.upChannel(API_UP_URL, chunkAudio(data), sampleRate);
}
Expand All @@ -147,10 +163,11 @@ public void recognize(byte[] data, int sampleRate){
* <p>Note: This feature is experimental.</p>
* @param tl
* @param af
* @param exceptionCallback If something went wrong on the HTTP downstream thread.
* @throws IOException
* @throws LineUnavailableException
*/
public void recognize(TargetDataLine tl, AudioFormat af) throws IOException, LineUnavailableException{
public void recognize(TargetDataLine tl, AudioFormat af, Catchable exceptionCallback) throws IOException, LineUnavailableException{
//Generates a unique ID for the response.
final long PAIR = MIN + (long)(Math.random() * ((MAX - MIN) + 1L));

Expand All @@ -165,7 +182,7 @@ public void recognize(TargetDataLine tl, AudioFormat af) throws IOException, Lin
//TODO Add implementation that sends feedback in real time. Protocol buffers will be necessary.

//Opens downChannel
this.downChannel(API_DOWN_URL);
this.downChannel(API_DOWN_URL, exceptionCallback);
//Opens upChannel
this.upChannel(API_UP_URL, tl, af);
}
Expand All @@ -175,10 +192,14 @@ public void recognize(TargetDataLine tl, AudioFormat af) throws IOException, Lin
* the best way to handle this is through the use of listeners.
* @param The URL you want to connect to.
*/
private void downChannel(String urlStr) {
private void downChannel(String urlStr, Catchable callback) {
final String url = urlStr;
new Thread ("Downstream Thread") {
public void run() {

Callable<Void> task = new Callable<Void>()
{
@Override
public Void call() throws Exception
{
// handler for DOWN channel http response stream - httpsUrlConn
// response handler should manage the connection.... ??
// assign a TIMEOUT Value that exceeds by a safe factor
Expand All @@ -191,7 +212,7 @@ public void run() {
// httpsUrlConn and allow it enough time to do its work.
Scanner inStream = openHttpsConnection(url);
if(inStream == null){
//ERROR HAS OCCURED
throw new GoogleHTTPException();
}
while(inStream.hasNextLine()){
String response = inStream.nextLine();
Expand All @@ -204,8 +225,18 @@ public void run() {
}
inStream.close();
System.out.println("Finished write on down stream...");
return null;
}
}.start();
};
Future<Void> future = Executors.newFixedThreadPool(1).submit(task);
try {
future.get();
} catch (ExecutionException ex) {
callback.onException(ex.getCause());
} catch (InterruptedException e)
{
callback.onException(e);
}
}


Expand Down
15 changes: 15 additions & 0 deletions src/com/darkprograms/speech/recognizer/GoogleHTTPException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.darkprograms.speech.recognizer;

/**
* Occurs if something went wrong with the HTTP connection. A cause may be a wrong API key.
*
* @author Jeremy Treder
*
*/
public class GoogleHTTPException extends RuntimeException
{
public GoogleHTTPException()
{
super("Something went wrong with the HTTP connection. Maybe API key wrong?");
}
}