I'm trying to develop a Twilio function using the serverless SDK that can serve audio files directly to HTTP requests, following the guide here which I've got working fine using the service editor in the Twilio console. However I'm now trying to use the serverless SDK to develop the service locally and the exact same setup just doesn't work.
I've got the mp3 audio file as a private asset at assets/hello.mp3
, and the Node function functions/handler.js
which is public. My function is:
const fs = require('fs');
exports.handler = function(context, event, callback) {
var phrase = event.phrase;
var filePath = Runtime.getAssets()[`/${phrase}.mp3`].path;
var buffer = fs.readFileSync(filePath);
var stat = fs.statSync(filePath);
var response = new Twilio.Response();
response.setBody(buffer);
response.appendHeader('Content-Type', 'audio/mpeg');
response.appendHeader('Content-Length', stat.size);
return callback(null, response);
};
The only modification from the example in the docs is that I'm allowing the user to specify the file name with the GET parameter phrase
.
Whenever I try to request to http://localhost:3000/handler?phrase=hello
Chrome detects that it's receiving an audio file but doesn't load or play it. The repsonse is:
{type: "Buffer",…}
data: [255, 243, 68, 196, 0, 17, 82, 130, 20, 0, 24, 68, 185, 52, 68, 74, 44, 234, 110, 238, 250, 23, 204,…]
type: "Buffer"
This indicates to me that the buffer is being parsed as JSON data rather than the raw audio data. However I've tried all the variants of buffer.toString()
, different encodings and file streams that I can think of and nothing fixes it. There are no errors and the HTTP status code is 200. The HTTP response headers are:
HTTP/1.1 200 OK
X-Powered-By: Express
Surrogate-Control: no-store
Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate
Pragma: no-cache
Expires: 0
Content-Type: audio/mpeg; charset=utf-8
Content-Length: 27077
ETag: W/"69c5-hX8H/5UaULdPYVqq2abJK7EeJmg"
Date: Mon, 22 Aug 2022 21:03:35 GMT
Connection: keep-alive
Keep-Alive: timeout=5
I've tried following a lot of examples where people have had similar problems serving non-text data with Node but the Twilio Response object seems fairly restrictive and I can't get any of them to work. Thanks for any suggestions!
Also the reason I'm trying to set up the function like this is that I've got quite a large number of possible sentences that I might want to play in a call, so I want to store several short phrases as assets and concatenate them together in a function. I want the clips to be private assets so they're accessible to the function with minimal latency, and the concatenation needs to be really fast so I don't want to use lots of TwiML <Play>
verbs in a row which might introduce pauses between words.