編輯:關於Android編程
1.由於粘貼了較大的代碼,造成內容比較長,可能會花費您較長的時間。
2.項目裡面沒有做權限判斷,所以如果發現有頁面發生崩潰可能是權限沒有打開,請打開權限後再進行嘗試。
3.錄制的GIF畫質好差,真實環境很好。
主播端 : /uploadfile/2016/0919/20160919100731416.gif
游客端 : /uploadfile/2016/0919/20160919100745416.gif
從github上Android" target="_blank">https://github.com/AnyRTC/RTMPCHybirdEngine-Android下載下來,導入AS,結構如下圖所示。
MainActivity.java
RTMPCHybird.Inst().Init(getApplicationContext()); RTMPCHybird.Inst().InitEngineWithAnyrtcInfo("你的開發者ID", "liveDemo", "LslMfUyvcW8hv6NgY0n8FOWf5t1K+YWpoMzRsqwkBiE", "d6ff4b7d1b549f497a0b94cf500fd549");
以上的四個參數可以在https://www.anyrtc.io注冊開發者賬號並創建一個應用可得,如下圖所示。你可以把它放在繼承Application的onCreate()方法中。
MainActivity.java
RTMPCHttpSDK.GetLiveList(this, RTMPCHybird.Inst().GetHttpAddr(), 你的開發者ID", "liveDemo", "d6ff4b7d1b549f497a0b94cf500fd549", mRTMPCHttpCallback); private RTMPCHttpSDK.RTMPCHttpCallback mRTMPCHttpCallback = new RTMPCHttpSDK.RTMPCHttpCallback() { @Override public void OnRTMPCHttpOK(String strContent) { mRecyclerViewUtils.endRefreshing(); try { listLive.clear(); JSONObject liveJson = new JSONObject(strContent); JSONArray liveList = liveJson.getJSONArray("LiveList"); JSONArray memberList = liveJson.getJSONArray("LiveMembers"); for (int i = 0; i < liveList.length(); i++) { LiveItemBean bean = new LiveItemBean(); JSONObject itemJson = new JSONObject(liveList.getString(i)); bean.setmHosterId(itemJson.getString("hosterId")); bean.setmRtmpPullUrl(itemJson.getString("rtmp_url")); bean.setmHlsUrl(itemJson.getString("hls_url")); bean.setmLiveTopic(itemJson.getString("topic")); bean.setmAnyrtcId(itemJson.getString("anyrtcId")); bean.setmMemNumber(memberList.getInt(i)); listLive.add(bean); } mAdapter.setDatas(listLive); } catch (JSONException e) { e.printStackTrace(); } } @Override public void OnRTMPCHttpFailed(int code) { } };
以上代碼可以獲取所有正在直播列表名單
RTMPUrlHelper.java
public class RTMPUrlHelper { /** * rtmp 推流地址 */ public static final String RTMP_PUSH_URL = "rtmp://192.168.7.207:1935/live/%s"; /** * rtmp 拉流地址 */ public static final String RTMP_PULL_URL = "rtmp://192.168.7.207:1935/live/%s"; /** * hls 地址 */ public static final String HLS_URL = "http://192.169.7.207/live/%s.m3u8"; /** * 分享頁面url地址 */ public static final String SHARE_WEB_URL = "http://123.59.68.21/rtmpc-demo/?%s"; }
PreStartLiveActivity.java
String anyrtcId = RTMPCHttpSDK.getRandomString(12); String rtmpPushUrl = String.format(RTMPUrlHelper.RTMP_PUSH_URL, anyrtcId); String rtmpPullUrl = String.format(RTMPUrlHelper.RTMP_PULL_URL, anyrtcId); String hlsUrl = String.format(RTMPUrlHelper.HLS_URL, anyrtcId); JSONObject item = new JSONObject(); try { item.put("hosterId", "hostID"); item.put("rtmp_url", rtmpPullUrl); item.put("hls_url", hlsUrl); item.put("topic", topic); item.put("anyrtcId", anyrtcId); } catch (JSONException e) { e.printStackTrace(); } Bundle bundle = new Bundle(); bundle.putString("hosterId", "hostID"); bundle.putString("rtmp_url", rtmpPushUrl); bundle.putString("hls_url", hlsUrl); bundle.putString("topic", topic); bundle.putString("andyrtcId", anyrtcId); bundle.putString("userData", item.toString()); Intent intent = new Intent(this, HosterActivity.class); intent.putExtras(bundle); startActivity(intent);
HosterActivity.java
mHosterId = getIntent().getExtras().getString("hosterId"); mRtmpPushUrl = getIntent().getExtras().getString("rtmp_url"); mAnyrtcId = getIntent().getExtras().getString("andyrtcId"); mUserData = getIntent().getExtras().getString("userData"); mHlsUrl = getIntent().getExtras().getString("hls_url"); mTopic = getIntent().getExtras().getString("topic");
這裡的R.id.rl_rtmpc_videos表示打開手機攝像頭捕獲的像呈現的地方,如下圖所示。
HosterActivity.java
mVideoView = new RTMPCVideoView((RelativeLayout) findViewById(R.id.rl_rtmpc_videos), RTMPCHybird.Inst().Egl(), true); mVideoView.setBtnCloseEvent(mBtnVideoCloseEvent); mHosterKit = new RTMPCHosterKit(this, mHosterListener); { VideoRenderer render = mVideoView.OnRtcOpenLocalRender(); mHosterKit.SetVideoCapturer(render.GetRenderPointer(), true); }
{ // Create and audio manager that will take care of audio routing, // audio modes, audio device enumeration etc. mRtmpAudioManager = RTMPAudioManager.create(this, new Runnable() { // This method will be called each time the audio state (number // and // type of devices) has been changed. @Override public void run() { onAudioManagerChangedState(); } }); // Store existing audio settings and change audio mode to // MODE_IN_COMMUNICATION for best possible VoIP performance. mRtmpAudioManager.init(); mRtmpAudioManager.setAudioDevice(RTMPAudioManager.AudioDevice.SPEAKER_PHONE); } mStartRtmp = true; /** * 開始推流 */ mHosterKit.StartPushRtmpStream(mRtmpPushUrl); /** * 建立RTC連線連接 */ mHosterKit.OpenRTCLine(mAnyrtcId, mHosterId, mUserData);
mHosterKit = new RTMPCHosterKit(this, mHosterListener);
這句代碼是主播直播的回調接口,可以做連麥、取消連麥、接收消息和彈幕消息、實時觀看人數和人員上下線等。實用的操作一般再此實行。
HosterActivity.java
/** * 主播回調信息接口 */ private RTMPCAbstractHoster mHosterListener = new RTMPCAbstractHoster() { /** * rtmp連接成功 */ @Override public void OnRtmpStreamOKCallback() { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.txt_rtmp_connection_status)).setText(R.string.str_rtmp_connect_success); } }); } /** * rtmp 重連次數 * @param times 重連次數 */ @Override public void OnRtmpStreamReconnectingCallback(final int times) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.txt_rtmp_connection_status)).setText(String.format(getString(R.string.str_reconnect_times), times)); } }); } /** * rtmp 推流狀態 * @param delayMs 推流延時 * @param netBand 推流碼流 */ @Override public void OnRtmpStreamStatusCallback(final int delayMs, final int netBand) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.txt_rtmp_status)).setText(String.format(getString(R.string.str_rtmp_status), delayMs, netBand)); } }); } /** * rtmp推流失敗回調 * @param code */ @Override public void OnRtmpStreamFailedCallback(int code) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.txt_rtmp_connection_status)).setTextColor(R.color.yellow); ((TextView) findViewById(R.id.txt_rtmp_connection_status)).setText(R.string.str_rtmp_connect_failed); } }); } /** * rtmp 推流關閉回調 */ @Override public void OnRtmpStreamClosedCallback() { finish(); } /** * RTC 連接回調 * @param code 0: 連接成功 * @param strErr 原因 */ @Override public void OnRTCOpenLineResultCallback(final int code, String strErr) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { if (code == 0) { ((TextView) findViewById(R.id.txt_rtc_connection_status)).setText(R.string.str_rtc_connect_success); } else { ((TextView) findViewById(R.id.txt_rtc_connection_status)).setTextColor(R.color.yellow); ((TextView) findViewById(R.id.txt_rtc_connection_status)).setText(R.string.str_rtmp_connect_failed); } } }); } /** * 游客有申請連線回調 * * @param strLivePeerID * @param strCustomID * @param strUserData */ @Override public void OnRTCApplyToLineCallback(final String strLivePeerID, final String strCustomID, final String strUserData) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ShowDialog(HosterActivity.this, strLivePeerID, strCustomID); } }); } /** * 視頻連線超過4人時回調 * @param strLivePeerID * @param strCustomID * @param strUserData */ @Override public void OnRTCLineFullCallback(final String strLivePeerID, String strCustomID, String strUserData) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(HosterActivity.this, getString(R.string.str_connect_full), Toast.LENGTH_LONG).show(); mHosterKit.RejectRTCLine(strLivePeerID, true); } }); } /** * 游客掛斷連線回調 * @param strLivePeerID */ @Override public void OnRTCCancelLineCallback(String strLivePeerID) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(HosterActivity.this, getString(R.string.str_line_disconnect), Toast.LENGTH_LONG).show(); } }); } /** * RTC 連接關閉回調 * @param code 207:請去AnyRTC官網申請賬號,如有疑問請聯系客服! * @param strReason */ @Override public void OnRTCLineClosedCallback(final int code, String strReason) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { if (code == 207) { Toast.makeText(HosterActivity.this, getString(R.string.str_apply_anyrtc_account), Toast.LENGTH_LONG).show(); finish(); } } }); } /** * 連線接通時的視頻圖像回調; * @param strLivePeerID */ @Override public void OnRTCOpenVideoRenderCallback(final String strLivePeerID) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { final VideoRenderer render = mVideoView.OnRtcOpenRemoteRender(strLivePeerID); if (null != render) { mHosterKit.SetRTCVideoRender(strLivePeerID, render.GetRenderPointer()); } } }); } /** * 連線關閉時的視頻圖像回調; * @param strLivePeerID */ @Override public void OnRTCCloseVideoRenderCallback(final String strLivePeerID) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { mHosterKit.SetRTCVideoRender(strLivePeerID, 0); mVideoView.OnRtcRemoveRemoteRender(strLivePeerID); } }); } /** * 消息回調 * @param strCustomID 消息的發送者id * @param strCustomName 消息的發送者昵稱 * @param strCustomHeader 消息的發送者頭像url * @param strMessage 消息內容 */ @Override public void OnRTCUserMessageCallback(final String strCustomID, final String strCustomName, final String strCustomHeader, final String strMessage) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { addChatMessageList(new ChatMessageBean(strCustomID, strCustomName, "", strMessage)); } }); } /** * 彈幕回調 * @param strCustomID 彈幕的發送者id * @param strCustomName 彈幕的發送者昵稱 * @param strCustomHeader 彈幕的發送者頭像url * @param strBarrage 彈幕的內容 */ @Override public void OnRTCUserBarrageCallback(final String strCustomID, final String strCustomName, final String strCustomHeader, final String strBarrage) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { addChatMessageList(new ChatMessageBean(strCustomID, strCustomName, "", strBarrage)); IDanmakuItem item = new DanmakuItem(HosterActivity.this, new SpannableString(strBarrage), mDanmakuView.getWidth(), 0, R.color.yellow_normol, 18, 1); mDanmakuView.addItemToHead(item); } }); } /** * 直播觀看總人數回調 * @param totalMembers 觀看總人數 */ @Override public void OnRTCMemberListWillUpdateCallback(final int totalMembers) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.txt_watcher_number)).setText(String.format(getString(R.string.str_live_watcher_number), totalMembers)); } }); } /** * 人員上下線回調 * @param strCustomID * @param strUserData */ @Override public void OnRTCMemberCallback(final String strCustomID, final String strUserData) { HosterActivity.this.runOnUiThread(new Runnable() { @Override public void run() { try { JSONObject userData = new JSONObject(strUserData); addChatMessageList(new ChatMessageBean(userData.getString("nickName"), "", userData.getString("headUrl"), "")); } catch (JSONException e) { e.printStackTrace(); } } }); } @Override public void OnRTCMemberListUpdateDoneCallback() { } };
接下來就要說對應這些回調的方法了,這裡可以做關閉直播、直播分享、切換攝像頭和發送消息。
HosterActivity.java
public void OnBtnClicked(View btn) { if (btn.getId() == R.id.btn_close) { mStartRtmp = false; mHosterKit.StopRtmpStream(); finish(); } else if (btn.getId() == R.id.btn_copy_hls) { int index = mHlsUrl.lastIndexOf("/"); int lastIndex = mHlsUrl.lastIndexOf("."); String shareUrl = String.format(RTMPUrlHelper.SHARE_WEB_URL, mHlsUrl.substring(index + 1, lastIndex)); mShareHelper.shareWeiXin(mTopic, shareUrl); } else if (btn.getId() == R.id.btn_switch_camera) { mHosterKit.SwitchCamera(); } else if (btn.getId() == R.id.btn_send_message) { String message = editMessage.getText().toString(); editMessage.setText(""); if (message.equals("")) { return; } if (mCheckBarrage.isChecked()) { mHosterKit.SendBarrage(mNickname, "", message); IDanmakuItem item = new DanmakuItem(HosterActivity.this, new SpannableString(message), mDanmakuView.getWidth(), 0, R.color.yellow_normol, 18, 1); mDanmakuView.addItemToHead(item); } else { mHosterKit.SendUserMsg(mNickname, "", message); } addChatMessageList(new ChatMessageBean(mNickname, mNickname, "", message)); } else if (btn.getId() == R.id.iv_host_text) { btnChat.clearFocus(); vaBottomBar.setDisplayedChild(1); editMessage.requestFocus(); softKeyboardUtil.showKeyboard(HosterActivity.this, editMessage); } }
MainActivity.java
@Override public void onItemChildClick(ViewGroup viewGroup, View view, int i) { Intent it = new Intent(this, GuestActivity.class); Bundle bundle = new Bundle(); bundle.putString("hls_url", listLive.get(i).getmHlsUrl()); bundle.putString("rtmp_url", listLive.get(i).getmRtmpPullUrl()); bundle.putString("anyrtcId", listLive.get(i).getmAnyrtcId()); bundle.putString("userData", new JSONObject().toString()); bundle.putString("topic", listLive.get(i).getmLiveTopic()); it.putExtras(bundle); startActivity(it); }
與主播端一樣,拿上個Activity傳過來的數據,其實這裡代碼與主播端的代碼基本上可以說是一模一樣,看完之後你應該會有我這樣的體會。
GuestActivity.java
mNickname = ((HybirdApplication)HybirdApplication.app()).getmNickname(); mRtmpPullUrl = getIntent().getExtras().getString("rtmp_url"); mAnyrtcId = getIntent().getExtras().getString("anyrtcId"); mHlsUrl = getIntent().getExtras().getString("hls_url"); mGuestId = mNickname;//getIntent().getExtras().getString("guestId"); mTopic = getIntent().getExtras().getString("topic");
mVideoView = new RTMPCVideoView((RelativeLayout) findViewById(R.id.rl_rtmpc_videos), RTMPCHybird.Inst().Egl(), false); mVideoView.setBtnCloseEvent(mBtnVideoCloseEvent); /** * 初始化rtmp播放器 */ mGuestKit = new RTMPCGuestKit(this, mGuestListener); VideoRenderer render = mVideoView.OnRtcOpenLocalRender(); { // Create and audio manager that will take care of audio routing, // audio modes, audio device enumeration etc. mRtmpAudioManager = RTMPAudioManager.create(this, new Runnable() { // This method will be called each time the audio state (number // and // type of devices) has been changed. @Override public void run() { onAudioManagerChangedState(); } }); // Store existing audio settings and change audio mode to // MODE_IN_COMMUNICATION for best possible VoIP performance. mRtmpAudioManager.init(); mRtmpAudioManager.setAudioDevice(RTMPAudioManager.AudioDevice.SPEAKER_PHONE); } mUserData = new JSONObject(); try { mUserData.put("nickName", mNickname); mUserData.put("headUrl", ""); } catch (JSONException e) { e.printStackTrace(); } /** * 開始播放rtmp流 */ mGuestKit.StartRtmpPlay(mRtmpPullUrl, render.GetRenderPointer()); /** * 開啟RTC連線連接 */ mGuestKit.JoinRTCLine(mAnyrtcId, mGuestId, mUserData.toString());
mGuestKit = new RTMPCGuestKit(this, mGuestListener);
這句代碼是觀看直播的回調接口,可以做申請連麥、斷開連麥、接收消息和彈幕消息、實時觀看人數和人員上下線等。實用的操作一般再此實行。
GuestActivity.java
/** * 觀看直播回調信息接口 */ private RTMPCAbstractGuest mGuestListener = new RTMPCAbstractGuest() { /** * rtmp 連接成功 */ @Override public void OnRtmplayerOKCallback() { } /** * rtmp 當前播放狀態 * @param cacheTime 當前緩存時間 * @param curBitrate 當前播放器碼流 */ @Override public void OnRtmplayerStatusCallback(int cacheTime, int curBitrate) { } /** * rtmp 播放緩沖區時長 * @param time 緩沖時間 */ @Override public void OnRtmplayerCacheCallback(int time) { } /** * rtmp 播放器關閉 * @param errcode */ @Override public void OnRtmplayerClosedCallback(int errcode) { } /** * 游客RTC 狀態回調 * @param code 回調響應碼:0:正常;101:主播未開啟直播; * @param strReason 原因描述 */ @Override public void OnRTCJoinLineResultCallback(final int code, String strReason) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { if (code == 0) { } else if (code == 101) { Toast.makeText(GuestActivity.this, R.string.str_hoster_not_live, Toast.LENGTH_LONG).show(); mHandler.sendEmptyMessageDelayed(CLOSED, 2000); } } }); } /** * 游客申請連線回調 * @param code 0:申請連線成功;-1:主播拒絕連線 */ @Override public void OnRTCApplyLineResultCallback(final int code) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { if (code == 0) { VideoRenderer render = mVideoView.OnRtcOpenRemoteRender("LocalCameraRender"); mGuestKit.SetVideoCapturer(render.GetRenderPointer(), true); } else if (code == -1) { Toast.makeText(GuestActivity.this, R.string.str_hoster_refused, Toast.LENGTH_LONG).show(); mStartLine = false; mBtnConnect.setText(R.string.str_connect_hoster); } } }); } /** * 當與主播連線成功時,其他用戶連線回調 * @param strLivePeerID * @param strCustomID * @param strUserData */ @Override public void OnRTCOtherLineOpenCallback(String strLivePeerID, String strCustomID, String strUserData) { } /** * 其他用戶連線回調 * @param strLivePeerID */ @Override public void OnRTCOtherLineCloseCallback(String strLivePeerID) { } /** * 掛斷連線回調 */ @Override public void OnRTCHangupLineCallback() { //主播連線斷開 GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { mGuestKit.HangupRTCLine(); mVideoView.OnRtcRemoveRemoteRender("LocalCameraRender"); mStartLine = false; mBtnConnect.setText(R.string.str_connect_hoster); } }); } /** * 主播已離開回調 * @param code * @param strReason */ @Override public void OnRTCLineLeaveCallback(int code, String strReason) { //主播關閉直播 GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(GuestActivity.this, R.string.str_hoster_leave, Toast.LENGTH_LONG).show(); mHandler.sendEmptyMessageDelayed(CLOSED, 2000); } }); } /** * 連線接通後回調 * @param strLivePeerID */ @Override public void OnRTCOpenVideoRenderCallback(final String strLivePeerID) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { final VideoRenderer render = mVideoView.OnRtcOpenRemoteRender(strLivePeerID); mGuestKit.SetRTCVideoRender(strLivePeerID, render.GetRenderPointer()); } }); } /** * 連線關閉後圖像回調 * @param strLivePeerID */ @Override public void OnRTCCloseVideoRenderCallback(final String strLivePeerID) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { mGuestKit.SetRTCVideoRender(strLivePeerID, 0); mVideoView.OnRtcRemoveRemoteRender(strLivePeerID); } }); } /** * 消息回調 * @param strCustomID 消息的發送者id * @param strCustomName 消息的發送者昵稱 * @param strCustomHeader 消息的發送者頭像url * @param strMessage 消息內容 */ @Override public void OnRTCUserMessageCallback(final String strCustomID, final String strCustomName, final String strCustomHeader, final String strMessage) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { addChatMessageList(new ChatMessageBean(strCustomID, strCustomName, "", strMessage)); } }); } /** * 彈幕回調 * @param strCustomID 彈幕的發送者id * @param strCustomName 彈幕的發送者昵稱 * @param strCustomHeader 彈幕的發送者頭像url * @param strBarrage 彈幕的內容 */ @Override public void OnRTCUserBarrageCallback(final String strCustomID, final String strCustomName, final String strCustomHeader, final String strBarrage) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { addChatMessageList(new ChatMessageBean(strCustomID, strCustomName, "", strBarrage)); IDanmakuItem item = new DanmakuItem(GuestActivity.this, new SpannableString(strBarrage), mDanmakuView.getWidth(), 0, R.color.yellow_normol, 18, 1); mDanmakuView.addItemToHead(item); } }); } /** * 觀看直播的總人數回調 * @param totalMembers 觀看直播的總人數 */ @Override public void OnRTCMemberListWillUpdateCallback(final int totalMembers) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.txt_watcher_number)).setText(String.format(getString(R.string.str_live_watcher_number), totalMembers)); } }); } /** * 人員上下線回調 * @param strCustomID * @param strUserData */ @Override public void OnRTCMemberCallback(final String strCustomID, final String strUserData) { GuestActivity.this.runOnUiThread(new Runnable() { @Override public void run() { try { JSONObject userData = new JSONObject(strUserData); addChatMessageList(new ChatMessageBean(userData.getString("nickName"), "", userData.getString("headUrl"), "")); } catch (JSONException e) { e.printStackTrace(); } } }); } @Override public void OnRTCMemberListUpdateDoneCallback() { } };
接下來就要說對應這些回調的方法了,這裡可以做直播分享、申請連麥、斷開連麥和發送消息。
GuestActivity.java
public void OnBtnClicked(View btn) { if(btn.getId() == R.id.btn_copy_hls) { int index = mHlsUrl.lastIndexOf("/"); int lastIndex = mHlsUrl.lastIndexOf("."); String shareUrl = String.format(RTMPUrlHelper.SHARE_WEB_URL, mHlsUrl.substring(index + 1, lastIndex)); mShareHelper.shareWeiXin(mTopic, shareUrl); } else if (btn.getId() == R.id.btn_line) { if (!mStartLine) { JSONObject json = new JSONObject(); try { json.put("guestId", mNickname); } catch (JSONException e) { e.printStackTrace(); } /** * 向主播申請連線 */ mGuestKit.ApplyRTCLine(json.toString()); mStartLine = true; mBtnConnect.setText(R.string.str_hangup_connect); } else { /** * 掛斷連線 */ mGuestKit.HangupRTCLine(); mVideoView.OnRtcRemoveRemoteRender("LocalCameraRender"); mStartLine = false; mBtnConnect.setText(R.string.str_connect_hoster); } } else if (btn.getId() == R.id.btn_send_message) { String message = editMessage.getText().toString(); editMessage.setText(""); if (message.equals("")) { return; } if (mCheckBarrage.isChecked()) { mGuestKit.SendBarrage(mNickname, "", message); IDanmakuItem item = new DanmakuItem(GuestActivity.this, new SpannableString(message), mDanmakuView.getWidth(), 0, R.color.yellow_normol, 18, 1); mDanmakuView.addItemToHead(item); } else { mGuestKit.SendUserMsg(mNickname, "", message); } addChatMessageList(new ChatMessageBean(mNickname, mNickname, "", message)); } else if (btn.getId() == R.id.iv_host_text) { btnChat.clearFocus(); vaBottomBar.setDisplayedChild(1); editMessage.requestFocus(); softKeyboardUtil.showKeyboard(GuestActivity.this, editMessage); } }
對於這個基於Anyrtc sdk的直播RTMPCHybirdEngine-Android核心的幾個類基本上介紹完成,我在此僅僅是大概介紹了幾點,可以讓你大概了解這個SDK的直播流程,方便您快速上手。
移植Android到不同的設備 Android允許提供不同的硬件平台和驅動支持Android的運行。硬件抽象層(Hardware Abstraction Layer)
在Android中,每個應用程序都有自己的進程,當需要在不同的進程之間傳遞對象時,該如何實現呢?顯然, Java中是不支持跨進程內存共享的。因此要傳遞對象,需要把
微信朋友圈氣泡大字是怎麼做的?近來,在微信朋友圈裡迅速出現了一種氣泡類型的大文字動態,在朋友圈裡可是新鮮得很啊,那麼這種氣泡大字是怎麼做的?小編特地了解到氣
Android測試支持庫包含 UI自動化模塊 ,它可以對Android應用進行自動黑盒測試。在API Level 18中引入了自動化模塊,它允許開發者在組成應用UI的控件