2017-02-20 28 views
1

У меня есть элемент <audio>, и я меняю скорость, начальную/конечную границы и высоту тона. Я хочу посмотреть, можно ли записывать звук, который я слышу в браузере. Однако я не хочу просто записывать с микрофоном из-за более низкого качества.Могу ли я записать вывод <audio> без использования микрофона?

Я мог бы делать те же эффекты на стороне сервера, но я бы предпочел, чтобы я не мог в основном дублировать одну и ту же функциональность с двумя разными технологиями.

В ответ на голосование флага, поскольку это «непонятно, что я прошу», я буду перефразировать.

У меня есть элемент <audio>, играющий на странице. У меня есть javascript, управляющий скоростью воспроизведения, объемом и т. Д. Затем я хочу, чтобы мой браузер записывал аудио , так как я слышу его. Это не микрофон. Я хочу создать новый аудиофайл, который будет как можно ближе к одному из них. Если он равен 75%, то новый файл будет иметь объем 75%.

Если вы считаете, что это невозможно, скажите так, это нормально. И если вам нужно больше разъяснений, все в порядке. Я просто предпочитаю, чтобы люди не спускали вниз и не плакали, не давая объяснений.

+2

Возможно, вы используете API-интерфейс 'captureStream(): https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/captureStream –

+0

Да в поддерживаемых браузерах используйте средство MediaElement.captureStream(), а также [MediaRecorder API] (https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder). Но обратите внимание, что эти технологии все еще находятся в активной разработке и что в текущих реализациях по-прежнему полно ошибок. Например, для вашего случая текущий стабильный FF остановит рендеринг исходного медиа-аудио, если вы измените его громкость во время записи ... – Kaiido

+0

Если вам нужна поддержка старых браузеров, вы также можете просто передать свой MediaElement в API WebAudio, благодаря метод ['createMediaElementSource'] (https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaElementSource). Оттуда вы сможете получить необработанные данные PCM на вашем носителе и сохранить его (обратите внимание, что регуляторы громкости должны выполняться самим webAudioApi). – Kaiido

ответ

3

В поддерживающих браузерах вы можете использовать метод MediaElement.captureStream() вместе с MediaRecorder API.

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

// here we will save all the chunks of our record 
 
const chunks = []; 
 
// wait for the original media is ready 
 
audio.oncanplay = function() { 
 
    audio.volume = 0.5; // just for your example 
 
    // FF still does prefix this unstable method 
 
    var stream = audio.captureStream ? audio.captureStream() : audio.mozCaptureStream(); 
 
    // create a MediaRecorder from our stream 
 
    var rec = new MediaRecorder(stream); 
 
    // every time we've got a bit of data, store it 
 
    rec.ondataavailable = e => chunks.push(e.data); 
 
    // once everything is done 
 
    rec.onstop = e => { 
 
    audio.pause(); 
 
    // concatenate our chunks into one file 
 
    let final = new Blob(chunks); 
 
    let a = new Audio(URL.createObjectURL(final)); 
 
    a.controls = true; 
 
    document.body.append(a); 
 
    }; 
 
    rec.start(); 
 
    // record for 6 seconds 
 
    setTimeout(() => rec.stop(), 6000); 
 
    // for demo, change volume at half-time 
 
    setTimeout(() => audio.volume = 1, 3000); 
 
}; 
 

 
// FF will "taint" the stream, even if the media is served with correct CORS... 
 
fetch("https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3").then(resp => resp.blob()).then(b => audio.src = URL.createObjectURL(b));
<audio id="audio" autoplay controls></audio>

Для более старых браузеров, вы можете использовать метод createMediaElementSource в WebAudio API,, передавать аудио медиа-элемента через API.
Оттуда вы сможете извлечь необработанные данные PCM в arrayBuffers и сохранить его.

В следующей демонстрации я буду использовать библиотеку recorder.js, которая делает очень help для извлечения + сохранить в wav-процесс.

audio.oncanplay = function(){ 
 
    var audioCtx = new AudioContext(); 
 
    var source = audioCtx.createMediaElementSource(audio); 
 
    var gainNode = audioCtx.createGain(); 
 

 
    gainNode.gain.value = 0.5; 
 

 
    source.connect(gainNode); 
 
    gainNode.connect(audioCtx.destination); 
 

 
    var rec = new Recorder(gainNode); 
 

 
    rec.record(); 
 
    setTimeout(function(){ 
 
    gainNode.gain.value = 1; 
 
    }, 3000); 
 
    setTimeout(function(){ 
 
    rec.stop() 
 
    audio.pause(); 
 
    rec.exportWAV(function(blob){ 
 
     var a = new Audio(URL.createObjectURL(blob)); 
 
     a.controls = true; 
 
     document.body.appendChild(a); 
 
     }); 
 
    }, 6000); 
 
    };
<script src="https://rawgit.com/mattdiamond/Recorderjs/master/dist/recorder.js"></script> 
 
<audio id="audio" crossOrigin="anonymous" controls src="https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3" autoplay></audio>

+1

работает через это. Но я понимаю, что вы имеете в виду быть экспериментальным, мне нужно было включить «Экспериментальные возможности веб-платформы» в флагах chrome: // для определения 'captureStream'. –

2

Как Kaiido упоминает в своем ответе, captureStream() это один из способов сделать это. Тем не менее, это еще не полностью поддерживается в Chrome и Firefox. MediaRecorder также не позволяет изменять настройки трека во время записи, а MediaStream, исходящий от captureStream(), может иметь эти (в зависимости от приложения) - таким образом, прекращение записи преждевременно.

Если вам нужна поддержка способ записи только аудио из медиа-элемента, вы можете использовать MediaElementAudioSourceNode, трубу, к MediaStreamAudioDestinationNode и трубе атрибута stream этого к MediaRecorder.

Вот пример, который вы можете использовать на странице с существующим аудио элемента:

const a = document.getElementsByTagName("audio")[0]; 
const ac = new AudioContext(); 
const source = ac.createMediaElementSource(a); 

// The media element source stops audio playout of the audio element. 
// Hook it up to speakers again. 
source.connect(ac.destination); 

// Hook up the audio element to a MediaStream. 
const dest = ac.createMediaStreamDestination(); 
source.connect(dest); 

// Record 10s of audio with MediaRecorder. 
const recorder = new MediaRecorder(dest.stream); 
recorder.start(); 
recorder.ondataavailable = ev => { 
    console.info("Finished recording. Got blob:", ev.data); 
    a.src = URL.createObjectURL(ev.data); 
    a.play(); 
}; 
setTimeout(() => recorder.stop(), 10 * 1000); 

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

+0

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

+1

Извините, неверный комментарий. Продолжение: MediaElementAudioSourceNode явно не упоминает об этом (поэтому пересылка их поддерживается спецификацией), но, по крайней мере, Firefox неправильно перенаправляет воспроизведениеRate. Я бы сказал, что это вопрос времени, пока это не будет поддержано. См. Https://bugzilla.mozilla.org/show_bug.cgi?id=966247 – pehrsons