最近项目有个需求,一个app需要能够播报金额,另一个需要播报叫号,因为金额和排队号是可变的,所以需要播放的音频是不固定的。方案有如下几种:

1、集成百度TTS,通过离在线的sdk接口进行播报;

2、录制表示数字,金额,小数点,英文字母的单个字符,然后先将所需的音频合成为一个音频,再播报,或者直接顺序播报一组音频;

具体实现:

由于本人在别的项目中使用过百度TTS语音播报,这种离在线系统的机制在网络不稳定时,可能出现不播报的情况,而本项目app很可能在一些网络环境较差的情况下使用,所以选择第二种实现方案。

需要使用的库

//exoplayer
implementation 'com.google.android.exoplayer:exoplayer:2.8.1'
implementation 'com.google.android.exoplayer:exoplayer-core:2.8.1'

具体播报方法如下:

先根据金额或者排队序号得到一组音频文件,然后使用下面方法即可正常播报。

音频文件放在app/assets目录下

public void playAudios(Context context, List<String> fileNames){
        if (fileNames == null){
            return;
        }
        if (player == null){
            player = ExoPlayerFactory.newSimpleInstance(context, new DefaultTrackSelector());
            //第一个参数是播放速度,第二个参数是播放音调的高低
            player.setPlaybackParameters(new PlaybackParameters(0.8f, 1.0f));
        }
        //  userAgent -> audio/mpeg  不能为空
        DefaultDataSourceFactory defaultDataSourceFactory = new DefaultDataSourceFactory(context, "audio/mpeg");
        //创建一个媒体连接源
        ConcatenatingMediaSource concatenatingMediaSource = new ConcatenatingMediaSource();
        for (int i=0;i<fileNames.size();i++){
            String fileName = fileNames.get(i);
            Log.e(TAG, "playAudios fileName: " + fileName);
            //创建一个播放数据源
            MediaSource mediaSource = new ExtractorMediaSource.Factory(defaultDataSourceFactory).createMediaSource(Uri.parse("file:///android_asset/" + fileName));
            concatenatingMediaSource.addMediaSource(mediaSource);
        }
        player.setPlayWhenReady(true);
        player.prepare(concatenatingMediaSource);
    }

如果在Activity直接调用该方法,可能出现未播报完,页面中止的情况,导致音频播报不完全,所以可以定义一个Service,然后在Service中开启一个线程播报,这样即使当前页面中止了,音频也可以正常完成播报。

/**
     * 进行语音播报操作(支付的语音播报)
     * @param numFileNames
     */
    private void playAudio(ArrayList<String> numFileNames){
        Log.e(TAG, "playAudio execute");
        new Thread(){
            @Override
            public void run() {
                List<String> fileNames2 = new ArrayList<>();
                fileNames2.add("xxx.mp3");
                player.playAudios(mContext, fileNames2);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (numFileNames != null){
                    List<String> fileNames = new ArrayList<>();
                    fileNames.addAll(numFileNames);
                    player.playAudios(mContext, fileNames);
                    numFileNames.clear();
                }
            }
        }.start();
    }

具体使用时需要注意以下几点:

1、Service需要在AndroidManifest.xml当中进行配置

<service android:name=".service.XXXService" android:enabled="true" android:exported="true"/>

2、每次调用playAudios方法时,传入的一组音频文件格式需要相同,因为默认是根据一组音频的第一个音频格式去解析后面的所有音频文件格式,如果这种音频格式不同,可能导致跟第一个音频不同格式的音频文件不能被正常解析,也不能正常播报。

具体代码,可以去我的资源里面下载相关类。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐