@jambonz/speech-utils 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/synth-audio.js +31 -3
  2. package/package.json +2 -2
@@ -33,6 +33,24 @@ const debug = require('debug')('jambonz:realtimedb-helpers');
33
33
  const EXPIRES = (process.env.JAMBONES_TTS_CACHE_DURATION_MINS || 4 * 60) * 60; // cache tts for 4 hours
34
34
  const TMP_FOLDER = '/tmp';
35
35
 
36
+
37
+ const trimTrailingSilence = (buffer) => {
38
+ assert.ok(buffer instanceof Buffer, 'trimTrailingSilence - argument is not a Buffer');
39
+
40
+ let offset = buffer.length;
41
+ while (offset > 0) {
42
+ // Get 16-bit value from the buffer (read in reverse)
43
+ const value = buffer.readUInt16BE(offset - 2);
44
+ if (value !== 0) {
45
+ break;
46
+ }
47
+ offset -= 2;
48
+ }
49
+
50
+ // Trim the silence from the end
51
+ return offset === buffer.length ? buffer : buffer.subarray(0, offset);
52
+ };
53
+
36
54
  /**
37
55
  * Synthesize speech to an mp3 file, and also cache the generated speech
38
56
  * in redis (base64 format) for 24 hours so as to avoid unnecessarily paying
@@ -104,7 +122,12 @@ async function synthAudio(client, logger, stats, { account_sid,
104
122
  text
105
123
  });
106
124
  let filePath;
107
- if (['nuance', 'nvidia'].includes(vendor)) {
125
+ if (['nuance', 'nvidia'].includes(vendor) ||
126
+ (
127
+ process.env.JAMBONES_TTS_TRIM_SILENCE &&
128
+ ['microsoft', 'azure'].includes(vendor)
129
+ )
130
+ ) {
108
131
  filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.r8`;
109
132
  }
110
133
  else filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.mp3`;
@@ -284,6 +307,7 @@ const synthMicrosoft = async(logger, {
284
307
  }) => {
285
308
  try {
286
309
  const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint} = credentials;
310
+ const trimSilence = filePath.endsWith('.r8');
287
311
  let content = text;
288
312
  const speechConfig = SpeechConfig.fromSubscription(apiKey, region);
289
313
  speechConfig.speechSynthesisLanguage = language;
@@ -297,7 +321,9 @@ const synthMicrosoft = async(logger, {
297
321
  */
298
322
  if (!content.startsWith('<speak')) content = `<speak>${text}</speak>`;
299
323
  }
300
- speechConfig.speechSynthesisOutputFormat = SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
324
+ speechConfig.speechSynthesisOutputFormat = trimSilence ?
325
+ SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm :
326
+ SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
301
327
  const synthesizer = new SpeechSynthesizer(speechConfig);
302
328
 
303
329
  if (content.startsWith('<speak>')) {
@@ -323,7 +349,9 @@ const synthMicrosoft = async(logger, {
323
349
  reject(cancellation.errorDetails);
324
350
  break;
325
351
  case ResultReason.SynthesizingAudioCompleted:
326
- resolve(Buffer.from(result.audioData));
352
+ let buffer = Buffer.from(result.audioData);
353
+ if (trimSilence) buffer = trimTrailingSilence(buffer);
354
+ resolve(buffer);
327
355
  synthesizer.close();
328
356
  stats.increment('tts.count', ['vendor:microsoft', 'accepted:yes']);
329
357
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/speech-utils",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "TTS-related speech utilities for jambonz",
5
5
  "main": "index.js",
6
6
  "author": "Dave Horton",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "homepage": "https://github.com/jambonz/speech-utils#readme",
26
26
  "dependencies": {
27
- "@aws-sdk/client-polly": "^3.303.0",
27
+ "@aws-sdk/client-polly": "^3.347.1",
28
28
  "@google-cloud/text-to-speech": "^4.2.1",
29
29
  "@grpc/grpc-js": "^1.8.13",
30
30
  "bent": "^7.3.12",