По следующему адресу:
https://www.tophtml.com/snl/15.mp3
есть один звук, который я хочу воспроизвести с использованием чистого Web Audio API
на following range
:
range from: second: 306.6
range to: second: 311.8
total: 5.2 seconds
Я скачал этот файл на рабочий стол (я использую Windows 10
), затем открыл его с помощью VLC
и получил следующую информацию о файле:
number of channels: 2
sample rate: 44100 Hz
bits per sample: 32 (float32)
Здесь у вас есть информация о понятиях по этому вопросу:
https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Basic_concepts_behind_Web_Audio_API#Audio_buffers_frames_samples_and_channels
, откуда я получил следующий отрывок:
Я хочу сыграть range
с комментариями выше (также вставив его здесь):
range from: second: 306.6
range to: second: 311.8
total: 5.2 seconds
, загрузив только тот фрагмент с сервера, который поддерживает заголовок запроса:Range
.
Тогда я попробовал следующий код:
...
let num_channels = 2;
let sample_rate = 44100;
let range_from = 0; // Goal: 306.6 seconds
let range_length = (sample_rate / num_channels) * 5.2; // Goal: 5.2 seconds
let range_to = range_from + (range_length - 1); // "range_to" is inclusive (confirmed)
request.setRequestHeader("Range", "bytes=" + range_from + "-" + range_to);
...
Мои вопросы:
Мне нужночтобы найти правильное значение для переменной: range_from
, чтобы она начала воспроизводиться с секунды: 306.6
.
Я хочу знать, является ли указанное выше значение для: range_length
правильнымили нет, так как, вероятно, есть байты, используемые для headers и т. д., я имею в виду: headers
+ data
.
Здесь у вас есть код, который у меня есть:
window.AudioContext = window.AudioContext || window.webkitAudioContext; // necessary for iPhone (maybe others). Could change a near future.
const URL = 'https://www.tophtml.com/snl/15.mp3';
const context = new AudioContext();
window.addEventListener('load', function() {
const button_option_1 = document.querySelector('.button_option_1');
const button_option_1_play = document.querySelector('.button_option_1_play');
button_option_1_play.disabled = true;
button_option_1.addEventListener('click', async function() {
let time_start, duration;
let buffer;
log('...', false);
button_option_1_play.disabled = true;
button_option_1_play.onclick = () => playBuffer(buffer);
//---
time_start = new Date().getTime();
let arrayBuffer = await fetch(URL);
// download complete
duration = sprintf('%.2fs', (new Date().getTime()-time_start)/1000);
log(sprintf('P2. Delay: +%s for download. Wait...', duration));
//---
time_start = new Date().getTime();
let audioBuffer = await decodeAudioData(context, arrayBuffer);
// decoding complete
duration = sprintf('%.2fs', (new Date().getTime()-time_start)/1000);
log(sprintf('P3. Delay: +%s for decoding.', duration));
//---
button_option_1_play.disabled = false;
buffer = audioBuffer;
button_option_1_play.click();
});
});
function playBuffer(buffer, from, duration) {
const source = context.createBufferSource(); // type of "source": "AudioBufferSourceNode"
source.buffer = buffer;
source.connect(context.destination);
source.start(context.currentTime, from, duration);
}
function log(text, append = true) {
let log = document.querySelector('.log');
if (!append)
log.innerHTML = '';
let entry = document.createElement('div');
entry.innerHTML = text;
log.appendChild(entry);
}
function decodeAudioData(context, arrayBuffer) {
return new Promise(async (resolve, reject) => {
if (false) {}
else if (context.decodeAudioData.length == 1) {
// console.log('decodeAudioData / Way 1');
let audioBuffer = await context.decodeAudioData(arrayBuffer);
resolve(audioBuffer);
}
else if (context.decodeAudioData.length == 2) {
// necessary for iPhone (Safari, Chrome) and Mac (Safari). Could change a near future.
// console.log('decodeAudioData / Way 2');
context.decodeAudioData(arrayBuffer, function onSuccess(audioBuffer) {
resolve(audioBuffer);
});
}
});
}
function fetch(url) {
return new Promise((resolve, reject) => {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
let num_channels = 2;
let sample_rate = 44100;
let range_from = 0; // Goal: 306.6 seconds
let range_length = (sample_rate / num_channels) * 5.2; // Goal: 5.2 seconds
let range_to = range_from + (range_length - 1); // "range_to" is inclusive (confirmed)
request.setRequestHeader("Range", "bytes=" + range_from + "-" + range_to);
request.onload = function() {
let arrayBuffer = request.response;
let byteArray = new Uint8Array(arrayBuffer);
// console.log(Array.from(byteArray)); // just logging info
resolve(arrayBuffer);
}
request.send();
});
}
.log {
display: inline-block;
font-family: "Courier New", Courier, monospace;
font-size: 13px;
margin-top: 10px;
padding: 4px;
background-color: #d4e4ff;
}
.divider {
border-top: 1px solid #ccc;
margin: 10px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/sprintf/1.1.1/sprintf.min.js"></script>
<button class="button_option_1">Option 1</button>
<button class="button_option_1_play">Play</button><br />
<div class="log">[empty]</div>
Здесь у вас есть соответствующие CodePen.io
:
https://codepen.io/anon/pen/RYXKmP
Не могли бы вы предоставитьправильное значение для: range_from
и используйте его для разветвленного кода на CodePen.io
?
Связанный вопрос: https://engineering.stackexchange.com/questions/23929
[EDIT 1]
Вот более простой CodePen.io
: https://codepen.io/anon/pen/YJKVde,, который сфокусирован на проверке способности браузера перемещаться при заданной случайной позиции к следующему действительному кадру.
Набыстрый эксперимент, который я сделал, используя комбинации { Windows 10, Android, iPhone } x { Native browser, Chrome, Firefox }
, код выше справа работает только на: { (Windows 10, Chrome), (Android, Chrome), (Android, Native browser) }
.
Жаль, что он не работает:
{ (iPhone, Safari), (iPhone, Chrome), (Windows 10, Firefox), (Android, Firefox) }
есть ли способ отправить запрос разработчикам браузера, чтобы обратить на это внимание?
Google Chrome
действительно хорошо работает на Windows 10
и Android
.
Было бы интересночто остальные браузеры делают то же самое.
Спасибо!