summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk10
-rw-r--r--AndroidManifest.xml20
-rw-r--r--res/layout/recorder.xml89
-rw-r--r--res/values/strings.xml27
-rw-r--r--src/com/android/speechrecorder/SpeechRecorderActivity.java389
5 files changed, 535 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..3d2809a
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+
+LOCAL_PACKAGE_NAME := SpeechRecorder
+
+include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..2197a97
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest package="com.android.speechrecorder"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+
+ <application android:label="@string/app_name">
+ <!-- Initial Page -->
+ <activity android:name="SpeechRecorderActivity"
+ android:label="@string/speechrecorderlabel">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/res/layout/recorder.xml b/res/layout/recorder.xml
new file mode 100644
index 0000000..0e0c215
--- /dev/null
+++ b/res/layout/recorder.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <LinearLayout android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView android:id="@+id/commandText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textSize="12pt"/>
+
+ <TextView android:id="@+id/statusText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+
+ <LinearLayout android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button android:id="@+id/recordButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/recordButton"/>
+
+ <Button android:id="@+id/redoButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/redoButton"/>
+ </LinearLayout>
+
+ <RadioGroup android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:padding="10dip"
+ android:orientation="vertical" android:layout_weight="30">
+
+ <RadioButton android:id="@+id/codec11KHzRadioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <RadioButton android:id="@+id/codec8KHzRadioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </RadioGroup>
+
+ <RadioGroup android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" android:layout_weight="30">
+
+ <RadioButton android:id="@+id/callRadioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/callRadioButton"/>
+
+ <RadioButton android:id="@+id/dialNanpRadioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/dialNanpRadioButton"/>
+
+ <RadioButton android:id="@+id/dialPairsRadioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/dialPairsRadioButton"/>
+ </RadioGroup>
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..3961bf2
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- application name and title of error dialogs-->
+ <string name="app_name">Speech Recorder</string>
+
+ <string name="speechrecorderlabel">Speech Recorder</string>
+ <string name="recordButton">Record</string>
+ <string name="redoButton">Redo</string>
+ <string name="callRadioButton">\"call ...\"\nUtterances</string>
+ <string name="dialNanpRadioButton">\"dial NANP\"\nUtterances</string>
+ <string name="dialPairsRadioButton">\"dial NANP PAIRS\"\nUtterances</string>
+</resources>
diff --git a/src/com/android/speechrecorder/SpeechRecorderActivity.java b/src/com/android/speechrecorder/SpeechRecorderActivity.java
new file mode 100644
index 0000000..d1d5855
--- /dev/null
+++ b/src/com/android/speechrecorder/SpeechRecorderActivity.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.speechrecorder;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.speech.srec.Recognizer;
+import android.speech.srec.WaveHeader;
+import android.speech.srec.MicrophoneInputStream;
+import android.util.Config;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.RadioButton;
+import android.widget.TextView;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class SpeechRecorderActivity extends Activity {
+ private static final String TAG = "SpeechRecorderActivity";
+
+ private static final int DURATION_SEC = 7;
+
+ private Handler mHandler;
+
+ private TextView mCommand;
+ private TextView mStatus;
+ private Button mRecord;
+ private Button mRedo;
+ private RadioButton m8KHz;
+ private RadioButton m11KHz;
+ private RadioButton mCall;
+ private RadioButton mDialNanp;
+ private RadioButton mDialPairs;
+
+ private InputStream mMicrophone;
+ private ByteArrayOutputStream mBaos;
+
+ private File mUtterance;
+ private int mSampleRate;
+ private Thread mThread;
+ private boolean mStoppedListening;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mHandler = new Handler();
+
+ setContentView(R.layout.recorder);
+ mCommand = (TextView) findViewById(R.id.commandText);
+ mStatus = (TextView) findViewById(R.id.statusText);
+ mRecord = (Button) findViewById(R.id.recordButton);
+ mRedo = (Button) findViewById(R.id.redoButton);
+ m8KHz = (RadioButton)findViewById(R.id.codec8KHzRadioButton);
+ m11KHz = (RadioButton)findViewById(R.id.codec11KHzRadioButton);
+ mCall = (RadioButton)findViewById(R.id.callRadioButton);
+ mDialNanp = (RadioButton)findViewById(R.id.dialNanpRadioButton);
+ mDialPairs = (RadioButton)findViewById(R.id.dialPairsRadioButton);
+
+ mCommand.setText("Please click 'Record' to begin");
+ mRecord.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ if (Config.LOGD) {
+ Log.d(TAG, "mRecord.OnClickListener.onClick");
+ }
+
+ setupRecording();
+ }
+ });
+
+ mRedo.setEnabled(false);
+ mRedo.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ if (Config.LOGD) {
+ Log.d(TAG, "mRedo.onClickListener.onClick");
+ }
+
+ mUtterance.delete();
+
+ setupRecording();
+ }
+ });
+
+ m8KHz.setText("PCM/16bit/8KHz");
+ m11KHz.setText("PCM/16bit/11KHz");
+ m11KHz.setChecked(true);
+ mCall.setChecked(true);
+ }
+
+ private void setupRecording() {
+ Log.d(TAG, "setupRecording");
+ // disable buttons
+ mRedo.setEnabled(false);
+ mRecord.setEnabled(false);
+ m8KHz.setFocusable(false);
+ m11KHz.setFocusable(false);
+ mCall.setFocusable(false);
+ mDialNanp.setFocusable(false);
+ mDialPairs.setFocusable(false);
+
+ // find the first utterance not covered
+ String[] utterances = mCall.isChecked() ? mCallUtterances :
+ mDialNanp.isChecked() ? mDialNanpUtterances :
+ mDialPairs.isChecked() ? mDialPairsUtterances :
+ null;
+ mUtterance = null;
+ int index = -1;
+ for (int i = 0; i < utterances.length; i++) {
+ File u = new File(getDir("recordings", MODE_PRIVATE),
+ utterances[i].toLowerCase().replace(' ', '_') + ".wav");
+ if (!u.exists()) {
+ mUtterance = u;
+ index = i;
+ break;
+ }
+ }
+
+ // check if done
+ if (mUtterance == null) {
+ mCommand.setText("Finished: Thank You!");
+ return;
+ }
+ Log.d(TAG, "going to record " + mUtterance.toString());
+
+ // fix up UI
+ mCommand.setText("Say: \"" + utterances[index] + "\"");
+ final String status = "item " + (index + 1) + "/" + utterances.length;
+
+ // start the microphone
+ mSampleRate = m8KHz.isChecked()? 8000 :
+ m11KHz.isChecked() ? 11025 :
+ 11025;
+ mBaos = new ByteArrayOutputStream(mSampleRate * 2 * 20);
+ try {
+ mMicrophone = new MicrophoneInputStream(mSampleRate, mSampleRate * 15);
+
+// mMicrophone = logInputStream(mUtterance.toString(), mMicrophone, mSampleRate);
+ } catch (IOException e) {
+
+ }
+
+ // post a number of delayed events to update the UI and to stop recording
+ // after a few seconds.
+ for (int i = 0; i <= DURATION_SEC; i++) {
+ final int remain = DURATION_SEC - i;
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ if (remain > 0) {
+ mStatus.setText(status + " Recording... " + remain);
+ }
+ else {
+ mStatus.setText(status);
+ stopRecording();
+ }
+ }
+ }, i * 1000);
+ }
+
+ // now start a thread to store the audio.
+ mStoppedListening = false;
+ mThread = new Thread() {
+ public void run() {
+ Log.d(TAG, "run audio capture thread");
+ byte buffer[] = new byte[512];
+ while (!mStoppedListening) {
+ try {
+ int rtn = 0;
+ rtn = mMicrophone.read(buffer, 0, 512);
+ if (rtn > 0) mBaos.write(buffer, 0, rtn);
+ } catch (IOException e) {
+ }
+ }
+ }
+ };
+ mThread.start();
+
+ // to avoid the button click
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ }
+
+ }
+
+ private void stopRecording() {
+ Log.d(TAG, "stopRecording");
+ mStoppedListening = true;
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+
+ }
+ try {
+ OutputStream out = new FileOutputStream(mUtterance.toString());
+ try {
+ byte[] pcm = mBaos.toByteArray();
+ Log.d(TAG, "byteArray length " + pcm.length);
+ WaveHeader hdr = new WaveHeader(WaveHeader.FORMAT_PCM,
+ (short)1, mSampleRate, (short)16, pcm.length);
+ hdr.write(out);
+ out.write(pcm);
+ } finally {
+ out.close();
+ mMicrophone.close();
+ mBaos.close();
+ }
+ } catch (IOException e) {
+
+
+ } finally {
+ }
+
+ // stop the recording
+ mRecord.setEnabled(true);
+
+ mRedo.setEnabled(true);
+
+ mCommand.setText("Got it!");
+ }
+
+
+ private final static String[] mCallUtterances = new String[] {
+ "Call Adam Varro",
+ "Call Alex Lloyd",
+ "Call Amod Karve",
+ "Call Ana Maria Lopez",
+ "Call Ben Sigelman",
+ "Call Chris Vennard",
+ "Call Dana Pogoda",
+ "Call Daryl Pregibon",
+ "Call Davi Robison",
+ "Call David Barrett Kahn",
+ "Call David Hyman",
+ "Call Douglas Gordin",
+ "Call Gregor Rothfuss",
+ "Call James Sheridan",
+ "Call Jason Charo",
+ "Call Jeff Reynar",
+ "Call Joel Ward",
+ "Call John Milton",
+ "Call Lajos Nagy",
+ "Call Lori Sobel",
+ "Call Martin Jansche",
+ "Call Meghan McGarry",
+ "Call Meghan Shakar",
+ "Call Nilka Thomas",
+ "Call Pedro Colijn",
+ "Call Pramod Adiddam",
+ "Call Rajeev Sivaram",
+ "Call Rich Armstrong",
+ "Call Robin Watson",
+ "Call Sam Morales",
+ };
+
+ private final static String[] mDialPairsUtterances = new String[] {
+ // all possible pairs
+ "Dial 000 000 0000",
+
+ "Dial 101 010 1010",
+ "Dial 111 111 1111",
+
+ "Dial 202 020 2020",
+ "Dial 212 121 2121",
+ "Dial 222 222 2222",
+
+ "Dial 303 030 3030",
+ "Dial 313 131 3131",
+ "Dial 323 232 3232",
+ "Dial 333 333 3333",
+
+ "Dial 404 040 4040",
+ "Dial 414 141 4141",
+ "Dial 424 242 4242",
+ "Dial 434 343 4343",
+ "Dial 444 444 4444",
+
+ "Dial 505 050 5050",
+ "Dial 515 151 5151",
+ "Dial 525 252 5252",
+ "Dial 535 353 5353",
+ "Dial 545 454 5454",
+ "Dial 555 555 5555",
+
+ "Dial 606 060 6060",
+ "Dial 616 161 6161",
+ "Dial 626 262 6262",
+ "Dial 636 363 6363",
+ "Dial 646 464 6464",
+ "Dial 656 565 6565",
+ "Dial 666 666 6666",
+
+ "Dial 707 070 7070",
+ "Dial 717 171 7171",
+ "Dial 727 272 7272",
+ "Dial 737 373 7373",
+ "Dial 747 474 7474",
+ "Dial 757 575 7575",
+ "Dial 767 676 7676",
+ "Dial 777 777 7777",
+
+ "Dial 808 080 8080",
+ "Dial 818 181 8181",
+ "Dial 828 282 8282",
+ "Dial 838 383 8383",
+ "Dial 848 484 8484",
+ "Dial 858 585 8585",
+ "Dial 868 686 8686",
+ "Dial 878 787 8787",
+ "Dial 888 888 8888",
+
+ "Dial 909 090 9090",
+ "Dial 919 191 9191",
+ "Dial 929 292 9292",
+ "Dial 939 393 9393",
+ "Dial 949 494 9494",
+ "Dial 959 595 9595",
+ "Dial 969 696 9696",
+ "Dial 979 797 9797",
+ "Dial 989 898 9898",
+ "Dial 999 999 9999",
+
+ };
+
+
+ private final static String[] mDialNanpUtterances = new String[] {
+ "Dial 211",
+ "Dial 411",
+ "Dial 511",
+ "Dial 811",
+ "Dial 911",
+ // random numbers
+ "Dial 653 5763",
+ "Dial 263 9072",
+ "Dial 202 9781",
+ "Dial 379 8229",
+ "Dial 874 9139",
+ "Dial 236 0163",
+ "Dial 656 7455",
+ "Dial 474 5254",
+ "Dial 348 8687",
+ "Dial 629 8602",
+
+ //"Dial 272 717 8405",
+ //"Dial 949 516 0162",
+ //"Dial 795 117 7190",
+ //"Dial 493 656 3767",
+ //"Dial 588 093 9218",
+ "Dial 511 658 3690",
+ "Dial 440 301 8489",
+ "Dial 695 713 6744",
+ "Dial 581 475 8712",
+ "Dial 981 388 3579",
+
+ "Dial 840 683 3346",
+ "Dial 303 467 7988",
+ "Dial 649 504 5290",
+ "Dial 184 577 4229",
+ "Dial 212 286 3982",
+ "Dial 646 258 0115",
+ "Dial 427 482 6852",
+ "Dial 231 809 9260",
+ "Dial 681 930 4301",
+ "Dial 246 650 8339",
+ };
+}