Share via


Menor latencia de síntesis de voz mediante el SDK de Voz

La latencia de síntesis es crítica para las aplicaciones. En este artículo, se presentarán los procedimientos recomendados para reducir la latencia y que los usuarios finales tengan el mejor rendimiento posible.

Habitualmente, la latencia se mide por first byte latency y finish latency, como se muestra a continuación:

Latencia Descripción Clave de la propiedad SpeechSynthesisResult
latencia del primer byte Indica el retraso entre el inicio de la tarea de síntesis y la recepción del primer fragmento de datos de audio. SpeechServiceResponse_SynthesisFirstByteLatencyMs
latencia de finalización Indica el retraso entre el inicio de la tarea de síntesis y la recepción de todos los datos de audio sintetizados. SpeechServiceResponse_SynthesisFinishLatencyMs

El SDK de Voz coloca las duraciones de la latencia en la colección Properties de SpeechSynthesisResult. En el siguiente código de ejemplo se muestran estos valores.

var result = await synthesizer.SpeakTextAsync(text);
Console.WriteLine($"first byte latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs)} ms");
Console.WriteLine($"finish latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs)} ms");
// you can also get the result id, and send to us when you need help for diagnosis
var resultId = result.ResultId;
Latencia Descripción Clave de la propiedad SpeechSynthesisResult
first byte latency Indica el retraso entre que se inicia la síntesis y que se recibe el primer fragmento de audio. SpeechServiceResponse_SynthesisFirstByteLatencyMs
finish latency Indica el retraso entre que se inicia la síntesis y que se recibe el todo el audio sintetizado. SpeechServiceResponse_SynthesisFinishLatencyMs

El SDK de Voz ha medido las latencias y las coloca en el bolsa de propiedades de SpeechSynthesisResult. Consulte los códigos siguientes para obtenerlas.

auto result = synthesizer->SpeakTextAsync(text).get();
auto firstByteLatency = std::stoi(result->Properties.GetProperty(PropertyId::SpeechServiceResponse_SynthesisFirstByteLatencyMs));
auto finishedLatency = std::stoi(result->Properties.GetProperty(PropertyId::SpeechServiceResponse_SynthesisFinishLatencyMs));
// you can also get the result id, and send to us when you need help for diagnosis
auto resultId = result->ResultId;
Latencia Descripción Clave de la propiedad SpeechSynthesisResult
first byte latency Indica el retraso entre que se inicia la síntesis y que se recibe el primer fragmento de audio. SpeechServiceResponse_SynthesisFirstByteLatencyMs
finish latency Indica el retraso entre que se inicia la síntesis y que se recibe el todo el audio sintetizado. SpeechServiceResponse_SynthesisFinishLatencyMs

El SDK de Voz ha medido las latencias y las coloca en el bolsa de propiedades de SpeechSynthesisResult. Consulte los códigos siguientes para obtenerlas.

SpeechSynthesisResult result = synthesizer.SpeakTextAsync(text).get();
System.out.println("first byte latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs) + " ms.");
System.out.println("finish latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs) + " ms.");
// you can also get the result id, and send to us when you need help for diagnosis
String resultId = result.getResultId();
Latencia Descripción Clave de la propiedad SpeechSynthesisResult
first byte latency Indica el retraso entre que se inicia la síntesis y que se recibe el primer fragmento de audio. SpeechServiceResponse_SynthesisFirstByteLatencyMs
finish latency Indica el retraso entre que se inicia la síntesis y que se recibe el todo el audio sintetizado. SpeechServiceResponse_SynthesisFinishLatencyMs

El SDK de Voz ha medido las latencias y las coloca en el bolsa de propiedades de SpeechSynthesisResult. Consulte los códigos siguientes para obtenerlas.

result = synthesizer.speak_text_async(text).get()
first_byte_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs))
finished_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs))
# you can also get the result id, and send to us when you need help for diagnosis
result_id = result.result_id
Latencia Descripción Clave de la propiedad SPXSpeechSynthesisResult
first byte latency Indica el retraso entre que se inicia la síntesis y que se recibe el primer fragmento de audio. SPXSpeechServiceResponseSynthesisFirstByteLatencyMs
finish latency Indica el retraso entre que se inicia la síntesis y que se recibe el todo el audio sintetizado. SPXSpeechServiceResponseSynthesisFinishLatencyMs

El SDK de Voz ha medido las latencias y las coloca en el bolsa de propiedades de SPXSpeechSynthesisResult. Consulte los códigos siguientes para obtenerlas.

SPXSpeechSynthesisResult *speechResult = [speechSynthesizer speakText:text];
int firstByteLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisFirstByteLatencyMs]];
int finishedLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisFinishLatencyMs]];
// you can also get the result id, and send to us when you need help for diagnosis
NSString *resultId = result.resultId;

La latencia del primer byte es menor que la latencia de finalización en la mayoría de los casos. La latencia del primer byte es independiente de la longitud del texto, mientras que la latencia de finalización aumenta con la longitud del texto.

Lo ideal es minimizar la latencia experimentada por el usuario (la latencia antes de que el usuario escucha el sonido) al tiempo de recorrido de una ruta de red, más la latencia del primer fragmento de audio del servicio de síntesis de voz.

Streaming

El streaming es fundamental para reducir la latencia. El código de cliente puede iniciar la reproducción cuando se recibe el primer fragmento de audio. En un escenario de servicio, puede reenviar los fragmentos de audio inmediatamente a los clientes, en lugar de esperar todo el audio.

Puede usar PullAudioOutputStream, PushAudioOutputStream, el evento Synthesizing y AudioDataStream del SDK de Voz para habilitar el streaming.

Tomando AudioDataStream como ejemplo:

using (var synthesizer = new SpeechSynthesizer(config, null as AudioConfig))
{
    using (var result = await synthesizer.StartSpeakingTextAsync(text))
    {
        using (var audioDataStream = AudioDataStream.FromResult(result))
        {
            byte[] buffer = new byte[16000];
            uint filledSize = 0;
            while ((filledSize = audioDataStream.ReadData(buffer)) > 0)
            {
                Console.WriteLine($"{filledSize} bytes received.");
            }
        }
    }
}

Puede usar PullAudioOutputStream, PushAudioOutputStream, el evento Synthesizing y AudioDataStream del SDK de Voz para habilitar el streaming.

Tomando AudioDataStream como ejemplo:

auto synthesizer = SpeechSynthesizer::FromConfig(config, nullptr);
auto result = synthesizer->SpeakTextAsync(text).get();
auto audioDataStream = AudioDataStream::FromResult(result);
uint8_t buffer[16000];
uint32_t filledSize = 0;
while ((filledSize = audioDataStream->ReadData(buffer, sizeof(buffer))) > 0)
{
    cout << filledSize << " bytes received." << endl;
}

Puede usar PullAudioOutputStream, PushAudioOutputStream, el evento Synthesizing y AudioDataStream del SDK de Voz para habilitar el streaming.

Tomando AudioDataStream como ejemplo:

SpeechSynthesizer synthesizer = new SpeechSynthesizer(config, null);
SpeechSynthesisResult result = synthesizer.StartSpeakingTextAsync(text).get();
AudioDataStream audioDataStream = AudioDataStream.fromResult(result);
byte[] buffer = new byte[16000];
long filledSize = audioDataStream.readData(buffer);
while (filledSize > 0) {
    System.out.println(filledSize + " bytes received.");
    filledSize = audioDataStream.readData(buffer);
}

Puede usar PullAudioOutputStream, PushAudioOutputStream, el evento Synthesizing y AudioDataStream del SDK de Voz para habilitar el streaming.

Tomando AudioDataStream como ejemplo:

speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)
result = speech_synthesizer.start_speaking_text_async(text).get()
audio_data_stream = speechsdk.AudioDataStream(result)
audio_buffer = bytes(16000)
filled_size = audio_data_stream.read_data(audio_buffer)
while filled_size > 0:
    print("{} bytes received.".format(filled_size))
    filled_size = audio_data_stream.read_data(audio_buffer)

Puede usar SPXPullAudioOutputStream, SPXPushAudioOutputStream, el evento Synthesizing y SPXAudioDataStream del SDK de Voz para habilitar el streaming.

Tomando AudioDataStream como ejemplo:

SPXSpeechSynthesizer *synthesizer = [[SPXSpeechSynthesizer alloc] initWithSpeechConfiguration:speechConfig audioConfiguration:nil];
SPXSpeechSynthesisResult *speechResult = [synthesizer startSpeakingText:inputText];
SPXAudioDataStream *stream = [[SPXAudioDataStream alloc] initFromSynthesisResult:speechResult];
NSMutableData* data = [[NSMutableData alloc]initWithCapacity:16000];
while ([stream readData:data length:16000] > 0) {
    // Read data here
}

Conexión previa y reutilización de SpeechSynthesizer

El SDK de Voz usa un WebSocket para comunicarse con el servicio. Lo ideal sería que la latencia de red fuera un tiempo de recorrido de ruta (RTT). Si la conexión se acaba de establecer, la latencia de red incluye tiempo adicional para establecer la conexión. El establecimiento de una conexión WebSocket necesita el protocolo de enlace TCP, el protocolo de enlace SSL, la conexión HTTP y la actualización del protocolo, lo que introduce un retraso. Para evitar la latencia de la conexión, se recomienda realizar una conexión previa y volver a usar SpeechSynthesizer.

Antes de conectar

Para realizar una conexión previa, establezca una conexión con el servicio Voz cuando sepa que la conexión se necesitará pronto. Por ejemplo, si va a crear un bot de voz en el cliente, puede conectarse previamente al servicio de síntesis de voz cuando el usuario empiece a hablar y llamar a SpeakTextAsync cuando el texto de respuesta del bot esté listo.

using (var synthesizer = new SpeechSynthesizer(uspConfig, null as AudioConfig))
{
    using (var connection = Connection.FromSpeechSynthesizer(synthesizer))
    {
        connection.Open(true);
    }
    await synthesizer.SpeakTextAsync(text);
}
auto synthesizer = SpeechSynthesizer::FromConfig(config, nullptr);
auto connection = Connection::FromSpeechSynthesizer(synthesizer);
connection->Open(true);
SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, (AudioConfig) null);
Connection connection = Connection.fromSpeechSynthesizer(synthesizer);
connection.openConnection(true);
synthesizer = speechsdk.SpeechSynthesizer(config, None)
connection = speechsdk.Connection.from_speech_synthesizer(synthesizer)
connection.open(True)
SPXSpeechSynthesizer* synthesizer = [[SPXSpeechSynthesizer alloc]initWithSpeechConfiguration:self.speechConfig audioConfiguration:nil];
SPXConnection* connection = [[SPXConnection alloc]initFromSpeechSynthesizer:synthesizer];
[connection open:true];

Nota:

Si el texto de síntesis está disponible, solo hay que llamar a SpeakTextAsync para sintetizar el audio. El SDK controlará la conexión.

Reutilización de SpeechSynthesizer

Otra forma de reducir la latencia de la conexión es volver a usar SpeechSynthesizer para que no sea necesario crear SpeechSynthesizer para cada síntesis. Se recomienda usar un grupo de objetos en el escenario de servicio; consulte nuestro código de ejemplo para C# y Java.

Transmisión de audio comprimido a través de la red

Si la red no es estable o tiene un límite de ancho de banda, el tamaño de la carga también afecta a la latencia. Entretanto, un formato de audio comprimido ayuda a ahorrar el ancho de banda de red de los usuarios, algo que resulta especialmente valioso para los usuarios de dispositivos móviles.

Se admiten muchos formatos comprimidos, como opus, webm, mp3, silk, etc. La lista completa se puede ver en SpeechSynthesisOutputFormat. Por ejemplo, la velocidad de bits del formato Riff24Khz16BitMonoPcm es de 384 kbps, mientras que Audio24Khz48KBitRateMonoMp3 solo cuesta 48 kbps. Nuestro SDK de Voz usará automáticamente un formato comprimido para la transmisión cuando se establece un formato de salida pcm. Para Linux y Windows, se necesita GStreamer para habilitar esta característica. Consulte esta instrucción para instalar y configurar GStreamer para el SDK de Voz. Para Android, iOS y macOS, no se necesita ninguna configuración adicional a partir de la versión 1.20.

Otras sugerencias

Almacenamiento en caché de archivos CRL

El SDK de Voz usa archivos CRL para comprobar la certificación. El almacenamiento en caché de los archivos CRL hasta que hayan expirado le ayuda a evitar tener que descargar archivos CRL cada vez. Para más información, consulte Configuración de OpenSSL para Linux.

Uso del SDK de Voz más reciente

El rendimiento del SDK de Voz sigue mejorando, así que intente usar el SDK de Voz más reciente en la aplicación.

Directriz de pruebas de carga

Puede usar la prueba de carga para probar la latencia y capacidad del servicio de síntesis de voz. Estas son algunas directrices:

  • El servicio de síntesis de voz tiene la capacidad de escalabilidad automática, pero tarda tiempo en escalar horizontalmente. Si la simultaneidad aumenta en un breve tiempo, es posible que el cliente obtenga una latencia larga o el código de error 429 (demasiadas solicitudes). Por consiguiente, se recomienda aumentar la simultaneidad paso a paso en la prueba de carga. Consulte este artículo para obtener más información, en particular, este ejemplo de patrones de carga de trabajo.
  • Puede usar nuestro ejemplo con el grupo de objetos (C# y Java) para la prueba de carga y para obtener los números de latencia. Puede modificar los turnos de prueba y la simultaneidad en el ejemplo para satisfacer la simultaneidad de destino.
  • El servicio tiene una limitación de cuota basada en el tráfico real; por tanto, si quiere realizar la prueba de carga con la simultaneidad mayor que el tráfico real, conéctese antes de la prueba.

Pasos siguientes