# ISpeechSynthesizer

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.ispeechsynthesizer/
> Summary: ISpeechSynthesizer: A provider that generates speech from text.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

A provider that generates speech from text.

```csharp
public interface ISpeechSynthesizer
```

## Remarks

ElevenLabs is an *implementation*, not a dependency. A consumer
wanting another provider registers their own implementation; tools know
only this contract.

The contract lives HERE, not in `Tracon.Voice`: the HTTP layer
(`Tracon.AspNetCore`) sees these types while serving the voice
endpoints, but it CANNOT reference `Tracon.Voice` (the package
direction rule). The same pattern was applied to the MCP abstractions —.

**DI lifetime — singleton.** The unnamed default is registered as a
singleton with `TryAdd`; a consumer's own registration wins. More
synthesizers are registered by name with `AddSpeechSynthesizer`.

**Tenant behavior — TENANT-INDEPENDENT implementation, tenant-gated calls.**
An instance is configured once, with its own credentials; it never reads the
tenant and no member takes a tenant parameter. Every Tracon call that carries a
tenant's text or audio resolves the instance through
[ISpeechProviderResolver](/api/tracon.ispeechproviderresolver/), which applies the tenant's egress policy to
[ISpeechSynthesizer.ProviderName](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_ProviderName) and, when the tenant has its own credential for that
provider, passes it in [SpeechRequest.Credential](/api/tracon.speechrequest/#Tracon_SpeechRequest_Credential) — only to an
implementation whose [ISpeechSynthesizer.SupportsTenantCredentials](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_SupportsTenantCredentials) is
[true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool). The platform health check calls the default instance
directly, with its configured credential and no tenant data.

## Properties

### <a id="Tracon_ISpeechSynthesizer_MaxCharactersPerRequest"></a> MaxCharactersPerRequest

The maximum number of characters accepted in a single
[ISpeechSynthesizer.SynthesizeAsync](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_SynthesizeAsync_Tracon_SpeechRequest_System_Threading_CancellationToken_) call.

```csharp
int MaxCharactersPerRequest { get; }
```

#### Property Value

 [int](https://learn.microsoft.com/dotnet/api/system.int32)

#### Remarks

The tool call (`speak`) AND the direct HTTP operator endpoint
(`POST /api/voice/speak`) read the SAME value — the limit is
applied consistently across both paths.

### <a id="Tracon_ISpeechSynthesizer_ProviderName"></a> ProviderName

The provider name. Used in cost records and health checks.

```csharp
string ProviderName { get; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)

#### Remarks

A tenant's egress policy and provider bindings name this value. Two
registrations that report the same name are one provider to the tenant's
checks.

### <a id="Tracon_ISpeechSynthesizer_SupportsTenantCredentials"></a> SupportsTenantCredentials

Gets whether the synthesizer honours a tenant credential passed in
[SpeechRequest.Credential](/api/tracon.speechrequest/#Tracon_SpeechRequest_Credential) and to
[ISpeechSynthesizer.ListVoicesWithCredentialAsync](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_ListVoicesWithCredentialAsync_Tracon_ModelProviderCredential_System_Threading_CancellationToken_).

```csharp
bool SupportsTenantCredentials { get; }
```

#### Property Value

 [bool](https://learn.microsoft.com/dotnet/api/system.boolean)

#### Remarks

The default is [false](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool). Tracon then refuses a call for a tenant
that has its own binding for [ISpeechSynthesizer.ProviderName](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_ProviderName) rather than make it on
the configured credential, which would bill the wrong account. An
implementation that returns [true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool) uses the credential for the
call it came with and never falls back to its configured one.

## Methods

### <a id="Tracon_ISpeechSynthesizer_ListVoicesAsync_System_Threading_CancellationToken_"></a> ListVoicesAsync\(CancellationToken\)

Lists the available voices.

```csharp
ValueTask<IReadOnlyList<VoiceDescriptor>> ListVoicesAsync(CancellationToken cancellationToken = default)
```

#### Parameters

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[IReadOnlyList](https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlylist\-1)<[VoiceDescriptor](/api/tracon.voicedescriptor/)\>\>

The voices, ordered by name.

### <a id="Tracon_ISpeechSynthesizer_ListVoicesWithCredentialAsync_Tracon_ModelProviderCredential_System_Threading_CancellationToken_"></a> ListVoicesWithCredentialAsync\(ModelProviderCredential?, CancellationToken\)

Lists the available voices with a tenant's own credential.

```csharp
ValueTask<IReadOnlyList<VoiceDescriptor>> ListVoicesWithCredentialAsync(ModelProviderCredential? credential, CancellationToken cancellationToken = default)
```

#### Parameters

`credential` [ModelProviderCredential](/api/tracon.modelprovidercredential/)?

The tenant's credential, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) for the configured one.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[IReadOnlyList](https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlylist\-1)<[VoiceDescriptor](/api/tracon.voicedescriptor/)\>\>

The voices, ordered by name.

#### Remarks

The default implementation calls [ISpeechSynthesizer.ListVoicesAsync](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_ListVoicesAsync_System_Threading_CancellationToken_)
when no credential is given and throws when one is: an implementation that
cannot use the tenant's credential must not list with its own instead. An
implementation whose [ISpeechSynthesizer.SupportsTenantCredentials](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_SupportsTenantCredentials) is
[true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool) overrides it.

#### Exceptions

 [NotSupportedException](https://learn.microsoft.com/dotnet/api/system.notsupportedexception)

`credential` is set and the implementation does not override
this method.

### <a id="Tracon_ISpeechSynthesizer_SynthesizeAsync_Tracon_SpeechRequest_System_Threading_CancellationToken_"></a> SynthesizeAsync\(SpeechRequest, CancellationToken\)

Synthesizes speech from a text.

```csharp
ValueTask<SpeechAudio> SynthesizeAsync(SpeechRequest request, CancellationToken cancellationToken = default)
```

#### Parameters

`request` [SpeechRequest](/api/tracon.speechrequest/)

The request.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[SpeechAudio](/api/tracon.speechaudio/)\>

The generated audio.

### <a id="Tracon_ISpeechSynthesizer_SynthesizeStreamingAsync_Tracon_SpeechRequest_System_Threading_CancellationToken_"></a> SynthesizeStreamingAsync\(SpeechRequest, CancellationToken\)

Synthesizes speech from a text and streams the audio piece by piece.

```csharp
IAsyncEnumerable<ReadOnlyMemory<byte>> SynthesizeStreamingAsync(SpeechRequest request, CancellationToken cancellationToken = default)
```

#### Parameters

`request` [SpeechRequest](/api/tracon.speechrequest/)

The request.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [IAsyncEnumerable](https://learn.microsoft.com/dotnet/api/system.collections.generic.iasyncenumerable\-1)<[ReadOnlyMemory](https://learn.microsoft.com/dotnet/api/system.readonlymemory\-1)<[byte](https://learn.microsoft.com/dotnet/api/system.byte)\>\>

The audio chunks.

#### Remarks

The streaming path is for low latency, and the voice layer uses
it. The signature is defined **now**: adding a member to
an interface later is a breaking change for consumers implementing that interface.

Streamed audio is **not stored as an attachment**. The
billed quantity is unknown until the stream ends, and the chunks are
not a valid file on their own; the `speak` tool uses the
non-streaming path for this reason.
