Нет, мы все еще не можем записать MediaStream, треки которого изменены после начала записи, при этом stop()
будет MediaRecorder. Вот очень связанная с этим Q / A , которая больше касалась записи видео.
Что можно сделать, так это создать своего рода слияние MediaStream.
С аудио гораздо проще, более того, поскольку вы уже используете API WebAudio: все, что вам нужно сделать, - это создать другой узел MediaStreamDestination и подключить / отключить различные источники.
const base = "https://upload.wikimedia.org/wikipedia/en/d/";
const urls = [
"d3/Beach_Boys_-_Good_Vibrations.ogg",
"dc/Strawberry_Fields_Forever_%28Beatles_song_-_sample%29.ogg"
].map( url => base + url );
const context = new AudioContext();
const button = document.querySelector( 'button' );
button.onclick = async () => {
button.disabled = true;
context.resume();
const audiobuffers = await Promise.all( urls.map( fetchAsAudioBuffer ) );
button.remove();
const streamNode = context.createMediaStreamDestination();
const stream = streamNode.stream;
const recorder = new MediaRecorder( stream );
const chunks = [];
recorder.ondataavailable = evt => chunks.push( evt.data );
recorder.onstop = evt => exportAudio( new Blob( chunks ) );
document.getElementById( 'record-stopper' ).onclick = evt => {
recorder.stop();
current_source.stop( 0 );
};
let current_index = 0;
let current_source = null;
document.getElementById( 'switcher' ).onclick = switchAudioSource;
switchAudioSource();
recorder.start();
function switchAudioSource() {
if( current_source ) {
current_source.stop( 0 );
}
current_index = (current_index + 1) % audiobuffers.length;
current_source = context.createBufferSource();
current_source.buffer = audiobuffers[ current_index ];
current_source.loop = true;
current_source.connect( streamNode );
current_source.connect( context.destination );
current_source.start( 0 );
}
};
function exportAudio( blob ) {
const aud = new Audio( URL.createObjectURL( blob ) );
aud.controls = true;
document.body.prepend( aud );
}
async function fetchAsAudioBuffer( url ) {
const buf = await fetchAsBuffer( url );
return context.decodeAudioData( buf );
}
async function fetchAsBuffer( url ) {
const resp = await fetch( url );
return resp.arrayBuffer();
}
button+.recording-controls,
audio+.recording-controls {
display: none;
}
<button>begin</button>
<div class="recording-controls">
<label>Recording...</label>
<button id="switcher">Switch Audio Sources</button>
<button id="record-stopper">Stop Recording</button>
</div>
Для видео, которое подразумевает запись CanvasMediaStreamTrack и рисование различных видеопотоков на источнике <canvas>
, но мы обычно теряем много качества при этом ...