Отправляет email-рассылки с помощью сервиса Sendsay

[prg] проиграть wav файл средствами запроса через ajax

здравствуйте.

возникла надобность реализовать некий проект, в котором нужно с сервера
забрать wav стрим и проиграть в html5 audio.

просто audio.src и url не подходит, потомучто там на сервере защита, которую
нужно отправить в заголовках.

как можно отправив xhr запрос получить аудио и проиграть его?

повторюсь, это именно стрим а не ссылка.

спасибо зарание за помощь.

Ответить   Mon, 15 Oct 2018 10:17:09 +0400 (#3587120)

 

Ответы:

Vande omentaina, gozaltech!

Интересная задачка. Посмотри в эту сторону, думаю, должно навести на
мысли по крайней мере:
https://stackoverflow.com/questions/30330856/how-do-i-play-audio-returned-from-an-xmlhttprequest-using-the-html5-audio-api

Ответить   Mon, 15 Oct 2018 23:13:22 +0300 (#3587218)

 

привет.

спасибо за ссылку. да, это я уже видел и реализовал, но дело в том, что
сервер возвращает стрим, а аджакс пока не загрузит полностью данные его не
возвращает.
вот мне и интересно, возможно ли играть стрим спомощью xmlhttprequest?

спасибо.

Ответить   Tue, 16 Oct 2018 02:05:04 +0400 (#3587232)

 

Приветствую всех.
Как вариант -- WebAudio, ScriptProcessorNode:
https://developer.mozilla.org/ru/docs/Web/API/ScriptProcessorNode

Ещё есть не ajax вариант -- это апплет Java.

Успехов. Анатолий.

Ответить   "i_chay" Tue, 16 Oct 2018 07:37:37 +0300 (#3587246)

 

я прочитал пример, но как возпроизвести полученный поток всеравно не понял.

есть ли какой нибудь реальный пример проигрывания файла а не шипения?

программистов"

https://subscribe.ru/catalog/industry.comp.tiflocomp.programming/rules

industry.comp.tiflocomp.programming-rules@subscribe.ru

industry.comp.tiflocomp.moders-list@subscribe.ru

https://subscribe.ru/archive/industry.comp.tiflocomp.programming/msg/3587246

Ответить   Tue, 16 Oct 2018 09:15:46 +0400 (#3587271)

 

здравствуйте еще раз.

вопрос поповоду примера снят.

я попробовал, но ксожалению, это тоже не тот эффект, когда мы без ajax даем
объекту audio source ввиде ссылки с стримом и он начинает играть, как только
поступит какая-та часть в буффер.

тутже пока аджакс полностью не загрузит файл, он играть не начинает.
хотя может быть я что-то делаю не так.

вот мой код в качестве примера что я делаю.

var audio = document.createElement('audio');
var form = document.getElementById("form_sound");
form.addEventListener("submit", e => {
e.preventDefault();
var fd = new FormData(form);
var xhr = new XMLHttpRequest();
var audioCtx = new AudioContext();
source = audioCtx.createBufferSource();

var scriptNode = audioCtx.createScriptProcessor(1024, 1, 1);
xhr.addEventListener("load", e => {
var audioData = xhr.response;
audioCtx.decodeAudioData(audioData, function(buffer) {
myBuffer = buffer;
source.buffer = myBuffer;
},
function(e){"Error with decoding audio data" + e.err});
});
xhr.addEventListener("error", e => {
console.log(e);
});
xhr.open("POST", '/');
xhr.responseType = 'arraybuffer';
xhr.send(fd);

scriptNode.onaudioprocess = function(audioProcessingEvent) {
var inputBuffer = audioProcessingEvent.inputBuffer;
var outputBuffer = audioProcessingEvent.outputBuffer;
for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
var inputData = inputBuffer.getChannelData(channel);
var outputData = outputBuffer.getChannelData(channel);
for (var sample = 0; sample < inputBuffer.length; sample++) {
outputData[sample] = inputData[sample];
}
}
}
source.connect(scriptNode);
scriptNode.connect(audioCtx.destination);
source.start();

source.onended = function() {
source.disconnect(scriptNode);
scriptNode.disconnect(audioCtx.destination);
}
});

Ответить   Tue, 16 Oct 2018 09:41:42 +0400 (#3587277)

 

Приветствую всех.
Похоже, что вам желательно освежить знания оп ajax:
https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
В частности, см. событие progress.
Плюс -- понять базовые концепции WebAudio, в частности, концепцию
узлов,благодаря которой вы можете объединять в цепочки различные источники и
обработчики аудиоданных.
Есть stream-узел, но пример со script-узлом, по-моему, более наглядный по
части использования ajax.
Ваш код за вас никто не напишет (imho).

Успехов. Анатолий.

Исходное сообщение > хотя может быть я что-то делаю не так.

Ответить   "i_chay" Tue, 16 Oct 2018 15:42:09 +0300 (#3587331)

 

здравствуйте.

вот уже склько дней пытаюсь справится с задачей, не получается.
я немогу получать данные в событии прогресса

Ответить   Thu, 18 Oct 2018 13:29:08 +0400 (#3587664)

 

Приветствую всех.

На данный момент в официальной документации по XmlHttpRequest явно указано,
что для типов ответа arraybuffer и blob свойство response будет содержать
данные только в обработчике onload.
В других обработчиках, в т.ч. onprogress это свойство будет null.
Однако, в документации Mozilla, ссылку на которую я привел в предыдущем
сообщении сказано следующее:
Примечание: Начиная с Gecko 9.0, можно быть уверенным, что события progress
будут приходить для каждого пакета данных, включая последний пакет в
случаях,
когда он получен, и соединение закрыто прежде, чем будет создано событие
progress. В этом случае, событие progress автоматически создастся, когда
будет
получено событие load для этого пакета. Это позволяет следить за процессом
загрузки с помощью только событий progress.

Примечание: В Gecko 12.0, если событие progress вызвано с responseType
"moz-blob", значение ответа будет
Blob,
содержащим все данные, полученные на текущий момент.
То есть для Mozilla можно получать данные в onprogress так:
request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'moz-blob';
request.onprogress = function(e) {
var data = request.response;
alert("size: " + data.size +", type: " + data.type);
}

Исходное сообщение > вот уже склько дней пытаюсь справится с задачей, не получается.

Ответить   "i_chay" Thu, 18 Oct 2018 21:32:25 +0300 (#3587735)

 

здравствуйте.

да, про moz-blob я читал, но тут есть две проблемы.

1. это работает только в firefox
2. для script processor node нужен arraybuffer
я читал что можно с помощью filereader преобразовать blob в arraybuffer
я сделал blob из xhr.response, и пытался преобразовать, но в итоге получил
пустой массив
пробовал и в load и в loadend событиях filereader

Ответить   Thu, 18 Oct 2018 22:59:46 +0400 (#3587760)

 

Приветствую всех.
А blob приходит не пустой?
У меня FileReader преобразует blob в ArrayBuffer:
var fileReader = new FileReader();
fileReader.onload = function(event) {
var data = event.target.result;
audioCtx.decodeAudioData(data, function(buffer) {
source.buffer = buffer;
});
source.start();
}

var audioCtx = new AudioContext();
var source = audioCtx.createBufferSource();
source.connect(audioCtx.destination);
...
// load in an audio track via XHR and decodeAudioData
request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'moz-blob';

request.onprogress = function(e) {
var d = request.response;
fileReader.readAsArrayBuffer(d);
}
}
...

Но существует особенность в методе AudioContext.audioCtx.decodeAudioData(),
который не работает с "голыми" фрагментами потокового аудио, а требует на
входе полноценного аудиофайла со всеми мета-данными для соответствующего
mime.

Как вариант: не использовать этот метод, а передавать данные в формате pcm,
8 bit, mono (в котором отсчет всегда равен одному байту и не требует
обработки ситуации с разрывами отсчетов) и формировать канальные данные для
AudioBuffer вручную.

Исходное сообщение > 2. для script processor node нужен arraybuffer

Ответить   "i_chay" Fri, 19 Oct 2018 00:36:15 +0300 (#3587765)

 

здравствуйте.

просто response FileReader не принимает, пишет аргумент 1 не является
объектом.

нет, блоб не пустой, alert выводит заголовки wav и данные

Ответить   Fri, 19 Oct 2018 03:58:48 +0400 (#3587775)

 

здравствуйте.

у меня так и не получилось в событии прогреса получить куски запросов ajax и
обработать для потокового воспроизведения.

оказалось, что на смену или как альтернатива xmlhttprequest пришел fetch
api, который может получать поток как readableStream.
в chrome он работает, а в firefox начиная с версии 57, нужно включить
соответствующую опцию в конфигах
javascript.options.streams;true

после чего, полученный поток можно прочитать, и передать webAudio для
последующего проигрывания.

это все работает, но есть небольшие щелчки при переключении буфферов.

ниже привожу рабочий код.
прозьба, если у кого нибудь есть замечания по поводу работы, или идеи для
улучшения, отписаться.

здесь можно прослушать пример работы
https://ttsapi.gozaltech.org

а тут код.

function wavify(data, numberOfChannels, sampleRate) {
var header = new ArrayBuffer(44);
var d = new DataView(header);
d.setUint8(0, "R".charCodeAt(0));
d.setUint8(1, "I".charCodeAt(0));
d.setUint8(2, "F".charCodeAt(0));
d.setUint8(3, "F".charCodeAt(0));
d.setUint32(4, data.byteLength / 2 + 44, true);
d.setUint8(8, "W".charCodeAt(0));
d.setUint8(9, "A".charCodeAt(0));
d.setUint8(10, "V".charCodeAt(0));
d.setUint8(11, "E".charCodeAt(0));
d.setUint8(12, "f".charCodeAt(0));
d.setUint8(13, "m".charCodeAt(0));
d.setUint8(14, "t".charCodeAt(0));
d.setUint8(15, " ".charCodeAt(0));
d.setUint32(16, 16, true);
d.setUint16(20, 1, true);
d.setUint16(22, numberOfChannels, true);
d.setUint32(24, sampleRate, true);
d.setUint32(28, sampleRate * 1 * 2);
d.setUint16(32, numberOfChannels * 2);
d.setUint16(34, 16, true);
d.setUint8(36, "d".charCodeAt(0));
d.setUint8(37, "a".charCodeAt(0));
d.setUint8(38, "t".charCodeAt(0));
d.setUint8(39, "a".charCodeAt(0));
d.setUint32(40, data.byteLength, true);
return concat(header, data);
};

function concat( buffer1, buffer2 ) {
var tmp = new Uint8Array( buffer1.byteLength + buffer2.byteLength );
tmp.set( new Uint8Array( buffer1 ), 0 );
tmp.set( new Uint8Array( buffer2 ), buffer1.byteLength );
return tmp.buffer;
}

function pad(buffer) {
var currentSample = new Float32Array(1);
buffer.copyFromChannel(currentSample, 0, 0);
let wasPositive = currentSample[0] > 0;
for (let i = 0; i < buffer.length; i += 1) {
buffer.copyFromChannel(currentSample, 0, i);
if ((wasPositive && currentSample[0] < 0) || (!wasPositive &&
currentSample[0] > 0)) {
break;
}
currentSample[0] = 0;
buffer.copyToChannel(currentSample, 0, i);
}
buffer.copyFromChannel(currentSample, 0, buffer.length - 1);
wasPositive = currentSample[0] > 0;
for (let i = buffer.length - 1; i > 0; i -= 1) {
buffer.copyFromChannel(currentSample, 0, i);
if ((wasPositive && currentSample[0] < 0) || (!wasPositive &&
currentSample[0] > 0)) {
break;
}
currentSample[0] = 0;
buffer.copyToChannel(currentSample, 0, i);
}
return buffer;
};

function tts(data) {
context = new (window.AudioContext || window.webkitAudioContext)();
var audioStack = [];
var nextTime = 0;
fetch('/', {
method: 'POST',
body: data
})
.then(function(response) {
var reader = response.body.getReader();
var rest = null;
var isFirstBuffer = true;
var numberOfChannels, sampleRate;

function read() {
return reader.read().then(({ value, done })=> {
var audioBuffer = null;
if (rest !== null) {
audioBuffer = concat(rest,value.buffer);
}else{
audioBuffer = value.buffer;
}
if (isFirstBuffer && audioBuffer.byteLength <= 44) {
rest = audioBuffer;
read();
return;
}
if (isFirstBuffer) {
isFirstBuffer = false;
var dataView = new DataView(audioBuffer);
numberOfChannels = dataView.getUint16(22, true);
sampleRate = dataView.getUint32(24, true);
audioBuffer = audioBuffer.slice(44);
}
if (audioBuffer.byteLength % 2 !== 0) {
rest = audioBuffer.slice(-2, -1);
audioBuffer = audioBuffer.slice(0, -1);
} else {
rest = null;
}

context.decodeAudioData(wavify(audioBuffer, numberOfChannels, sampleRate),
function(buffer) {

audioStack.push(buffer);
if (audioStack.length) {
scheduleBuffers();
}
}, function(err) {
console.log("err(decodeAudioData): "+err);
});
if (done) {
console.log('done');
return;
}
read();
});
}
read();
})

function scheduleBuffers() {
while ( audioStack.length) {
var buffer = audioStack.shift();
var source = context.createBufferSource();
source.buffer = pad(buffer);
source.connect(context.destination);
if (nextTime == 0)
nextTime = context.currentTime + 0.2;
source.start(nextTime);
nextTime += source.buffer.duration;};
}}

Ответить   Fri, 19 Oct 2018 14:08:27 +0400 (#3587837)

 

Здравствуйте, gozaltech <be***@l*****.ru>.

* Исходное сообщение * g> есть ли какой нибудь реальный пример проигрывания файла а не шипения?

<...>

Следите за цитированием. Не оставляйте в цитатах то, что не
относится к сути обсуждаемого.

Ответить   Tue, 16 Oct 2018 10:24:57 +0300 (#3587318)

 

Vande omentaina, i_chay!

А они разве не вымерли, как динозавры? Вроде объявили о прекращении
поддержки браузерами.

Ответить   Sat, 20 Oct 2018 00:50:59 +0300 (#3587956)

 

Приветствую всех.
Если речь о теге <applet>, то он устарел и не проходит валидацию, но указан
в спецификации.
Необходимо заменять его на <object>.

А что поддерживают браузеры и что не поддерживают, зависит от их версии,
движка, операционной системы и _вроде_ от погоды на Сатурне.
Исходное сообщение От: "Menelion Elensu'le:" <meneli***@o*****.org>
Кому: ""industry.comp.tiflocomp.programming" (5364038)" <i_ch***@r*****.ru>
Отправлено: 20 октября 2018 г. 0:50
Тема: [prg] Re[2]: проиграть wav файл средствами запроса через ajax

программистов"

https://subscribe.ru/catalog/industry.comp.tiflocomp.programming/rules

industry.comp.tiflocomp.programming-rules@subscribe.ru

industry.comp.tiflocomp.moders-list@subscribe.ru

https://subscribe.ru/archive/industry.comp.tiflocomp.programming/msg/3587956

https://subscribe.ru/feedback

Ответить   "i_chay" Sat, 20 Oct 2018 19:55:15 +0300 (#3588033)