Отправка большого двоичного объекта как Uint8Array в NodeJS и сохранение его в файл

Я пытаюсь отправить большой двоичный объект из нового API MediaRecorder в Firefox в NodeJS, чтобы сохранить его в файле. Blob содержит запись в виде преобразованного webm-файла. Я делю этот blob-объект определенного размера перед отправкой, чтобы иметь возможность отправить его через полосу пропускания, предоставляемую каналом данных webrtc. Это выглядит так:

var blobToBuffer = function(blob, cb) {
  var reader = new FileReader();
  reader.onload = function() {
    cb(reader.result);
  };
  reader.readAsArrayBuffer(blob);
};

blobToBuffer(blob, function(buffer){
  var sendInterval = setInterval(function(){
    var currentEnd = dataSend + dis._dataChunkSize;
    if(currentEnd > buffer.byteLength){
      currentEnd = buffer.byteLength;
    } 
    var part = Array.apply([], new Uint8Array(buffer.slice(dataSend, currentEnd)));
    dis.dataChannel.send(
      JSON.stringify({
        payload: part
      })
    );
    dataSend = currentEnd;
    if(dataSend + 1 >= buffer.byteLength){
      dis.dataChannel.send(JSON.stringify({action: 'dataEnd'}));
      clearInterval(sendInterval);
    }
  }, 1000);
});

На стороне nodeJS я пытаюсь преобразовать данные обратно в файл webm следующим образом:

fs.appendFile('my/path/file.webm', new Buffer(new Uint8Array(message.payload)), function(error){
    if(error){
        console.log(error);
    } else {
        console.log('Chunk successfully written');
    }
});

Он сообщает мне, что блок был записан, но файл пуст. Я попробовал то же самое со строкой в ​​кодировке base64, полученной из большого двоичного объекта, и это сработало, но показалось мне плохой идеей из-за возможного повреждения данных.

Что мне не хватает? Или есть лучший способ перенести большой двоичный объект с JavaScript на NodeJS?

ИЗМЕНИТЬ

Конструктор uint8array, похоже, не принимает данные, поступающие в виде строки:

'0': 39, '1': 209, '2': 79, '3': 0, '4': 230, '5': 133,
'6': 190, '7': 138, '8': 188, '9': 103, '10': 131,

После новой части Uint8Array (message.payload) длина массива все еще равна 0. Итак, как это сделать?

ИЗМЕНИТЬ II

После добавления .toString () при использовании JSON.stringify () мне удалось получить UInt8Array по своему желанию. Однако, поскольку код показан выше, он записывает в файл только [объект uint8array].

РЕДАКТИРОВАТЬ III - Решение

Использование приведенного выше кода отлично работает.


person stiller_leser    schedule 24.10.2015    source источник


Ответы (1)


[object uint8array] - это то, что вы должны получить, если используете toString на uint8array. Просто преобразуйте буфер в строку и отправьте строку. Если вы хотите, вы можете попробовать кодировку base64, но я не думаю, что она вам понадобится.

var str = ""; // string version of the part
for{var i = 0; i < part.length; i++){
    str += String.fromCharCode( part[i] );
}
dis.dataChannel.send(
  JSON.stringify({
    payload: str
  })
);

Если Nodejs не нравится строка как есть, используйте btoa, чтобы преобразовать ее в кодировку base64. Не волнуйтесь, вы не получите повреждение, это причина, по которой base64 не позволяет некоторым транспортным протоколам неправильно интерпретировать необработанную двоичную строку.

dis.dataChannel.send(
  JSON.stringify({
    payload: btoa(str)   // encode string as base64;
  })
);

Также убедитесь, что типы пантомимы верны.

person Blindman67    schedule 24.10.2015
comment
Большое Вам спасибо. Я действительно заставил его работать (см. Выше). Использование toString () было довольно наивной проблемой. Интересно, какая из них работает лучше. - person stiller_leser; 24.10.2015
comment
Для всех желающих: я создал тест на JSPerf. jsperf.com/filereader-reading-blob-and-stringify/2 - следите за инструкциями в консоли вашего браузера. Суть: используйте ArrayBuffer и обработайте его на NodeJS - person stiller_leser; 28.10.2015