Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Create new SimpleSpeechUI examples for Android and iOS.

  • Loading branch information...
commit 41021ed9c0c5e64969fabeb1d39bd6ee5096171a 1 parent 852e74c
Jay Lieske authored
Showing with 3,305 additions and 0 deletions.
  1. +8 −0 Android/Speech/SimpleSpeechUI/.classpath
  2. +23 −0 Android/Speech/SimpleSpeechUI/.gitignore
  3. +44 −0 Android/Speech/SimpleSpeechUI/.project
  4. +2 −0  Android/Speech/SimpleSpeechUI/.settings/org.eclipse.core.resources.prefs
  5. +12 −0 Android/Speech/SimpleSpeechUI/.settings/org.eclipse.jdt.core.prefs
  6. +24 −0 Android/Speech/SimpleSpeechUI/AndroidManifest.xml
  7. +29 −0 Android/Speech/SimpleSpeechUI/README.markdown
  8. +5 −0 Android/Speech/SimpleSpeechUI/libs/.gitignore
  9. +5 −0 Android/Speech/SimpleSpeechUI/lint.xml
  10. +40 −0 Android/Speech/SimpleSpeechUI/proguard.cfg
  11. +11 −0 Android/Speech/SimpleSpeechUI/project.properties
  12. BIN  Android/Speech/SimpleSpeechUI/res/drawable/ic_launcher.png
  13. +25 −0 Android/Speech/SimpleSpeechUI/res/layout/speech.xml
  14. +13 −0 Android/Speech/SimpleSpeechUI/res/values/strings.xml
  15. +350 −0 Android/Speech/SimpleSpeechUI/src/example/simplespeechui/SimpleSpeechUIDemo.java
  16. +185 −0 Android/Speech/SimpleSpeechUI/src/example/simplespeechui/SpeechAuth.java
  17. +39 −0 Android/Speech/SimpleSpeechUI/src/example/simplespeechui/SpeechConfig.java
  18. +26 −0 iOS/Speech/SimpleSpeechUI/.gitignore
  19. +5 −0 iOS/Speech/SimpleSpeechUI/ATTSpeechKit/.gitignore
  20. +19 −0 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIAppDelegate.h
  21. +46 −0 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIAppDelegate.m
  22. +26 −0 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIViewController.h
  23. +308 −0 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIViewController.m
  24. +39 −0 iOS/Speech/SimpleSpeechUI/Classes/SpeechAuth.h
  25. +246 −0 iOS/Speech/SimpleSpeechUI/Classes/SpeechAuth.m
  26. +21 −0 iOS/Speech/SimpleSpeechUI/Classes/SpeechConfig.h
  27. +41 −0 iOS/Speech/SimpleSpeechUI/Classes/SpeechConfig.m
  28. +29 −0 iOS/Speech/SimpleSpeechUI/README.markdown
  29. BIN  iOS/Speech/SimpleSpeechUI/Resources/Default-568h@2x.png
  30. BIN  iOS/Speech/SimpleSpeechUI/Resources/Default-Portrait.png
  31. BIN  iOS/Speech/SimpleSpeechUI/Resources/Default.png
  32. +308 −0 iOS/Speech/SimpleSpeechUI/Resources/MainWindow-iPad.xib
  33. +295 −0 iOS/Speech/SimpleSpeechUI/Resources/MainWindow.xib
  34. +302 −0 iOS/Speech/SimpleSpeechUI/Resources/SimpleSpeechUIViewController-iPad.xib
  35. +360 −0 iOS/Speech/SimpleSpeechUI/Resources/SimpleSpeechUIViewController.xib
  36. +44 −0 iOS/Speech/SimpleSpeechUI/SimpleSpeechUI-Info.plist
  37. +340 −0 iOS/Speech/SimpleSpeechUI/SimpleSpeechUI.xcodeproj/project.pbxproj
  38. +7 −0 iOS/Speech/SimpleSpeechUI/SimpleSpeechUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  39. +11 −0 iOS/Speech/SimpleSpeechUI/SimpleSpeechUI_Prefix.pch
  40. +17 −0 iOS/Speech/SimpleSpeechUI/main.m
View
8 Android/Speech/SimpleSpeechUI/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
View
23 Android/Speech/SimpleSpeechUI/.gitignore
@@ -0,0 +1,23 @@
+.svn
+
+# Mac ignores
+.DS_Store
+
+# Rails ignores
+*.log
+tmp/
+
+# Xcode ignores
+build/
+*.pbxuser
+*.mode2v3
+*.swp
+*~.nib
+*.pbxuser
+*.perspective
+*.perspectivev3
+
+# Android ignores
+local.properties
+/bin
+/gen
View
44 Android/Speech/SimpleSpeechUI/.project
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>SimpleSpeechUI</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+ <filteredResources>
+ <filter>
+ <id>0</id>
+ <name></name>
+ <type>22</type>
+ <matcher>
+ <id>org.eclipse.ui.ide.multiFilter</id>
+ <arguments>1.0-name-matches-true-false-.DS_Store</arguments>
+ </matcher>
+ </filter>
+ </filteredResources>
+</projectDescription>
View
2  Android/Speech/SimpleSpeechUI/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
View
12 Android/Speech/SimpleSpeechUI/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Tue Feb 21 19:15:57 PST 2012
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
View
24 Android/Speech/SimpleSpeechUI/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="example.simplespeechui"
+ android:versionCode="2"
+ android:versionName="1.6" >
+
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:allowBackup="false">
+ <activity android:name=".SimpleSpeechUIDemo"
+ android:label="@string/app_title"
+ android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale">
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
View
29 Android/Speech/SimpleSpeechUI/README.markdown
@@ -0,0 +1,29 @@
+Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+Copyright 2012 AT&T Intellectual Property. All rights reserved.
+For more information contact developer.support@att.com http://developer.att.com
+
+# SimpleSpeechUI example Android app for AT&T Speech SDK
+
+This sample app includes Android source code and an Eclipse project to show how to call the AT&T Speech SDK from an application that wants a custom speech UI. The app displays a simple client-side mashup. Pressing a button initiates a speech interaction, a text area shows the recognition result, and a web view uses the recognized speech to search a website. The text area also shows the progress of the speech interaction, and the button changes to "stop" or "cancel" during the phases of the interaction.
+
+## Setting up the project
+
+The SimpleSpeechUI Eclipse project is already configured to link with the Speech SDK, but it needs a copy of the files from the Speech SDK distribution. Follow these steps to add the latest SpeechKit to the project.
+
+1. If it's not present, create a `libs` subdirectory of this sample app.
+2. Unzip the AT&T Speech SDK for Android into its own folder.
+2. Copy the file `ATTSpeechKit.jar` into the `libs` subfolder.
+4. Expand the `libs` group within the Eclipse project window. You should see the ATTSpeechKit JAR there.
+
+## Running the sample
+
+Before building the sample app, you will need to add the configuration for your Speech API account: the URL of the service, your developer ID, and its password. Set those values in `SpeechConfig.java`. Before distributing your app to the public, make sure you add code to obfuscate those credentials.
+
+## Understanding the sample
+
+The main code of the sample app is in the `SimpleSpeechUIDemo` class. Look in the `setupSpeechService` method and `SpeechButtonListener` inner class for examples of setting up and starting a speech interaction. Look in the `SpeechResultListener`/`SpeechErrorListener` inner classes for handling recognition responses and errors. Look in the `SpeechStateListener` and `SpeechLevelListener` inner classes for examples of handling SpeechKit callbacks for a custom UI.
+
+## Reusable OAuth code
+
+An example of OAuth client credential validation is in the class `SpeechAuth`. You may use that class in your own applications, or you can use any other OAuth library. Look in `SimpleSpeechUIDemo.validateOAuth()` for an example of calling `SpeechAuth` to obtain an access token.
View
5 Android/Speech/SimpleSpeechUI/libs/.gitignore
@@ -0,0 +1,5 @@
+# Ignore everything in this directory
+*
+
+# Except this file
+!.gitignore
View
5 Android/Speech/SimpleSpeechUI/lint.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+ <issue id="SetJavaScriptEnabled" severity="ignore" />
+ <issue id="TypographyEllipsis" severity="informational" />
+</lint>
View
40 Android/Speech/SimpleSpeechUI/proguard.cfg
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
View
11 Android/Speech/SimpleSpeechUI/project.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
View
BIN  Android/Speech/SimpleSpeechUI/res/drawable/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
25 Android/Speech/SimpleSpeechUI/res/layout/speech.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+ <WebView android:id="@+id/webview"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="6dp">
+ <Button android:id="@+id/speak_button"
+ android:layout_width="110dp"
+ android:layout_height="wrap_content"
+ android:text="@string/button_speak"/>
+ <TextView android:id="@+id/result"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="6dp"
+ android:text="@string/result"/>
+ </LinearLayout>
+</LinearLayout>
View
13 Android/Speech/SimpleSpeechUI/res/values/strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Simple Speech UI</string>
+ <string name="app_title">Simple Speech with UI Hooks</string>
+ <string name="result"> </string>
+ <string name="button_speak">Press to Talk</string>
+ <string name="button_wait">Please wait</string>
+ <string name="button_stop">Stop</string>
+ <string name="button_cancel">Cancel</string>
+ <string name="status_listening">(Listening...)</string>
+ <string name="status_audio">(Listening [level %d])</string>
+ <string name="status_processing">(Processing...)</string>
+</resources>
View
350 Android/Speech/SimpleSpeechUI/src/example/simplespeechui/SimpleSpeechUIDemo.java
@@ -0,0 +1,350 @@
+/*
+Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+Copyright 2012 AT&T Intellectual Property. All rights reserved.
+For more information contact developer.support@att.com http://developer.att.com
+*/
+package example.simplespeechui;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.List;
+
+import com.att.android.speech.ATTSpeechError;
+import com.att.android.speech.ATTSpeechError.ErrorType;
+import com.att.android.speech.ATTSpeechAudioLevelListener;
+import com.att.android.speech.ATTSpeechErrorListener;
+import com.att.android.speech.ATTSpeechResult;
+import com.att.android.speech.ATTSpeechResultListener;
+import com.att.android.speech.ATTSpeechService;
+import com.att.android.speech.ATTSpeechStateListener;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * SimpleSpeechUI is a basic demonstration of using the ATTSpeechKit
+ * to do voice recognition with a custom UI.
+ * It is designed to introduce a developer to making
+ * a new application that uses the AT&T SpeechKit Android library.
+ * It also documents some of the more basic Android methods for those developers
+ * that are new to Android as well.
+**/
+public class SimpleSpeechUIDemo extends Activity {
+ private Button speakButton = null;
+ private String text = ""; // last Speech to Text result
+ private TextView resultView = null;
+ private WebView webView = null;
+ private String oauthToken = null;
+
+ /**
+ * Called when the activity is first created. This is where we'll hook up
+ * our views in XML layout files to our application.
+ **/
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // First, we specify which layout resource we'll be using.
+ setContentView(R.layout.speech);
+
+ // This is the Speak button that the user presses to start a speech
+ // interaction.
+ speakButton = (Button)findViewById(R.id.speak_button);
+ speakButton.setOnClickListener(speechButtonListener);
+
+ // This will show the recognized text.
+ resultView = (TextView)findViewById(R.id.result);
+
+ // This will show a website receiving the recognized text.
+ webView = (WebView)findViewById(R.id.webview);
+ configureWebView();
+ }
+
+ /**
+ * Called when the activity is coming to the foreground.
+ * This is where we will fetch a fresh OAuth token.
+ **/
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ // Set the ATTSpeechService parameters.
+ setupSpeechService();
+ // Fetch the OAuth credentials.
+ validateOAuth();
+ }
+
+ /** Convenience routine to get speech service. **/
+ private ATTSpeechService getSpeechService()
+ {
+ return ATTSpeechService.getSpeechService(this);
+ }
+
+ /**
+ * Perform the action of the "Push to Talk" button.
+ * Starts the SpeechKit service that listens to the microphone and returns
+ * the recognized text.
+ **/
+ private void setupSpeechService() {
+ // The ATTSpeechKit uses a singleton object to interface with the
+ // speech server.
+ ATTSpeechService speechService = getSpeechService();
+
+ // Register for the success and error callbacks.
+ speechService.setSpeechResultListener(speechResultListener);
+ speechService.setSpeechErrorListener(speechErrorListener);
+
+ // Register for callbacks to update our custom UI.
+ speechService.setShowUI(false);
+ speechService.setSpeechStateListener(speechStateListener);
+ speechService.setAudioLevelListener(speechLevelListener);
+
+ // Next, we'll put in some basic parameters.
+ // First is the Request URL. This is the URL of the speech recognition
+ // service that you were given during onboarding.
+ try {
+ speechService.setRecognitionURL(new URI(SpeechConfig.serviceUrl()));
+ }
+ catch (URISyntaxException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ /**
+ * This callback object will get the speech status change notifications.
+ **/
+ private final SpeechStateListener speechStateListener = new SpeechStateListener();
+ private class SpeechStateListener implements ATTSpeechStateListener {
+ @Override public void onStateChanged(SpeechState newSpeechState) {
+ switch (newSpeechState) {
+ case RECORDING:
+ // Speech SDK has started capturing audio from the microphone.
+ resultView.setText(R.string.status_listening);
+ // Change the button behavior to manually endpoint audio.
+ speakButton.setText(R.string.button_stop);
+ speakButton.setOnClickListener(stopButtonListener);
+ break;
+ case PROCESSING:
+ // Speech SDK is done capturing audio and is now waiting for the server.
+ resultView.setText(R.string.status_processing);
+ // Change the button behavior to cancel waiting.
+ speakButton.setText(R.string.button_cancel);
+ speakButton.setOnClickListener(cancelButtonListener);
+ break;
+ default:
+ // Speech SDK is not interacting with the user.
+ // Restore the button behavior to start listening.
+ speakButton.setText(R.string.button_speak);
+ speakButton.setOnClickListener(speechButtonListener);
+ // Make sure the Speech to Text result appears instead of
+ // status message.
+ resultView.setText(text);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Handle a press on the "Push to Talk" button.
+ **/
+ private final SpeechButtonListener speechButtonListener = new SpeechButtonListener();
+ private class SpeechButtonListener implements View.OnClickListener {
+ @Override public void onClick(View v) {
+ // Re-access the singleton ATTSpeechService for this activity.
+ ATTSpeechService speechService = getSpeechService();
+
+ // Set the OAuth token that was fetched in the background.
+ speechService.setBearerAuthToken(oauthToken);
+
+ // Add extra arguments for speech recognition.
+ // The parameter is the name of the current screen within this app.
+ speechService.setXArgs(
+ Collections.singletonMap("ClientScreen", "main"));
+
+ // Finally we have all the information needed to start the speech service.
+ speechService.startListening();
+ Log.v("SimpleSpeechUI", "Starting speech interaction");
+ }
+ };
+
+ /**
+ * Handle a press on the "Stop" button.
+ **/
+ private final StopButtonListener stopButtonListener = new StopButtonListener();
+ private class StopButtonListener implements View.OnClickListener {
+ @Override public void onClick(View v) {
+ // Re-access the singleton ATTSpeechService for this activity.
+ ATTSpeechService speechService = getSpeechService();
+ // End microphone input and wait for the server to process the audio.
+ speechService.stopListening();
+ }
+ };
+
+ /**
+ * Handle a press on the "Cancel" button.
+ **/
+ private final CancelButtonListener cancelButtonListener = new CancelButtonListener();
+ private class CancelButtonListener implements View.OnClickListener {
+ @Override public void onClick(View v) {
+ // Re-access the singleton ATTSpeechService for this activity.
+ ATTSpeechService speechService = getSpeechService();
+ // Stop waiting for the server to process audio.
+ speechService.cancel();
+ // The speech service won't make any more callbacks, so restore the
+ // UI to normal.
+ speechStateListener.onStateChanged(ATTSpeechStateListener.SpeechState.IDLE);
+ }
+ };
+
+ /**
+ * This callback object will get all the speech audio level notifications.
+ **/
+ private final SpeechLevelListener speechLevelListener = new SpeechLevelListener();
+ private class SpeechLevelListener implements ATTSpeechAudioLevelListener {
+ @Override public void onAudioLevel(int level) {
+ // Show the audio level.
+ resultView.setText(getString(R.string.status_audio, level));
+ }
+
+ }
+
+ /**
+ * This callback object will get all the speech success notifications.
+ **/
+ private final SpeechResultListener speechResultListener = new SpeechResultListener();
+ private class SpeechResultListener implements ATTSpeechResultListener {
+ public void onResult(ATTSpeechResult result) {
+ // The hypothetical recognition matches are returned as a list of strings.
+ List<String> textList = result.getTextStrings();
+ String resultText = null;
+ if (textList != null && textList.size() > 0) {
+ // There may be multiple results, but this example will only use
+ // the first one, which is the most likely.
+ resultText = textList.get(0);
+ }
+ if (resultText != null && resultText.length() > 0) {
+ // This is where your app will process the recognized text.
+ Log.v("SimpleSpeechUI", "Recognized "+textList.size()+" hypotheses.");
+ handleRecognition(resultText);
+ }
+ else {
+ // The speech service did not recognize what was spoken.
+ Log.v("SimpleSpeechUI", "Recognized no hypotheses.");
+ alert("Didn't recognize speech", "Please try again.");
+ }
+ }
+ }
+
+ /** Make use of the recognition text in this app. **/
+ private void handleRecognition(String resultText) {
+ // In this example, we set display the text in the result view.
+ text = resultText;
+ resultView.setText(resultText);
+ // And then perform a search on a website using the text.
+ String query = URLEncoder.encode(resultText);
+ String url = "http://en.m.wikipedia.org/w/index.php?search="+query;
+ webView.loadUrl(url);
+ }
+
+ /** Configure the webview that displays websites with the recognition text. **/
+ private void configureWebView() {
+ webView.getSettings().setJavaScriptEnabled(true);
+ webView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ return false; // Let the webview display the URL
+ }
+ });
+ }
+
+ /**
+ * This callback object will get all the speech error notifications.
+ **/
+ private final SpeechErrorListener speechErrorListener = new SpeechErrorListener();
+ private class SpeechErrorListener implements ATTSpeechErrorListener {
+ public void onError(ATTSpeechError error) {
+ ErrorType resultCode = error.getType();
+ if (resultCode == ErrorType.USER_CANCELED) {
+ // The user canceled the speech interaction.
+ // This can happen through several mechanisms:
+ // pressing a cancel button in the speech UI;
+ // pressing the back button; starting another activity;
+ // or locking the screen.
+
+ // In all these situations, the user was instrumental
+ // in canceling, so there is no need to put up a UI alerting
+ // the user to the fact.
+ Log.v("SimpleSpeechUI", "User canceled.");
+ }
+ else {
+ // Any other value for the result code means an error has occurred.
+ // The argument includes a message to help the programmer
+ // diagnose the issue.
+ String errorMessage = error.getMessage();
+ Log.v("SimpleSpeechUI", "Recognition error #"+resultCode+": "+errorMessage);
+
+ alert("Speech Error", "Please try again later.");
+ }
+ }
+ }
+
+ /**
+ * Start an asynchronous OAuth credential check.
+ * Disables the Speak button until the check is complete.
+ **/
+ private void validateOAuth() {
+ SpeechAuth auth =
+ SpeechAuth.forService(SpeechConfig.oauthUrl(), SpeechConfig.oauthScope(),
+ SpeechConfig.oauthKey(), SpeechConfig.oauthSecret());
+ auth.fetchTo(new OAuthResponseListener());
+ speakButton.setText(R.string.button_wait);
+ speakButton.setEnabled(false);
+ }
+
+ /**
+ * Handle the result of an asynchronous OAuth check.
+ **/
+ private class OAuthResponseListener implements SpeechAuth.Client {
+ public void
+ handleResponse(String token, Exception error)
+ {
+ if (token != null) {
+ oauthToken = token;
+ speakButton.setText(R.string.button_speak);
+ speakButton.setEnabled(true);
+ }
+ else {
+ Log.v("SimpleSpeechUI", "OAuth error: "+error);
+ // There was either a network error or authentication error.
+ // Show alert for the latter.
+ alert("Speech Unavailable",
+ "This app was rejected by the speech service. Contact the developer for an update.");
+ }
+ }
+ }
+
+ private void alert(String header, String message) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage(message)
+ .setTitle(header)
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+}
View
185 Android/Speech/SimpleSpeechUI/src/example/simplespeechui/SpeechAuth.java
@@ -0,0 +1,185 @@
+/*
+Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+Copyright 2012 AT&T Intellectual Property. All rights reserved.
+For more information contact developer.support@att.com http://developer.att.com
+*/
+package example.simplespeechui;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Locale;
+
+import org.json.JSONObject;
+
+import android.os.Handler;
+
+/**
+ * Fetches OAuth client credentials, calling an interface when done.
+ * Performs the load over a separate thread so that it doesn't block the main UI.
+**/
+public class SpeechAuth
+{
+ /** Supplies OAuth response back to client. **/
+ public interface Client {
+ /**
+ * Called on client's thread to return OAuth token on success,
+ * or an Exception on failure.
+ * @param token the OAuth token on success,
+ * or null if authentication failed
+ * @param error null on success,
+ * or the exception if authentication failed
+ **/
+ public void
+ handleResponse(String token, Exception error);
+ }
+
+ /**
+ * Sets up an OAuth client credentials authentication.
+ * Follow this with a call to fetchTo() to actually load the data.
+ * @param oauthService the URL of the OAuth client credentials service
+ * @param apiKey the OAuth client ID
+ * @param apiSecret the OAuth client secret
+ * @throws IllegalArgumentException for bad URL, etc.
+ **/
+ public static SpeechAuth
+ forService(String oauthService, String oauthScope,
+ String apiKey, String apiSecret)
+ throws IllegalArgumentException
+ {
+ try {
+ URL url = new URL(oauthService);
+ HttpURLConnection request = (HttpURLConnection)url.openConnection();
+ String data = String.format(Locale.US, OAUTH_DATA,
+ oauthScope, apiKey, apiSecret);
+ byte[] bytes = data.getBytes("UTF8");
+ request.setConnectTimeout(CONNECT_TIMEOUT);
+ request.setReadTimeout(READ_TIMEOUT);
+ return new SpeechAuth(request, bytes);
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ catch (ClassCastException e) {
+ throw new IllegalArgumentException("URL must be HTTP: "+oauthService, e);
+ }
+ }
+
+ private static final String OAUTH_DATA =
+ "grant_type=client_credentials&scope=%s&client_id=%s&client_secret=%s";
+ /** The OAuth server is quite quick. The only timeouts will be for network failures. **/
+ private static final int CONNECT_TIMEOUT = 5*1000; // milliseconds
+ private static final int READ_TIMEOUT = 5*1000;
+
+ /**
+ * Create a loader for a URLConnection that returns the response data to a client.
+ **/
+ private
+ SpeechAuth(HttpURLConnection request, byte[] postData)
+ {
+ this.connection = request;
+ this.postData = postData;
+ }
+
+ private Client client; // becomes null after cancel()
+ private HttpURLConnection connection;
+ private byte[] postData; // becomes null after getResponseStream()
+
+ /**
+ * Begin fetching the credentials asynchronously.
+ * This must be invoked on a thread with a Looper,
+ * and the client will be called back on this thread.
+ **/
+ public void
+ fetchTo(Client client)
+ {
+ this.client = client;
+ // TODO: prevent starting twice
+ final Handler callingThread = new Handler();
+ Thread reader = new Thread(connection.getURL().toString()) {
+ @Override public void run() {
+ performFetch(callingThread);
+ }
+ };
+ reader.start();
+ }
+
+ /**
+ * Stop the loading.
+ * This should only be called from the same thread that called start().
+ **/
+ public void
+ cancel()
+ {
+ // TODO: figure out a way to implement cancel()
+ client = null;
+ //connection.disconnect();
+ }
+
+ /**
+ * Posts request data, gets bytes of response, and calls client when done.
+ * Performs blocking I/O, so it must be called from its own thread.
+ **/
+ private void
+ performFetch(Handler callingThread)
+ {
+ try {
+ // Post the credentials.
+ connection.setDoOutput(true);
+ OutputStream out = connection.getOutputStream();
+ out.write(postData);
+ out.close();
+ // Wait for the response.
+ // Note that getInputStream will throw exception for non-200 status.
+ InputStream response = connection.getInputStream();
+ byte[] data = readAllBytes(response);
+ // Extract the token from JSON.
+ String body = new String(data, "UTF8");
+ JSONObject json = new JSONObject(body);
+ final String token = json.getString("access_token");
+ // Give it back to the client.
+ callingThread.post(new Runnable() {
+ public void run() {
+ if (client != null)
+ client.handleResponse(token, null);
+ }
+ });
+ }
+ catch (final Exception ex) {
+ callingThread.post(new Runnable() {
+ public void run() {
+ if (client != null)
+ client.handleResponse(null, ex);
+ }
+ });
+ }
+ // XXX: Should we close the connection?
+ // finally { connection.close(); }
+ }
+
+ private static final int BLOCK_SIZE = 16*1024;
+
+ /**
+ * Reads the stream until EOF. Returns all the bytes read.
+ * @param input stream to read
+ * @param maxLength maximum number of bytes to read
+ * @return all the bytes from the steam
+ * @throws IOException
+ * @throws InputTooLargeException when length exceeds
+ **/
+ private static byte[]
+ readAllBytes(InputStream input)
+ throws IOException
+ {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream(BLOCK_SIZE);
+ byte[] block = new byte[BLOCK_SIZE];
+ int n;
+ while ((n = input.read(block)) > 0)
+ buffer.write(block, 0, n);
+ return buffer.toByteArray();
+ }
+}
View
39 Android/Speech/SimpleSpeechUI/src/example/simplespeechui/SpeechConfig.java
@@ -0,0 +1,39 @@
+/*
+Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+Copyright 2012 AT&T Intellectual Property. All rights reserved.
+For more information contact developer.support@att.com http://developer.att.com
+*/
+package example.simplespeechui;
+
+/** Configuration parameters for this application's account on Speech API. **/
+public class SpeechConfig {
+ private SpeechConfig() {} // can't instantiate
+
+ /** The URL of AT&T Speech API. **/
+ static String serviceUrl() {
+ return "https://api.att.com/speech/v3/speechToText";
+ }
+
+ /** The URL of AT&T Speech API OAuth service. **/
+ static String oauthUrl() {
+ return "https://api.att.com/oauth/token";
+ }
+
+ /** The OAuth scope of AT&T Speech API. **/
+ static String oauthScope() {
+ return "SPEECH";
+ }
+
+ /** Unobfuscates the OAuth client_id credential for the application. **/
+ static String oauthKey() {
+ // TODO: Replace this with code to unobfuscate your OAuth client_id.
+ return myUnobfuscate(MY_OBFUSCATED_CLIENT_ID);
+ }
+
+ /** Unobfuscates the OAuth client_secret credential for the application. **/
+ static String oauthSecret() {
+ // TODO: Replace this with code to unobfuscate your OAuth client_secret.
+ return myUnobfuscate(MY_OBFUSCATED_CLIENT_SECRET);
+ }
+}
View
26 iOS/Speech/SimpleSpeechUI/.gitignore
@@ -0,0 +1,26 @@
+# VCS ignores
+.svn
+
+# Mac ignores
+.DS_Store
+
+# Rails ignores
+*.log
+tmp/
+
+# Xcode ignores
+build/
+DerivedData/
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.swp
+*~.nib
+*.pbxuser
+*.perspective
+*.perspectivev3
+
+# Xcode 4.0 ignores
+DerivedData/
+xcuserdata/
+*.xcuserstate
View
5 iOS/Speech/SimpleSpeechUI/ATTSpeechKit/.gitignore
@@ -0,0 +1,5 @@
+# Ignore everything in this directory
+*
+
+# Except this file
+!.gitignore
View
19 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIAppDelegate.h
@@ -0,0 +1,19 @@
+// SimpleSpeechUIAppDelegate.h
+// SimpleSpeechUI
+//
+// Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+// Copyright 2012 AT&T Intellectual Property. All rights reserved.
+// For more information contact developer.support@att.com http://developer.att.com
+
+#import <UIKit/UIApplication.h>
+
+@class SimpleSpeechUIViewController;
+
+@interface SimpleSpeechUIAppDelegate : NSObject <UIApplicationDelegate>
+
+@property (nonatomic, retain) IBOutlet UIWindow *window;
+@property (nonatomic, retain) IBOutlet SimpleSpeechUIViewController *viewController;
+
+@end
+
View
46 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIAppDelegate.m
@@ -0,0 +1,46 @@
+// SimpleSpeechUIAppDelegate.m
+// SimpleSpeechUI
+//
+// Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+// Copyright 2012 AT&T Intellectual Property. All rights reserved.
+// For more information contact developer.support@att.com http://developer.att.com
+
+#import "SimpleSpeechUIAppDelegate.h"
+#import "SimpleSpeechUIViewController.h"
+
+@implementation SimpleSpeechUIAppDelegate
+
+@synthesize window;
+@synthesize viewController;
+
+
+#pragma mark -
+#pragma mark Application lifecycle
+
+- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
+{
+ // Override point for customization after application launch.
+
+ // Hook up the UI from Interface Builder.
+ self.window.rootViewController = self.viewController;
+ [self.window makeKeyAndVisible];
+
+ return YES;
+}
+
+- (void) applicationDidBecomeActive: (UIApplication*) application
+{
+ // Since the app has come to the foreground, (re-)initialize SpeechKit.
+ [viewController prepareSpeech];
+}
+
+- (void) dealloc
+{
+ [viewController release];
+ [window release];
+ [super dealloc];
+}
+
+
+@end
View
26 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIViewController.h
@@ -0,0 +1,26 @@
+// SimpleSpeechUIViewController.h
+// SimpleSpeech
+//
+// Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+// Copyright 2012 AT&T Intellectual Property. All rights reserved.
+// For more information contact developer.support@att.com http://developer.att.com
+
+#import <UIKit/UIViewController.h>
+#import "ATTSpeechKit.h"
+
+
+@interface SimpleSpeechUIViewController : UIViewController <ATTSpeechServiceDelegate>
+
+@property (retain, nonatomic) IBOutlet UILabel* textLabel;
+@property (retain, nonatomic) IBOutlet UIWebView* webView;
+@property (retain, nonatomic) IBOutlet UIButton* talkButton;
+
+// Initialize SpeechKit for this app.
+- (void) prepareSpeech;
+
+// Message sent by "Press to Talk" button in UI
+- (IBAction) buttonPressed: (id) sender;
+
+@end
+
View
308 iOS/Speech/SimpleSpeechUI/Classes/SimpleSpeechUIViewController.m
@@ -0,0 +1,308 @@
+// SimpleSpeechViewController.m
+// SimpleSpeech
+//
+// Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+// Copyright 2012 AT&T Intellectual Property. All rights reserved.
+// For more information contact developer.support@att.com http://developer.att.com
+
+#import "SimpleSpeechUIViewController.h"
+#import "SpeechConfig.h"
+#import "SpeechAuth.h"
+
+@interface SimpleSpeechUIViewController ()
+@property (retain, nonatomic) NSString* text;
+- (void) speechAuthFailed: (NSError*) error;
+@end
+
+@implementation SimpleSpeechUIViewController
+
+@synthesize textLabel;
+@synthesize webView;
+@synthesize talkButton;
+@synthesize text;
+
+#pragma mark -
+#pragma mark Lifecyle
+
+- (instancetype) init{
+ self = [super init];
+ if (self != nil) {
+ self.text = @"";
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ self.textLabel = nil;
+ self.webView = nil;
+ self.talkButton = nil;
+ self.text = nil;
+ [super dealloc];
+}
+
+
+// Initialize SpeechKit for this app.
+- (void) prepareSpeech
+{
+ // Access the SpeechKit singleton.
+ ATTSpeechService* speechService = [ATTSpeechService sharedSpeechService];
+
+ // Point to the SpeechToText API.
+ speechService.recognitionURL = SpeechServiceUrl();
+
+ // Hook ourselves up as a delegate so we can get called back with the response.
+ speechService.delegate = self;
+
+ // Use a custom speech UI.
+ speechService.showUI = NO;
+
+ // Choose the speech recognition package.
+ speechService.speechContext = @"WebSearch";
+
+ // Enable the Speex codec, which provides better speech recognition accuracy.
+ speechService.audioFormat = ATTSKAudioFormatSpeex_WB;
+
+ // Start the OAuth background operation, disabling the Talk button until
+ // it's done.
+ talkButton.enabled = NO;
+ [[SpeechAuth authenticatorForService: SpeechOAuthUrl()
+ withId: SpeechOAuthKey()
+ secret: SpeechOAuthSecret()
+ scope: SpeechOAuthScope()]
+ fetchTo: ^(NSString* token, NSError* error) {
+ if (token) {
+ speechService.bearerAuthToken = token;
+ talkButton.enabled = YES;
+ }
+ else
+ [self speechAuthFailed: error];
+ }];
+
+ // Wake the audio components so there is minimal delay on the first request.
+ [speechService prepare];
+}
+
+#pragma mark -
+#pragma mark UI
+
+- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation
+{
+ return YES;
+}
+
+#pragma mark -
+#pragma mark Actions
+
+// Perform the action of the "Push to talk" button
+- (void) startListening
+{
+ NSLog(@"Starting speech request");
+
+ // Start listening via the microphone.
+ ATTSpeechService* speechService = [ATTSpeechService sharedSpeechService];
+
+ // Add extra arguments for speech recogniton.
+ // The parameter is the name of the current screen within this app.
+ speechService.xArgs =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ @"main", @"ClientScreen", nil];
+
+ [speechService startListening];
+}
+
+// Perform the action of the "Stop" button
+- (void) stopListening
+{
+ NSLog(@"Manually ending microphone input");
+ [[ATTSpeechService sharedSpeechService] stopListening];
+}
+
+// Perform the action of the "Cancel" button
+- (void) cancelProcessing
+{
+ NSLog(@"Manually canceling speech request");
+ [[ATTSpeechService sharedSpeechService] cancel];
+}
+
+- (IBAction) buttonPressed: (id) sender
+{
+ // The action to perform depends on the current state of the speech interaction.
+ // Make sure this code is kept in sync with -[speechService:willEnterState:].
+ ATTSpeechServiceState speechState =
+ [[ATTSpeechService sharedSpeechService] currentState];
+ switch (speechState) {
+ case ATTSpeechServiceStateRecording:
+ // Speech SDK is capturing audio from the microphone.
+ // The button behavior to manually endpoint audio.
+ [self stopListening];
+ break;
+ case ATTSpeechServiceStateProcessing:
+ // Speech SDK is waiting for the server.
+ // The button behavior is to cancel waiting.
+ [self cancelProcessing];
+ break;
+ default:
+ // Speech SDK is not interacting with the user.
+ // The button behavior to start listening.
+ [self startListening];
+ break;
+ }
+}
+
+// Make use of the recognition text in this app.
+- (void) handleRecognition: (NSString*) recognizedText
+{
+ // Display the recognized text.
+ self.text = recognizedText;
+ [self.textLabel setText: recognizedText];
+
+ // Load a website using the recognized text.
+ // First make the recognizedText safe for use as a search term in a URL.
+ NSString* escapedTerm =
+ [recognizedText stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
+ NSString* urlString =
+ [NSString stringWithFormat: @"http://en.m.wikipedia.org/w/index.php?search=%@", escapedTerm];
+ NSURL* url = [NSURL URLWithString: urlString];
+ NSURLRequest* request = [NSURLRequest requestWithURL: url];
+ [self.webView loadRequest:request];
+}
+
+#pragma mark -
+#pragma mark Speech Service Delegate Methods
+
+/**
+ The Speech SDK calls this method when it transitions among states in a recording
+ interaction, for example, from capturing to processing.
+ The method argument contains the state the service will enter, and
+ speechService.currentState contains the state the service is leaving.
+ Upon exiting this delegate callback, the service will be in the new state.
+ @param speechService The service notifying the delegate that the state is changing.
+ @param newState The state the service is changing to.
+ **/
+- (void) speechService: (ATTSpeechService*) speechService
+ willEnterState: (ATTSpeechServiceState) newState
+{
+ switch (newState) {
+ case ATTSpeechServiceStateRecording:
+ // Speech SDK has started capturing audio from the microphone.
+ textLabel.text = @"(Listening...)";
+ // Change the button behavior to manually endpoint audio.
+ [talkButton setTitle: @"Stop" forState: UIControlStateNormal];
+ break;
+ case ATTSpeechServiceStateProcessing:
+ // Speech SDK is done capturing audio and is now waiting for the server.
+ textLabel.text = @"(Processing...)";
+ // Change the button behavior to cancel waiting.
+ [talkButton setTitle: @"Cancel" forState: UIControlStateNormal];
+ break;
+ default:
+ // Speech SDK is not interacting with the user.
+ // Restore the button behavior to start listening.
+ [talkButton setTitle: @"Press to Talk" forState: UIControlStateNormal];
+ break;
+ }
+}
+
+/**
+ The Speech SDK calls this method repeatedly as it captures audio. The callback
+ rate is roughly 1/10 second. An application can use the audio level data to
+ update its UI.
+ @param speechService The service notifying the delegate about the audio level.
+ @param level The audio level.
+**/
+- (void) speechService: (ATTSpeechService*) speechService
+ audioLevel: (float) level
+{
+ // Show the audio level in the text label.
+ textLabel.text = [NSString stringWithFormat: @"(Listening [level %.2f])",
+ level];
+}
+
+/**
+ The Speech SDK calls this method when it returns a recognition result. The
+ ATTSpeechService object will contain properties that include the response data
+ and recognized text.
+ @param speechService The service notifying the delegate of success.
+**/
+- (void) speechServiceSucceeded: (ATTSpeechService*) speechService
+{
+ NSLog(@"Speech service succeeded");
+
+ // Extract the needed data from the SpeechService object:
+ // For raw bytes, read speechService.responseData.
+ // For a JSON tree, read speechService.responseDictionary.
+ // For the n-best ASR strings, use speechService.responseStrings.
+
+ // In this example, use the ASR strings.
+ // There can be 0 strings, 1 empty string, or 1 non-empty string.
+ // Display the recognized text in the interface is it's non-empty,
+ // otherwise have the user try again.
+ NSArray* nbest = speechService.responseStrings;
+ NSString* recognizedText = @"";
+ if (nbest != nil && nbest.count > 0)
+ recognizedText = [nbest objectAtIndex: 0];
+ if (recognizedText.length) { // non-empty?
+ [self handleRecognition: recognizedText];
+ }
+ else {
+ UIAlertView* alert =
+ [[UIAlertView alloc] initWithTitle: @"Didn't recognize speech"
+ message: @"Please try again."
+ delegate: self
+ cancelButtonTitle: @"OK"
+ otherButtonTitles: nil];
+ [alert show];
+ [alert release];
+ }
+}
+
+/**
+ The Speech SDK calls this method when speech recognition fails. The reasons for
+ failure can include the user canceling, network errors, or server errors.
+ @param speechService The service notifying the delegate of failure.
+ @param error The error that has occurred.
+**/
+- (void) speechService: (ATTSpeechService*) speechService
+ failedWithError: (NSError*) error
+{
+ // First restore the UI to its state before speech processing.
+ textLabel.text = text;
+
+ if ([error.domain isEqualToString: ATTSpeechServiceErrorDomain]
+ && (error.code == ATTSpeechServiceErrorCodeCanceledByUser)) {
+ NSLog(@"Speech service canceled");
+ // Nothing else to do in this case
+ return;
+ }
+ NSLog(@"Speech service had an error: %@", error);
+
+ UIAlertView* alert =
+ [[UIAlertView alloc] initWithTitle: @"An error occurred"
+ message: @"Please try again later."
+ delegate: self
+ cancelButtonTitle: @"OK"
+ otherButtonTitles: nil];
+ [alert show];
+ [alert release];
+}
+
+#pragma mark -
+#pragma mark OAuth
+
+/* The SpeechAuth authentication failed. */
+- (void) speechAuthFailed: (NSError*) error
+{
+ NSLog(@"OAuth error: %@", error);
+ UIAlertView* alert =
+ [[UIAlertView alloc] initWithTitle: @"Speech Unavailable"
+ message: @"This app was rejected by the speech service. Contact the developer for an update."
+ delegate: self
+ cancelButtonTitle: @"OK"
+ otherButtonTitles: nil];
+ [alert show];
+ [alert release];
+}
+
+@end
View
39 iOS/Speech/SimpleSpeechUI/Classes/SpeechAuth.h
@@ -0,0 +1,39 @@
+// SpeechAuth.h
+//
+// Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+// Copyright 2012 AT&T Intellectual Property. All rights reserved.
+// For more information contact developer.support@att.com http://developer.att.com
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSError;
+
+/**
+ * Type of block called when SpeechAuth gets credential or fails.
+ * token will be the OAuth bearer token.
+ * If there's an problem authenticating, token will be nil and
+ * error will contain the error.
+ * TO DO: document the keys in error.userInfo
+**/
+typedef void (^SpeechAuthBlock)(NSString* token, NSError* error);
+
+/**
+ * Fetches OAuth client credentials, calling a block when done.
+**/
+@interface SpeechAuth : NSObject {
+}
+
+/** Creates a SpeechAuth object with the given credentials. **/
++ (SpeechAuth*) authenticatorForService: (NSURL*) oauth_url
+ withId: (NSString*) client_id
+ secret: (NSString*) client_secret
+ scope: (NSString*) oauth_scope;
+
+/*! Beging fetching the credentials. Will call block when done. !*/
+- (void) fetchTo: (SpeechAuthBlock) block;
+
+/*! Stop fetching. Once stopped, loading may not resume. !*/
+- (void) cancel;
+
+@end
View
246 iOS/Speech/SimpleSpeechUI/Classes/SpeechAuth.m
@@ -0,0 +1,246 @@
+// SpeechAuth.m
+//
+// Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+// Copyright 2012 AT&T Intellectual Property. All rights reserved.
+// For more information contact developer.support@att.com http://developer.att.com
+
+#import "SpeechAuth.h"
+#import "ATTSpeechKit.h"
+
+typedef enum
+{
+ LoaderStateUnknown = 0,
+ LoaderStateInitialized,
+ LoaderStateConnecting,
+ LoaderStateReceivedResponse,
+ LoaderStateReceivedData,
+ LoaderStateFinished,
+ LoaderStateFailed,
+ LoaderStateCanceling,
+ LoaderStateCanceled
+} LoaderState;
+
+// Memory Management
+//
+// This object will retain its initialiation parameters (the NSURLRequest)
+// during the lifetime of this object.
+// It will retain the connection, response, data, and delegate only between
+// the call to start and the callbacks to the delegate.
+// It will also add a retain of itself during that interval. That way, the
+// client can autorelease this object after starting, and this object
+// will remain in memory while active.
+
+@interface SpeechAuth () {
+ @private
+ LoaderState state;
+}
+@property (copy) SpeechAuthBlock authenticatedBlock;
+@property (copy) NSURLRequest* request;// Make a copy in case it's mutable
+@property (retain) NSURLConnection* connection;
+@property (retain) NSURLResponse* response;
+@property (retain) NSMutableData* data;
+
+- (NSInteger) statusCode;
+- (void) clear;
+@end
+
+@implementation SpeechAuth
+
+@synthesize authenticatedBlock = _authenticatedBlock;
+@synthesize request = _request;
+@synthesize connection = _connection;
+@synthesize response = _response;
+@synthesize data = _data;
+
+
+- (id) initWithRequest: (NSURLRequest*) request
+{
+ self = [super init];
+ if (self != nil)
+ {
+ // First see if the request can be handled.
+ if (![NSURLConnection canHandleRequest: request]) {
+ [self release];
+ return nil;
+ }
+ self.request = request;
+ self.data = [NSMutableData data];
+ _connection = nil; // Create connection when client wants to start loading.
+ _response = nil;
+ state = LoaderStateInitialized;
+ }
+ return self;
+}
+
+/** Tune the timeout values based on application behavior. **/
+static const NSTimeInterval CONNECT_TIMEOUT = 10.0; // seconds
+
++ (SpeechAuth*) authenticatorForService: (NSURL*) oauth_url
+ withId: (NSString*) client_id
+ secret: (NSString*) client_secret
+ scope: (NSString*) oauth_scope
+{
+ NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: oauth_url];
+ NSString* postString = [NSString stringWithFormat:
+ @"grant_type=client_credentials&scope=%@&client_id=%@&client_secret=%@",
+ oauth_scope, client_id, client_secret];
+ request.HTTPMethod = @"POST";
+ request.HTTPBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
+ request.timeoutInterval = CONNECT_TIMEOUT;
+ return [[[self alloc] initWithRequest: request] autorelease];
+
+}
+
+- (void) dealloc
+{
+ // We should have already been cleared, but just in case...
+ [_connection cancel];
+
+ self.request = nil;
+ self.response = nil;
+ self.data = nil;
+ self.authenticatedBlock = nil;
+ self.connection = nil;
+
+ [super dealloc];
+}
+
+- (NSInteger) statusCode
+{
+ int code;
+ if (_response == nil)
+ code= 100; // HTTP "Continue"
+ else if ([_response respondsToSelector: @selector(statusCode)])
+ code = [(NSHTTPURLResponse*)_response statusCode];
+ // The other kind of response we support is file: URLs.
+ // The behavior of NSURLConnection in that case is to only call connection:didReceiveResponse:
+ // when the file is found.
+ // When it's not found, it calls connection:didFailWithError: directly.
+ // So if our response is non-nil, assume it's OK.
+ else
+ code = 200 ;
+ return code;
+}
+
+- (void) start
+{
+ state = LoaderStateConnecting;
+ // Add a retention to this object do it doesn't dispose during the connection.
+ [self retain];
+
+ // Allocate the NSURLConnection and start it in one step.
+ self.connection = [NSURLConnection connectionWithRequest: _request
+ delegate: self];
+
+ if (_connection == nil) {
+ state = LoaderStateFailed;
+ // Report the error the delegate on the next time through the runloop.
+ [[NSOperationQueue mainQueue] addOperationWithBlock: ^{
+ // TO DO: the arguments to NSError are completely arbitrary!
+ NSError* error = [NSError errorWithDomain: ATTSpeechServiceErrorDomain
+ code: ATTSpeechServiceErrorCodeConnectionFailure
+ userInfo: nil];
+ _authenticatedBlock(nil, error);
+ [self clear];
+ }];
+ return;
+ }
+ // Don't call [_connection start], since it's already started.
+}
+
+- (void) fetchTo: (SpeechAuthBlock) block
+{
+ self.authenticatedBlock = block;
+ [self start];
+}
+
+- (void) clear
+{
+ // Completely dispose the connection, delegate, and response data
+ // when we are done.
+ self.authenticatedBlock = nil;
+ [_connection cancel];
+ self.connection = nil;
+ self.response = nil;
+ _data.length = 0;
+ // And release the retain count we added during start.
+ [self release];
+}
+
+- (void) cancel
+{
+ // Completely dispose the connection when we cancel it.
+ if (state != LoaderStateFinished)
+ {
+ state = LoaderStateCanceling;
+ [self clear];
+ }
+}
+
+// NSURLConnection delegate methods
+
+
+- (void) connection: (NSURLConnection*) connection
+ didReceiveResponse: (NSURLResponse*) response
+{
+ // The connection just got a new response. Clear out anything we've already loaded.
+ self.response = response;
+ _data.length = 0;
+ state = LoaderStateReceivedResponse;
+}
+
+- (void) connection: (NSURLConnection*) connection
+ didReceiveData: (NSData*) data
+{
+ // The connection is sending us some data incrementally.
+ [_data appendData: data];
+ state = LoaderStateReceivedData;
+}
+
+- (void) connectionDidFinishLoading: (NSURLConnection*) connection
+{
+ // Loading is complete.
+ state = LoaderStateFinished;
+
+ NSError* error = nil;
+ BOOL succeeded = NO;
+ if (self.statusCode == 200 && _data.length) {
+ // Use iOS 5 JSON library to decode OAuth response.
+ // Be very circumspect about the data types so that we don't crash on bad data.
+ NSDictionary* json = [NSJSONSerialization JSONObjectWithData: _data options: 0 error: &error];
+ if ([json isKindOfClass: [NSDictionary class]]) {
+ id token = [json objectForKey: @"access_token"];
+ if (token != nil) {
+ // We have a token, so give it to the delegate.
+ _authenticatedBlock([token description], nil);
+ succeeded = YES;
+ }
+ }
+ }
+ if (!succeeded) {
+ // TO DO: What data should we put in the userInfo?
+ if (error == nil)
+ error = [NSError errorWithDomain: ATTSpeechServiceHTTPErrorDomain
+ code: self.statusCode userInfo: nil];
+ _authenticatedBlock(nil, error);
+ }
+
+ // The callback is complete, so clean up.
+ [self clear];
+}
+
+- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error
+{
+ // Loading failed.
+ state = LoaderStateFailed;
+
+ _authenticatedBlock(nil, error);
+
+ // The callback is complete, so clean up.
+ [self clear];
+}
+
+@end
+
+
View
21 iOS/Speech/SimpleSpeechUI/Classes/SpeechConfig.h
@@ -0,0 +1,21 @@
+// SpeechConfig.h
+//
+// Declares customization parameters for this application's use of
+// AT&T Speech SDK.
+
+@class NSString, NSURL;
+
+/** The URL of AT&T Speech API. **/
+NSURL* SpeechServiceUrl(void);
+
+/** The URL of AT&T Speech API OAuth service. **/
+NSURL* SpeechOAuthUrl(void);
+
+/** Unobfuscates the OAuth client_id credential for the application. **/
+NSString* SpeechOAuthKey(void);
+
+/** Unobfuscates the OAuth client_secret credential for the application. **/
+NSString* SpeechOAuthSecret(void);
+
+/** The OAuth scope for the Speech API requests. **/
+NSString* SpeechOAuthScope(void);
View
41 iOS/Speech/SimpleSpeechUI/Classes/SpeechConfig.m
@@ -0,0 +1,41 @@
+// SpeechConfig.m
+//
+// Implements customization parameters for this application's use of
+// AT&T Speech SDK.
+//
+// Customize the functions declared here with the parameters of your application.
+
+#import "SpeechConfig.h"
+
+
+/** The URL of AT&T Speech API. **/
+NSURL* SpeechServiceUrl(void)
+{
+ return [NSURL URLWithString: @"https://api.att.com/speech/v3/speechToText"];
+}
+
+/** The URL of AT&T Speech API OAuth service. **/
+NSURL* SpeechOAuthUrl(void)
+{
+ return [NSURL URLWithString: @"https://api.att.com/oauth/token"];
+}
+
+/** Unobfuscates the OAuth client_id credential for the application. **/
+NSString* SpeechOAuthKey(void)
+{
+ #error Add code to unobfuscate your Speech API credentials, then delete this line.
+ return MY_UNOBFUSCATE(my_obfuscated_client_id);
+}
+
+/** Unobfuscates the OAuth client_secret credential for the application. **/
+NSString* SpeechOAuthSecret(void)
+{
+ #error Add code to unobfuscate your Speech API credentials, then delete this line.
+ return MY_UNOBFUSCATE(my_obfuscated_client_secret);
+}
+
+/** The OAuth scope for the Speech API requests. **/
+NSString* SpeechOAuthScope(void)
+{
+ return @"SPEECH";
+}
View
29 iOS/Speech/SimpleSpeechUI/README.markdown
@@ -0,0 +1,29 @@
+Licensed by AT&T under 'Software Development Kit Tools Agreement' 2012.
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION: http://developer.att.com/sdk_agreement/
+Copyright 2012 AT&T Intellectual Property. All rights reserved.
+For more information contact developer.support@att.com http://developer.att.com
+
+# SimpleSpeechUI example app for AT&T Speech SDK
+
+This sample app includes source code and an Xcode project to show how to call the AT&T Speech SDK from an application that wants a custom speech UI. The app displays a simple client-side mashup. Pressing a button initiates a speech interaction, a text area shows the recognition result, and a web view uses the recognized speech to search a website. The text area also shows the progress of the speech interaction, and the button changes to "stop" or "cancel" during the phases of the interaction.
+
+## Setting up the project
+
+The SimpleSpeechUI Xcode project is already configured to link with the Speech SDK, but it needs a copy of the files from the Speech SDK distribution. Follow these steps to add the latest SpeechKit to the project.
+
+1. Unzip the AT&T Speech SDK into its own folder.
+2. Copy the files `ATTSpeechKit.a` and `ATTSpeechKit.h` into the `ATTSpeechKit` subfolder of this sample app.
+3. Open the SimpleSpeechUI Xcode project.
+4. Expand the `ATTSpeechKit` group within the project window. Both files should appear in black text, not red (which would indicate that Xcode can't find them).
+
+## Running the sample
+
+Before building the sample app, you will need to add the configuration for your Speech API account: the URL of the service, your application's API key and API secret. Set those values in `SpeechConfig.m`. Before distributing your app to the public, make sure you add code to obfuscate those credentials.
+
+## Understanding the speech code
+
+The main code of the sample app is in the `SimpleSpeechViewController` class. Look in the `-[prepareSpeech]` and `-[listen:]` methods for examples of setting up and starting a speech interaction. Look in the `-[speechServiceSucceeded:]` and `[speechService:failedWithError:]` methods for examples of handling recognition responses. Look in `[buttonPressed:]`, `[speechService:willEnterState:]` and `[speechService:audioLevel:]` for examples of handling SpeechKit callbacks for a custom UI.
+
+## Reusable OAuth code
+
+The SpeechAuth class provides example code for authenticating your application with the OAuth client credentials protocol. It performs an asynchronous network request for an OAuth access token that can be used in the Speech API. Look in `-[SimpleSpeechViewController prepareSpeech]` for examples of calling SpeechAuth to obtain an access token.
View
BIN  iOS/Speech/SimpleSpeechUI/Resources/Default-568h@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  iOS/Speech/SimpleSpeechUI/Resources/Default-Portrait.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  iOS/Speech/SimpleSpeechUI/Resources/Default.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
308 iOS/Speech/SimpleSpeechUI/Resources/MainWindow-iPad.xib
@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1552</int>
+ <string key="IBDocument.SystemVersion">12E55</string>
+ <string key="IBDocument.InterfaceBuilderVersion">3084</string>
+ <string key="IBDocument.AppKitVersion">1187.39</string>
+ <string key="IBDocument.HIToolboxVersion">626.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="NS.object.0">2083</string>
+ </object>
+ <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>IBProxyObject</string>
+ <string>IBUICustomObject</string>
+ <string>IBUIViewController</string>
+ <string>IBUIWindow</string>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBProxyObject" id="841351856">
+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+ <string key="targetRuntimeIdentifier">IBIPadFramework</string>
+ </object>
+ <object class="IBProxyObject" id="427554174">
+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+ <string key="targetRuntimeIdentifier">IBIPadFramework</string>
+ </object>
+ <object class="IBUICustomObject" id="664661524">
+ <string key="targetRuntimeIdentifier">IBIPadFramework</string>
+ </object>
+ <object class="IBUIViewController" id="943309135">
+ <string key="IBUINibName">SimpleSpeechUIViewController-iPad</string>
+ <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics" id="735413460">
+ <int key="IBUIStatusBarStyle">2</int>
+ </object>
+ <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
+ <int key="IBUIInterfaceOrientation">1</int>
+ <int key="interfaceOrientation">1</int>
+ </object>
+ <string key="targetRuntimeIdentifier">IBIPadFramework</string>
+ <bool key="IBUIHorizontal">NO</bool>
+ </object>
+ <object class="IBUIWindow" id="117978783">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{768, 1024}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MSAxIDEAA</bytes>
+ </object>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <reference key="IBUISimulatedStatusBarMetrics" ref="735413460"/>
+ <string key="targetRuntimeIdentifier">IBIPadFramework</string>
+ <bool key="IBUIResizesToFullScreen">YES</bool>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="841351856"/>
+ <reference key="destination" ref="664661524"/>
+ </object>
+ <int key="connectionID">4</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">viewController</string>
+ <reference key="source" ref="664661524"/>
+ <reference key="destination" ref="943309135"/>
+ </object>
+ <int key="connectionID">11</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="664661524"/>
+ <reference key="destination" ref="117978783"/>
+ </object>
+ <int key="connectionID">14</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="841351856"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">3</int>
+ <reference key="object" ref="664661524"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">SimpleSpeechUI App Delegate</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="427554174"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="943309135"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">SimpleSpeechUI View Controller</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="117978783"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.CustomClassName</string>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.CustomClassName</string>
+ <string>-2.IBPluginDependency</string>
+ <string>10.CustomClassName</string>
+ <string>10.IBLastUsedUIStatusBarStylesToTargetRuntimesMap</string>
+ <string>10.IBPluginDependency</string>
+ <string>12.IBLastUsedUIStatusBarStylesToTargetRuntimesMap</string>
+ <string>12.IBPluginDependency</string>
+ <string>3.CustomClassName</string>
+ <string>3.IBPluginDependency</string>
+ </object>
+ <object class="NSArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UIApplication</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>UIResponder</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>SimpleSpeechUIViewController</string>
+ <object class="NSMutableDictionary">
+ <string key="NS.key.0">IBCocoaTouchFramework</string>
+ <integer value="0" key="NS.object.0"/>
+ </object>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <object class="NSMutableDictionary">
+ <string key="NS.key.0">IBCocoaTouchFramework</string>
+ <integer value="0" key="NS.object.0"/>
+ </object>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>SimpleSpeechUIAppDelegate</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <reference key="dict.values" ref="0"/>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <reference key="dict.values" ref="0"/>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">15</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">SimpleSpeechUIAppDelegate</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>viewController</string>
+ <string>window</string>
+ </object>
+ <object class="NSArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>SimpleSpeechUIViewController</string>
+ <string>UIWindow</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>viewController</string>
+ <string>window</string>
+ </object>
+ <object class="NSArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">viewController</string>
+ <string key="candidateClassName">SimpleSpeechUIViewController</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">window</string>
+ <string key="candidateClassName">UIWindow</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/SimpleSpeechUIAppDelegate.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">SimpleSpeechUIViewController</string>
+ <string key="superclassName">UIViewController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">listen:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">listen:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">listen:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>talkButton</string>
+ <string>textLabel</string>
+ <string>webView</string>
+ </object>
+ <object class="NSArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UIButton</string>
+ <string>UILabel</string>
+ <string>UIWebView</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>talkButton</string>
+ <string>textLabel</string>
+ <string>webView</string>
+ </object>
+ <object class="NSArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">talkButton</string>
+ <string key="candidateClassName">UIButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">textLabel</string>
+ <string key="candidateClassName">UILabel</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">webView</string>
+ <string key="candidateClassName">UIWebView</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/SimpleSpeechUIViewController.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBIPadFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
+ <real value="1552" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
+ <integer value="3100" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <string key="IBCocoaTouchPluginVersion">2083</string>
+ </data>
+</archive>
View
295 iOS/Speech/SimpleSpeechUI/Resources/MainWindow.xib
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1552</int>
+ <string key="IBDocument.SystemVersion">12E55</string>
+ <string key="IBDocument.InterfaceBuilderVersion">3084</string>
+ <string key="IBDocument.AppKitVersion">1187.39</string>
+ <string key="IBDocument.HIToolboxVersion">626.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="NS.object.0">2083</string>
+ </object>
+ <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>IBProxyObject</string>
+ <string>IBUICustomObject</string>
+ <string>IBUIViewController</string>
+ <string>IBUIWindow</string>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBProxyObject" id="841351856">
+ <string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="IBProxyObject" id="427554174">
+ <string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="IBUICustomObject" id="664661524">
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="IBUIViewController" id="943309135">
+ <string key="IBUINibName">SimpleSpeechUIViewController</string>
+ <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+ <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
+ <int key="IBUIInterfaceOrientation">1</int>
+ <int key="interfaceOrientation">1</int>
+ </object>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <bool key="IBUIHorizontal">NO</bool>
+ </object>
+ <object class="IBUIWindow" id="117978783">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{320, 480}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView"/>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MSAxIDEAA</bytes>
+ </object>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClearsContextBeforeDrawing">NO</bool>
+ <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <bool key="IBUIResizesToFullScreen">YES</bool>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="841351856"/>
+ <reference key="destination" ref="664661524"/>
+ </object>
+ <int key="connectionID">4</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">viewController</string>
+ <reference key="source" ref="664661524"/>
+ <reference key="destination" ref="943309135"/>
+ </object>
+ <int key="connectionID">11</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="664661524"/>
+ <reference key="destination" ref="117978783"/>
+ </object>
+ <int key="connectionID">14</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="841351856"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">3</int>
+ <reference key="object" ref="664661524"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">SimpleSpeechUI App Delegate</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="427554174"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="943309135"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="117978783"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.CustomClassName</string>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.CustomClassName</string>
+ <string>-2.IBPluginDependency</string>
+ <string>10.CustomClassName</string>
+ <string>10.IBPluginDependency</string>
+ <string>12.IBPluginDependency</string>
+ <string>3.CustomClassName</string>
+ <string>3.IBPluginDependency</string>
+ </object>
+ <object class="NSArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>UIApplication</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>UIResponder</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>SimpleSpeechUIViewController</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>SimpleSpeechUIAppDelegate</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <reference key="dict.values" ref="0"/>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <reference key="dict.values" ref="0"/>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">15</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">