Azure Speech Services
A Flutter package for real-time Speech-to-Text (STT), Text-to-Speech (TTS), Realtime-Translation using Microsoft Azure Cognitive Services. No Azure SDK binary dependency: it communicates directly with the Azure WebSocket/REST APIs.
- STT: Stream-based real-time transcription with intermediate (hypothesis) and finalized results, multi-language identification (LID), and auto-silence timeout.
- TTS: Synthesize text to audio bytes using any Azure Neural voice, with configurable output format. *. Translation: Stream-based real-time translation in many different languages
- Cross-platform: Mobile (iOS, Android), Desktop (macOS, Windows, Linux), and Web.
Example app
Getting Started
Installation
import 'package:azure_speech_services/azure_speech_services.dart';
Authentication
Both STT and TTS use the same AzureSpeechConfig. You must provide exactly one credential:
// Option A: Subscription Key
final config = AzureSpeechConfig.subscriptionKey(
region: 'westeurope', // or other supported region
key: 'YOUR_AZURE_KEY',
);
// Option B: Short-lived Authorization Token (recommended for Web)
final config = AzureSpeechConfig.authorizationToken(
region: 'westeurope', // or other supported region
token: 'YOUR_BACKEND_GENERATED_TOKEN',
);
Web security note: Browser WebSocket APIs cannot set custom HTTP headers. On Web, auth is passed as a URL query parameter. Always use authorizationToken (generated server-side) on Web: never expose subscriptionKey in the browser URL.
To generate a short-lived token:
curl -X POST \
"https://westeurope.api.cognitive.microsoft.com/sts/v1.0/issueToken" \
-H "Content-Length: 0" \
-H "Ocp-Apim-Subscription-Key: YOUR_KEY"
Speech-to-Text (STT)
Permissions
STT requires microphone access. TTS does not.
Android — android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
iOS — ios/Runner/Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access for speech recognition.</string>
macOS — macos/Runner/DebugProfile.entitlements and Release.entitlements:
<key>com.apple.security.device.audio-input</key>
<true/>
Basic usage
final azureStt = AzureSpeechToText(
config: AzureSpeechConfig.subscriptionKey(
region: 'westeurope', // or other supported region
key: 'YOUR_AZURE_KEY',
),
sttConfig: SpeechToTextConfig(
languages: ['en-US'],
textClearTimeout: const Duration(seconds: 2),
),
);
// Start / stop
await azureStt.start();
await azureStt.stop();
// Check state
azureStt.isListening;
// Dispose when done
await azureStt.dispose();
Listening to transcription updates
azureStt.stream emits TranscriptionState on every change:
StreamBuilder<TranscriptionState>(
stream: azureStt.stream,
builder: (context, snapshot) {
final state = snapshot.data ?? const TranscriptionState();
if (state.error != null) return Text('Error: ${state.error}');
return Column(
children: [
if (state.detectedLanguage != null)
Text('Detected: ${state.detectedLanguage}'),
// Combined text (finalized + intermediate)
Text(state.text),
// state.intermediateText // live hypothesis (no punctuation)
// state.finalizedText // list of confirmed sentences
// state.isListening // mic active
],
);
},
)
Using the BLoC cubit
AzureSpeechToText owns a TranscriptionCubit. Provide it higher in the widget tree to avoid rebuilding the whole subtree:
BlocProvider.value(
value: azureStt.cubit,
child: MyWidget(),
)
// Then in a descendant:
BlocBuilder<TranscriptionCubit, TranscriptionState>(
builder: (context, state) => Text(state.text),
)
Language Identification (LID)
The number of languages you provide determines the mode automatically:
| Mode | Languages count |
|---|---|
| Single language (fastest) | 1 |
| At-Start LID | 1 - 4 |
| Continuous LID | 1 - 10 |
Bare language codes are expanded automatically ("it" → "it-IT").
// Single language: fastest, no identification overhead
SpeechToTextConfig(languages: ['en-US'])
// At-Start: identifies once at the beginning of the session
SpeechToTextConfig(
languages: ['en-US', 'it', 'es-ES', 'fr-FR'],
languageIdMode: .atStart, // default
)
// Continuous: re-identifies throughout the session, up to 10 languages
SpeechToTextConfig(
languages: ['en-US', 'it-IT', 'es-ES', 'de-DE', 'pt-PT', 'nb-NO', 'sv-SE', 'uk-UA'],
languageIdMode: .continuous,
)
External audio stream
To bypass the microphone (e.g. VoIP or file audio), pass your own Stream<Uint8List> to start(). It must emit raw PCM: 16 kHz, mono, 16-bit little-endian — the same format the microphone produces.
await azureStt.start(); // uses mic by default
// or supply your own audio source instead
await azureStt.start(externalAudioStream: myPcmStream);
Text-to-Speech (TTS)
No microphone permissions required.
Basic usage
final azureTts = AzureTextToSpeech(
config: AzureSpeechConfig.subscriptionKey(
region: 'westeurope', // or other supported region
key: 'YOUR_AZURE_KEY',
),
);
// 1. Fetch available voices
final voices = await azureTts.listVoices();
// 2. Pick a voice
final voice = voices.firstWhere(
(v) => v.locale == 'en-US' && v.gender == 'Female',
orElse: () => voices.first,
);
// 3. Synthesize: returns raw audio bytes
final audioBytes = await azureTts.synthesize(
TtsRequest(
text: 'Hello from Azure Speech Flutter!',
voice: voice,
outputFormat: .audio16khz128kbitrateMonoMp3, // default
),
);
Output formats
AudioOutputFormat covers MP3, PCM, mulaw, Opus, and WebM at various sample rates and bitrates. The default is audio16khz128kbitrateMonoMp3.
Playing the audio
The package returns raw bytes. Plug them into any audio player. Example with just_audio:
class _BytesAudioSource extends StreamAudioSource {
final List<int> bytes;
_BytesAudioSource(this.bytes) : super(tag: 'tts');
@override
Future<StreamAudioResponse> request([int? start, int? end]) async {
start ??= 0;
end ??= bytes.length;
return StreamAudioResponse(
sourceLength: bytes.length,
contentLength: end - start,
offset: start,
contentType: 'audio/mpeg',
stream: Stream.value(Uint8List.fromList(bytes.sublist(start, end))),
);
}
}
final player = AudioPlayer();
await player.setAudioSource(_BytesAudioSource(audioBytes));
await player.play();
Voice metadata
Each TtsVoice exposes:
| Field | Description |
|---|---|
name |
Azure short name (e.g. en-US-JennyNeural) |
locale |
BCP-47 locale (e.g. en-US) |
localeName |
Locale display name (e.g. English (United States)) |
localName |
Voice display name in its own language |
gender |
"Male" or "Female" |
License
MIT. See LICENSE.
Libraries
- azure_speech_services
- Flutter package for real-time Speech-to-Text and Text-to-Speech using Microsoft Azure Cognitive Services.