Skip to content

Commit f356a22

Browse files
authored
Adding quickstart for KWRecognizer+SpeechRecognizer using streams. (#655)
1 parent 6d14d5e commit f356a22

39 files changed

+697
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/libraries
5+
/.idea/modules.xml
6+
/.idea/workspace.xml
7+
.DS_Store
8+
/build
9+
/captures
10+
.externalNativeBuild
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>keyword-recognizer</name>
4+
<comment>Project keyword-recognizer created by Buildship.</comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
16+
</natures>
17+
</projectDescription>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
arguments=
2+
auto.sync=false
3+
build.scans.enabled=false
4+
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
5+
connection.project.dir=
6+
eclipse.preferences.version=1
7+
gradle.user.home=
8+
java.home=C\:/Program Files/Java/jdk-14.0.1
9+
jvm.arguments=
10+
offline.mode=false
11+
override.workspace.settings=true
12+
show.console.view=true
13+
show.executions.view=true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Quickstart: Keyword Recognition in Java on Android
2+
3+
This sample demonstrates how to recognize keywords with Java using the Speech SDK for Android.
4+
See the [accompanying article](https://docs.microsoft.com/azure/cognitive-services/speech-service/quickstart-java-android) on the SDK documentation page which describes how to build this sample from scratch in Android Studio.
5+
6+
> **Note:**
7+
> this sample is *not* for the Speech Devices SDK and the Roobo device.
8+
> If you are looking for further information on these, visit the [Speech Devices SDK](https://docs.microsoft.com/azure/cognitive-services/speech-service/speech-devices-sdk) page.
9+
10+
## Prerequisites
11+
12+
* A subscription key for the Speech service. See [Try the speech service for free](https://docs.microsoft.com/azure/cognitive-services/speech-service/get-started).
13+
* A PC (Windows, Linux, Mac) capable to run Android Studio.
14+
* Version 3.1 of [Android Studio](https://developer.android.com/studio/).
15+
* Android device or emulator (API 23: Android 6.0 Marshmallow or higher) [enabled for development](https://developer.android.com/studio/debug/dev-options) with a working microphone.
16+
17+
## Build the sample
18+
19+
> Note: more detailed step-by-step instructions are available [here](https://docs.microsoft.com/azure/cognitive-services/speech-service/quickstart-java-android).
20+
21+
* **By building this sample you will download the Microsoft Cognitive Services Speech SDK. By downloading you acknowledge its license, see [Speech SDK license agreement](https://aka.ms/csspeech/license201809).**
22+
* [Download the sample code to your development PC.](/README.md#get-the-samples)
23+
* Open this folder as a project in Android Studio.
24+
* Edit the `MainActivity` source:
25+
* Replace the string `YourSubscriptionKey` with your own subscription key.
26+
* Replace the string `YourServiceRegion` with the service region of your subscription.
27+
For example, replace with `westus` if you are using the 30-day free trial subscription.
28+
* Press Ctrl+F9, or select **Build** \> **Make Project**.
29+
30+
## Run the sample
31+
32+
* Connect your Android device to your development PC.
33+
* Press Shift+F10, or select **Run** \> **Run 'app'**.
34+
* In the deployment target windows that comes up, pick your Android device.
35+
36+
## Note on Android permission handling
37+
38+
Please note that this Speech SDK sample requires the RECORD_AUDIO permissions. As for Android API levels up to 22, requesting the permissions is handled at installation time but from API level 23 users are able to grant/revoke permissions at any time.
39+
40+
Note that this quickstart targets minSdkVersion 23.
41+
42+
## References
43+
44+
* [Quickstart article on the SDK documentation site](https://docs.microsoft.com/azure/cognitive-services/speech-service/quickstart-java-android)
45+
* [Speech SDK API reference for Java](https://aka.ms/csspeech/javaref)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
compileSdkVersion 28
5+
defaultConfig {
6+
applicationId "com.microsoft.cognitiveservices.speech.samples.quickstart"
7+
minSdkVersion 23
8+
targetSdkVersion 28
9+
versionCode 1
10+
versionName "1.0"
11+
}
12+
buildTypes {
13+
release {
14+
minifyEnabled false
15+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
16+
}
17+
}
18+
compileOptions {
19+
sourceCompatibility JavaVersion.VERSION_1_8
20+
targetCompatibility JavaVersion.VERSION_1_8
21+
}
22+
}
23+
24+
dependencies {
25+
implementation fileTree(include: ['*.jar'], dir: 'libs')
26+
27+
// Speech SDK
28+
implementation 'com.microsoft.cognitiveservices.speech:client-sdk:1.12.0'
29+
30+
implementation 'com.android.support:appcompat-v7:27.1.1'
31+
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.microsoft.cognitiveservices.speech.samples.quickstart">
4+
5+
<uses-permission android:name="android.permission.RECORD_AUDIO" />
6+
7+
<application
8+
android:allowBackup="true"
9+
android:icon="@mipmap/ic_launcher"
10+
android:label="@string/app_name"
11+
android:roundIcon="@mipmap/ic_launcher_round"
12+
android:supportsRtl="true"
13+
android:theme="@style/AppTheme">
14+
<activity android:name=".MainActivity">
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
18+
<category android:name="android.intent.category.LAUNCHER" />
19+
</intent-filter>
20+
</activity>
21+
</application>
22+
23+
</manifest>
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
4+
//
5+
// <code>
6+
package com.microsoft.cognitiveservices.speech.samples.quickstart;
7+
8+
import android.content.res.AssetManager;
9+
import android.support.v4.app.ActivityCompat;
10+
import android.support.v7.app.AppCompatActivity;
11+
import android.os.Bundle;
12+
import android.util.Log;
13+
import android.view.View;
14+
import android.widget.Button;
15+
import android.widget.TextView;
16+
17+
import com.microsoft.cognitiveservices.speech.AudioDataStream;
18+
import com.microsoft.cognitiveservices.speech.KeywordRecognitionModel;
19+
import com.microsoft.cognitiveservices.speech.SpeechConfig;
20+
import com.microsoft.cognitiveservices.speech.SpeechRecognitionResult;
21+
import com.microsoft.cognitiveservices.speech.SpeechRecognizer;
22+
import com.microsoft.cognitiveservices.speech.audio.AudioConfig;
23+
import com.microsoft.cognitiveservices.speech.KeywordRecognizer;
24+
import com.microsoft.cognitiveservices.speech.KeywordRecognitionResult;
25+
import com.microsoft.cognitiveservices.speech.ResultReason;
26+
import com.microsoft.cognitiveservices.speech.audio.PushAudioInputStream;
27+
28+
import java.io.InputStream;
29+
import java.util.Arrays;
30+
import java.util.concurrent.ExecutorService;
31+
import java.util.concurrent.Executors;
32+
import java.util.concurrent.Future;
33+
import java.util.concurrent.atomic.AtomicBoolean;
34+
35+
import static android.Manifest.permission.*;
36+
37+
public class MainActivity extends AppCompatActivity {
38+
39+
private ExecutorService es = Executors.newFixedThreadPool(3);
40+
41+
// Replace below with your own subscription key
42+
private static String speechSubscriptionKey = "YourSubscriptionKey";
43+
// Replace below with your own service region (e.g., "westus").
44+
private static String serviceRegion = "YourServiceRegion";
45+
46+
@Override
47+
protected void onCreate(Bundle savedInstanceState) {
48+
super.onCreate(savedInstanceState);
49+
setContentView(R.layout.activity_main);
50+
51+
// Note: we need to request the permissions
52+
int requestCode = 5; // unique code for the permission request
53+
ActivityCompat.requestPermissions(MainActivity.this, new String[]{RECORD_AUDIO, INTERNET}, requestCode);
54+
}
55+
56+
void enableButton(final boolean enabled) {
57+
final Button btn = (Button) this.findViewById(R.id.button);
58+
runOnUiThread(() -> {
59+
btn.setEnabled(enabled);
60+
});
61+
}
62+
63+
void updateText(final String text) {
64+
final TextView txt = (TextView) this.findViewById(R.id.hello); // 'hello' is the ID of your text view
65+
runOnUiThread(() -> {
66+
txt.setText(text);
67+
});
68+
69+
}
70+
71+
final AtomicBoolean stopPumping = new AtomicBoolean();
72+
private Runnable pump(final AudioDataStream src, final PushAudioInputStream dst)
73+
{
74+
return () -> {
75+
try {
76+
final byte[] buffer = new byte[300];
77+
while (!stopPumping.get()) {
78+
if (!src.canReadData(300))
79+
{
80+
continue;
81+
}
82+
long count = src.readData(buffer);
83+
if (count == 0) {
84+
break;
85+
}
86+
if (count < 300) {
87+
dst.write(Arrays.copyOf(buffer, (int) count));
88+
} else {
89+
dst.write(buffer);
90+
}
91+
}
92+
} catch (Exception ex)
93+
{
94+
Log.e("SpeechSDKDemo", "Pump got an exception");
95+
}
96+
};
97+
}
98+
99+
public void onSpeechButtonClicked(View v) {
100+
enableButton(false);
101+
updateText("Say \"Computer\"");
102+
Runnable asyncTask = () -> {
103+
try {
104+
AssetManager am = getAssets();
105+
AudioConfig config = AudioConfig.fromDefaultMicrophoneInput();
106+
assert(config != null);
107+
108+
KeywordRecognizer reco = new KeywordRecognizer(config);
109+
assert(reco != null);
110+
111+
InputStream is = am.open("kws.table");
112+
KeywordRecognitionModel model = KeywordRecognitionModel.fromStream(is, "computer", false);
113+
Future<KeywordRecognitionResult> task = reco.recognizeOnceAsync(model);
114+
assert(task != null);
115+
116+
KeywordRecognitionResult result = task.get();
117+
assert(result != null);
118+
119+
if (result.getReason() == ResultReason.RecognizedKeyword) {
120+
updateText("Recognized " + result.getText());
121+
}
122+
else {
123+
updateText("Error: got the wrong sort of recognition.");
124+
reco.close();
125+
enableButton(true);
126+
return;
127+
}
128+
AudioDataStream audioDataStream = AudioDataStream.fromResult(result);
129+
130+
PushAudioInputStream srInputStream = PushAudioInputStream.create();
131+
AudioConfig srAudioConfig = AudioConfig.fromStreamInput(srInputStream);
132+
SpeechConfig srConfig = SpeechConfig.fromSubscription(speechSubscriptionKey, serviceRegion);
133+
SpeechRecognizer speechRecognizer = new SpeechRecognizer(srConfig, srAudioConfig);
134+
/* We pump the audio into the push stream */
135+
stopPumping.set(false);
136+
es.execute(pump(audioDataStream, srInputStream));
137+
SpeechRecognitionResult srResult = speechRecognizer.recognizeOnceAsync().get();
138+
stopPumping.set(true);
139+
if (srResult.getReason() == ResultReason.RecognizedSpeech) {
140+
updateText("Recognized Speech " + srResult.getText());
141+
}
142+
else {
143+
updateText("Error: got the wrong sort of recognition.");
144+
}
145+
audioDataStream.detachInput();
146+
audioDataStream.close();
147+
reco.close();
148+
config.close();
149+
speechRecognizer.close();
150+
srAudioConfig.close();
151+
srConfig.close();
152+
srInputStream.close();
153+
} catch (Exception ex) {
154+
Log.e("SpeechSDKDemo", "unexpected " + ex.getMessage());
155+
enableButton(true);
156+
assert(false);
157+
}
158+
enableButton(true);
159+
};
160+
es.execute(asyncTask);
161+
}
162+
}
163+
// </code>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="match_parent"
6+
android:layout_height="match_parent"
7+
tools:context=".MainActivity">
8+
9+
<TextView
10+
android:id="@+id/hello"
11+
android:layout_width="366dp"
12+
android:layout_height="295dp"
13+
android:text="Hello World!"
14+
app:layout_constraintBottom_toBottomOf="parent"
15+
app:layout_constraintLeft_toLeftOf="parent"
16+
app:layout_constraintRight_toRightOf="parent"
17+
app:layout_constraintTop_toTopOf="parent"
18+
app:layout_constraintVertical_bias="0.925" />
19+
20+
<Button
21+
android:id="@+id/button"
22+
android:layout_width="wrap_content"
23+
android:layout_height="wrap_content"
24+
android:layout_marginStart="16dp"
25+
android:onClick="onSpeechButtonClicked"
26+
android:text="Button"
27+
app:layout_constraintBottom_toTopOf="@+id/hello"
28+
app:layout_constraintStart_toStartOf="parent"
29+
app:layout_constraintTop_toTopOf="parent"
30+
app:layout_constraintVertical_bias="0.072" />
31+
32+
</android.support.constraint.ConstraintLayout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3+
<background android:drawable="@color/ic_launcher_background"/>
4+
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
5+
</adaptive-icon>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3+
<background android:drawable="@color/ic_launcher_background"/>
4+
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
5+
</adaptive-icon>
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<color name="colorPrimary">#3F51B5</color>
4+
<color name="colorPrimaryDark">#303F9F</color>
5+
<color name="colorAccent">#FF4081</color>
6+
</resources>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<color name="ic_launcher_background">#0078D4</color>
4+
</resources>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<resources>
2+
<string name="app_name">Quickstart</string>
3+
</resources>

0 commit comments

Comments
 (0)