首页 > 其他分享 >冲刺4

冲刺4

时间:2024-06-17 11:13:05浏览次数:12  
标签:return mediaPlayer 冲刺 callback private new null

客户端部分代码:

public class MediaPlayer
        implements android.media.MediaPlayer.OnPreparedListener
        , android.media.MediaPlayer.OnCompletionListener
        , android.media.MediaPlayer.OnErrorListener {

    private String TAG = "MediaPlayer";

    public static int STATE_INIT = 0; //初始化

    public static int STATE_PLAY = 1; //播放中

    public static int STATE_WAIT = 2; //等待下一句

    public static int STATE_COMPLETE = 3; //播放结束


    private int MaxQueue = 10;
    //播放器回调
    private QCloudPlayerCallback callback;

    private BlockingQueue<File> audioQueue; //语音队列

    private BlockingQueue<ArrayList<Subtitle>> allSubtitles;

    private List<String> audioTextQueue; //语音文本队列

    private List<String>  utteranceIdQueue; //语音文本队列对应的utteranceId

    private List<Boolean>  isDeleteFlags; //是否在播放完成后删除音频文件,入参音频支持byte[]和File,入参File时保留音频文件,入参byte[]时需要删除临时文件

    private String currentSentenceString; //正在播放的文本

    private int currentTextIndex; //当前播放的文本下标

    private android.media.MediaPlayer mediaPlayer; //播放器

    private File playingFile; //正在播放的文件

    private boolean isDeleteFlag;//正在播放的文件播放完成后是否需要删除

    private FileInputStream fis;

    private AtomicBoolean isPlaying = new AtomicBoolean(false); //是否正在播放

    private volatile boolean pauseFlag = false; //暂停标识

    private volatile boolean isExceptionCompletion = false; //pause 异常结束播放的标识

    private AtomicInteger state = new AtomicInteger(STATE_INIT);

    private List<Subtitle> subtitles;

    private int index = 0;

    public MediaPlayer(QCloudPlayerCallback callback) {
        this.callback = callback;
        mediaPlayer = new android.media.MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setLooping(false);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnErrorListener(this);
        mediaPlayer.setOnPreparedListener(this);
        this.audioQueue = new ArrayBlockingQueue<>(MaxQueue + 5);
        this.allSubtitles = new ArrayBlockingQueue<>(MaxQueue + 5);
        this.audioTextQueue = new ArrayList<>();
        this.utteranceIdQueue = new ArrayList<>();
        this.isDeleteFlags = new ArrayList<>();
        currentSentenceString = "";
        currentTextIndex = 0;


        Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                if (isPlaying.get() && mediaPlayer != null && !pauseFlag) {
                    try {
                        if (mediaPlayer.isPlaying()) { //防止报-38的错误
                            int duration = mediaPlayer.getDuration();
                            if (subtitles == null || subtitles.size() == 0) {
                                // 使用平均时长计算progress
                                if (duration != 0) {
                                    int currentPosition = mediaPlayer.getCurrentPosition();
                                    int textIndex = currentSentenceString.length() * currentPosition / duration;
                                    if (currentTextIndex == textIndex && textIndex < currentSentenceString.length()) {
                                        currentTextIndex = currentTextIndex + 1;
                                        String currentPlayString = currentSentenceString.substring(textIndex, textIndex + 1);
                                        if (callback != null) {
                                            callback.onTTSPlayProgress(currentPlayString, textIndex);
                                        }
                                    }
                                }
                            } else {
                                // 使用Server端回复的subtitiles计算progress,前提是设置mTtsController.setOnlineParam("EnableSubtitle", true);
                                if (duration != 0 && subtitles != null) {
                                    int currentPosition = mediaPlayer.getCurrentPosition();
                                    for (int i = subtitles.size() - 1; i >= index; i--) {
                                        int beginTime = subtitles.get(i).getBeginTime();
                                        if (currentPosition >= beginTime) {
                                            for (int j = index; j < i; j++) {
                                                if (callback != null)  {
                                                    String text = subtitles.get(j).getText();
                                                    int beginIndex = subtitles.get(j).getBeginIndex();
                                                    callback.onTTSPlayProgress(text, beginIndex);
                                                }
                                            }
                                            index = i;
                                        }
                                    }
                                }
                            }
                        }
                    }catch (Exception e){
                        //因这里与播放器不在同一个线程,调用mediaPlayer相关方法可能引发IllegalStateException、空指针等异常,这里try catch所有可能的异常
                        //不影响下次执行,无需处理
                        Log.i(TAG, "MediaPlayerTimer Exception:" + e);
                    }
                }
            }
        };
        timer.schedule(timerTask, 0,16);
        pauseFlag = false;
    }

    synchronized public QPlayerError enqueue(byte[] audio,String text,String utteranceId) {
        return this.enqueue(audio, text, utteranceId, "");
    }

    synchronized public QPlayerError enqueue(byte[] audio,String text,String utteranceId, String responseJson) {
        if (audioQueue.size() >= MaxQueue){    //播放队列上限,请在onTTSPlayNext回调后再入参
            return new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_PLAY_QUEUE_IS_FULL);
        }
        if (audio == null){
            return new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_AUDIO_READ_FAILEDL);
        }

        //将byteBuffer保存到文件
        try {
            File file = File.createTempFile("MediaPlayerDemo", ".mp3");
            OutputStream os = new FileOutputStream(file);
            os.write(audio);
            os.flush();
            os.close();

            //数据入库
            try {
                this.audioQueue.put(file);
                this.audioTextQueue.add(text);
                this.utteranceIdQueue.add(utteranceId);
                this.isDeleteFlags.add(true);
                this.allSubtitles.put(parseJson(responseJson));

                // 检查是否需要
                if (!pauseFlag && isPlaying.compareAndSet(false, true)) {
                    playAudio(dequeue());
                }
                return null;

            } catch (InterruptedException e) {
                return new QPlayerError(e, QplayerErrorCode.QPLAYER_ERROR_CODE_UNKNOW);
            }

        } catch (IOException e) {
            return new QPlayerError(e,QplayerErrorCode.QPLAYER_ERROR_CODE_UNKNOW);
        }
    }


    synchronized public QPlayerError enqueue(File audio,String text,String utteranceId, String responseJson) {
        if (audioQueue.size() >= MaxQueue){    //播放队列上限,请在onTTSPlayNext回调后再入参
            return new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_PLAY_QUEUE_IS_FULL);
        }
        if (audio == null){
            return new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_AUDIO_READ_FAILEDL);
        }
        try{
            if(!audio.exists())
            {
                return new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_AUDIO_READ_FAILEDL);
            }
        } catch (SecurityException e){
            return new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_AUDIO_READ_FAILEDL);
        }

        //数据入库
        try {
            this.audioQueue.put(audio);
            this.audioTextQueue.add(text);
            this.utteranceIdQueue.add(utteranceId);
            this.isDeleteFlags.add(false);
            this.allSubtitles.add(parseJson(responseJson));

            // 检查是否需要
            if (!pauseFlag && isPlaying.compareAndSet(false, true)) {
                playAudio(dequeue());
            }
            return null;

        } catch (InterruptedException e) {
            return new QPlayerError(e,QplayerErrorCode.QPLAYER_ERROR_CODE_UNKNOW);
        }
    }

    private ArrayList<Subtitle> parseJson(String json) {
        ArrayList<Subtitle> subtitles = new ArrayList<>();
        try {
            if (TextUtils.isEmpty(json)) {
                return subtitles;
            }
            JSONObject jsonObject = new JSONObject(json);
            JSONObject response = jsonObject.getJSONObject("Response");
            if (response == null) {
                return subtitles;
            }
            // 解析Subtitles
            JSONArray subtitlesArray = response.getJSONArray("Subtitles");
            for (int i = 0; i < subtitlesArray.length(); i++) {
                JSONObject item = subtitlesArray.getJSONObject(i);
                subtitles.add(new Subtitle(
                        item.getString("Text"),
                        item.getInt("BeginTime"),
                        item.getInt("EndTime"),
                        item.getInt("BeginIndex"),
                        item.getInt("EndIndex"),
                        item.getString("Phoneme")
                ));
            }
            return subtitles;
        } catch (JSONException e) {
            Log.e(TAG,"parse json error: "+ e.getMessage());
        }
        return subtitles;
    }


    public int getAudioQueueSize(){
        return audioQueue.size();
    }

    public int getAudioAvailableQueueSize(){
        return MaxQueue - audioQueue.size();
    }

    public int getPlayState(){
        return state.get();
    }

    /**
     * 数据出队列
     * @return audio
     */
    public File dequeue() {
        try {
            if (this.audioTextQueue.size() > 0) {
                this.currentSentenceString = this.audioTextQueue.get(0);
                this.audioTextQueue.remove(0);

                String utteranceId = this.utteranceIdQueue.get(0);
                this.utteranceIdQueue.remove(0);

                isDeleteFlag = isDeleteFlags.get(0);
                isDeleteFlags.remove(0);

                if (callback != null){
                    callback.onTTSPlayNext(currentSentenceString, utteranceId);
                }
            }
            ArrayList<Subtitle> tempSubtitles = this.allSubtitles.poll(100, TimeUnit.MILLISECONDS);
            if (tempSubtitles != null) {
                subtitles = Collections.synchronizedList(tempSubtitles);
            }
            index = 0;
            return this.audioQueue.poll(100, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            if (callback != null) {
                callback.onTTSPlayError(new QPlayerError(e,QplayerErrorCode.QPLAYER_ERROR_CODE_UNKNOW));
            }
            Log.e(TAG, "dequeue Exception:" + e);
            return null;
        }

    }



    @Override
    public void onCompletion(android.media.MediaPlayer mediaPlayer) {
//        Log.d("sendError","MusicService.onCompletion()"+"mp.isPlaying()?"+mediaPlayer.isPlaying());
        //删除音频文件
        deleteAudioFile();
        if (pauseFlag) {
            isExceptionCompletion=true;
            return;
        }

        playOnCompletionException();

    }

    private void playOnCompletionException(){
        // 检查是否需要
        File audio = dequeue();
        if (audio != null) {
            //还有数据,继续播放
            playAudio(audio);
        } else {
            //没有数据了,设置未播放
            isPlaying.set(false);
            //设置为等待状态
            state.set(STATE_WAIT);
            if (callback != null)  {
                callback.onTTSPlayWait();
            }
        }
    }


    @Override
    public boolean one rror(android.media.MediaPlayer mediaPlayer, int i, int i1) {
        //出错了
        if (callback != null) {
            callback.onTTSPlayStop();
        }

        //设置没有播放
        isPlaying.set(false);

        //删除音频文件
        deleteAudioFile();

        //设置状态为结束
        state.set(STATE_COMPLETE);

        if (callback != null) {
            callback.onTTSPlayError(new QPlayerError(null,QplayerErrorCode.QPLAYER_ERROR_CODE_EXCEPTION));
        }

        return false;
    }

    @Override
    public void onPrepared(android.media.MediaPlayer mediaPlayer) {
        int status = state.get();
        //设置正在播放
        isPlaying.set(true);

        //开始播放
        mediaPlayer.start();

        //设置为播放状态
        state.set(STATE_PLAY);

        if (callback != null) {
            //播放器准备好了
            if (status == STATE_INIT) {
                //第一次播放
                callback.onTTSPlayStart();
            } else if (status == STATE_WAIT) {
                //非连续,恢复播放
                callback.onTTSPlayResume();

            }
        }
    }

    //播放音频
    private void playAudio(File audio) {
        if (mediaPlayer == null){
            mediaPlayer = new android.media.MediaPlayer();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setLooping(false);
            mediaPlayer.setOnCompletionListener(this);
            mediaPlayer.setOnErrorListener(this);
            mediaPlayer.setOnPreparedListener(this);
        }
        try {
            playingFile = audio;
            //先reset mediaplayer
            mediaPlayer.reset();
            //设置播放文件的目录
            fis = new FileInputStream(playingFile);
            int fileLen = fis.available();
            mediaPlayer.setDataSource(fis.getFD(), 0, fileLen);
            //当句的下标重置
            currentTextIndex = 0;
            // 开始播放
            mediaPlayer.prepare();
            fis.close();

        } catch (Exception e) {
            if (callback != null) {
                callback.onTTSPlayError(new QPlayerError(e,QplayerErrorCode.QPLAYER_ERROR_CODE_EXCEPTION));
            }
            Log.e(TAG, "playAudio Exception:" + e);
        }
    }

    //停止播放
    private QPlayerError stopAudio() {
        try {
            pauseFlag = true;
            if(mediaPlayer != null){
                mediaPlayer.stop();
                mediaPlayer.release();
            }
            mediaPlayer = null;
            state.set(STATE_INIT);
            return null;
        } catch (Exception e) {
            return null;
//            return new QPlayerError(e,QPLAYER_ERROR_CODE_EXCEPTION);
        }
    }

    private void deleteAudioFile() {
        if (!isDeleteFlag){
            playingFile = null;
            return;
        }

        if (playingFile != null
                && playingFile.exists()) {
            if(!playingFile.delete() ) {
                Log.e(TAG, "remove file " + playingFile.getName() + " fail");
            }
            playingFile = null;
        }
    }

    //stop后清理所有音频文件
    private void deleteAllAudioFile() {
        try {
            File f = null;
            do {
                if (audioQueue.size() < 1) {
                    f = null;
                    break;
                }
                f = audioQueue.poll(200, TimeUnit.MILLISECONDS);
                boolean b  = isDeleteFlags.get(0);
                isDeleteFlags.remove(0);

                if (b && f != null && f.exists()) {
                    f.delete();
                    f = null;
                }
            }while (f != null);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Log.e(TAG, "io Exception:" + e);
        }
        isDeleteFlags.clear();
        audioQueue.clear();
    }




    /**
     * 停止播放
     */
    public QPlayerError StopPlay() {

        QPlayerError error = stopAudio();
        deleteAllAudioFile();
        this.audioTextQueue.clear();
        this.utteranceIdQueue.clear();
        isPlaying.set(false);
        pauseFlag = false;
        //调用回调
        if (callback != null) {
            callback.onTTSPlayStop();
        }
        return error;
    }

    public QPlayerError PausePlay(){
        if(mediaPlayer == null){
            return null;
        }

        //处于播放状态时 才会调pause
        if(state.get() == STATE_PLAY){
            pauseFlag = true;
            mediaPlayer.pause();
            if (callback != null) {
                callback.onTTSPlayPause();
            }
        }
        return null;
    }

    public QPlayerError ResumePlay(){

        if (!pauseFlag) return null;
        pauseFlag = false;
        //设置为播放状态
        if(isExceptionCompletion){
            //点击pause 时调 mediaPlayer方法调用的方法
            playOnCompletionException();
            isExceptionCompletion = false;
        }else{
            if(mediaPlayer == null){
                return null;
            }
            mediaPlayer.start();
        }
        if (callback != null) {
            callback.onTTSPlayResume();
        }
        return null;
    }

}

标签:return,mediaPlayer,冲刺,callback,private,new,null
From: https://www.cnblogs.com/qmz-znv2/p/18251977

相关文章

  • 蓝桥杯备考冲刺必刷题(C++) | 3792 小蓝的礼物
    学习C++从娃娃抓起!记录下蓝桥杯备考比赛学习过程中的题目,记录每一个瞬间。附上汇总贴:蓝桥杯备考冲刺必刷题(C++)|汇总-CSDN博客【题目描述】小蓝想要给她的女朋友小桥买一份生日礼物,她来到了一家礼品店。在店里,她看中了N......
  • 冲刺08
    fragment_register_select_role.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_......
  • 冲刺03
    这是我们的任务看板我负责了安卓端页面部分activity_child_main代码如下:<?xmlversion="1.0"encoding="utf-8"?><androidx.drawerlayout.widget.DrawerLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http:/......
  • 冲刺04
    activity_login.xml<?xmlversion="1.0"encoding="UTF-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layou......
  • 冲刺05
    activity_parent.xml<?xmlversion="1.0"encoding="UTF-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layo......
  • 冲刺07
    fragment_reg_parent_fill_inf.xml<?xmlversion="1.0"encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"androi......
  • 冲刺06fragment_reg_chi_fil_inf.xml
    <?xmlversion="1.0"encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent&......
  • 五一冲刺(政策查询系统)1
    今日课上的政策查询系统极限测试寥寥草草将功能实现了,把内部代码进行完善一下完整代码:index.jsp<%@pagecontentType="text/html;charset=UTF-8"language="java"%><!DOCTYPEhtml><htmllang="en"xmlns:th="http://www.thymeleaf.org"><......
  • 五一冲刺(政策查询系统)2
    packageDao;importBean.Menu;importBean.bean;importBean.policy;importDBUtil.dbutil;importorg.apache.ibatis.io.Resources;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibatis.session.SqlSessionFactory;importorg.apache.ibatis.ses......
  • 蓝桥杯备考冲刺必刷题(C++) | 3791 珠宝的最大交替和
    学习C++从娃娃抓起!记录下蓝桥杯备考比赛学习过程中的题目,记录每一个瞬间。附上汇总贴:蓝桥杯备考冲刺必刷题(C++)|汇总-CSDN博客【题目描述】小莉是一位珠宝设计师,她非常喜欢玩珠子。她有一个长度为N......