Reputation: 61
Currently, I'm trying to convert a response of Kinesis Vides Stream GetMedia API to an audio file but have had no success in this. According to AWS documentation, - result of GetMedia request? it's recommended to use Kinesis Video Stream Parser Library. But I'd like to use js/ts implementation. Is it possible to convert this stream to an audio file using just js/ts?
Thank you for your help.
Upvotes: 2
Views: 1179
Reputation: 41
I finally figured out how to convert a Kinesis Video Stream into an audio file. This is how I did it with Node.js and the AWS SDK for JavaScript:
>> mkdir aws-sdk-js && cd aws-sdk-js
>> npm init
After choosing the default npm options, open the newly generated package.json
file and add the following:
"dependencies": {
"aws-sdk": "^2.1587.0”,
“ebml”: “^3.0.0”
}
Now install the SDK modules:
>> npm install
>> touch index.js
Then in the index.js
file, copy and paste the following:
const AWS = require("aws-sdk");
const ebml = require("ebml");
const fs = require("fs");
const region = "<your AWS region>";
const streamInfo = {
streamName: "<your Kinesis Video stream name>",
startFragmentNumber: "<your Kinesis Video fragment number>",
//streamArn: "<your Kinesis Video stream ARN>"
};
// Suppress AWS SDK version warning message
process.env["AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE"] = 1;
async function main() {
//const streamName = streamInfo.streamArn.split("stream/")[1].split("/")[0];
const streamName = streamInfo.streamName;
const fragmentNumber = streamInfo.startFragmentNumber;
const raw = await getMedia(streamName, fragmentNumber);
const wav = Converter.createWav(raw, 8000);
fs.writeFile("audio.wav", Buffer.from(wav.buffer), (err) => {
if (err) throw err;
console.log("Audio file saved.");
});
return {};
};
async function getMedia(streamName, fragmentNumber) {
// Obtain the Kinesis Video endpoint URL
const kinesisvideo = new AWS.KinesisVideo({region: region});
var params = {
APIName: "GET_MEDIA",
StreamName: streamName
};
const end = await kinesisvideo.getDataEndpoint(params).promise();
// Get the raw audio data
const kinesisvideomedia = new AWS.KinesisVideoMedia({endpoint: end.DataEndpoint, region:region});
var params = {
StartSelector: {
StartSelectorType: "FRAGMENT_NUMBER",
AfterFragmentNumber: fragmentNumber,
},
StreamName: streamName
};
const data = await kinesisvideomedia.getMedia(params).promise();
const decoder = new ebml.Decoder();
let chunks = [];
decoder.on("data", chunk => {
if(chunk[1].name == "SimpleBlock"){
chunks.push(chunk[1].data);
}
});
decoder.write(data["Payload"]);
// Join the audio chunks
const margin = 4;
var sumLength = 0;
chunks.forEach( chunk => {
sumLength += chunk.byteLength - margin;
})
var sample = new Uint8Array(sumLength);
var pos = 0;
chunks.forEach(chunk => {
let tmp = new Uint8Array(chunk.byteLength - margin);
for(var e = 0; e < chunk.byteLength - margin; e++){
tmp[e] = chunk[e + margin];
}
sample.set(tmp, pos);
pos += chunk.byteLength - margin;
})
return sample.buffer;
}
class Converter {
// Convert the raw audio into wav format
static createWav(samples, sampleRate) {
const len = samples.byteLength;
const view = new DataView(new ArrayBuffer(44 + len));
this._writeString(view, 0, "RIFF");
view.setUint32(4, 32 + len, true);
this._writeString(view, 8, "WAVE");
this._writeString(view, 12, "fmt ");
view.setUint32(16, 16, true);
view.setUint16(20, 1, true);
view.setUint16(22, 1, true);
view.setUint32(24, sampleRate, true);
view.setUint32(28, sampleRate * 2, true);
view.setUint16(32, 2, true);
view.setUint16(34, 16, true);
this._writeString(view, 36, "data");
view.setUint32(40, len, true);
let offset = 44;
const srcView = new DataView(samples);
for (var i = 0; i < len; i+=4, offset+=4) {
view.setInt32(offset, srcView.getUint32(i));
}
return view;
}
static _writeString(view, offset, string) {
for (var i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
}
}
main();
Run the script:
>> node index.js
and this should output the audio.wav
file!
Upvotes: 1