Воспроизведение аудио
Есть переменная 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, время: 06:34. |