美文网首页三方
Android 腾讯互动直播集成

Android 腾讯互动直播集成

作者: __素颜__ | 来源:发表于2018-10-22 16:21 被阅读495次

    最近刚用完互动直播sdk 做完直播,简单记录下。

    官网:https://cloud.tencent.com/product/ilvb

    随心博 demo:https://cloud.tencent.com/document/product/268/7658

    直播接口:https://cloud.tencent.com/document/product/268/7685

    直播API: https://zhaoyang21cn.github.io/iLiveSDK_Help/android_help/

    一.旁路推流

    首先先弄懂“旁路”的概念

    凡是通过url观看的直播都是旁路直播,旁路直播要进行旁路推流,否则旁路直播无法观看直播。

    向在app内我们是通过joinRoom() 加入的房间,所以不属于旁路直播。

    二.主播方

    大概流程是这个样子,根据自己需求进行变更

    1.向服务器请求房间号。

    2.根据房间号,创建房间。

     public void createRoom() {
            ILVLiveRoomOption hostOption = new ILVLiveRoomOption(”主播ID“)
                    .roomDisconnectListener(this)
                    .autoCamera(true)
                    .videoMode(ILiveConstants.VIDEOMODE_BSUPPORT)
                    .controlRole(CurLiveInfo.getCurRole())
                    //角色是主播 一定不能设置错  主播走核心机房  观众走边缘机房
    //                .controlRole("LiveMaster")
                    .videoRecvMode(AVRoomMulti.VIDEO_RECV_MODE_SEMI_AUTO_RECV_CAMERA_VIDEO);
         
            int ret = ILVLiveManager.getInstance().createRoom(“房间ID”, hostOption, new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                
                   if (getView()!=null)
                       getView().enterRoomComplete(MySelfInfo.getInstance().getIdStatus(), true);
                    ILiveLog.d(TAG, "ILVB-SXB|startEnterRoom->create room sucess");
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                
                   if (getView()!=null)
                       getView().errRoomFail();
                    ILiveLog.d(TAG, "ILVB-SXB|createRoom->create room failed:" + module + "|" + errCode + "|" + errMsg);
                }
            });
      
        }
    

    4.创建房间成功后有旁路直播开启旁路推流。

    
    public void pushStream() {
            /**
             * 旁路直播 退出房间时必须退出推流。否则会占用后台channel。
             */
            ILivePushOption option = new ILivePushOption();
            option.encode(ILivePushOption.Encode.HLS);
    //        option.setRecordFileType(ILivePushOption.RecordFileType.RECORD_HLS_FLV_MP4);
            option.setRecordFileType(ILivePushOption.RecordFileType.RECORD_HLS_FLV_MP4);
    //        option.channelName("跟ios协商");
            //推流格式 到时候跟ios统一
            pushStream(option);
    
    
        }
    /**
         * 开启推流
         *
         * @param option
         */
        public void pushStream(ILivePushOption option) {
            if (!isPushed) {
                ILiveRoomManager.getInstance().startPushStream(option, new ILiveCallBack<ILivePushRes>() {
                    @Override
                    public void onSuccess(ILivePushRes data) {
    //                List<ILivePushUrl> liveUrls = data.getUrls();
                        Log.i("pushStream", "推流成功!!!!!!!");
                     
                    }
    
                    @Override
                    public void onError(String module, int errCode, String errMsg) {
                        Log.i("pushStream", "推流失败!!!!!!!");
                    }
                });
            }
        }
    

    5.退出房间前:在房间发送自定义消息告诉观众主播要退出房间,方便观众端切换主播已离开界面,并停止推流。

    发送自定义消息退出房间

     public void sendExitRoomMSG() {
            ILVCustomCmd cmd = new ILVCustomCmd();
            cmd.setCmd(Constans.AVIMCMD_EXITLIVE);
            cmd.setParam(sendExitRoomJson());
            cmd.setType(ILVText.ILVTextType.eGroupMsg);
            ILVLiveManager.getInstance().sendCustomCmd(cmd, new ILiveCallBack<TIMMessage>() {
                @Override
                public void onSuccess(TIMMessage data) {
                 
                   if (isPushed) {
                        stopStream();
                    }
                    callExitRoom();
    
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                }
    
            });
        }
    

    停止推流

     /**
         * 退出直播的时候关闭推流
         */
        public void stopStream() {
            ILiveRoomManager.getInstance().stopPushStream(streamChannelID, new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                    SxbLog.e(TAG, "stopPush->success");
                    isPushed = false;
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                    SxbLog.e(TAG, "stopPush->failed:" + module + "|" + errCode + "|" + errMsg);
                }
            });
    
        }
    

    6.退出房间。

    private void callExitRoom() {
            ILiveSDK.getInstance().getAvVideoCtrl().setLocalVideoPreProcessCallback(null);
            quitLiveRoom();
        }
    
    

    三.观众方

    大概流程是这个样子,根据自己需求进行变更。

    1.向服务器请求房间号。

    2.根据房间号加入房间。

     //加入房间
        public void joinRoom(int roomId) {
            ILVLiveManager.getInstance().quitRoom(null);
            this.rommId = roomId + "";
            ILVLiveRoomOption memberOption = new ILVLiveRoomOption(ConfigUtils.getUid())
                    .autoCamera(false)
                    .roomDisconnectListener(this)
                    .videoMode(ILiveConstants.VIDEOMODE_BSUPPORT)
                    .controlRole("Guest")
                    .authBits(AVRoomMulti.AUTH_BITS_JOIN_ROOM | AVRoomMulti.AUTH_BITS_RECV_AUDIO | AVRoomMulti.AUTH_BITS_RECV_CAMERA_VIDEO | AVRoomMulti.AUTH_BITS_RECV_SCREEN_VIDEO)
                    .videoRecvMode(AVRoomMulti.VIDEO_RECV_MODE_SEMI_AUTO_RECV_CAMERA_VIDEO)
                    .autoMic(false);
            int ret = ILVLiveManager.getInstance().joinRoom(roomId, memberOption, new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                    ILiveLog.d(TAG, "ILVB-Suixinbo|startEnterRoom->join room sucess");
                    if (null != mGuestLiveView)
    
                        mGuestLiveView.enterRoomComplete(true);
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                    LogUtils.d("suyan", "===========加入房间失败" + module + errCode + errMsg);
                    if (null != mGuestLiveView) {
                        mGuestLiveView.enterRoomComplete(false);
                    }
                }
            });
        }
    

    3.加入房间成功后,在房间发送自定义消息,告诉房间内有人加入,方便主播统计目前的房间人数。

     /**
         * 发送信令,点赞,进入房间
         */
    
        public int sendGroupCmd(int cmd, String param) {
            ILVCustomCmd customCmd = new ILVCustomCmd();
            //1.传cmd
            customCmd.setCmd(cmd);
            //2.创建自定义数据
            String json = sendCusJsn();
            //3.传自定义数据
            customCmd.setParam(json);
            //4.设置自定义类型
            customCmd.setType(ILVText.ILVTextType.eGroupMsg);
            return sendCmd(customCmd);
        }
    

    4.退出房间前:发送房间自定义消息,告诉主播观众退出,方便主播统计目前的在线人数。

    5.退出直播间。

      public void startExitRoom() {
            if (ILiveSDK.getInstance() != null && ILiveSDK.getInstance().getAvVideoCtrl() != null) {
                ILiveSDK.getInstance().getAvVideoCtrl().setLocalVideoPreProcessCallback(null);
            }
            quitLiveRoom();
        }
     private void quitLiveRoom() {
            ILVLiveManager.getInstance().quitRoom(new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                    //1.回调给页面
                    if (null != mGuestLiveView) {
                        LogUtils.d("suyan", "=========退出成功");
                        mGuestLiveView.quiteRoomComplete(true);
                    }
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                    if (null != mGuestLiveView) {
                        mGuestLiveView.quiteRoomComplete(false);
                    }
                }
            });
        }
    

    自己封装了一个观众端的使用类,也是根据互动直播demo改的

    package com.jyjt.ydyl.txlive.presenters;
    
    import android.app.Activity;
    import android.content.Context;
    import android.text.TextUtils;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonSyntaxException;
    import com.jyjt.ydyl.Entity.LiveCusEntity;
    import com.jyjt.ydyl.tools.ConfigUtils;
    import com.jyjt.ydyl.tools.Constans;
    import com.jyjt.ydyl.tools.LogUtils;
    import com.jyjt.ydyl.tools.ToastUtil;
    import com.jyjt.ydyl.txlive.LiveDetailActivity;
    import com.jyjt.ydyl.txlive.event.LiveMessageEvent;
    import com.jyjt.ydyl.txlive.views.GuestLiveView;
    import com.tencent.TIMConversationType;
    import com.tencent.TIMCustomElem;
    import com.tencent.TIMElem;
    import com.tencent.TIMElemType;
    import com.tencent.TIMGroupSystemElem;
    import com.tencent.TIMGroupSystemElemType;
    import com.tencent.TIMMessage;
    import com.tencent.av.sdk.AVRoomMulti;
    import com.tencent.ilivesdk.ILiveCallBack;
    import com.tencent.ilivesdk.ILiveConstants;
    import com.tencent.ilivesdk.ILiveSDK;
    import com.tencent.ilivesdk.core.ILiveLog;
    import com.tencent.ilivesdk.core.ILiveRoomManager;
    import com.tencent.ilivesdk.core.ILiveRoomOption;
    import com.tencent.livesdk.ILVCustomCmd;
    import com.tencent.livesdk.ILVLiveConstants;
    import com.tencent.livesdk.ILVLiveManager;
    import com.tencent.livesdk.ILVLiveRoomOption;
    import com.tencent.livesdk.ILVText;
    import com.tencent.openqq.protocol.imsdk.im_common;
    
    import org.json.JSONObject;
    import org.json.JSONTokener;
    
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 观众端,直播帮助类
     * <p>
     * 1.加入房间
     * 2.离开房间
     * 3.发送点赞,和加入房间指令
     * 4.解析传过来的自定义消息(点赞,其他成员加入,用户退出直播, 达到上限,主播回来了)
     * 5.房间链接断开监听
     * <p>
     * 苏艳
     */
    
    public class GuestLiveHelper implements ILiveRoomOption.onRoomDisconnectListener, Observer {
        private final String TAG = "LiveHelper";
        private GuestLiveView mGuestLiveView;
        public Activity mContext;
        private String rommId;
        Gson gson;
    
        public GuestLiveHelper(Activity context, GuestLiveView mGuestLiveView) {
            mContext = context;
            this.mGuestLiveView = mGuestLiveView;
            LiveMessageEvent.getInstance().addObserver(this);
            GsonBuilder builder = new GsonBuilder();
            gson = builder.create();
        }
    
        //加入房间
        public void joinRoom(int roomId) {
            ILVLiveManager.getInstance().quitRoom(null);
            this.rommId = roomId + "";
            ILVLiveRoomOption memberOption = new ILVLiveRoomOption(ConfigUtils.getUid())
                    .autoCamera(false)
                    .roomDisconnectListener(this)
                    .videoMode(ILiveConstants.VIDEOMODE_BSUPPORT)
                    .controlRole("Guest")
                    .authBits(AVRoomMulti.AUTH_BITS_JOIN_ROOM | AVRoomMulti.AUTH_BITS_RECV_AUDIO | AVRoomMulti.AUTH_BITS_RECV_CAMERA_VIDEO | AVRoomMulti.AUTH_BITS_RECV_SCREEN_VIDEO)
                    .videoRecvMode(AVRoomMulti.VIDEO_RECV_MODE_SEMI_AUTO_RECV_CAMERA_VIDEO)
                    .autoMic(false);
            int ret = ILVLiveManager.getInstance().joinRoom(roomId, memberOption, new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                    ILiveLog.d(TAG, "ILVB-Suixinbo|startEnterRoom->join room sucess");
                    if (null != mGuestLiveView)
    
                        mGuestLiveView.enterRoomComplete(true);
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                    LogUtils.d("suyan", "===========加入房间失败" + module + errCode + errMsg);
                    if (null != mGuestLiveView) {
                        mGuestLiveView.enterRoomComplete(false);
                    }
                }
            });
        }
    
        //退出房间
        public void startExitRoom() {
            if (ILiveSDK.getInstance() != null && ILiveSDK.getInstance().getAvVideoCtrl() != null) {
                ILiveSDK.getInstance().getAvVideoCtrl().setLocalVideoPreProcessCallback(null);
            }
            quitLiveRoom();
        }
    
        private void quitLiveRoom() {
            ILVLiveManager.getInstance().quitRoom(new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                    //1.回调给页面
                    if (null != mGuestLiveView) {
                        LogUtils.d("suyan", "=========退出成功");
                        mGuestLiveView.quiteRoomComplete(true);
                    }
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
                    if (null != mGuestLiveView) {
                        mGuestLiveView.quiteRoomComplete(false);
                    }
                }
            });
        }
    
    
        /**
         * 发送信令,点赞,进入房间
         */
    
        public int sendGroupCmd(int cmd, String param) {
            ILVCustomCmd customCmd = new ILVCustomCmd();
            //1.传cmd
            customCmd.setCmd(cmd);
            //2.创建自定义数据
            String json = sendCusJsn();
            //3.传自定义数据
            customCmd.setParam(json);
            //4.设置自定义类型
            customCmd.setType(ILVText.ILVTextType.eGroupMsg);
            return sendCmd(customCmd);
        }
    
        //邀请上麦用的,暂时用不到
        public int sendC2CCmd(final int cmd, String param, String destId) {
            ILVCustomCmd customCmd = new ILVCustomCmd();
            customCmd.setDestId(destId);
            customCmd.setCmd(cmd);
            customCmd.setParam(param);
            customCmd.setType(ILVText.ILVTextType.eC2CMsg);
            return sendCmd(customCmd);
        }
    
        private int sendCmd(final ILVCustomCmd cmd) {
            return ILVLiveManager.getInstance().sendCustomCmd(cmd, new ILiveCallBack() {
                @Override
                public void onSuccess(Object data) {
                    LogUtils.d(TAG, "suyan" + cmd.getCmd() + "|" + cmd.getParam() + "====发送成功");
                }
    
                @Override
                public void onError(String module, int errCode, String errMsg) {
    //                Toast.makeText(mContext, "sendCmd->failed:" + module + "|" + errCode + "|" + errMsg, Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        @Override
        public void onRoomDisconnect(int errCode, String errMsg) {
            if (null != mGuestLiveView) {
                //房间异常退出,通常指断网,或者没电
                mGuestLiveView.roomDisconnect(errCode, errMsg);
            }
        }
    
        // 解析文本消息
        private void processTextMsg(LiveMessageEvent.SxbMsgInfo info) {
            if (null == info.data || !(info.data instanceof ILVText)) {
                return;
            }
            ILVText text = (ILVText) info.data;
            if (text.getType() == ILVText.ILVTextType.eGroupMsg
                    && !text.getDestId().equals(rommId)) {
                if (TextUtils.isEmpty(rommId)) {
                    LogUtils.d("suyan","========当前的roomid为空");
                }
                return;
            }
    
            String name = info.senderId;
            if (null != info.profile && !TextUtils.isEmpty(info.profile.getNickName())) {
                name = info.profile.getNickName();
            }
    
            if (null != mGuestLiveView)
                mGuestLiveView.refreshText(text.getText(), name);
        }
    
        // 解析自定义信令
        private void processCmdMsg(LiveMessageEvent.SxbMsgInfo info) {
            if (null == info.data || !(info.data instanceof ILVCustomCmd)) {
                return;
            }
            ILVCustomCmd cmd = (ILVCustomCmd) info.data;
            if (cmd.getType() == ILVText.ILVTextType.eGroupMsg
                    && !cmd.getDestId().equals(rommId)) {
                if (TextUtils.isEmpty(rommId)) {
                    LogUtils.d("suyan","========当前的roomid为空");
                }
                return;
            }
    
            String name = info.senderId;
            if (null != info.profile && !TextUtils.isEmpty(info.profile.getNickName())) {
                name = info.profile.getNickName();
            }
    
            handleCustomMsg(cmd.getCmd(), cmd.getParam(), info.senderId, name);
        }
    
        private void processOtherMsg(LiveMessageEvent.SxbMsgInfo info) {
            if (null == info.data || !(info.data instanceof TIMMessage)) {
                return;
            }
            TIMMessage currMsg = (TIMMessage) info.data;
    
            // 过滤非当前群组消息
            if (currMsg.getConversation() != null && currMsg.getConversation().getPeer() != null) {
                if (currMsg.getConversation().getType() == TIMConversationType.Group
                        && !rommId.equals(currMsg.getConversation().getPeer())) {
                    if (TextUtils.isEmpty(rommId)) {
                        LogUtils.d("suyan","========当前的roomid为空");
                    }
                    return;
                }
            }
    
            for (int j = 0; j < currMsg.getElementCount(); j++) {
                if (currMsg.getElement(j) == null)
                    continue;
                TIMElem elem = currMsg.getElement(j);
                TIMElemType type = elem.getType();
    
    
                //系统消息
                if (type == TIMElemType.GroupSystem) {  // 群组解散消息
                    if (TIMGroupSystemElemType.TIM_GROUP_SYSTEM_DELETE_GROUP_TYPE == ((TIMGroupSystemElem) elem).getSubtype()) {
                        if (null != mGuestLiveView)
                            mGuestLiveView.dismissGroup("host", null);
                    }
                } else if (type == TIMElemType.Custom) {
                    try {
                        final String strMagic = "/index/article";
                        String customText = new String(((TIMCustomElem) elem).getData(), "UTF-8");
                        if (!customText.startsWith(strMagic))   // 检测前缀
                            continue;
                        JSONTokener jsonParser = new JSONTokener(customText.substring(strMagic.length() + 1));
                        JSONObject json = (JSONObject) jsonParser.nextValue();
                        String action = json.optString("action", "");
                        if (action.equals("force_exit_room") || action.equals("force_disband_room")) {
                            JSONObject objData = json.getJSONObject("data");
                            String strRoomNum = objData.optString("room_num", "");
                            if (strRoomNum.equals(String.valueOf(ILiveRoomManager.getInstance().getRoomId()))) {
                                if (null != mGuestLiveView) {
                                    mGuestLiveView.forceQuitRoom("管理员已将房间解散或将您踢出房间!");
                                }
                            }
                        }
                    } catch (Exception e) {
                    }
                }
            }
        }
    
        @Override
        public void update(Observable observable, Object o) {
    
            LiveMessageEvent.SxbMsgInfo info = (LiveMessageEvent.SxbMsgInfo) o;
            LogUtils.d("suyan", "======收到消息" + info.msgType);
            switch (info.msgType) {
                case LiveMessageEvent.MSGTYPE_TEXT:
                    processTextMsg(info);
                    break;
                case LiveMessageEvent.MSGTYPE_CMD:
                    processCmdMsg(info);
                    break;
                case LiveMessageEvent.MSGTYPE_OTHER:
                    LogUtils.d("suyan", "=======其他消息");
                    processOtherMsg(info);
                case LiveMessageEvent.MSGTYPE_DDETAIL:
                    LogUtils.d("suyan", "=======刷新房间数据");
                    processDetailMsg(info);
                    break;
            }
        }
    
        // 解析自定义信令
        private void processDetailMsg(LiveMessageEvent.SxbMsgInfo info) {
            if (null != info && !TextUtils.isEmpty(info.senderId)) {
                if (null != mGuestLiveView) {
                    mGuestLiveView.refreshData(info.senderId);
                }
            }
    
        }
    
        private void handleCustomMsg(int action, String param, String identifier, String nickname) {
            LogUtils.d(TAG, "handleCustomMsg->action: " + action);
            if (null == mGuestLiveView) {
                return;
            }
            LiveCusEntity mliveCusEntity = updateGson(param);
            if (mliveCusEntity != null) {
                LogUtils.d("suyan", "===========解析后的数据" + mliveCusEntity.getContent().getLike_num() + "=" + mliveCusEntity.getContent().getOnline_num() + "=" + mliveCusEntity.getUser().getUid());
            }
            switch (action) {
                case Constans.AVIMCMD_PRAISE://点赞
                    mGuestLiveView.refreshGoodLike();
                    break;
                case Constans.AVIMCMD_ENTERLIVE://其他成员加入
                    mGuestLiveView.memberJoin(identifier, nickname);
                    break;
                case Constans.AVIMCMD_EXITLIVE: //用户退出直播
                    mGuestLiveView.hostOffline(identifier, nickname);
                    break;
                case ILVLiveConstants.ILVLIVE_CMD_LINKROOM_LIMIT:   // 达到上限
                    LogUtils.d("suyan","========到达上限");
                    break;
                case Constans.AVIMCMD_HOST_BACK://主播回来了
                    LogUtils.d("suyan","========主播回来了");
                    //昵称:nickname  id:identifier
                case Constans.AVIMCMD_PRAISE_TOTAL://观众进入房间,主播发送现在的总点赞数
                    try {
                        if (mliveCusEntity != null && !TextUtils.isEmpty(mliveCusEntity.getContent().getLike_num())) {
                            mGuestLiveView.refreshTotalGoodLike(Long.parseLong(mliveCusEntity.getContent().getLike_num()));
                        }
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                    }
                default:
                    break;
            }
        }
    
        //解析jsong
        public LiveCusEntity updateGson(String jsonTest) {
            if (!TextUtils.isEmpty(jsonTest)) {
                LiveCusEntity mLiveCusEntity;
                try {
                    mLiveCusEntity = gson.fromJson(jsonTest, LiveCusEntity.class);
                    return mLiveCusEntity;
                } catch (JsonSyntaxException e) {
                    e.printStackTrace();
                    return null;
                }
            } else {
                return null;
            }
        }
    
        //发送json
        public String sendCusJsn() {
            LiveCusEntity liveCusEntity = new LiveCusEntity();
            LiveCusEntity.LiveContent mLiveContent = new LiveCusEntity.LiveContent();
            liveCusEntity.setContent(mLiveContent);
            LiveCusEntity.User mUser = new LiveCusEntity.User();
            mUser.setUid(ConfigUtils.getUid());
            liveCusEntity.setUser(mUser);
            String json = gson.toJson(liveCusEntity, LiveCusEntity.class);
            LogUtils.d("suyan", "==========自定义数据" + json);
            return json;
        }
    
        //销毁
        public void onDestory() {
            mGuestLiveView = null;
            mContext = null;
            LiveMessageEvent.getInstance().deleteObserver(this);
            ILVLiveManager.getInstance().quitRoom(null);
            ILiveRoomManager.getInstance().onDestory();
            ILVLiveManager.getInstance().onDestory();
        }
    }
    
    

    相关文章

      网友评论

        本文标题:Android 腾讯互动直播集成

        本文链接:https://www.haomeiwen.com/subject/zzcgzftx.html