国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Android端實(shí)現(xiàn)多人音視頻聊天應(yīng)用(一)

raoyi / 2123人閱讀

作者:聲網(wǎng)Agora用戶,資深A(yù)ndroid開發(fā)者吳東洋。
本系列文章分享了基于Agora SDK 2.1實(shí)現(xiàn)多人視頻通話的實(shí)踐經(jīng)驗(yàn)。

自從2016年,鼓吹“互聯(lián)網(wǎng)寒冬”的論調(diào)甚囂塵上,2017年亦有愈演愈烈之勢(shì)。但連麥直播、在線抓娃娃、直播問答、遠(yuǎn)程狼人殺等類型的項(xiàng)目卻異軍突起,成了投資人的風(fēng)口,創(chuàng)業(yè)者的藍(lán)海和用戶的必裝App,而這些方向的項(xiàng)目都有一個(gè)共同的特點(diǎn)——都依賴視頻通話和全互動(dòng)直播技術(shù)。

聲網(wǎng)Agora.io的SDK讓App和網(wǎng)站都可以實(shí)現(xiàn)高質(zhì)量的音頻通話、視頻通話、全互動(dòng)直播。我試著通過該SDK實(shí)現(xiàn)一個(gè)多人視頻通話應(yīng)用。本文先分享集成的部分。

環(huán)境

聲網(wǎng)Agora.io SDK的兼容性良好,對(duì)硬件設(shè)備和軟件系統(tǒng)的要求不高,開發(fā)環(huán)境和測試環(huán)境滿足以下條件即可:

Android SDK API Level >= 16

Android Studio 2.0 或以上版本

支持語音和視頻功能的真機(jī)

App 要求 Android 4.1 或以上設(shè)備

以下是我試用聲網(wǎng)Agora.io SDK的開發(fā)環(huán)境和測試環(huán)境:

開發(fā)環(huán)境

Windows 10 家庭中文版

Java Version SE 8

Android Studio 3.2 Canary 4

測試環(huán)境

Samsung Nexus (Android 4.4.2 API 19)

Mi Note 3 (Android 7.1.1 API 25)

集成

步驟一:首先點(diǎn)此下載完整的SDK和官方demo

步驟二:既然我們要把聲網(wǎng)Agora.io集成到自己的項(xiàng)目里,所以不必運(yùn)行sample,我們自己新建一個(gè)HelloAgora項(xiàng)目,注意一定要支持C++哦。

步驟三:把libs文件夾里的arm64-v8a、、armeabi-v7a以及x86文件夾復(fù)制粘貼到app module的libs里。如果有NDK開發(fā)的必要,則把libs->include文件夾里的兩個(gè).h頭文件復(fù)制粘貼到合適位置。

步驟四:首先在app module的build.gradle文件的android代碼塊中添加如下代碼:

sourceSets {
    main {
        jniLibs.srcDirs = ["../../../libs"]
    }
}

然后在app module的build.gradle文件的android->defaultConfig代碼塊中添加如下代碼:

ndk {
    abiFilters "armeabi-v7a", "x86" 
}

接下來在app module的build.gradle文件的dependencies代碼塊中添加如下代碼:

compile "io.agora.rtc:full-sdk:2.0.0"

如果用復(fù)制粘貼jar的方式,那么此處添加如下代碼:

compile fileTree(dir: "../../../libs", include: ["*.jar"])

如果有自定義NDK的必要,可以繼續(xù)在app module的build.gradle文件的android代碼塊中添加如下代碼:

externalNativeBuild {
    ndkBuild {
        path "src/main/cpp/Android.mk"
    }
}

然后在app module的build.gradle文件的android->defaultConfig代碼塊中添加如下代碼:

externalNativeBuild {
    ndkBuild {
        arguments "NDK_APPLICATION_MK:=src/main/cpp/Application.mk"
    }
}

最后sync一下,聲網(wǎng)Agora.io的SDK就集成到項(xiàng)目中來了。

權(quán)限

SDK集成完畢后,為了保證SDK能正常運(yùn)行,我們需要在AndroidManisfest.xml 文件中聲明以下權(quán)限:















這些權(quán)限都是Android開發(fā)過程中的常見權(quán)限,有經(jīng)驗(yàn)的程序員都會(huì)感覺眼熟,WRITE_EXTERNAL_STORAGE等敏感權(quán)限適配Android 6.0以后版本的問題并非本文關(guān)注重點(diǎn),在此不做贅述。

混淆代碼

集成SDK并聲明了權(quán)限后,就該考慮混淆的問題了,我們需要在project的proguard-rules.pro文件里添加以下代碼:

-keep class io.agora.**{*;}

經(jīng)過以上過程后,我們已經(jīng)完成了聲網(wǎng)Agora.io SDK的快速集成,邁出了走向連麥直播、在線抓娃娃、直播問答、遠(yuǎn)程狼人殺等風(fēng)口的第一步。在接下來的文章里,我將繼續(xù)分享APP ID鑒權(quán)、Token鑒權(quán)、一對(duì)一視頻聊天、創(chuàng)建群聊room、分屏、窗口切換和前后攝像頭切換等內(nèi)容。

鑒權(quán)

APP ID鑒權(quán)

所謂APP ID,就是在 Agora創(chuàng)建每個(gè)項(xiàng)目都有的一個(gè)唯一標(biāo)識(shí)。App ID 可以明確你的項(xiàng)目及組織身份,并在 joinChannel 方法中作為參數(shù),連接到 Agora 實(shí)時(shí)網(wǎng)絡(luò)中,實(shí)現(xiàn)實(shí)時(shí)通信或直播功能。不同的App ID在Agora實(shí)時(shí)網(wǎng)絡(luò)中的通話是完全隔離的;Agora 提供的頻道信息、計(jì)費(fèi)、管理服務(wù)也都是基于 App ID。

申請(qǐng)APP ID的操作很簡便,只要在Agora官網(wǎng)https://dashboard.agora.io/pr...“項(xiàng)目”中點(diǎn)擊“添加新項(xiàng)目”,只需輸入項(xiàng)目名就可生成APP ID,全過程如下圖所示:

找到,把“<#YOUR APP ID#>”替換為圖中的馬賽克里的字符串。

<#YOUR APP ID#>

以上就是APP ID鑒權(quán)的全過程。

盡管App ID鑒權(quán)在最大程度上方便了開發(fā)者使用 Agora 的服務(wù)。但App ID 鑒權(quán)的安全性不佳,一旦有別有用心的人非法獲取了你的 App ID,他就可以在 Agora 提供的SDK中使用你的App ID。如果你的項(xiàng)目對(duì)安全性要求高,或者增加用戶權(quán)限設(shè)置的話,建議采用Token鑒權(quán)。

Token鑒權(quán)

在通信和直播場景中存在著多個(gè)角色,而每種角色又對(duì)應(yīng)著一些默認(rèn)權(quán)限。比如在直播場景中,主播可以發(fā)布流、訂閱流、邀請(qǐng)嘉賓;觀眾可以訂閱流、申請(qǐng)連麥;管理員則可以踢人或禁言。

Token鑒權(quán)的步驟比APP ID鑒權(quán)稍微復(fù)雜一些,在上文項(xiàng)目列表中查看 App ID 的地方,啟用該項(xiàng)目的 App Certificate:

首先,點(diǎn)擊激活項(xiàng)目右上方的 編輯 按鈕。

將你的 App Certificate 保存在服務(wù)器端,且對(duì)任何客戶端均不可見。當(dāng)項(xiàng)目的 App Certificate 被啟用后,你必須使用 Token。例如: 在啟用 App Certificate 前,你可以使用 App ID 加入頻道。但啟用了 App Certificate 后,你就必須使用 Token 加入頻道。后臺(tái)如何用App Certificate生成Token本文不做贅述。

初始化Agora

RtcEngine 類包含應(yīng)用程序調(diào)用的主要方法,調(diào)用 RtcEngine 的接口最好在同一個(gè)線程進(jìn)行,不建議在不同的線程同時(shí)調(diào)用。

目前 Agora Native SDK 只支持一個(gè) RtcEngine 實(shí)例,每個(gè)應(yīng)用程序僅創(chuàng)建一個(gè) RtcEngine 對(duì)象 。 RtcEngine 類的所有接口函數(shù),如無特殊說明,都是異步調(diào)用,對(duì)接口的調(diào)用建議在同一個(gè)線程進(jìn)行。所有返回值為 int 型的 API,如無特殊說明,返回值 0 為調(diào)用成功,返回值小于 0 為調(diào)用失敗。

IRtcEngineEventHandler接口類用于SDK向應(yīng)用程序發(fā)送回調(diào)事件通知,應(yīng)用程序通過繼承該接口類的方法獲取 SDK 的事件通知。

接口類的所有方法都有缺省(空)實(shí)現(xiàn),應(yīng)用程序可以根據(jù)需要只繼承關(guān)心的事件。在回調(diào)方法中,應(yīng)用程序不應(yīng)該做耗時(shí)或者調(diào)用可能會(huì)引起阻塞的 API(如 SendMessage),否則可能影響 SDK 的運(yùn)行。

private RtcEngine mRtcEngine;

/**
 * Tutorial Step 1
 * 初始化Agora,創(chuàng)建 RtcEngine 對(duì)象
 */
private void initializeAgoraEngine() {
    try {
        mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
    } catch (Exception e) {
        Log.e(LOG_TAG, Log.getStackTraceString(e));

        throw new RuntimeException("Agora初始化失敗了,檢查一下是哪兒出錯(cuò)了
" + Log.getStackTraceString(e));
    }
}

private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
    @Override
    public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //設(shè)置遠(yuǎn)端視頻顯示屬性
                setupRemoteVideo(uid);
            }
        });
    }

    @Override
    public void onUserOffline(int uid, int reason) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //其他用戶離開當(dāng)前頻道回調(diào)
                onRemoteUserLeft();
            }
        });
    }

    @Override
    public void onUserMuteVideo(final int uid, final boolean muted) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //其他用戶已停發(fā)/已重發(fā)視頻流回調(diào)
                onRemoteUserVideoMuted(uid, muted);
            }
        });
    }
};

 

private void onRemoteUserLeft() {
    FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);
    container.removeAllViews();

    //文案可隨意定制
    View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk);
    tipMsg.setVisibility(View.VISIBLE);
}

 

private void onRemoteUserVideoMuted(int uid, boolean muted) {
    FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);

    SurfaceView surfaceView = (SurfaceView) container.getChildAt(0);

    Object tag = surfaceView.getTag();
    if (tag != null && (Integer) tag == uid) {
        surfaceView.setVisibility(muted ? View.GONE : View.VISIBLE);
    }
}

打開視頻模式

enableVideo()方法用于打開視頻模式。可以在加入頻道前或者通話中調(diào)用,在加入頻道前調(diào)用,則自動(dòng)開啟視頻模式,在通話中調(diào)用則由音頻模式切換為視頻模式。調(diào)用 disableVideo() 方法可關(guān)閉視頻模式。

setVideoProfile()方法設(shè)置視頻編碼屬性(Profile)。每個(gè)屬性對(duì)應(yīng)一套視頻參數(shù),如分辨率、幀率、碼率等。 當(dāng)設(shè)備的攝像頭不支持指定的分辨率時(shí),SDK 會(huì)自動(dòng)選擇一個(gè)合適的攝像頭分辨率,但是編碼分辨率仍然用 setVideoProfile() 指定的。

該方法僅設(shè)置編碼器編出的碼流屬性,可能跟最終顯示的屬性不一致,例如編碼碼流分辨率為 640x480,碼流的旋轉(zhuǎn)屬性為 90 度,則顯示出來的分辨率為豎屏模式。

/**
 * Tutorial Step 2
 * 打開視頻模式,并設(shè)置本地視頻屬性
 */
private void setupVideoProfile() {
    //打開視頻模式
    mRtcEngine.enableVideo();
    //設(shè)置本地視頻屬性
    mRtcEngine.setVideoProfile(Constants.VIDEO_PROFILE_360P, false);
}

設(shè)置本地視頻顯示屬性

setupLocalVideo( VideoCanvas local )方法用于設(shè)置本地視頻顯示信息。應(yīng)用程序通過調(diào)用此接口綁定本地視頻流的顯示視窗(view),并設(shè)置視頻顯示模式。 在應(yīng)用程序開發(fā)中,通常在初始化后調(diào)用該方法進(jìn)行本地視頻設(shè)置,然后再加入頻道。退出頻道后,綁定仍然有效,如果需要解除綁定,可以調(diào)用 setupLocalVideo(null) 。

/**
 * Tutorial Step 3
 * 設(shè)置本地視頻顯示屬性
 */
private void setupLocalVideo() {
    FrameLayout container = (FrameLayout) findViewById(R.id.local_video_view_container);
    SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
    surfaceView.setZOrderMediaOverlay(true);
    container.addView(surfaceView);
    mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_ADAPTIVE, 0));
}

加入一個(gè)頻道

joinChannel(String token,String channelName,String optionalInfo,int optionalUid )方法讓用戶加入通話頻道,在同一個(gè)頻道內(nèi)的用戶可以互相通話,多個(gè)用戶加入同一個(gè)頻道,可以群聊。 使用不同 App ID 的應(yīng)用程序是不能互通的。如果已在通話中,用戶必須調(diào)用 leaveChannel() 退出當(dāng)前通話,才能進(jìn)入下一個(gè)頻道。

/**
 * Tutorial Step 4
 * 加入一個(gè)頻道
 */
private void joinChannel() {
    //如果不指定UID,Agroa將自動(dòng)生成并分配一個(gè)UID
    mRtcEngine.joinChannel(null, "demoChannel1", "Extra Optional Data", 0);
}

設(shè)置遠(yuǎn)端視頻顯示屬性

setupRemoteVideo( VideoCanvas remote)方法用于綁定遠(yuǎn)程用戶和顯示視圖,即設(shè)定 uid 指定的用戶用哪個(gè)視圖顯示。調(diào)用該接口時(shí)需要指定遠(yuǎn)程視頻的 uid,一般可以在進(jìn)頻道前提前設(shè)置好。

如果應(yīng)用程序不能事先知道對(duì)方的 uid,可以在 APP 收到 onUserJoined 事件時(shí)設(shè)置。如果啟用了視頻錄制功能,視頻錄制服務(wù)會(huì)做為一個(gè)啞客戶端加入頻道,因此其他客戶端也會(huì)收到它的 onUserJoined 事件,APP 不應(yīng)給它綁定視圖(因?yàn)樗粫?huì)發(fā)送視頻流),如果 APP 不能識(shí)別啞客戶端,可以在 onFirstRemoteVideoDecoded 事件時(shí)再綁定視圖。解除某個(gè)用戶的綁定視圖可以把 view 設(shè)置為空。退出頻道后,SDK 會(huì)把遠(yuǎn)程用戶的綁定關(guān)系清除掉。

/**
 * Tutorial Step 5
 * 設(shè)置遠(yuǎn)端視頻顯示屬性
 */
private void setupRemoteVideo(int uid) {
    FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);

    if (container.getChildCount() >= 1) {
        return;
    }

    SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
    container.addView(surfaceView);
    mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_ADAPTIVE, uid));

    surfaceView.setTag(uid);
    //文案可隨意定制
    View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk);
    tipMsg.setVisibility(View.GONE);
}

離開當(dāng)前頻道

leaveChannel()方法用于離開頻道,即掛斷或退出通話。

當(dāng)調(diào)用 joinChannel() API 方法后,必須調(diào)用 leaveChannel() 結(jié)束通話,否則無法開始下一次通話。 不管當(dāng)前是否在通話中,都可以調(diào)用 leaveChannel(),沒有副作用。該方法會(huì)把會(huì)話相關(guān)的所有資源釋放掉。該方法是異步操作,調(diào)用返回時(shí)并沒有真正退出頻道。在真正退出頻道后,SDK 會(huì)觸發(fā) onLeaveChannel 回調(diào)。

/**
 * Tutorial Step 6
 * 離開當(dāng)前頻道
 */
private void leaveChannel() {
    mRtcEngine.leaveChannel();
}

public void onEncCallClicked(View view) {
    finish();
}

@Override
protected void onDestroy() {
    super.onDestroy();

    leaveChannel();
    RtcEngine.destroy();
    mRtcEngine = null;
}

管理攝像頭

switchCamera()方法用于在前置/后置攝像頭間切換。除此以外Agora還提供了一下管理攝像頭的方法:例如setCameraTorchOn(boolean isOn)設(shè)置是否打開閃光燈、setCameraAutoFocusFaceModeEnabled(boolean enabled)設(shè)置是否開啟人臉對(duì)焦功能等等。

/**
 * Tutorial Step 7
 * 切換前置/后置攝像頭
 */
public void onSwitchCameraClicked(View view) {
    mRtcEngine.switchCamera();
}

將自己靜音

muteLocalAudioStream(boolean muted)方法用于靜音/取消靜音。該方法可以允許/禁止往網(wǎng)絡(luò)發(fā)送本地音頻流。但該方法并沒有禁用麥克風(fēng),不影響錄音狀態(tài)。

/**
 * Tutorial Step 8
 * 將自己靜音
 */
public void onLocalAudioMuteClicked(View view) {
    ImageView iv = (ImageView) view;
    if (iv.isSelected()) {
        iv.setSelected(false);
        iv.clearColorFilter();
    } else {
        iv.setSelected(true);
        iv.setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
    }

    mRtcEngine.muteLocalAudioStream(iv.isSelected());
}

暫停本地視頻流

muteLocalVideoStream(boolean muted)方法用于暫停發(fā)送本地視頻流,但該方法并沒有禁用攝像頭,不影響本地視頻流獲取。

/**
 * Tutorial Step 9
 * 暫停本地視頻流
 */
public void onLocalVideoMuteClicked(View view) {
    ImageView iv = (ImageView) view;
    if (iv.isSelected()) {
        iv.setSelected(false);
        iv.clearColorFilter();
    } else {
        iv.setSelected(true);
        iv.setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
    }

    mRtcEngine.muteLocalVideoStream(iv.isSelected());

    FrameLayout container = (FrameLayout) findViewById(R.id.local_video_view_container);
    SurfaceView surfaceView = (SurfaceView) container.getChildAt(0);
    surfaceView.setZOrderMediaOverlay(!iv.isSelected());
    surfaceView.setVisibility(iv.isSelected() ? View.GONE : View.VISIBLE);
}

運(yùn)行效果

拿兩部手機(jī)安裝編譯好的App,如果能看見兩個(gè)自己,說明你成功了。

通過本文的學(xué)習(xí),我們已經(jīng)掌握了利用Agora SDK進(jìn)行一對(duì)一聊天的技巧,接下來的文章中,我將繼續(xù)介紹如何實(shí)現(xiàn)多人聊天室。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/69029.html

相關(guān)文章

  • Android實(shí)現(xiàn)多人視頻聊天應(yīng)用(二):實(shí)現(xiàn)多人通話

    摘要:我們先實(shí)現(xiàn)一個(gè)瀑布流瀑布流的實(shí)現(xiàn)方式很多,本文采用結(jié)合的來實(shí)現(xiàn)。有了一個(gè)可用的瀑布流之后,下面我們就可以實(shí)現(xiàn)動(dòng)態(tài)聊天窗了動(dòng)態(tài)聊天窗的要點(diǎn)在于的大小由視頻的寬高比決定,因此及其對(duì)應(yīng)的就該注意不要寫死尺寸。 作者:聲網(wǎng)用戶,資深A(yù)ndroid工程師吳東洋本系列文章分享了基于Agora SDK 2.1實(shí)現(xiàn)多人視頻通話的實(shí)踐經(jīng)驗(yàn)。 在上一篇《Android 多人視頻聊天應(yīng)用的開發(fā)(一)一對(duì)一聊...

    The question 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

raoyi

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<