知乎专栏 |
目录
// 写入文本 // 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; } }