Android多人視頻聊天應用的開發(二)一對一聊天

在上一篇《Android多人視頻聊天應用的開發(一)快速集成》中我們討論瞭如何配置Agora Android SDK,本文我們將探索使用Agora進行一對一視頻聊天的奧祕。

 

鑑權

APP ID鑑權

所謂APP ID,就是在 Agora創建每個項目都有的一個唯一標識。App ID 可以明確你的項目及組織身份,並在 joinChannel 方法中作爲參數,連接到 Agora 實時網絡中,實現實時通信或直播功能。不同的App ID在Agora實時網絡中的通話是完全隔離的;Agora 提供的頻道信息、計費、管理服務也都是基於 App ID。

申請APP ID的操作很簡便,只要在Agora官網https://dashboard.agora.io/projects右側欄目的“項目”中點擊“添加新項目”,只需輸入項目名就可生成APP ID,全過程如下圖所示:

QQ圖片20180325165721.png

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

<string name="agora_app_id"><#YOUR APP ID#></string>

以上就是APP ID鑑權的全過程。

儘管App ID鑑權在最大程度上方便了開發者使用 Agora 的服務。但App ID 鑑權的安全性不佳,一旦有別有用心的人非法獲取了你的 App ID,他就可以在 Agora 提供的SDK中使用你的App ID。如果你的項目對安全性要求高,或者增加用戶權限設置的話,建議採用Token鑑權。

Token鑑權

在通信和直播場景中存在着多個角色,而每種角色又對應着一些默認權限。比如在直播場景中,主播可以發佈流、訂閱流、邀請嘉賓;觀衆可以訂閱流、申請連麥;管理員則可以踢人或禁言。

Token鑑權的步驟比APP ID鑑權稍微複雜一些,在上文項目列表中查看 App ID 的地方,啓用該項目的 App Certificate:

首先,點擊激活項目右上方的 編輯 按鈕。

QQ圖片20180325170935.png

將你的 App Certificate 保存在服務器端,且對任何客戶端均不可見。當項目的 App Certificate 被啓用後,你必須使用 Token。例如: 在啓用 App Certificate 前,你可以使用 App ID 加入頻道。但啓用了 App Certificate 後,你就必須使用 Token 加入頻道。後臺如何用App Certificate生成Token本文不做贅述。

 

初始化Agora

RtcEngine 類包含應用程序調用的主要方法,調用 RtcEngine 的接口最好在同一個線程進行,不建議在不同的線程同時調用。

目前 Agora Native SDK 只支持一個 RtcEngine 實例,每個應用程序僅創建一個 RtcEngine 對象 。 RtcEngine 類的所有接口函數,如無特殊說明,都是異步調用,對接口的調用建議在同一個線程進行。所有返回值爲 int 型的 API,如無特殊說明,返回值 0 爲調用成功,返回值小於 0 爲調用失敗。

IRtcEngineEventHandler接口類用於SDK嚮應用程序發送回調事件通知,應用程序通過繼承該接口類的方法獲取 SDK 的事件通知。

接口類的所有方法都有缺省(空)實現,應用程序可以根據需要只繼承關心的事件。在回調方法中,應用程序不應該做耗時或者調用可能會引起阻塞的 API(如 SendMessage),否則可能影響 SDK 的運行。

private RtcEngine mRtcEngine;

/**
 * Tutorial Step 1
 * 初始化Agora,創建 RtcEngine 對象
 */
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初始化失敗了,檢查一下是哪兒出錯了\n" + 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() {
                //設置遠端視頻顯示屬性
                setupRemoteVideo(uid);
            }
        });
    }

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

    @Override
    public void onUserMuteVideo(final int uid, final boolean muted) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //其他用戶已停發/已重發視頻流回調
                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()方法用於打開視頻模式。可以在加入頻道前或者通話中調用,在加入頻道前調用,則自動開啓視頻模式,在通話中調用則由音頻模式切換爲視頻模式。調用 disableVideo() 方法可關閉視頻模式。

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

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

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

 

設置本地視頻顯示屬性

setupLocalVideo( VideoCanvas local )方法用於設置本地視頻顯示信息。應用程序通過調用此接口綁定本地視頻流的顯示視窗(view),並設置視頻顯示模式。 在應用程序開發中,通常在初始化後調用該方法進行本地視頻設置,然後再加入頻道。退出頻道後,綁定仍然有效,如果需要解除綁定,可以調用 setupLocalVideo(null) 。

/**
 * Tutorial Step 3
 * 設置本地視頻顯示屬性
 */
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));
}

 

加入一個頻道

joinChannel(String token,String channelName,String optionalInfo,int optionalUid )方法讓用戶加入通話頻道,在同一個頻道內的用戶可以互相通話,多個用戶加入同一個頻道,可以羣聊。 使用不同 App ID 的應用程序是不能互通的。如果已在通話中,用戶必須調用 leaveChannel() 退出當前通話,才能進入下一個頻道。

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

 

設置遠端視頻顯示屬性

setupRemoteVideo( VideoCanvas remote)方法用於綁定遠程用戶和顯示視圖,即設定 uid 指定的用戶用哪個視圖顯示。調用該接口時需要指定遠程視頻的 uid,一般可以在進頻道前提前設置好。

如果應用程序不能事先知道對方的 uid,可以在 APP 收到 onUserJoined 事件時設置。如果啓用了視頻錄製功能,視頻錄製服務會做爲一個啞客戶端加入頻道,因此其他客戶端也會收到它的 onUserJoined 事件,APP 不應給它綁定視圖(因爲它不會發送視頻流),如果 APP 不能識別啞客戶端,可以在 onFirstRemoteVideoDecoded 事件時再綁定視圖。解除某個用戶的綁定視圖可以把 view 設置爲空。退出頻道後,SDK 會把遠程用戶的綁定關係清除掉。

/**
 * Tutorial Step 5
 * 設置遠端視頻顯示屬性
 */
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);
}

 

離開當前頻道

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

當調用 joinChannel() API 方法後,必須調用 leaveChannel() 結束通話,否則無法開始下一次通話。 不管當前是否在通話中,都可以調用 leaveChannel(),沒有副作用。該方法會把會話相關的所有資源釋放掉。該方法是異步操作,調用返回時並沒有真正退出頻道。在真正退出頻道後,SDK 會觸發 onLeaveChannel 回調。

/**
 * Tutorial Step 6
 * 離開當前頻道
 */
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)設置是否打開閃光燈、setCameraAutoFocusFaceModeEnabled(boolean enabled)設置是否開啓人臉對焦功能等等。

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

 

將自己靜音

muteLocalAudioStream(boolean muted)方法用於靜音/取消靜音。該方法可以允許/禁止往網絡發送本地音頻流。但該方法並沒有禁用麥克風,不影響錄音狀態。

/**
 * 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)方法用於暫停發送本地視頻流,但該方法並沒有禁用攝像頭,不影響本地視頻流獲取。

/**
 * 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);
}


運行效果

拿兩部手機安裝編譯好的App,如果能看見兩個自己,說明你成功了

微信圖片_20180409155704.jpg


通過本文的學習,我們已經掌握了利用Agora進行一對一聊天的技巧,接下來的文章中,我將繼續介紹多人聊天室等知識。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章