Menurunkan latensi sintesis ucapan menggunakan Speech SDK
Latensi sintesis sangat penting untuk aplikasi Anda. Dalam artikel ini, kami akan memperkenalkan praktik terbaik untuk menurunkan latensi dan menghadirkan performa terbaik bagi pengguna akhir Anda.
Biasanya, kami mengukur latensi berdasarkan first byte latency
dan finish latency
, sebagai berikut:
Latensi | Deskripsi | Kunci properti SpeechSynthesisResult |
---|---|---|
latensi byte pertama | Menunjukkan penundaan waktu antara permulaan tugas sintesis dan penerimaan gugus pertama data audio. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
latensi akhir | Menunjukkan penundaan waktu antara permulaan tugas sintesis dan penerimaan seluruh data audio yang disintesiskan. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK menempatkan durasi latensi dalam koleksi Properti SpeechSynthesisResult
. Contoh kode berikut menunjukkan nilai-nilai ini.
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;
Latensi | Deskripsi | Kunci properti SpeechSynthesisResult |
---|---|---|
first byte latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan gugus audio pertama. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan seluruh audio yang disintesiskan. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK mengukur latensi dan memasukkannya ke dalam kantong properti SpeechSynthesisResult
. Lihat kode berikut untuk mendapatkannya.
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;
Latensi | Deskripsi | Kunci properti SpeechSynthesisResult |
---|---|---|
first byte latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan gugus audio pertama. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan seluruh audio yang disintesiskan. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK mengukur latensi dan memasukkannya ke dalam kantong properti SpeechSynthesisResult
. Lihat kode berikut untuk mendapatkannya.
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();
Latensi | Deskripsi | Kunci properti SpeechSynthesisResult |
---|---|---|
first byte latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan gugus audio pertama. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan seluruh audio yang disintesiskan. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK mengukur latensi dan memasukkannya ke dalam kantong properti SpeechSynthesisResult
. Lihat kode berikut untuk mendapatkannya.
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
Latensi | Deskripsi | Kunci properti SPXSpeechSynthesisResult |
---|---|---|
first byte latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan gugus audio pertama. | SPXSpeechServiceResponseSynthesisFirstByteLatencyMs |
finish latency |
Menunjukkan penundaan waktu antara permulaan sintesis dan penerimaan seluruh audio yang disintesiskan. | SPXSpeechServiceResponseSynthesisFinishLatencyMs |
Speech SDK mengukur latensi dan memasukkannya ke dalam kantong properti SPXSpeechSynthesisResult
. Lihat kode berikut untuk mendapatkannya.
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;
Latensi byte pertama lebih rendah dari latensi akhir dalam banyak kasus. Latensi byte pertama tidak bergantung pada panjang teks, sedangkan latensi akhir bertambah seiring panjang teks.
Idealnya, kami ingin meminimalkan latensi yang dialami pengguna (latensi sebelum pengguna mendengar suara) ke satu waktu perjalanan rute jaringan plus latensi gugus audio pertama layanan sintesis ucapan.
Streaming
Streaming sangat penting untuk menurunkan latensi. Kode klien dapat memulai pemutaran saat gugus audio pertama diterima. Dalam skenario layanan, Anda dapat meneruskan gugus audio langsung ke klien, tanpa menunggu seluruh audio.
Anda dapat menggunakan PullAudioOutputStream
, PushAudioOutputStream
, Synthesizing
peristiwa, dan AudioDataStream
Speech SDK untuk mengaktifkan streaming.
Ambil contoh AudioDataStream
:
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.");
}
}
}
}
Anda dapat menggunakan PullAudioOutputStream
, PushAudioOutputStream
, Synthesizing
peristiwa, dan AudioDataStream
Speech SDK untuk mengaktifkan streaming.
Ambil contoh AudioDataStream
:
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;
}
Anda dapat menggunakan PullAudioOutputStream
, PushAudioOutputStream
, Synthesizing
peristiwa, dan AudioDataStream
Speech SDK untuk mengaktifkan streaming.
Ambil contoh AudioDataStream
:
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);
}
Anda dapat menggunakan PullAudioOutputStream
, PushAudioOutputStream
, Synthesizing
peristiwa, dan AudioDataStream
Speech SDK untuk mengaktifkan streaming.
Ambil contoh AudioDataStream
:
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)
Anda dapat menggunakan SPXPullAudioOutputStream
, SPXPushAudioOutputStream
, Synthesizing
peristiwa, dan SPXAudioDataStream
Speech SDK untuk mengaktifkan streaming.
Ambil contoh AudioDataStream
:
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
}
Pra-penyambungan dan penggunaan kembali SpeechSynthesizer
Speech SDK menggunakan websocket untuk berkomunikasi dengan layanan.
Idealnya, latensi jaringan harus berupa satu rute waktu perjalanan (RTT).
Jika koneksi baru dibuat, latensi jaringan mencakup waktu tambahan untuk membuat koneksi.
Pembentukan koneksi websocket membutuhkan jabat tangan TCP, jabat tangan SSL, koneksi HTTP, dan peningkatan protokol, yang menimbulkan penundaan waktu.
Untuk menghindari latensi koneksi, sebaiknya pra-hubungkan dan gunakan kembali SpeechSynthesizer
.
Pra-sambung
Untuk melakukan pra-koneksi, buat koneksi ke layanan Ucapan saat Anda tahu koneksi diperlukan segera. Misalnya, jika Anda membangun bot ucapan di klien, Anda dapat melakukan pra-koneksi ke layanan sintesis ucapan saat pengguna mulai berbicara, dan memanggil SpeakTextAsync
saat teks balasan bot siap.
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];
Catatan
Jika teks sintesis tersedia, cukup panggil SpeakTextAsync
untuk mensintesiskan audio. SDK akan menangani koneksi.
Menggunakan Kembali SpeechSynthesizer
Cara lain untuk mengurangi latensi koneksi adalah dengan menggunakan kembali SpeechSynthesizer
sehingga Anda tidak perlu membuat SpeechSynthesizer
baru untuk setiap sintesis.
Sebaiknya gunakan kumpulan objek dalam skenario layanan, lihat contoh kode kami untuk C# dan Java.
Mengirimkan audio terkompresi melalui jaringan
Ketika jaringan tidak stabil atau dengan bandwidth terbatas, ukuran payload juga memengaruhi latensi. Sementara itu, format audio terkompresi membantu menghemat bandwidth jaringan pengguna, yang sangat berharga bagi pengguna seluler.
Kami mendukung kebanyakan format terkompresi termasuk opus
, webm
, mp3
, silk
, dan sebagainya, lihat daftar lengkap SpeechSynthesisOutputFormat.
Misalnya, laju bit format Riff24Khz16BitMonoPcm
adalah 384 kbps, sedangkan Audio24Khz48KBitRateMonoMp3
hanya memerlukan 48 kbps.
SDK Azure Cognitive Service untuk Ucapan akan otomatis menggunakan format terkompresi untuk transmisi jika format output pcm
diatur.
Untuk Linux dan Windows, GStreamer
diperlukan untuk mengaktifkan fitur ini.
Lihat petunjuk ini untuk memasang dan mengonfigurasi GStreamer
untuk Speech SDK.
Untuk Android, iOS, dan macOS, tidak ada konfigurasi tambahan yang diperlukan mulai versi 1.20.
Tips lainnya
Menyimpan cache file CRL
Speech SDK menggunakan file CRL untuk memeriksa sertifikasi. Penembolokan file CRL sampai kedaluwarsa membantu Anda menghindari pengunduhan file CRL setiap saat. Lihat Cara mengonfigurasi OpenSSL untuk Linux untuk mengetahui detailnya.
Menggunakan Speech SDK terbaru
Kami terus menyempurnakan performa Speech SDK, jadi coba gunakan Speech SDK terbaru di aplikasi Anda.
Panduan pengujian pemuatan
Anda dapat menggunakan uji beban untuk menguji kapasitas dan latensi layanan sintesis ucapan. Berikut adalah beberapa panduan:
- Layanan sintesis ucapan memiliki kemampuan untuk menskalakan otomatis, tetapi membutuhkan waktu untuk meluaskan skala. Jika konkurensi ditingkatkan dalam waktu singkat, klien mungkin mendapatkan latensi panjang atau
429
kode kesalahan (terlalu banyak permintaan). Jadi, sebaiknya Anda meningkatkan konkurensi Anda langkah demi langkah dalam pengujian pemuatan. Lihat artikel ini untuk detail selengkapnya, terutama contoh pola beban kerja ini. - Anda dapat menggunakan sampel kami menggunakan kumpulan objek (C# dan Java) untuk pengujian beban dan mendapatkan angka latensi. Anda dapat memodifikasi giliran tes dan konkurensi dalam sampel untuk memenuhi persetujuan target Anda.
- Layanan ini memiliki batasan kuota berdasarkan lalu lintas nyata, oleh karena itu, jika Anda ingin melakukan pengujian beban dengan konkurensi yang lebih tinggi dari lalu lintas nyata Anda, sambungkan sebelum pengujian Anda.
Langkah berikutnya
- Lihat contohnya di GitHub