知乎专栏 |
// 写入文本 // byte[] content= "你好".getBytes(); // String params = "data_type=text"; // AIUIMessage msg = new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0, "tag=write_data_1", content); // mAIUIAgent.sendMessage(msg); AIUIMessage aiuiMessage = new AIUIMessage(0, 0, 0, "", null); aiuiMessage.msgType = AIUIConstant.CMD_WRITE; aiuiMessage.arg1 = 0; aiuiMessage.arg2 = 0; // 在输入参数中设置tag,则对应结果中也将携带该tag,可用于关联输入输出 aiuiMessage.params = "data_type=text,tag=text-tag"; aiuiMessage.data = "天气".getBytes(StandardCharsets.UTF_8); mAIUIAgent.sendMessage(aiuiMessage);
package cn.netkiller.aiui; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; import com.iflytek.aiui.player.common.data.MetaItem; import com.iflytek.aiui.player.core.AIUIPlayer; import com.iflytek.aiui.player.core.PlayState; import com.iflytek.aiui.player.core.PlayerListener; import com.iflytek.aiui.player.players.KuwoMusicRemote; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import kotlin.Unit; import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function2; public class MusicSkillComponent { private static final String TAG = MusicSkillComponent.class.getSimpleName(); private static MusicSkillComponent musicSkillComponent = null; private static String kuwoParams = null; private static int playListIndex = 0; //当前播放歌曲序号 private static JSONArray mPlayList = null; //播放列表 private static AIUIPlayer mAIUIPlayer = null; private static KuwoMusicRemote kuwoRemote = null; private final Context context; private final PlayerListener mPlayListener = new PlayerListener() { @Override public void onMediaUrl(@NonNull JSONObject jsonObject) { Log.d(TAG, "onMediaUrl: " + jsonObject); } @Override public void onPlayerReady() { Log.i(TAG, "onPlayerReady()"); } @Override public void onStateChange(@NonNull PlayState state) { Log.i(TAG, "onStateChange: PlayState is" + state); switch (state) { case READY: Log.d(TAG, "AIUIPlayer 播放准备就绪"); break; case PLAYING: Log.d(TAG, "播放"); break; case PAUSED: Log.d(TAG, "停止"); break; case LOADING: Log.d(TAG, "音乐加载中……"); break; case COMPLETE: Log.d(TAG, "继续"); startPlayMusic(); break; case IDLE: long currentPosition = mAIUIPlayer.getCurrentPosition(); Log.d(TAG, String.format("CurrentPosition: %l", currentPosition)); break; case ERROR: Log.d(TAG, "播放出错"); break; default: break; } } @Override public void onMediaChange(@NonNull MetaItem metaItem) { String songName = metaItem.getTitle(); //歌名 String author = metaItem.getAuthor(); //作者 playListIndex = getPlayIndex(songName); Log.d(TAG, "onMediaChange: " + metaItem); } @Override public void onError(int code, @NonNull String info) { Log.e(TAG, "onError 播放出错:" + code + " ,错误信息为:" + info); // 真实错误码需要从 info 中解析 "track link failed code: 40006 description:" if (info.isEmpty()) { if (code == 200001) { Log.d(TAG, "歌曲\"" + "" + "\"播放出错: " + code + "\nINFO:产品未通过酷我验收,仅支持获取奇数id资源\n"); if (!mAIUIPlayer.next()) { } } } } @Override public void onPlayerRelease() { } }; public MusicSkillComponent(Context context) { this.context = context; initSDK(); } public synchronized static MusicSkillComponent getInstance(Context context) { if (musicSkillComponent == null) { musicSkillComponent = new MusicSkillComponent(context); } return musicSkillComponent; } public boolean previous() { if (mAIUIPlayer != null) { return mAIUIPlayer.previous(); } return false; } public boolean next() { if (mAIUIPlayer != null) { return mAIUIPlayer.next(); } return false; } public void pause() { if (mAIUIPlayer == null) { return; } if (mAIUIPlayer.getCurrentState() == PlayState.PLAYING) { mAIUIPlayer.pause(); } } public void resume() { if (mAIUIPlayer == null) { return; } if (mAIUIPlayer.getCurrentState() == PlayState.PAUSED) { mAIUIPlayer.resume(); } } public boolean play(@NonNull JSONObject object) { // Log.d(TAG, object.toString()); try { JSONArray musics = object.getJSONArray("result"); if (null != musics) { mPlayList = musics; playListIndex = 0; } return startPlayMusic(); } catch (JSONException e) { e.printStackTrace(); } return false; } public void initSDK() { //TODO 开发者需要实现生成sn的代码,参考:https://www.yuque.com/iflyaiui/zzoolv/tgftb5 //注意事项1: sn每台设备需要唯一!!!!WakeupEngine的sn和AIUI的sn要一致 //注意事项2: 获取的值要保持稳定,否则会重复授权,浪费授权量 String serialNumber = "test"; String appId = "c84e1ddb"; String appKey = "7a1583c3190b83fe4d62573ee9cfbfc1"; //TODO 设置酷我音乐SDK设置相关参数,appid和appkey请使用自己的进行开发,并且与aiui.cfg一致 kuwoParams = "appId=" + appId + ",appKey=" + appKey + "," + "serialNumber=" + serialNumber + ",deviceModel=" + serialNumber + ",userId=" + serialNumber; if (null == kuwoRemote) { kuwoRemote = new KuwoMusicRemote(kuwoParams); // 酷我SDK日志开关 :true 打开,false 关闭 kuwoRemote.setDebug(false); if (null != kuwoRemote) { Log.i(TAG, "KuwoRemote 初始化成功"); } } if (null == mAIUIPlayer) { mAIUIPlayer = new AIUIPlayer(context, kuwoParams); // 播放前焦点占用设置 mAIUIPlayer.setParameter("customAudioFocus", "true"); // 回调信息设置 mAIUIPlayer.addListener(mPlayListener); // AIUIPlayer SDK调试日志设置 :true 打开,false 关闭 mAIUIPlayer.setDebug(false); // 初始化播放器 mAIUIPlayer.initialize(); Log.i(TAG, "AIUIPlayer 初始化成功"); } } public void release() { mPlayList = null; if (null != mAIUIPlayer) { mAIUIPlayer.release(); mAIUIPlayer = null; } if (null != kuwoRemote) { kuwoRemote.destroy(); kuwoRemote = null; } } private void activate() { // if (isActivated) { //// showToast("当前设备已激活酷我音乐"); // return; // } kuwoRemote.active(() -> { Log.i(TAG, "激活成功"); return null; }, (errCode, errInfo) -> { Log.i(TAG, "激活失败,错误码为:" + errCode + " ,信息为: " + errInfo); return null; }); } private void login() { //酷我不强制用户登陆,开发者自己实现登陆代码,可参考下方酷狗音乐代码,改一下接口 // Intent intent = new Intent(KuwoDemo.this, LoginActivity.class); // startActivityForResult(intent, 3); } private void logout() { kuwoRemote.logout(new Function0<Unit>() { @Override public Unit invoke() { Log.i(TAG, "酷我账号退出成功"); // LoginBtn.setText("手机登陆"); return null; } }, new Function2<Integer, String, Unit>() { @Override public Unit invoke(Integer errCode, String errInfo) { Log.i(TAG, "酷我账号退出失败,错误码为:" + errCode + " ,信息为: " + errInfo); return null; } }); } public void stop() { if (mAIUIPlayer != null) { mAIUIPlayer.stop(); } } private boolean startPlayMusic() { if (null == mPlayList || mPlayList.length() == 0) { Log.w(TAG, "播放列表为空"); return false; } Log.i(TAG, "mPlayList is: " + mPlayList.toString()); mAIUIPlayer.reset(); return mAIUIPlayer.play(mPlayList, "musicX", "", false, playListIndex); } //构建虚假播放信息测试AIUIPlayer SDK播放是否可以正常调用 // private void mockPlayMusic() { // try { // JSONArray musiclist = new JSONArray(); // JSONObject music = new JSONObject(); // music.put("source", "kuwo"); // music.put("songname", "天地龙鳞"); // music.put("itemid", "353833243"); // musiclist.put(0, music); // mPlayList = musiclist; // } catch (JSONException e) { // e.printStackTrace(); // } // // if (null == mPlayList || mPlayList.length() == 0) { //// showToast("播放列表为空"); // return; // } // Log.i(TAG, "mPlayList is:\n" + mPlayList.toString()); // mAIUIPlayer.reset(); // mAIUIPlayer.play(mPlayList, "musicX", "", false, playListIndex); // } // 获取当前播放下标 private int getPlayIndex(String songName) { if (mPlayList != null) { try { String playData = null; for (int i = 0; i < mPlayList.length(); i++) { playData = mPlayList.getJSONObject(i).toString(); if (playData.contains(songName)) { return i; } } } catch (JSONException e) { e.printStackTrace(); return 0; } } return 0; } }
通过 itemId 获取 audio URL
kuwoRemote.getAudioUrl("26383685", "128kmp3", new Function1<AudioUrl, Unit>() { @Override public Unit invoke(AudioUrl audioUrl) { Log.d(TAG, audioUrl.toString()); return null; } }, new Function2<Integer, String, Unit>() { @Override public Unit invoke(Integer code, String msg) { Log.d(TAG, "Code: " + code + ", Msg: " + msg); return null; } });
日志输出结果
AudioUrl(expiretime=, itemid=26383685, source=kuwo, audiopath=http://other.player.ri01.sycdn.kuwo.cn/6dcbdb125c72dfff3978fe29ab50fdd4/64eeef6f/resource/n2/27/48/2060696053.mp3)
package cn.netkiller.skill; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.util.Log; import com.alibaba.fastjson.JSONObject; import java.text.NumberFormat; import java.text.ParseException; public class ControlSkillComponent { private static final String TAG = ControlSkillComponent.class.getName(); private final Context context; private MusicSkillComponent musicSkillComponent = null; public ControlSkillComponent(Context context, JSONObject object) { this.context = context; musicSkillComponent = MusicSkillComponent.getInstance(context); Log.d(TAG, "控制技能: " + object); String semanticIntent = object.getString("intent"); switch (semanticIntent) { case "PAUSE": musicSkillComponent.pause(); break; case "CHOOSE_NEXT": musicSkillComponent.next(); break; case "CHOOSE_PREVIOUS": musicSkillComponent.previous(); break; case "VOLUME_MINUS": this.volume("VOLUME_MINUS"); break; case "VOLUME_PLUS": this.volume("VOLUME_PLUS"); break; case "VOLUME_MIN": this.volume("VOLUME_MIN"); break; case "VOLUME_MAX": this.volume("VOLUME_MAX"); break; case "MUTE": this.volume("MUTE"); break; case "VOLUME_SET": JSONObject slots = (JSONObject) object.getJSONArray("slots").get(0); String stringPercent = slots.getString("value"); try { double doublePercent = (Double) NumberFormat.getPercentInstance().parse(stringPercent); // int percent = floatPercent.intValue(); this.volume(doublePercent); Log.d(TAG, String.valueOf(doublePercent)); } catch (ParseException e) { Log.e(TAG, e.toString()); } break; case "SETTING_OPEN": Log.e(TAG, "设置无线网络"); this.wifi(); break; case "SHUTDOWN": break; case "RESET": break; } } public void wifi() { // context.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); Intent intent = new Intent(); intent.setAction("androad.network.wlan"); intent.putExtra("message", ""); context.sendBroadcast(intent); } private void volume(String control) { AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); // int minVolume = audioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC); int minVolume = 10; int stepVolume = 5; int currentMusicVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); int currentTTSVolume = audioManager.getStreamVolume(AudioManager.STREAM_ALARM); switch (control) { case "VOLUME_MINUS": //步进减小 currentMusicVolume -= stepVolume; if (currentMusicVolume < minVolume) { currentMusicVolume = minVolume; } currentTTSVolume -= stepVolume; if (currentTTSVolume < minVolume) { currentTTSVolume = minVolume; } break; case "VOLUME_PLUS": //步进累加 currentMusicVolume += stepVolume; if (currentMusicVolume >= maxVolume) { currentMusicVolume = maxVolume; } currentTTSVolume += stepVolume; if (currentTTSVolume > maxVolume) { currentTTSVolume = maxVolume; } break; case "VOLUME_MAX": // 最大 currentMusicVolume = currentTTSVolume = maxVolume; break; case "VOLUME_MIN": //最小 currentMusicVolume = currentTTSVolume = minVolume; break; case "MUTE": //静音 currentMusicVolume = currentTTSVolume = minVolume; break; } audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentMusicVolume, AudioManager.FLAG_SHOW_UI); audioManager.setStreamVolume(AudioManager.STREAM_ALARM, currentTTSVolume, AudioManager.FLAG_PLAY_SOUND); Log.d(TAG, String.format("volume: currentMusicVolume=%s, currentTTSVolume=%s, maxVolume=%s", currentMusicVolume, currentTTSVolume, maxVolume)); } private void volume(double percent) { if (percent < 0.3) { return; } AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int currentMusicVolume, currentTTSVolume; currentMusicVolume = currentTTSVolume = (int) (maxVolume * percent); audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentMusicVolume, AudioManager.FLAG_SHOW_UI); audioManager.setStreamVolume(AudioManager.STREAM_ALARM, currentTTSVolume, AudioManager.FLAG_PLAY_SOUND); Log.d(TAG, String.format("volume: currentMusicVolume=%s, currentTTSVolume=%s, maxVolume=%s", currentMusicVolume, currentTTSVolume, maxVolume)); } }
implementation 'com.belerweb:pinyin4j:2.5.1'
package cn.netkiller.ai.utils; import android.util.Log; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; public class Pinyin { private static final String TAG = Pinyin.class.getName(); public static String toPinyin(String hanzi) { char[] chars = hanzi.trim().toCharArray(); String hanyupinyin = ""; //输出格式设置 HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); /** * 输出大小写设置 * * LOWERCASE:输出小写 * UPPERCASE:输出大写 */ defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); /** * 输出音标设置 * * WITH_TONE_MARK:直接用音标符(必须设置WITH_U_UNICODE,否则会抛出异常) * WITH_TONE_NUMBER:1-4数字表示音标 * WITHOUT_TONE:没有音标 */ // defaultFormat.setToneType(HanyuPinyinToneType.WITH_TONE_MARK); // 必须设置WITH_U_UNICODE,否则会抛出异常 defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); /** * 特殊音标ü设置 * * WITH_V:用v表示ü * WITH_U_AND_COLON:用"u:"表示ü * WITH_U_UNICODE:直接用ü */ // defaultFormat.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE); defaultFormat.setVCharType(HanyuPinyinVCharType.WITH_V); // 中文的正则表达式 String hanziRegex = "[\\u4E00-\\u9FA5]+"; try { for (int i = 0; i < chars.length; i++) { // 判断为中文,则转换为汉语拼音 if (String.valueOf(chars[i]).matches(hanziRegex)) { hanyupinyin += PinyinHelper .toHanyuPinyinStringArray(chars[i], defaultFormat)[0]; } else { // 不为中文,则不转换 hanyupinyin += chars[i]; } } } catch (BadHanyuPinyinOutputFormatCombination e) { Log.e(TAG, "字符不能转成汉语拼音"); } return hanyupinyin; } }
package com.iflytek.mscv5plusdemo; import androidx.appcompat.app.AppCompatActivity; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.Window; import android.widget.Toast; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechEvent; import com.iflytek.cloud.SpeechSynthesizer; import com.iflytek.cloud.SynthesizerListener; import com.iflytek.speech.setting.TtsSettings; public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); tts(); } private InitListener initListener = new InitListener() { @Override public void onInit(int code) { Log.d("TAG", "InitListener init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案"); } else { // 初始化成功,之后可以调用startSpeaking方法 // 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成, // 正确的做法是将onCreate中的startSpeaking调用移至这里 } } }; private SpeechSynthesizer speechSynthesizer; private void setParam() { // Log.d("", String.valueOf(speechSynthesizer.isSpeaking())); // 清空参数 speechSynthesizer.setParameter(SpeechConstant.PARAMS, null); //设置合成 // if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) { //设置使用云端引擎 speechSynthesizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); //设置发音人 speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan"); // } else if (mEngineType.equals(SpeechConstant.TYPE_LOCAL)) { // //设置使用本地引擎 // speechSynthesizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL); // //设置发音人资源路径 // speechSynthesizer.setParameter(ResourceUtil.TTS_RES_PATH, getResourcePath()); // //设置发音人 // speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME, voicerLocal); // } else { // speechSynthesizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_XTTS); // //设置发音人资源路径 // speechSynthesizer.setParameter(ResourceUtil.TTS_RES_PATH, getResourcePath()); // //设置发音人 // speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME, voicerXtts); // } //mTts.setParameter(SpeechConstant.TTS_DATA_NOTIFY,"1");//支持实时音频流抛出,仅在synthesizeToUri条件下支持 //设置合成语速 // speechSynthesizer.setParameter(SpeechConstant.SPEED, mSharedPreferences.getString("speed_preference", "50")); // //设置合成音调 // speechSynthesizer.setParameter(SpeechConstant.PITCH, mSharedPreferences.getString("pitch_preference", "50")); // //设置合成音量 // speechSynthesizer.setParameter(SpeechConstant.VOLUME, mSharedPreferences.getString("volume_preference", "50")); // //设置播放器音频流类型 // speechSynthesizer.setParameter(SpeechConstant.STREAM_TYPE, mSharedPreferences.getString("stream_preference", "3")); // mTts.setParameter(SpeechConstant.STREAM_TYPE, AudioManager.STREAM_MUSIC+""); // 设置播放合成音频打断音乐播放,默认为true speechSynthesizer.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true"); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 speechSynthesizer.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); speechSynthesizer.setParameter(SpeechConstant.TTS_AUDIO_PATH, getExternalFilesDir("msc").getAbsolutePath() + "/tts.pcm"); } public void tts() { speechSynthesizer = SpeechSynthesizer.createSynthesizer(this, initListener); // 设置参数 // setParam(); // Log.d(TAG, "准备点击: " + System.currentTimeMillis()); String text = "你好小虎"; setParam(); speechSynthesizer.stopSpeaking(); int code = speechSynthesizer.startSpeaking(text, synthesizerListener); // /** // * 只保存音频不进行播放接口,调用此接口请注释startSpeaking接口 // * text:要合成的文本,uri:需要保存的音频全路径,listener:回调接口 // */ // String path = getExternalFilesDir("msc").getAbsolutePath() + "/tts.pcm"; // int code = mTts.synthesizeToUri(text, path, mTtsListener); if (code != ErrorCode.SUCCESS) { showTip("语音合成失败,错误码: " + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案"); } // // // mTts.pauseSpeaking(); // // mTts.resumeSpeaking(); } SynthesizerListener synthesizerListener = new SynthesizerListener() { @Override public void onSpeakBegin() { showTip("开始播放"); // Log.d(TtsDemo.TAG, "开始播放:" + System.currentTimeMillis()); } @Override public void onSpeakPaused() { showTip("暂停播放"); } @Override public void onSpeakResumed() { showTip("继续播放"); } @Override public void onBufferProgress(int percent, int beginPos, int endPos, String info) { // 合成进度 // mPercentForBuffering = percent; // showTip(String.format(getString(R.string.tts_toast_format),mPercentForBuffering, mPercentForPlaying)); } @Override public void onSpeakProgress(int percent, int beginPos, int endPos) { // 播放进度 // mPercentForPlaying = percent; // showTip(String.format(getString(R.string.tts_toast_format), // mPercentForBuffering, mPercentForPlaying)); } @Override public void onCompleted(SpeechError error) { if (error == null) { showTip("播放完成"); } else { showTip(error.getPlainDescription(true)); } } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因 // 若使用本地能力,会话id为null if (SpeechEvent.EVENT_SESSION_ID == eventType) { String sid = obj.getString(SpeechEvent.KEY_EVENT_AUDIO_URL); // Log.d(TAG, "session id =" + sid); } //实时音频流输出参考 /*if (SpeechEvent.EVENT_TTS_BUFFER == eventType) { byte[] buf = obj.getByteArray(SpeechEvent.KEY_EVENT_TTS_BUFFER); Log.e("MscSpeechLog", "buf is =" + buf); }*/ } }; private void showTip(final String str) { Toast mToast; // if (mToast != null) { // mToast.cancel(); // } mToast = Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT); mToast.show(); } }
package cn.netkiller.album.religion.ai; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import com.iflytek.cloud.RequestListener; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechEvent; import com.iflytek.cloud.VoiceWakeuper; import com.iflytek.cloud.WakeuperListener; import com.iflytek.cloud.WakeuperResult; import com.iflytek.cloud.util.ResourceUtil; import java.nio.charset.StandardCharsets; import cn.netkiller.album.religion.ContextHolder; import cn.assets.album.religion.R; public class Wakeup { private static final String TAG = Wakeup.class.getSimpleName(); private final int curThresh = 1450; private final String threshStr = "门限值:"; private final String keep_alive = "1"; private final String ivwNetMode = "0"; private final Context context; // 查询资源请求回调监听 private final RequestListener requestListener = new RequestListener() { @Override public void onEvent(int eventType, Bundle params) { // 以下代码用于获取查询会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因 //if(SpeechEvent.EVENT_SESSION_ID == eventType) { // Log.d(TAG, "sid:"+params.getString(SpeechEvent.KEY_EVENT_SESSION_ID)); //} } @Override public void onCompleted(SpeechError error) { if (error != null) { Log.d(TAG, "error:" + error.getErrorCode()); showTip(error.getPlainDescription(true)); } } @Override public void onBufferReceived(byte[] buffer) { try { String resultInfo = new String(buffer, StandardCharsets.UTF_8); Log.d(TAG, "resultInfo:" + resultInfo); // JSONTokener tokener = new JSONTokener(resultInfo); // JSONObject object = new JSONObject(tokener); // // int ret = object.getInt("ret"); // if (ret == 0) { // String uri = object.getString("dlurl"); // String md5 = object.getString("md5"); // Log.d(TAG, "uri:" + uri); // Log.d(TAG, "md5:" + md5); // showTip("请求成功"); // } } catch (Exception e) { e.printStackTrace(); } } }; private VoiceWakeuper voiceWakeuper; // 唤醒结果内容 private String resultString; private final WakeuperListener wakeuperListener = new WakeuperListener() { @Override public void onResult(WakeuperResult result) { Log.d(TAG, "onResult"); try { String text = result.getResultString(); Log.d(TAG, text); // JSONObject object; // object = new JSONObject(text); // StringBuffer buffer = new StringBuffer(); // buffer.append("【RAW】 " + text); // buffer.append("\n"); // buffer.append("【操作类型】" + object.optString("sst")); // buffer.append("\n"); // buffer.append("【唤醒词id】" + object.optString("id")); // buffer.append("\n"); // buffer.append("【得分】" + object.optString("score")); // buffer.append("\n"); // buffer.append("【前端点】" + object.optString("bos")); // buffer.append("\n"); // buffer.append("【尾端点】" + object.optString("eos")); // resultString = buffer.toString(); showTip(text); } catch (Exception e) { resultString = "结果解析出错"; e.printStackTrace(); } } @Override public void onError(SpeechError error) { showTip(error.getPlainDescription(true)); } @Override public void onBeginOfSpeech() { } @Override public void onEvent(int eventType, int isLast, int arg2, Bundle obj) { // EVENT_RECORD_DATA 事件仅在 NOTIFY_RECORD_DATA 参数值为 真 时返回 if (eventType == SpeechEvent.EVENT_RECORD_DATA) { final byte[] audio = obj.getByteArray(SpeechEvent.KEY_EVENT_RECORD_DATA); Log.i(TAG, "ivw audio length: " + audio.length); } } @Override public void onVolumeChanged(int volume) { } }; // 设置门限值 : 门限值越低越容易被唤醒 public Wakeup() { this.context = ContextHolder.getContext(); // String param = "appid=" + context.getString(R.string.app_id) + "," + SpeechConstant.ENGINE_MODE + "=" + SpeechConstant.MODE_MSC; // SpeechUtility.createUtility(context, param); voiceWakeuper = VoiceWakeuper.createWakeuper(context, null); if (null == voiceWakeuper) { // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688 Toast.makeText(context , "创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化" , Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "准备唤醒", Toast.LENGTH_LONG).show(); // 清空参数 voiceWakeuper.setParameter(SpeechConstant.PARAMS, null); // 唤醒门限值,根据资源携带的唤醒词个数按照“id:门限;id:门限”的格式传入 voiceWakeuper.setParameter(SpeechConstant.IVW_THRESHOLD, "0:1450"); // 设置唤醒模式 voiceWakeuper.setParameter(SpeechConstant.IVW_SST, "wakeup"); // 设置持续进行唤醒 voiceWakeuper.setParameter(SpeechConstant.KEEP_ALIVE, "1"); // 设置闭环优化网络模式 voiceWakeuper.setParameter(SpeechConstant.IVW_NET_MODE, "1"); // 设置唤醒资源路径 voiceWakeuper.setParameter(SpeechConstant.IVW_RES_PATH, getResource()); // 设置唤醒录音保存路径,保存最近一分钟的音频 voiceWakeuper.setParameter(SpeechConstant.IVW_AUDIO_PATH, context.getExternalFilesDir("msc").getAbsolutePath() + "/ivw.wav"); voiceWakeuper.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); // 如有需要,设置 NOTIFY_RECORD_DATA 以实时通过 onEvent 返回录音音频流字节 //voiceWakeuper.setParameter( SpeechConstant.NOTIFY_RECORD_DATA, "1" ); // 启动唤醒 /* voiceWakeuper.setParameter(SpeechConstant.AUDIO_SOURCE, "-1");*/ } } public void startListening(WakeuperListener wakeuperListener) { //非空判断,防止因空指针使程序崩溃 voiceWakeuper = VoiceWakeuper.getWakeuper(); if (voiceWakeuper != null) { resultString = ""; voiceWakeuper.startListening(wakeuperListener); } else { showTip("唤醒未初始化"); } } private void stopListening() { voiceWakeuper = VoiceWakeuper.getWakeuper(); if (voiceWakeuper != null) { voiceWakeuper.stopListening(); } } public void cancel() { // 销毁合成对象 voiceWakeuper = VoiceWakeuper.getWakeuper(); if (voiceWakeuper != null) { voiceWakeuper.cancel(); } } public void destroy() { // 销毁合成对象 voiceWakeuper = VoiceWakeuper.getWakeuper(); if (voiceWakeuper != null) { voiceWakeuper.destroy(); } } private String getResource() { final String resPath = ResourceUtil.generateResourcePath(context, ResourceUtil.RESOURCE_TYPE.assets, "ivw/" + context.getString(R.string.app_id) + ".jet"); Log.d(TAG, "resPath: " + resPath); return resPath; } /** * 查询闭环优化唤醒资源 * 请在闭环优化网络模式1或者模式2使用 */ // public void queryResource() { // int ret = voiceWakeuper.queryResource(getResource(), requestListener); // showTip("updateResource ret:" + ret); // } private void showTip(final String str) { // runOnUiThread(new Runnable() { // @Override // public void run() { Toast.makeText(context.getApplicationContext(), str, Toast.LENGTH_SHORT).show(); // } // }); } }