LIVE173網路聊天交友影音視訊live秀-live173 app影音視訊聊天室 》 《直播173視訊》 《視訊裸聊直播秀場 - 女主播聊天室 - 成人秀視頻》 《金瓶梅視訊聊天交友》 《173影音視訊》 《視訊辣妹脫衣秀女郎 - 美女主播直播間熱舞 - 視訊網站主播

您可排除寂寞無聊的夜晚,讓站上美女陪妳聊一整晚。本站為成人影音聊天室,站上在24小時內皆有正妹輪班陪你聊天,你只要挑選喜歡的女生進入她們包廂,即可線上即時視訊聊天。若你是第一次到本站,可先試試免費視訊來試玩一下,喜歡本站再加入會員可得購買點數的優惠。為即時線上互動的聊天平台,利用視訊及音訊功能達到線上Live直播的功能,比起純文字聊天更有感觀的視覺衝極,本站可一次看四位視訊美女的視訊,免費視訊讓第一次來的新手可先試玩熟悉介面免加入會員,若想先跟主持人試玩互動可使用撥打付費電話的方式搶先體驗。各位網友可自行挑選正妹來做一對一或一對多視訊聊天。您可以在聊天時開啟視訊(webcam)及通話(麥克風)的功能,讓主持人可以看到您與聽到您的聲音,網路無國界。

本文源自RTC 開發者社區,資深Android工程師吳東洋

本系列文章分享了基於Agora SDK 2.1實現多人視頻通話的實踐經驗。

在上一篇《Android 多人視頻聊天應用的開發(一)一對一聊天》中我們學習了如何使用聲網Agora SDK 進行一對一的聊天,本篇主要討論如何使用 Agora SDK 進行多人聊天。主要需要實現以下功能:

上一篇已經實現過的聊天功能 隨著加入人數和他們的手機攝像頭解析度的變化,顯示不同的UI,即所謂的「分屏」 點擊分屏中的小窗,可以放大顯示該聊天窗 分屏根據前期技術調研,分屏顯示最好的方式是採用瀑布流結合動態聊天窗實現,這樣比較方便的能夠適應UI的變化。所謂瀑布流,就是目前比較流行的一種列表布局,會在介面上呈現參差不齊的多欄布局。我們先實現一個瀑布流:

瀑布流的實現方式很多,本文採用結合 GridLayoutManager的RecyclerView 來實現。我們首先自定義一個 RecyclerView,命名為 GridVideoViewContainer。核心代碼如下:

int count = uids.size(); if (count <= 2) { // 只有本地視頻或聊天室內只有另外一個人 this.setLayoutManager(new LinearLayoutManager(activity.getApplicationContext(), orientation, false)); } else if (count > 2) { //多人聊天室 int itemSpanCount = getNearestSqrt(count); this.setLayoutManager(new GridLayoutManager(activity.getApplicationContext(), itemSpanCount, orientation, false)); } 複製代碼根據上面的代碼可以看出,在聊天室里只有自己的本地視頻或者只有另外一個人的時候,採用 LinearLayoutManager,這樣的布局其實與前文的一對一聊天類似;而在真正意義的多人聊天室里,則採用 GridLayoutManager 實現瀑布流,其中 itemSpanCount 就是瀑布流的列數。

有了一個可用的瀑布流之後,下面我們就可以實現動態聊天窗了: 動態聊天窗的要點在於 item 的大小由視頻的寬高比決定,因此 Adapter 及其對應的 layout 就該注意不要寫死尺寸。在 Adapter 里控制 item 具體尺寸的代碼如下:

if (force mItemWidth == 0 mItemHeight == 0) { WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics();windowManager.getDefaultDisplay().getMetrics(outMetrics); int count = uids.size(); int DividerX = 1; int DividerY = 1; if (count == 2) { DividerY = 2; } else if (count >= 3) { DividerX =getNearestSqrt(count); DividerY = (int) Math.ceil(count * 1.f / DividerX); } int width = outMetrics.widthPixels; int height = outMetrics.heightPixels; if (width > height) { mItemWidth = width /DividerY; mItemHeight = height / DividerX; } else { mItemWidth = width / DividerX; mItemHeight = height / DividerY; } } 複製代碼以上代碼根據視頻的數量確定了列數和行數,然後根據列數和螢幕寬度確定了視頻的寬度,接著根據視頻的寬高比和視頻寬度確定了視頻高度。同時也考慮了手機的橫豎屏情況(就是if (width > height)這行代碼)。

該 Adapter 對應的 layout 的代碼如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/user_control_mask" android:layout_width="match_parent" android:layout_height="match_parent"android:orientation="vertical"> <ImageView android:id="@+id/default_avatar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"android:visibility="gone" android:src="@drawable/icon_default_avatar" android:contentDescription="DEFAULT_AVATAR" /> <ImageView android:id="@+id/indicator" android:layout_width="wrap_content"android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/video_indicator_bottom_margin"android:contentDescription="VIDEO_INDICATOR" /> <LinearLayout android:id="@+id/video_info_container" android:layout_width="wrap_content" android:layout_height="wrap_content"android:layout_alignParentTop="true" android:layout_marginTop="24dp" android:layout_marginStart="15dp" android:layout_marginLeft="15dp" android:visibility="gone" android:orientation="vertical"><TextView android:id="@+id/video_info_metadata" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" style="@style/NotificationUIText" /></LinearLayout> </RelativeLayout> 複製代碼我們可以看到,layout 中有關尺寸的屬性都 是wrap_content,這就使得 item 大小隨視頻寬高比變化成為可能。

把分屏的布局寫好之後,我們就可以在每一個 item 上播放聊天視頻了。

播放聊天視頻在 Agora SDK 中一個遠程視頻的顯示只和該用戶的 UID 有關,所以使用的數據源只需要簡單定義為包含 UID 和對應的 SurfaceView 即可,就像這樣:

private final HashMap<Integer, SurfaceView> mUidsList = new HashMap<>(); 複製代碼每當有人加入了我們的聊天頻道,都會觸發onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed)方法,第一個 uid 就是他們的 UID;接下來我們要為每個 item 新建一個 SurfaceView 並為其創建渲染視圖,最後將它們加入剛才創建好的mUidsList里並調用setupRemoteVideo(VideoCanvas remote )方法播放這個聊天視頻。這個過程的完整代碼如下:

@Override public void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed) { doRenderRemoteUi(uid); } private void doRenderRemoteUi(final int uid) { runOnUiThread(new Runnable() {@Override public void run() { if (isFinishing()) { return; } if (mUidsList.containsKey(uid)) { return; } SurfaceView surfaceV = RtcEngine.CreateRendererView(getApplicationContext());mUidsList.put(uid, surfaceV); boolean useDefaultLayout = mLayoutType == LAYOUT_TYPE_DEFAULT; surfaceV.setZOrderOnTop(true); surfaceV.setZOrderMediaOverlay(true); rtcEngine().setupRemoteVideo(newVideoCanvas(surfaceV, VideoCanvas.RENDER_MODE_HIDDEN, uid)); if (useDefaultLayout) { log.debug("doRenderRemoteUi LAYOUT_TYPE_DEFAULT " + (uid & 0xFFFFFFFFL)); switchToDefaultVideoView(); } else {int bigBgUid = mSmallVideoViewAdapter == null ? uid : mSmallVideoViewAdapter.getExceptedUid(); log.debug("doRenderRemoteUi LAYOUT_TYPE_SMALL " + (uid & 0xFFFFFFFFL) + " " + (bigBgUid &0xFFFFFFFFL)); switchToSmallVideoView(bigBgUid); } } }); } 複製代碼以上代碼與前文中播放一對一視頻的代碼如出一撤,但是細心的讀者可能已經發現我們並沒有將生成的 SurfaceView 放在介面里,這正是與一對一視頻的不同之處:我們要在一個抽象的 VideoViewAdapter 類里將 SurfaceView 放出來,關鍵代碼如下:

SurfaceView target = user.mView; VideoViewAdapterUtil.stripView(target); holderView.addView(target, 0, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 複製代碼一般 Android 工程師看見 holderView 就明白這是 ViewHolder 的 layout 的根 layout 了,而 user 是哪兒來的,詳見文末的代碼,文中不做贅述。

這樣在多人聊天的時候我們就能使用分屏的方式播放用戶聊天視頻了,如果想放大某一個用戶的視頻該怎麼辦呢?

全屏和小窗當用戶雙擊某一個 item 的時候,他希望對應的視頻能夠全屏顯示,而其他的視頻則變成小窗口,那麼我們先定義一個雙擊事件接口:

public interface VideoViewEventListener { void onItemDoubleClick(View v, Object item); } 具體實現方式如下: mGridVideoViewContainer.setItemEventHandler(new VideoViewEventListener() { @Override public voidonItemDoubleClick(View v, Object item) { log.debug("onItemDoubleClick " + v + " " + item + " " + mLayoutType); if (mUidsList.size() < 2) { return; } UserStatusData user = (UserStatusData) item;int uid = (user.mUid == 0) ? config().mUid : user.mUid; if (mLayoutType == LAYOUT_TYPE_DEFAULT && mUidsList.size() != 1) { switchToSmallVideoView(uid); } else { switchToDefaultVideoView(); }} }); 複製代碼將被選中的視頻全屏播放的方法很容易理解,我們只看生成小窗列表的方法:

private void switchToSmallVideoView(int bigBgUid) { HashMap<Integer, SurfaceView> slice = new HashMap<>(1); slice.put(bigBgUid, mUidsList.get(bigBgUid)); Iterator<SurfaceView>iterator = mUidsList.values().iterator(); while (iterator.hasNext()) { SurfaceView s = iterator.next(); s.setZOrderOnTop(true); s.setZOrderMediaOverlay(true); }mUidsList.get(bigBgUid).setZOrderOnTop(false); mUidsList.get(bigBgUid).setZOrderMediaOverlay(false); mGridVideoViewContainer.initViewContainer(this, bigBgUid, slice, mIsLandscape);bindToSmallVideoView(bigBgUid); mLayoutType = LAYOUT_TYPE_SMALL; requestRemoteStreamType(mUidsList.size()); } 複製代碼小窗列表要注意移除全屏的那個 UID,此外一切都和正常瀑布流視圖相同,包括雙擊小窗的item將其全屏播放。

到了這裡我們就已經使用 Agora SDK 完成了一個有基本功能的簡單多人聊天 demo,要產品化還有很多的東西要做,在這裡先做一個簡單的總結吧!

總結聲網Agora 提供了高質量的視頻通信 SDK,不僅覆蓋了主流的作業系統,集成效率也比較高,而且還支持包括聊天,會議,直播等功能在內的多個模式的視頻通話。SDK 中 API 設計基本能夠滿足大部分的開發需要,而且隱藏了底層開發,只需要提供 SurfaceView 和 UID 即可播放視頻,這樣對於 App層的開發者來說十分友好。非常適合有視頻聊天開發需求的開發者。在視頻領域創業大爆發的今天,建議更多的想要從事該領域的開發者可以嘗試下。

如果參考本文時遇到開發問題,歡迎訪問聲網 Agora問答版塊,發帖與聲網工程師交流。

歡迎關注,會陸續發布一些知識點總結,減少你的讀書時間,一起交流面試經驗!每月隨機抽取20名粉絲進入高級技術交流群(大量資料、BAT員工)!

div class="pgc-img">...

裸聊網站 - 網聊視訊直播 - 寂寞交友網 | 免費視訊美女聊天網站 - 美女裸聊視頻直播 | 線上金瓶梅視訊 | 視頻裸聊 - 真人秀視頻聊天室 - 色情免費視訊妹色聊 | UT視訊聊天秀 | 辣妹視訊交友網站交友 - 美女視訊網紅 - 韓國美女視訊 | 視訊聊天一對一 - 網路視頻聊天室 | 成人金瓶梅視訊觀看 | 173 live免費贈點 | 美女主播免費視訊視頻聊天室 | 寶貝裸聊吧 - 聊天網視訊 - 網絡美女主播直播平台 | 色聊聊天室 - 真人裸聊 | 173免費視訊美女聊天 | meme免費視訊加入會員再送點數 | 173視訊交友 - 台灣視訊173聊天室 | 免費視訊美女裸體 - 美女視頻裸體 | 免費視訊173 live |

正妹線上陪你聊Live - 聊天唱歌跳舞 精彩表演秀‎。直播視訊交友聊天表演 影音體驗美眉魅力 立即入會 儲值有優惠 趕快來體驗唷。

Copyright © 2020 By 金瓶梅聊天視訊 All Rights Reserved.