Text-to-Speech and Speech-to-Text
GeminiClient exposes Gemini's audio surface in two complementary forms:
| Surface | Entry point |
|---|---|
| Text-to-speech (TTS) | client.SpeakAsync(text, voiceName, modelId, languageCode) or SpeakAdvancedAsync |
| Voice library and custom voices | GeminiNextGenClient.Voices |
| Speech-to-text (STT, MEAI) | ((Microsoft.Extensions.AI.ISpeechToTextClient)client).GetTextAsync(stream, options) |
| Speech-to-text (convenience) | client.TranscribeAsync(audioData, mimeType, modelId, prompt) |
| Gemini 3.5 Transcribe | client.Transcribe35FileAsync(fileUri, mimeType, transcriptionConfig) or Transcribe35Async |
The default TTS model is gemini-3.8-flash-lite-tts. Set modelId to
gemini-3.8-flash-tts for studio narration and complex multi-speaker work.
Both models accept turn-level SpeechMetadata.Style and prebuilt, designed,
or replicated voices. The 3.1 preview remains available by passing its model ID.
Synthesizing speech
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Useful helpers shipped alongside SpeakAsync:
GeminiAudioTags— strongly-typed constants for emotion / style / delivery / pacing tags.GeminiVoices— 30 prebuilt voice names, plusGeminiVoices.Allfor iteration.client.ListTtsModelsAsync()— live discovery of every TTS-capable model.AudioResult.SampleRateHz/AudioResult.ParseSampleRateHz(mime)— extract the sample rate from raw PCM MIME types when one is present.SpeakAdvancedAsync— add a style, use avoice_...orvoicekey_..., or request raw PCM viaAudioResponseFormatMimeType.AudioL16.GeminiNextGenClient.Voices— list, create, inspect, and delete stored voices.
Transcribing through MEAI
GeminiClient implements Microsoft.Extensions.AI.ISpeechToTextClient, so anything
that consumes that interface can swap providers without code changes.
1 2 3 4 5 6 7 | |
The implementation auto-sniffs WAV / Ogg / FLAC / MP3 magic bytes and falls back
to audio/wav. Pass a custom MIME type via
SpeechToTextOptions.RawRepresentationFactory when you know the format already.
For the dedicated Gemini 3.5 Transcribe model, upload a file with the Files API
and pass its URI to Transcribe35FileAsync. The returned GenerateContentResponse
retains word timestamps and speaker annotations. For example:
1 2 3 4 5 6 7 8 | |
Use Mode = AudioTranscriptionConfigMode.Smart for cleanup and formatting;
Google does not allow Smart mode together with word timestamps or diarization.
Round-trip walk-through
The full TTS → save WAV → STT flow is wired up in
samples/AudioRoundTrip,
which you can run with:
1 2 3 | |
The sample:
- Synthesizes speech with
SpeakAsync, defaulting toGeminiVoices.Puck. - Saves the returned WAV audio (
audio_round_trip.wav) so you can play it back locally. The helper adds a header only for raw PCM output. - Calls
ISpeechToTextClient.GetTextAsyncon the WAV stream and prints the transcribed text — proving the new STT interface plugs into any MEAI-aware pipeline.
The sample handles HTTP 429 and service unavailability with an explanatory message.
Live-API counterpart
For real-time bidirectional voice over WebSocket (instead of REST round-trips),
see samples/LiveAudioPlayback.
It uses gemini-3.1-flash-live-preview, captures the streamed PCM chunks
into per-turn WAV files via the same AudioResult.WriteWavFile helper, and
prints text transcriptions alongside the audio. The Live-API surface is
covered in depth in the Live API guide.