前段時間開發出一個語音連麥的小功能demo,平常自己玩玩,和小夥伴語音連麥,很好用,哈哈哈。使用的也是anyRTC的API功能。廢話少說,開整!
不知道anyRTC的,可以點擊這裏瞭解官網,Android文檔!
demo下載
代碼還沒有上傳到GitHub,日後上傳更新demo。
demo演示
看波視頻~ 省的給大家截圖,視頻來的實在,簡單明瞭
主播端:點擊觀看
遊客端:點擊觀看
代碼實現
這個是結合anyRTC的後臺服務的,這個也是服務也是對外開放的
1.註冊登錄
我這邊使用的楊振杰封裝的HTTP:
implementation 'com.yanzhenjie:okalle:0.1.7'
- 註冊
public void signUp(){
JSONObject params = new JSONObject();
try {
params.put("sex",0);
params.put("userName", Build.MODEL);
} catch (JSONException e) {
e.printStackTrace();
}
Kalle.post(String.format(Constants.SERVER,"user/signUp"))
.addHeader(Constants.CONTENT_TYPE,"application/json")
.body(new JsonBody(params.toString()))
.perform(new SimpleCallback<String>() {
@Override
public void onResponse(SimpleResponse<String, String> response) {
Log.i(TAG, "onResponse:signUp response ="+response.succeed());
if (response.succeed().contains("success")){
signUpBean =gson.fromJson(response.succeed(),SignUpBean.class);
if (signUpBean !=null){
String uid =signUpBean.getData().getUid();
SpUtil.putString(Constants.UID,uid);
signIn(uid);
}
}
}
@Override
public void onException(Exception e) {
super.onException(e);
e.printStackTrace();
}
});
}
- 登錄
public void signIn(String uid){
JSONObject params = new JSONObject();
try {
params.put("cType",1);
params.put("pkg",ARApplication.the().getApplicationContext().getPackageName());
params.put("uid",uid);
} catch (JSONException e) {
e.printStackTrace();
}
Kalle.post(String.format(Constants.SERVER,"user/signIn"))
.addHeader(Constants.CONTENT_TYPE,"application/json")
.body(new JsonBody(params.toString()))
.perform(new SimpleCallback<String>() {
@Override
public void onResponse(SimpleResponse<String, String> response) {
Log.i(TAG, "onResponse: signIn success ="+response.succeed());
if (response.succeed().contains("success")){
signInBean =gson.fromJson(response.succeed(),SignInBean.class);
getRoomList(signInBean);
if (loginListener !=null){
loginListener.loginSuccess(signInBean);
}
}
}
@Override
public void onException(Exception e) {
super.onException(e);
e.printStackTrace();
}
});
}
2.主播創建和獲取房間
- 創建房間
a.首先需要初始化Rtc和Rtm實例
//創建RTC實例,appid 可以去anyRTC官網註冊
mRtcEngine =RtcEngine.create(mContext, appId,mEventHandler);
//創建RTM實例,appid同上
mRtmClient =RtmClient.createInstance(mContext, appId,mClientListener);
b.然後登錄AR RTM
public void login(String rtmToken,String userId, final ResultCallback<Void> callback){
if (mRtmClient !=null){
if (mIsLogin) {
if (callback != null)
callback.onSuccess(null);
return;
}
mRtmClient.login(rtmToken, String.valueOf(userId), new ResultCallback<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "rtm login success");
mIsLogin = true;
if (callback != null)
callback.onSuccess(aVoid);
}
@Override
public void onFailure(ErrorInfo errorInfo) {
Log.e(TAG, String.format("rtm join %s", errorInfo.getErrorDescription()));
mIsLogin = false;
if (callback != null)
callback.onFailure(errorInfo);
}
});
}
}
c.然後主播加入房間
加入RTC和RTM頻道
RTC:音視頻通話
RTM:實時消息
//加入RTM頻道,完成主播和遊客實時消息的發送
public void joinChannel(final String channelId, ResultCallback<Void> callback) {
if (mRtmClient != null) {
leaveChannel();
Log.w(TAG, String.format("joinChannel %s", channelId));
try {
final RtmChannel rtmChannel = mRtmClient.createChannel(channelId, mChannelListener);
if (rtmChannel == null) return;
rtmChannel.join(new ResultCallback<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "rtm join success");
mRtmChannel = rtmChannel;
getMembers();
}
@Override
public void onFailure(ErrorInfo errorInfo) {
Log.e(TAG, String.format("rtm join %s", errorInfo.getErrorDescription()));
//AlertUtil.showToast("RTM login failed, see the log to get more info");
mRtmChannel = rtmChannel;
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
//加入RTC頻道,實現主播和遊客語音連麥
public void joinChannel(String rtcToken,String channelId, String userId) {
if (mRtcEngine != null){
mRtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
mRtcEngine.joinChannel(rtcToken, channelId, null, userId);
mRtcEngine.muteLocalAudioStream(false);
//mRtcEngine.setEnableSpeakerphone(true);
createStreamingInstance();
}
}
- 獲取房間列表
//獲取房間列表
public void getRoomList(SignInBean signInBean){
JSONObject params = new JSONObject();
try {
params.put("count", Integer.MAX_VALUE);
params.put("rType", Constants.R_TYPE_LIVE);
} catch (JSONException e) {
e.printStackTrace();
}
Kalle.post(String.format(Constants.SERVER,"user/getRoomList"))
.addHeader(Constants.CONTENT_TYPE,"application/json")
.addHeader(Constants.AUTHORIZATION,"Bearer "+signInBean.getData().getUserToken())
.body(new JsonBody(params.toString()))
.perform(new SimpleCallback<String>() {
@Override
public void onResponse(SimpleResponse<String, String> response) {
Log.i(TAG, "onResponse: getRoomList ="+response.succeed());
if (response.succeed().contains("success")){
roomListBean =gson.fromJson(response.succeed(), RoomListBean.class);
if (roomListener !=null){
roomListener.showRoomList(roomListBean);
}
}
}
@Override
public void onException(Exception e) {
super.onException(e);
e.printStackTrace();
Log.i(TAG, "onException: ===> ="+e.getMessage());
}
});
}
注:上面展示語音連麥的部分功能,創建房間的是主播,下拉刷新出來加入房間的是遊客
3.遊客加入房間
加入房間第一步就是加入RTM頻道,然後申請上麥後,主播同意後,再加入RTC頻道,進行語音通話。
- 加入房間
//調用服務接口,加入房間,接入有人進入房間
public void joinRoom(String roomId,String roomName,String pullRtmpUrl){
JSONObject params = new JSONObject();
try {
params.put("cType",1);
params.put("pkg",ARApplication.the().getApplicationContext().getPackageName());
params.put("roomId",roomId);
} catch (JSONException e) {
e.printStackTrace();
}
Kalle.post(String.format(Constants.SERVER,"user/joinRoom"))
.addHeader(Constants.CONTENT_TYPE,"application/json")
.addHeader(Constants.AUTHORIZATION,"Bearer "+signInBean.getData().getUserToken())
.body(new JsonBody(params.toString()))
.perform(new SimpleCallback<String>() {
@Override
public void onResponse(SimpleResponse<String, String> response) {
Log.i(TAG, "onResponse: joinRoom data ="+response.succeed());
if (response.succeed().contains("success")){
joinRoomBean =gson.fromJson(response.succeed(),JoinRoomBean.class);
if (roomListener !=null){
roomListener.joinRoom(joinRoomBean,roomId,roomName,pullRtmpUrl);
}
}
}
@Override
public void onException(Exception e) {
super.onException(e);
e.printStackTrace();
Log.i(TAG, "onException: e="+e.getMessage());
}
});
}
然後進行RTM加入房間,和上面主播加入房間一樣。
- 申請上麥流程
a.遊客點擊上麥,給主播發一條RTM消息,通知主播“我要上麥”
//點擊按鈕事件,進行發送消息
try {
jsonObject.put("cmd","apply");
} catch (JSONException e) {
e.printStackTrace();
}
mChatRoomManager.getRtmManager().sendMessageToPeer(mAnchorId,jsonObject.toString(),null);
//發送P to P消息
public void sendMessageToPeer(final String userId, final String content, final ResultCallback<Void> callback) {
if (TextUtils.isEmpty(userId)) return;
if (mRtmClient != null) {
RtmMessage message = mRtmClient.createMessage(content);
mRtmClient.sendMessageToPeer(userId, message, null, new ResultCallback<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, String.format("sendMessageToPeer %s %s", userId, content));
if (callback != null)
callback.onSuccess(aVoid);
}
@Override
public void onFailure(ErrorInfo errorInfo) {
Log.e(TAG, String.format("sendMessageToPeer %s", errorInfo.getErrorDescription()));
if (callback != null)
callback.onFailure(errorInfo);
}
});
}
}
b.主播收到消息,然後彈出對話框,然後進行:確定上麥、拒絕上麥的操作!
//主播收到消息,進行的邏輯操作!
applyDialog =new ApplyDialog(this, "連麥申請", mChannelData.getName(userId) + "申請連麥",
"拒絕", "確定", () -> {
try {
object.put("cmd",Constants.MIC_REJECT_LINE);
} catch (JSONException e) {
e.printStackTrace();
}
mChatRoomManager.getRtmManager().sendMessageToPeer(userId,object.toString(),null);
}, () -> {
try {
object.put("cmd",Constants.MIC_ACCEPT_LINE);
} catch (JSONException e) {
e.printStackTrace();
}
mChatRoomManager.getRtmManager().sendMessageToPeer(userId,object.toString(),null);
});
applyDialog.show();
c.主播同意上麥後,遊客加入RTC頻道,進行連麥。
//遊客收到同意上麥的操作邏輯
micState = MIC_STATE_DOWN;
isJoinMic =true;
autoTipDialog =new AutoTipDialog(this,R.drawable.success_tip,"同意上麥");
autoTipDialog.show();
mJoinMic.setImageResource(R.drawable.down_mic);
String rtcToken = Optional.ofNullable(serverManager)
.map(ARServerManager::getJoinRoomBean)
.map(JoinRoomBean::getData)
.map(JoinRoomBean.DataBean::getRoom)
.map(JoinRoomBean.DataBean.RoomBeans::getRtcToken)
.orElse("");
Log.i(TAG, "onAcceptLineUpdated: rtcToken ="+rtcToken);
mChatRoomManager.joinRtcChannel(rtcToken,roomId); //j加入RTC頻道
mediaPlayerKit.mute(true);
if (isMic){
mChatMic.setImageResource(R.drawable.mic_close);
}else {
mChatMic.setImageResource(R.drawable.mic_open);
}
mChatRoomManager.getRtcManager().muteLocalAudioStream(isMic);
if (isSpeaker){
mSpeaker.setImageResource(R.drawable.speaker_close);
}else {
mSpeaker.setImageResource(R.drawable.speaker_open);
}
mChatRoomManager.getRtcManager().getRtcEngine().setEnableSpeakerphone(!isSpeaker);
rlMusic.setVisibility(View.VISIBLE);
mChatMic.setVisibility(View.VISIBLE);
mSpeaker.setVisibility(View.GONE);
mFrameLayout.setVisibility(View.VISIBLE);
rvGuestLog.setVisibility(View.GONE);
mLogList.add(new LogBean(R.drawable.circle,getDate(),"上麥成功"));
這個時候就可以和你的小夥伴進行語音操作啦!
最後釋放RTC和RTM資源,主播退出刪除房間,遊客退出房間就可以啦!
如有不懂的地方,歡迎大家留言。
作者:anyRTC-東慕雨