Воспроизведение аудио
Есть переменная JS. В ней данные в формате wave. Как их лучше воспроизвести в фоне. Визуализация не нужна. Нужно будет отловить событие - проигрывание завершено.
|
Цитата:
|
Хороший вопрос. Если честно, пока не знаю. Наверное string. Планируется получать ответ с сервера, из php. Запрос планируется отправлять через Ajax.
Как тогда нужно их, данные, отдавать из php ? |
В свою переменную затолкайте ссылку либо на сам файл, либо на роут, который должен вернуть этот самый аудио-файл с соответствующими заголовками.
Дальше все просто (со своими нюансами): https://developer.mozilla.org/ru/doc...oElement/Audio
const audio = new Audio(audioFileUrl);
audio.addEventListener('canplaythrough', () => {
audio.play();
});
|
На стороне сервера не хочется сохранять файл, это занимает время, некий ресурс, так же надо отслеживать время жизни этого файла, определять время через которое этот файл надо подчистить - удалить файл.
Если делать заголовки на php, как ловить на JS ? |
Цитата:
|
Программно создаю сам на php. Вот описание протокола. Он не сложный.
http://microsin.net/programming/pc/wav-format.html Да, мы простых путей не ищем. :) |
Цитата:
Я ж сразу об этом написал: Цитата:
|
А можно по подробней про ссылку на [...] и роут с заголовками ?
Ссылку я кстати читал, до всех вопросов. Но там src/url который я так понимаю хочет файл, а у меня его нету. :) Если речь о роуте типа Человека Понятные Урлы, так смысл в нем ? Хотя ... Отправляю ссылку уникальную, ее получается надо где-то сохранить, что бы потом ловить к ней обращение ? Через файл ? Через базу ? Что то реализация не выстраивается .. |
Цитата:
Google: о передаче файла клиенту Хабр: тоже самое В третьем сообщении этой темы вы написали, что файл собираетесь с сервера тянуть с помощью асинхронного запроса, значит файл у вас генерится по требованию клиента, значит публичный адрес у этого скрипта есть. Прочитайте хотя бы статью на хабре, там даже пример кода есть. Вам только нужно подставить свой content-type и отдавать не файл из файловой системы, а тот, который вы сгенерили. |
Лучше всего создать численный типизированный массив, скажем myArray и поместить в него стандартный заголовок аудиофайла формата wav, в конце за ним поместить данные из переменной JS, преобразовав их перед этим в числа. После этого подключить этот массив в качестве src к элементу аудио так:
audio.src = URL.createObjectURL(new Blob([myArray], {type: audio/wav}));
|
Цитата:
// мой вариант
new Audio('/api/get-wav').addEventListener('canplaythrough', function () { this.play(); });
// ваш вариант
fetch('/api/get-wav').then(res => res.blob()).then(blob => {
const audio = new Audio( URL.createObjectURL(blob) );
audio.addEventListener('canplaythrough', () => audio.play());
});
|
Лучше тем, что без этого заголовка получатся сырые данные, т. е., будет неизвестно, как их следует читать - с какой частотой семплированья, с каким количеством стереоканалов, сколько байт приходится на семпл и т. п. Хот может я забыл предусмотреть, что в переменной js уже есть этот заголовок, но трудно это представить, если там может всё быть в формате string. А если требуется вывести сообщение об окончании воспроизведения, а то для этого подходит событие onended, т. к., canplaythgrough используют для вывода сообщения, что аудио/видео будет воспроизводиться до конца без остановки.
|
Цитата:
Цитата:
Т.е. чтобы имплементировать воспроизведения аудио нужно будет, в любом случае, получить этот аудиофайл от сервера. Таки вопрос: нахрена нам что-то вручную делать, если можно просто скормить классу Audio ссылку на аудиофайл? |
Nexus,
так было бы просто сделать, если бы этот аудиофайл был статическим. Но изложенная ситуация допускает, что это должен быть не постоянный, а сгенерированный аудиофайл, и возможно с каждым новым ajax-запросом его содержимое должно быть каким-то другим. Т. е., должен каждый раз быть новый звук. Я сам с этим имел дело. Поэтому изложил способ, которым я пользовался чтобы подключить эти сгенерированные данные к элементу аудио, чтобы не приходилось создавать временный файл на жёстком диске. |
Ну если его надо один раз получить, проиграть и забыть, то без разницы каким способом.
Другое дело, если его надо получать и проигрывать. Может быть даже используя полноценный элемент <audio>, с возможностью двигать таймкоды. Тогда, конечно в БЛОБ сохранять. |
Пробую отдавать файл на стороне сервера:
header('Content-type: application/octet-stream');
header('Content-Length: '.filesize('wave.wav'));
header('Content-Disposition: attachment; filename="wave.wav"');
readfile('wave.wav');
Смотрю что пересывается. Содержимое похоже на формат wave файла. Подправляю для случая с переменой:
header('Content-type: application/octet-stream');
header('Content-Length: '.mb_strlen($rawWave, '8bit'));
Смотрю что пересылается. Что прям непонятно что. Что не так я делаю? Как правильно отправлять данные ? |
Видимо без исследования в шестнадцатеричном редакторе содержимого того, что получается не обойтись. Почему Вы просто не подключаете этот файл к аудио:
<audio src="wave.wav"></audio> |
Такого кода должно быть достаточно, другое дело, что Chrome не воспроизводит wav-файлы.
header('Content-Type: audio/wav');
header('Content-Length: ' . mb_strlen($rawWave, '8bit'));
header('Content-Disposition: attachment; filename="wave.wav"');
echo $rawWave;
|
echo $rawWave; Да помогло, что то не сообразил. Данные получаю ответом на запрос:
...
success: function(data) {
}
...
Это по сути прочитанный файл в переменную. Как запустить эти данные на воспроизведения, я что то так и не понял до конца, если вообще такое возможно.
audio = new Audio('/api/get-wav').addEventListener('canplaythrough', function () { this.play(); });
audio.src = URL.createObjectURL(new Blob([data], {type: audio/wav}));
}
Но нужна тогда ссылка /api/get-wav а ее генерить бы не хотелось бы. |
Удалось запустить воспроизведение двумя способами:
var audio = new Audio();
audio.src = URL.createObjectURL(new Blob([data], {type: "audio/x-wav"}));
audio.play();
var wavString = data;
var audio = new Audio();
var len = wavString.length;
var buf = new ArrayBuffer(len);
var view = new Uint8Array(buf);
for (var i = 0; i < len; i++) {
view[i] = wavString.charCodeAt(i) & 0xff;
}
var blob = new Blob([view], {type: "audio/x-wav"});
audio.src = URL.createObjectURL(blob);
audio.play();
Оба варианта портят звук. Второй вариант портит меньше. В чем может быть причина ?? |
Что бы не портились данные пришлось закодироваться. :)
Но возникла другая проблема, где то обрезаются по длине.
toFile("len.txt", strlen($rawWave));
echo base64_encode($rawWave);
success: function(data) {
var decodeWave = atob(data);
var len = decodeWave.length;
console.log(len);
Получаю: 95384 71538 Куда могли деться 23846 ?? |
him, покажите код, который отправляет запрос на сервер и получает содержимое вашего wav-файла.
|
Цитата:
https://wtools.io/php-sandbox/b22Y
<?php
$string = '������';
var_dump([
strlen($string), // 4
mb_strlen($string, 'UTF-8') // 1
]);
alert('������'.length);// 2
|
header('Content-type: audio/x-wav');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.mb_strlen($rawWave, '8bit'));
toFile("len.txt", strlen($rawWave)); // 95384
toFile("len2.txt", mb_strlen($rawWave, '8bit')); // 95384
echo base64_encode($rawWave);
$.ajax({
type: "POST",
..
success: function(data) {
var decodeWave = atob(data);
var len = decodeWave.length; // 71538
console.log(len);
Как то так .. |
Вобщем, на обычном компьютере все работает. Но радость моя была не долгой.
На iPad-е аудио не проигрывается. Лазил в интернете. Своя система безопасности (статья от 2012 года). Нужно пользователю что то нажать. Ну у меня вроде нажимает. Да, у меня нету тега <audio> в html документе. Но он вроде не обязательный. В чем может быть проблема еще ?
<form>
<input type="button" id="But" value="Проиграть">
</form>
...
$(document).on('click', '#But', function(e) {
...
$.ajax({
..
success: function(data) {
var audio = new Audio();
...
var blob = new Blob([view], {type: "audio/wav"});
audio.src = URL.createObjectURL(blob);
audio.addEventListener('ended', function () { console.log(" ended !! ");});
audio.play();
...
|
Цитата:
Попробуйте предзагружать аудио и воспроизводить его сразу после нажатия пользователем на кнопку. |
Цитата:
|
Цитата:
Пользователь выбирает что ему надо, и жмет кнопку. На основании этих данных формируется ответ. Или я не правильно что то понял ? Цитата:
|
Цитата:
Если запустить непосредственно в обработчике 'click' - это одно. Но вы запускаете уже в обработчике другого события - какого то события XMLHttpRequest. Надо бы проверить, может быть на fetch они среагируют более благосклонно. |
Цитата:
PS. Да и это может относится к mp3, к примеру, но wav таких не содержит. |
Цитата:
Цитата:
Хорошо. Коментирую строку audio.play(); Добавляю в форму дополнительную кнопку "Проиграть" Но как это сделать в коде ? Просто добавить:
$(document).on('click', '#play', function(e) {
audio.play();
});
не получится. Пропадут var audio = new Audio(); audio.src = URL.createObjectURL(blob); |
| Часовой пояс GMT +3, время: 01:20. |