解决React.js框架下播放amr格式的音频

962 阅读2分钟

平板生成的音频为amr格式,audio标签无法播放,最近项目上就遇到了这种情况,环境为React.js语言的UMI框架,分页列表可播放多个amr文件,网上找了一个叫benz-amr-recorder的插件,api写的详细,但是没有这种情况的实例,自己摸索着,最后搞定,自己写的样式。才疏学浅,各路高人多指教。

1.benz-amr-recorder安装到项目里

npm install benz-amr-recorder

2.引入benz-amr-recorder插件,初始化数据

import React,{useState,useEffect} from 'react';
import BenzAmrRecorder from 'benz-amr-recorder';

interface mediaprops{
    children?:any,
    list:never[],
    dataindex:number,
    customstyle?:boolean
}
const Index = (props:mediaprops)=>{
const {list,dataindex,customstyle=false} = props;//从父组件获取列表及当前项的位置和自定义样式
const [detail,setDetail] = useState({...list[dataindex],amr:new BenzAmrRecorder(),intervalTime:undefined})//初始化当前项的信息,包括独有的amr音频管理对象和控制播放时间的变量

const [amrAdoDuration,setAmrAdoDuration] = useState(0);//记录音频的长度
const [amrAdoCurPos,setAmrAdoCurPos] = useState(0);//记录音频播放的位置
const [playStat,setPlayStat] = useState(false);//记录音频是否播放

3.初始化benz-amr-recorder插件

useEffect(()=>{
       //读出并展示音频的播放时长
       detail['amr'].initWithUrl(detail.url).then(()=>{
            setAmrAdoDuration(Math.round(detail['amr'].getDuration()));
       })
})

4.监听当前子项是否在播放音频

useEffect(()=>{
       if(detail['amr'].isPlaying()){//是的话,给当前子项设置一个定时器,每一秒更新一下播放到哪儿了
        detail['intervalTime'] = setInterval(()=>{
            setAmrAdoCurPos(Math.round(detail['amr'].getCurrentPosition()));
        },1000);
       } else{//否,清除当前子项的定时器
        if(detail['intervalTime']) clearInterval(detail['intervalTime'])
       }
    },[detail['amr'].isPlaying()]);

5.处理点击播放和暂停

return (
            <li className={customstyle}>
            {props.children}
            {
                detail['mediatype']==='audio'?//是否为音频
                <div className={styles.audioicon}>
                    {
                        detail.mediaSuffix.indexOf('amr')>-1?//是否媒体标题后缀为amr
                        <>
                        //下面就是amr播放器,用了一下antd的Process组件
                        <Process
                            percent={amrAdoCurPos===0?0:Math.round((amrAdoCurPos/amrAdoDuration)*100)}
                            format={percent=>percent?formatTime(Math.round(percent/100*amrAdoDuration))+'/'+formatTime(amrAdoDuration):'00:00/00:00'}
                            style={{fontSize:16}}
                        />
                        <div style={{alignSelf:'flex-start'}} onClick={()=>{
                            setPlayStat(!playStat);//设置播放暂停的状态
                            detail.amr.playOrPauseOrResume();//播放或者暂停时,再被点了一次,暂停或者播放或者从头开始播放
                            detail.amr.onEnded(()=>{
                               //结束的时候,播放完了要把状态都重新初始化
                               setAmrAdoCurPos(Math.round(detail['amr'].getDuration()));
                                setPlayStat(false);
                                //清理定时器
                                if(detail['intervalTime']) clearInterval(detail['intervalTime'])
                            })
                        }}>
                        //自己封装的组件,其实就是antd中CaretRightOutlined,PauseOutlined俩图标根据状态playStat展示
                            <IconPreview
                                imgurl={!playStat?'CaretRightOutlined':'PauseOutlined'}
                                imgstyle={{width:'auto',height:'auto',border:'1px solid #d9d9d9',padding:'4px 3px 2px 5px',borderRadius:4,cursot:'pointer',marginTop:8}}
                            />
                        </div>
                        </>:<Audio src={detail.url} controls={true} controlsList="nodownload" autoPlay="true"/>
                    }
                </div>:null
            }
            </li>
    )

6.最后贴一下时间格式处理函数和样式

const formatTime=(param:any)=>{
        if(param<60){//一分以内
            if(param<10){
                return '00:0'+param;
            }else{
                return '00:'+param;
            }
        }else if (param>=60&&param<3600){//一分到十分之间
            let cop_sStr = param%60;
            let sStr = cop_sStr+'';

            if(cop_sStr<10){
                sStr = '0'+cop_sStr;
            }

            if(param<600){//十分以内
                return '0'+parseInt((param/60)+'')+':'+sStr;
            }else{
                return parseInt((param/60)+'')+':'+sStr;                
            }
        }else{
            let cop_sStr = param%60;
            let sStr = cop_sStr+'';

            if(cop_sStr<10){
                sStr = '0'+cop_sStr;
            }

            let cop_mStr = param/60%60;
            let mStr = cop_mStr+'';

            if(cop_mStr<10){//1分到10分
                mStr = '0'+cop_mStr;
            }

            if(param<36000&&param>=3600){
                return '0'+parseInt((param/3600)+'')+':'+mStr+':'+sStr;
            }else{
                return parseInt((param/3600)+'')+':'+mStr+':'+sStr;                
            }
        }
    }
.audioicon{
    border:1px solid red;
    display:flex;
    flex-direction:column;
    justify-content:center;
    align-items:center;
    padding:0 65px 0 16px;
}