Audio API implementa reproductor de audio

Hay muchas bibliotecas de reproductores de audio en el mercado, como wavesurfer.js , howler.js, etc., pero ninguna de ellas admite el procesamiento de archivos de audio de gran tamaño, y los archivos de más de 100 M pueden hacer que el programa se bloquee. En resumen, no satisface mis necesidades actuales, por lo que planeo implementar un reproductor de audio por mi cuenta, de modo que, sin importar los requisitos, sea técnicamente controlable. A continuación, presentamos brevemente la implementación de wavesurferJs, y howlerJs, y luego explicamos cómo usar la API de audio para implementar un reproductor de voz personalizado.

Descarga de recursos específicos de github

wavesurferjs

Lo elegí al principio wavesurferJsprincipalmente por su función de gráfico de audio.
El efecto es el siguiente: ¿
inserte la descripción de la imagen aquí
No es hermoso?
Aquí están los pasos de implementación:

  1. inicialización
this.playWavesurfer = WaveSurfer.create({
    
    
	container: '#waveform2',
	mediaType: 'audio',
	height: 43,
	scrollParent: false,
	hideScrollbar: true,
	waveColor: '#ed6c00',
	interact: true,
	progressColor: '#dd5e98',
	cursorColor: '#ddd5e9',
	interact: true,
	cursorWidth: 1,
	barHeight: 1,
	barWidth: 1,
	plugins: [
		WaveSurfer.microphone.create()
	]
});
  1. Carga dinámicamente URL de audio
this.playWavesurfer.load(this.audioUrl);
  1. Configure la carga y calcule la duración total del audio después de la finalización
this.playWavesurfer.on('loading', (percent, xhr) => {
    
    
		this.audioLoadPercent = percent - 1;
	})
	this.playWavesurfer.on('ready', () => {
    
    
		this.audioLoading = false;
		const duration = this.playWavesurfer.getDuration();
		this.duration = this.formatTime(duration);
		this.currentTime = this.formatTime(0);
	})
  1. Calcular la duración durante la reproducción
this.playWavesurfer.on('audioprocess', function () {
    
    
	const duration = that.playWavesurfer.getDuration();
	const currentTime = that.playWavesurfer.getCurrentTime();
	that.currentTime = that.formatTime(currentTime);
	that.duration = that.formatTime(duration);
	if (that.currentTime === that.duration) {
    
    
		that.audioPlayingFlag = false;
	}
});
  1. reproducir pausar
this.playWavesurfer.playPause.bind(this.playWavesurfer)();
  1. avance rápido, rebobinado
this.playWavesurfer.skip(15);
//this.playWavesurfer.skip(-15);
  1. juego múltiple
this.playWavesurfer.setPlaybackRate(value, true);

De esta manera, las funciones básicas probablemente se realicen.

Realizado usando howlerJs

  1. Inicialice y cargue dinámicamente rutas de audio
this.howler = new Howl({
    
    
	src: [this.audioUrl]
});
  1. Calcule la duración total del audio después de cargar
this.howler.on('load', () => {
    
    
	this.audioLoading = false;
	const duration = this.howler.duration();
	this.duration = this.formatTime(duration);
	this.currentTime = this.formatTime(0);
});

  1. Obtener la hora actual durante la reproducción
this.currentTime = this.formatTime(this.howler.seek());
  1. terminado de jugar
this.howler.on('end', () => {
    
    
	this.audioPlayingFlag = false;
	this.siriWave2.stop();
	this.currentTime = "00:00:00";
	this.progressPercent = 0;
	cancelAnimationFrame(this.playTimer);
})
  1. avance rápido, rebobinado
this.howler.seek(this.howler.seek() + 15);
//this.howler.seek(this.howler.seek() - 15);
  1. Establecer reproducción múltiple
this.howler.rate(value);
  1. reproducir pausar
this.howler.play();
// this.howler.pause();
  1. Ubicar manualmente la duración de la reproducción
<div id="waveform2" ref="waveform2" @click="changProgress">
	<div class="bar" v-if="!audioLoading&&!audioPlayingFlag"></div>
	<div class="progress" :style="{width: `${progressPercent}`}"></div>
</div>
changProgress(e) {
    
    
	if (this.howler.playing()) {
    
    
		this.howler.seek((e.offsetX / this.$refs['waveform2'].offsetWidth)*this.howler.duration());
	}
},

De esta manera, las funciones básicas probablemente se realicen.

Use la API de audio para implementar el reproductor

Imagen de efecto: siriwave.js
inserte la descripción de la imagen aquí
utilizado temporalmente por la biblioteca de animación

Primero defina la etiqueta de audio oculta, que se puede generar dinámicamente en js

<audio :src="audioUrl" style="display: none;" controls ref="audio"></audio>
this.audio = this.$refs['audio'];
  1. Después de obtener la url de audio, se debe cargar la carga dinámica
this.audio.load();
  1. Audio cargado
this.audio.addEventListener("canplaythrough", () => {
    
    
	this.audioLoading = false;
	console.log('music ready');
}, false);
  1. Calcule la duración del audio después de escuchar se puede reproducir
this.audio.addEventListener("canplay", this.showTime, false);
showTime() {
    
    
	if (!isNaN(this.audio.duration)) {
    
    
		this.duration = this.formatTime(this.audio.duration);
		this.currentTime = this.formatTime(this.audio.currentTime);
	}
},
  1. Cambios de hora durante la reproducción para calcular la hora actual
this.audio.addEventListener("timeupdate", this.showTime, true);
  1. Escuche los eventos de reproducción
this.audio.addEventListener('play', () => {
    
    
	this.audioPlaying();
}, false);
  1. terminado de jugar
this.audio.addEventListener('ended', () => {
    
    
	this.audioPlayingFlag = false;
	this.siriWave2.stop();
	this.currentTime = "00:00:00";
	this.progressPercent = 0;
	cancelAnimationFrame(this.playTimer);
}, false)
  1. hacia adelante hacia atrás
this.audio.currentTime += 15;
// this.audio.currentTime -= 15;
  1. Establecer multiplicador de reproducción
this.audio.playbackRate = value;
  1. reproducir pausar
this.audio.play();
// this.audio.pause();
  1. posicionamiento de audio
<div id="waveform2" ref="waveform2" @click="changProgress">
	<div class="bar" v-if="!audioLoading&&!audioPlayingFlag"></div>
	<div class="progress" :style="{width: `${progressPercent}`}"></div>
</div>

Calcular el tiempo de posicionamiento

changProgress(e) {
    
    
	// if (this.audioPlayingFlag) {
    
    
		this.audio.currentTime = (e.offsetX / this.$refs['waveform2'].offsetWidth)*this.audio.duration;
		this.progressPercent = ((this.audio.currentTime/this.audio.duration) * 100) + '%';
	// }
},
  1. Realización de animación Siri
this.siriWave = new SiriWave({
    
    
	container: that.$refs['waveform'],
		height: 43,
		cover: true,
		color: '#ed6c00',
		speed: 0.03,
		amplitude: 1,
		frequency: 6
	});

Iniciar animación, detener animación

this.siriWave.start();
// this.siriWave.stop();

De esta manera, las funciones básicas probablemente se realicen. Incluso si carga un archivo de audio grande, no se atascará.

Paso en el hoyo

inserte la descripción de la imagen aquí
Un gran escollo encontrado aquí es la función de posicionamiento de reproducción de audio incorporada, que se puede ubicar en el navegador externo y el código principal de vscode, pero no puedo ubicarlo en el complemento de vscode, y volverá automáticamente a 0 . Busqué en la documentación y encontré esta descripción en MDN:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Configuring_servers_for_Ogg_media#Handle_HTTP_1.1_byte_range_requests_correctly

Manejar correctamente las solicitudes de rango de bytes HTTP 1.1
Para admitir la búsqueda y reproducción de regiones de los medios que aún no se han descargado, Gecko utiliza solicitudes de rango de bytes HTTP 1.1 para recuperar los medios desde la posición de destino de búsqueda. Además, Gecko usa solicitudes de rango de bytes para buscar el final de los medios (suponiendo que sirva el Content-Length encabezado) para determinar la duración de los medios.
Su servidor debe aceptar el Accept-Rangesencabezado HTTP : bytes si puede aceptar solicitudes de rango de bytes. Debe devolver 206: contenido parcial para todas las solicitudes de rango de bytes; de lo contrario, los navegadores no pueden estar seguros de que realmente admite solicitudes de rango de bytes.
Su servidor también debe devolver 206: contenido parcial para el rango de solicitud: bytes = 0- también.

Se ha comprobado que está response headerrelacionado con . Verifiqué los diferentes conjuntos de recursos MP3 response headery los resultados son los siguientes (parece que segmentfault no admite tablas de rebajas, por lo que el diseño a continuación es un poco desordenado): es decir,
debe
Content-Typereproducirse cuando lo configuro en audio/mpeg, y configúrelo en application/octet-stream no puede.
Content-Lengthdebe. No tiene nada que ver con Aceptar-Rangos.

Chrome
Content-Typeno tiene nada que hacer, configúralo application/octet-streampara que sea jugable.
Content-Length, Accept-Rangesdebe tener que cambiar el tiempo actual.

Es decir , necesita que el encabezado de respuesta sea correcto Content-Type. Chrome requiere encabezados con y .Content-Length
Content-LengthAccept-Ranges

Entonces se me ocurrió que el sistema de complementos de vscode usaService Worker

const headers = {
    
    
		'Content-Type': entry.mime,
		'Content-Length': entry.data.byteLength.toString(),
		'Access-Control-Allow-Origin': '*',
	};

Efectivamente, no se agregó el campo Rangos de aceptación

const headers = {
    
    
	'Content-Type': entry.mime,
	'Content-Length': entry.data.byteLength.toString(),
	'Access-Control-Allow-Origin': '*',
};

/**
 * @author lichangwei
 * @description 音频额外处理 否则无法调节进度
 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Configuring_servers_for_Ogg_media#Handle_HTTP_1.1_byte_range_requests_correctly
 */

if (entry.mime === 'audio/mpeg') {
    
    
	headers['Accept-Ranges'] = 'bytes';
}

Después de agregarlo, está listo para usar.

Hacer un seguimiento

Echa un vistazo a la implementación de notas de voz de Evernote.
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí
¿Cómo evita Evernote el procesamiento de archivos grandes?

  • En primer lugar, la línea de audio real se dibuja durante el proceso de grabación.
  • Una vez que finaliza la grabación, se reemplaza con un cable de audio falso

De hecho, está bien procesar los datos de audio en tiempo real durante el proceso de grabación, para que el navegador no se bloquee. El archivo de audio generado después de la grabación tiene demasiados datos para procesar, y la memoria aumenta directamente en 2-3G. por lo que hará que el programa se bloquee.

Implementación posterior del mapa de audio

El hermano Meng presta atención ~

Supongo que te gusta

Origin blog.csdn.net/woyebuzhidao321/article/details/131293758
Recomendado
Clasificación