快速加载音频WaveSurfer和PeakJs

问题描述 投票:0回答:1

我有这样的实现,后端传输音频文件。我想要一种能够快速加载和播放音频文件的方法:一切都按预期工作,但似乎存在不稳定的行为,需要很长时间才能加载到我的网页上:

我是 React Js 新手。

import React, { useState,useEffect, useRef } from 'react';
import { Icon } from '@iconify/react';
import { podcastIcons } from '@/db/data';
import axios from 'axios';
import WaveSurfer from 'wavesurfer.js';


const PlayFile: React.FC = () => {
    const [linkName, setLinkName] = useState<string>(''); // State for link name
    
    
    const [audioURL, setAudioURL] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(false);
    const waveformRef = useRef<HTMLDivElement | null>(null); // Reference to the waveform container
    const waveSurfer = useRef<WaveSurfer | null>(null); // Reference to the WaveSurfer instance
    
    const handleSubmit = async (event: React.FormEvent) => {
        event.preventDefault();

        const formData = new FormData();
        formData.append('link_name', linkName);
        try {
                        const response = await axios.post('http://localhost:8000/submitform/', formData, {
                            headers: {
                                'Content-Type': 'multipart/form-data',
                            },
                        });
            const audioBlob = new Blob([response.data], { type: 'audio/mpeg' });
            const audioUrl = URL.createObjectURL(audioBlob);
            setAudioURL(audioUrl); // Set audio UR
            

            // Initialize Wavesurfer after the audio is set
            console.log('checking waveform');
            if (waveformRef.current && waveSurfer.current === null) {
                waveSurfer.current = WaveSurfer.create({
                    container: waveformRef.current,
                    waveColor: '#ddd',
                    progressColor: '#333',
                    cursorColor: '#333',
                    height: 64,
                    barWidth: 1,
                    responsive: true,
                   // backend: 'MediaElement'
                });
            }

            // Load the audio file into Wavesurfer
            console.log('after checking ...');
            if (waveSurfer.current && audioUrl) {
                console.log('Waveform loaded with audio URL:', audioUrl);
                waveSurfer.current.load(audioUrl);
            }
            //    } catch (error) {
            // console.error('Error generating the podcast:', error);
            //     } 
                    } catch (error) {
                        console.error('Error submitting the form', error);
                    }finally {
            setIsLoading(false);
              }
    };
  
);
return (

        <form onSubmit={handleSubmit} className=" bg-gradient-to-r from-emerald-100 to-lime-200 flex text-black flex-col lg:flex-row lg:space-x-8 p-6 font-sans py-12 px-6">

         
                </div>
                 
                {/* Link Name Input Field */}
                <div className="mb-6">
                    <label className="font-semibold mb-2">Document Link</label>
                    <input
                        type="Document link"
                        value={linkName}
                        onChange={(e) => setLinkName(e.target.value)}
                        className="border rounded w-full py-2 px-3"
                        placeholder="Link to Document"
                    />
                </div>
                <button className="bg-black text-white py-3 px-8 rounded w-full">
                    Create podcast
                </button>
           
            {/* Show the audio player and waveform if the audio URL is available */}
            {audioURL && (
                <div className="mt-4">
                    <div className="waveform" ref={waveformRef}></div> {/* Waveform container */}
                    <div className="mt-2 flex gap-4">
                        <button onClick={() => waveSurfer.current?.playPause()} className="bg-green-500 text-white py-2 px-4 rounded">
                            {waveSurfer.current?.isPlaying() ? 'Pause' : 'Play'}
                        </button>
                        <button onClick={() => waveSurfer.current?.stop()} className="bg-red-500 text-white py-2 px-4 rounded">
                            Stop
                        </button>
                     
                    </div>
                </div>
            )}

            </div>
        </form>
    );
};

export default PlayFile;

我已经尝试过上面的代码,它有时有效,有时则无效。我正在寻找优化代码并获得以可扩展的方式处理前端音频渲染的实践经验。说明最佳实践的示例将受到高度赞赏。 使用peaks.js、howler和其他针对性能进行优化的类似库的解决方案也受到欢迎。

reactjs blob vite html5-audio wavesurfer.js
1个回答
0
投票

在 React 应用程序中采用 Howler.js 具有许多优势,可以直接解决您当前实施中面临的挑战:

  1. 性能改进:通过流式传输有效处理大型音频文件,减少加载时间和内存使用量。
  2. 更简单、更可靠的代码:简单的 API 最大限度地降低了复杂性,使您的应用程序更易于维护且不易出现错误。
  3. 更好的用户体验:更快的播放启动和响应控制增强了整体用户体验。
  4. 强大的资源管理:适当的清理和错误处理确保 随着时间的推移,您的应用程序将保持稳定和性能。
  5. 跨浏览器一致性:Howler.js 抽象了浏览器 不一致,在不同的环境中提供统一的体验 环境。

通过利用 Howler.js,您可以在 React 应用程序中创建可扩展、高效且用户友好的音频播放功能,解决不稳定的加载行为并提高整体性能。

试试这个代码:

如果您稍后决定合并波形可视化等高级功能,您可以将专用库(例如 WaveSurfer.js)与 Howler.js 一起集成,从而保持模块化且高效的架构。

import React, { useState, useRef, useEffect } from 'react';
import axios from 'axios';
import { Howl } from 'howler';

const PlayFileWithHowler = () => {
    const [linkName, setLinkName] = useState('');
    const [isLoading, setIsLoading] = useState(false);
    const [howl, setHowl] = useState(null);
    const [isPlaying, setIsPlaying] = useState(false);

    const handleSubmit = async (event) => {
        event.preventDefault();
        setIsLoading(true);

        const formData = new FormData();
        formData.append('link_name', linkName);

        try {
            const response = await axios.post('http://localhost:8000/submitform/', formData, {
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
                responseType: 'blob', // Ensure the response is a blob
            });

            const audioBlob = new Blob([response.data], { type: 'audio/mpeg' });
            const audioUrl = URL.createObjectURL(audioBlob);

            const newHowl = new Howl({
                src: [audioUrl],
                html5: true, // Use HTML5 Audio to enable streaming large files
                onend: () => setIsPlaying(false),
                onplay: () => setIsPlaying(true),
                onpause: () => setIsPlaying(false),
                onstop: () => setIsPlaying(false),
                onloaderror: (id, error) => console.error('Load error:', error),
                onplayerror: (id, error) => console.error('Play error:', error),
            });

            setHowl(newHowl);
        } catch (error) {
            console.error('Error submitting the form', error);
            // Optionally, set an error state here to display to the user
        } finally {
            setIsLoading(false);
        }
    };

    const handlePlayPause = () => {
        if (howl) {
            howl.playing() ? howl.pause() : howl.play();
        }
    };

    const handleStop = () => {
        if (howl) {
            howl.stop();
        }
    };

    // Cleanup Howl on unmount
    useEffect(() => {
        return () => {
            if (howl) {
                howl.unload();
            }
        };
    }, [howl]);

    return (
        <form onSubmit={handleSubmit} className="bg-gradient-to-r from-emerald-100 to-lime-200 flex flex-col lg:flex-row lg:space-x-8 p-6 font-sans py-12 px-6">
            {/* Link Name Input Field */}
            <div className="mb-6 flex-1">
                <label className="font-semibold mb-2 block">Document Link</label>
                <input
                    type="text"
                    value={linkName}
                    onChange={(e) => setLinkName(e.target.value)}
                    className="border rounded w-full py-2 px-3"
                    placeholder="Link to Document"
                    required
                />
            </div>
            <div className="flex items-end">
                <button
                    type="submit"
                    className="bg-black text-white py-3 px-8 rounded w-full"
                    disabled={isLoading}
                >
                    {isLoading ? 'Loading...' : 'Create Podcast'}
                </button>
            </div>

            {/* Show the audio controls if Howl is initialized */}
            {howl && (
                <div className="mt-4 w-full">
                    <div className="flex gap-4">
                        <button
                            type="button"
                            onClick={handlePlayPause}
                            className="bg-green-500 text-white py-2 px-4 rounded"
                        >
                            {isPlaying ? 'Pause' : 'Play'}
                        </button>
                        <button
                            type="button"
                            onClick={handleStop}
                            className="bg-red-500 text-white py-2 px-4 rounded"
                        >
                            Stop
                        </button>
                    </div>
                </div>
            )}
        </form>
    );
};

export default PlayFileWithHowler;
© www.soinside.com 2019 - 2024. All rights reserved.