Skip to content
Shiny.NET

Speech

NuGet package Shiny.AppDeviceBridge.Speech

The speech bridge recognizes speech on the device, streams dictation as events, speaks text and lists voices.

Terminal window
dotnet add package Shiny.AppDeviceBridge.Speech
builder.UseAppDeviceBridge(
bridge => bridge.AddSpeechBridge(),
webApp => { /* … */ }
);
Client C# TypeScript
ISpeechBridge AddSpeechBridgeClient() SpeechBridge

Built on Shiny.Speech, which is still a prerelease package.

Topic Details
Recognizing once recognize listens until a pause and returns { "text": … }. It gives up after timeoutMs: 15 s by default, 60 s at most. text is null if nothing was heard.
Dictation POST listener keeps the microphone open and streams speech.partial and speech.result events until you delete it. It needs a listener for one of them to start (409 without) and stops once neither has one, so a page that goes away can’t leave the microphone on. speech.ended says why it stopped: Stopped, PageClosed or Error.
One microphone a recognition and a listener can’t run at once. The second gets 409 microphone_busy.
Speaking speak waits until the text has been spoken, unless you pass "wait": false, which returns 204 straight away and raises speech.spoken when done. A new utterance interrupts the current one. Text is capped at 4,000 characters.
Platforms Linux has no OS speech engine, so its endpoints return 501. To use a cloud provider or Whisper there, pass o => o.RegisterSpeechServices = false and register your own ISpeechToTextService / ITextToSpeechService.
Platform setup Android needs RECORD_AUDIO, plus a <queries> entry for android.intent.action.TTS_SERVICE. Apple platforms need NSSpeechRecognitionUsageDescription and NSMicrophoneUsageDescription, plus the com.apple.security.device.audio-input entitlement for sandboxed apps.

recognize is one utterance in, text out. A listener keeps dictating and streams partial and final results as events — listen to onPartial or onResult first, or starting it answers 409.

import { SpeechBridge } from "@shinyorg/appdevicebridge";
const speech = new SpeechBridge();
await speech.requestAccess();
const { text } = await speech.recognize({ culture: "en-US", silenceTimeoutMs: 1500 });
await speech.onPartial(r => input.value = r.text);
await speech.onResult(r => submit(r.text));
await speech.startListener({ culture: "en-US", keywords: ["stop"] });
await speech.speak({ text: "Order received", rate: 1.0, wait: true });
GET/_bridge/speech/status#

What is supported, and whether the microphone or the speaker is in use.

C#ISpeechBridge.GetStatusAsyncTSSpeechBridge.getStatus
Response
200 SpeechStatus
SpeechStatus · 5 fields
recognitionSupportedboolean
synthesisSupportedboolean
listeningboolean
recognizingboolean
speakingboolean
POST/_bridge/speech/access#

Requests microphone and speech recognition permission.

C#ISpeechBridge.RequestAccessAsyncTSSpeechBridge.requestAccess
Response
200 SpeechAccessResult
SpeechAccessResult · 1 field
accessAccessState
POST/_bridge/speech/recognize#

Listens until the speaker goes quiet and returns what was heard. text is null when nothing was heard before the timeout.

C#ISpeechBridge.RecognizeAsyncTSSpeechBridge.recognize
Body
application/json · RecognizeRequest
RecognizeRequest · 5 fields
culturestring | nullA culture name such as en-US; the device's when null.
silenceTimeoutMsnumber | nullHow much quiet ends it, 500–10,000 ms.
timeoutMsnumber | nullThe longest it waits in all, 1,000–60,000 ms; 15 seconds when null.
preferOnDeviceboolean | nullKeep audio on the device where the platform allows.
keywordsstring[] | nullAt most 32, each at most 64 characters.
Response
200 RecognizeResult
RecognizeResult · 1 field
textstring | nullWhat was heard; null when nothing was.
GET/_bridge/speech/listener#

The running dictation, or null when there is none.

C#ISpeechBridge.GetListenerAsyncTSSpeechBridge.getListener
Response
200 SpeechListener · or 204 when there is none
SpeechListener · 2 fields
culturestring | null
keywordsstring[] | null
POST/_bridge/speech/listener#

Starts dictation. Results arrive through onPartial, onResult and onKeyword, so listen first: without a listener for onPartial or onResult it fails with 409. It ends when stopped or once neither has a listener left.

C#ISpeechBridge.StartListenerAsyncTSSpeechBridge.startListener
Body
application/json · SpeechListenerRequest
SpeechListenerRequest · 4 fields
culturestring | nullA culture name such as en-US; the device's when null.
silenceTimeoutMsnumber | nullHow much quiet ends a phrase, 500–10,000 ms.
preferOnDeviceboolean | nullKeep audio on the device where the platform allows.
keywordsstring[] | nullWords that raise onKeyword. At most 32, each at most 64 characters.
Response
200 SpeechListener
SpeechListener · 2 fields
culturestring | null
keywordsstring[] | null
Errors
409Conflict
DELETE/_bridge/speech/listener#

Stops dictation.

C#ISpeechBridge.StopListenerAsyncTSSpeechBridge.stopListener
Response
204 No content
POST/_bridge/speech/speak#

Speaks text, interrupting anything already being spoken. With wait it returns once speech ends; without, it returns null straight away and onSpoken says when it ended.

C#ISpeechBridge.SpeakAsyncTSSpeechBridge.speak
Body
application/json · SpeakRequest
SpeakRequest · 7 fields
textstringAt most 4,000 characters.
culturestring | nullA culture name such as en-US.
voicestring | nullA voice's id.
pitchnumber | null0.5–2.
ratenumber | null0.25–4.
volumenumber | null0–1.
waitbooleanReturn once speech ends rather than straight away.
Response
200 SpeakResult · or 204 when there is none
SpeakResult · 1 field
completedbooleanFalse when it was interrupted.
DELETE/_bridge/speech/speak#

Stops speaking.

C#ISpeechBridge.StopSpeakingAsyncTSSpeechBridge.stopSpeaking
Response
204 No content
GET/_bridge/speech/voices#

The voices installed, optionally for one culture such as en-US.

C#ISpeechBridge.GetVoicesAsyncTSSpeechBridge.getVoices
ParameterInType
culturequerystring | nulloptional
Response
200 SpeechVoice[]
SpeechVoice · 3 fields
idstring
namestring
culturestring | null
GET/_bridge/speech/cultures#

The cultures voices exist for.

C#ISpeechBridge.GetCulturesAsyncTSSpeechBridge.getCultures
Response
200 string[]
EVENTspeech.partial#

Dictation's best guess so far, replaced as the speaker goes on.

C#ISpeechBridge.OnPartialAsyncTSSpeechBridge.onPartial
Payload
SpeechRecognized
textstring
confidencenumber | null0–1, where the platform reports one.
EVENTspeech.result#

A finished phrase from dictation.

C#ISpeechBridge.OnResultAsyncTSSpeechBridge.onResult
Payload
SpeechRecognized
textstring
confidencenumber | null0–1, where the platform reports one.
EVENTspeech.keyword#

One of the dictation's keywords was heard.

C#ISpeechBridge.OnKeywordAsyncTSSpeechBridge.onKeyword
Payload
SpeechKeyword
keywordstring
EVENTspeech.spoken#

An utterance finished or was interrupted.

C#ISpeechBridge.OnSpokenAsyncTSSpeechBridge.onSpoken
Payload
SpeakResult
completedbooleanFalse when it was interrupted.
EVENTspeech.error#

Recognition or synthesis failed.

C#ISpeechBridge.OnErrorAsyncTSSpeechBridge.onError
Payload
SpeechError
sourceSpeechErrorSource
messagestring

JSON property names are camelCase and enums travel as their names. A ? marks a property the payload may omit;| null one that may be null.

SpeechStatusobject#
recognitionSupportedboolean
synthesisSupportedboolean
listeningboolean
recognizingboolean
speakingboolean
AccessStateenum#

Where a permission stands. Reported by every bridge that needs one; the names match Shiny's own.

"Unknown""NotSupported""NotSetup""Disabled""Restricted""Denied""Available"
RecognizeRequestobject#
culture?string | nullA culture name such as en-US; the device's when null.
silenceTimeoutMs?number | nullHow much quiet ends it, 500–10,000 ms.
timeoutMs?number | nullThe longest it waits in all, 1,000–60,000 ms; 15 seconds when null.
preferOnDevice?boolean | nullKeep audio on the device where the platform allows.
keywords?string[] | nullAt most 32, each at most 64 characters.
RecognizeResultobject#
textstring | nullWhat was heard; null when nothing was.
SpeechListenerobject#
culturestring | null
keywordsstring[] | null
SpeechListenerRequestobject#
culture?string | nullA culture name such as en-US; the device's when null.
silenceTimeoutMs?number | nullHow much quiet ends a phrase, 500–10,000 ms.
preferOnDevice?boolean | nullKeep audio on the device where the platform allows.
keywords?string[] | nullWords that raise onKeyword. At most 32, each at most 64 characters.
SpeakRequestobject#
textstringAt most 4,000 characters.
culture?string | nullA culture name such as en-US.
voice?string | nullA voice's id.
pitch?number | null0.5–2.
rate?number | null0.25–4.
volume?number | null0–1.
wait?booleanReturn once speech ends rather than straight away.
SpeakResultobject#
completedbooleanFalse when it was interrupted.
SpeechVoiceobject#
idstring
namestring
culturestring | null
SpeechRecognizedobject#
textstring
confidencenumber | null0–1, where the platform reports one.
SpeechKeywordobject#
keywordstring
SpeechEndReasonenum#

Why dictation ended.

"Stopped""PageClosed""Error"
SpeechErrorSourceenum#
"Recognition""Synthesis"

These routes sit under AppDeviceBridgePolicies.Bridges like every other bridge: callers on this device by default. See Security.