爲了讓大家體驗基於 Agora SDK 實現的互動直播場景,我們三年前開發了應用 Agora Live。近 期,我們對 Agora Live 進行了一次“史詩級”更新。 我們不僅重新設計了 UI,並且還增加了多人連麥直播、PK 直播、虛擬主播功能。 更重要的是,我們決定把這份代碼也開源給所有開發者。 希望大家能更快速地實現這些社交娛樂中最熱門的實時互動場景,並創新出更多別具一格的玩法!

圖:新版 Aogra Live(iOS)

新版本 Agora Live 已經上線應用商店,僅面向 Android 和 iOS 用戶。 iOS 用戶 可以在 App Store 搜索「Agora Live」直接下載或更新。 Android 用戶 可以掃描下方二維碼,或訪問聲網官網下載中心下載。

一個 App,多種熱門場景

新版 Agora Live 目前已經支持四種時下最熱門的實時互動場景,包括:

  • 單主播直播場景:這是 Agora Live 最初就支持的功能,支持美顏、文字消息、添加背景音樂等功能。

  • 多人連麥直播場景:在直播的基礎上,還可邀請另外 6 名觀衆進行連麥。

  • PK 直播場景:就像大家在陌陌、抖音等應用中看到的 PK 直播一樣,主播可以向另一個主播發起 PK 邀請。兩個直播間的觀衆會同時看到兩個主播在線互動。

  • 虛擬主播場景:與單主播直播場景類似,只不過App 會爲主播生成一個實時的虛擬形象,虛擬形象的表情會與主播同步。在直播過程中,還可以邀請觀衆上麥。

App 中所有音視頻實時互動與文字消息、控制指令(如邀請上麥),都是基於聲網 Agora Native SDK 、聲網 Agora 實時消息 RTM SDK 實現的。美顏、虛擬形象則是基於聲網Agora 的生態合作伙伴相芯科技 FaceUnity SDK 實現的。

核心功能的實現

爲了便於大家快速熟悉源碼,我們簡單講解以下核心功能的代碼。 以下以 Swift 代碼爲例。

這個示例中, 直播間、房主與觀衆連麥 ,都是基於 Agora RTC SDK 實現的。我們通過以下代碼可以讓用戶加入RTC頻道,實現音視頻的互通。

func join(channel: String, token: String? = nil, streamId: Int, success: Completion = nil) {
        agoraKit.join(channel: channel, token: token, streamId: streamId) { [unowned self] in
            self.channelStatus = .ing
            if let success = success {
                success()
            }
        }
  }

在直播間中的 文字消息、控制指令 (比如邀請觀衆上麥)等,都是基於 Agora 實時消息 RTM SDK 實現的。在這裏我們集成 RTM SDK 後,通過以下代碼讓用戶加入 RTM 頻道。

func joinChannel(_ id: String, delegate: AgoraRtmChannelDelegate, success: Completion, fail: ErrorCompletion) {
        do {
            let channel = try createChannel(id: id, delegate: delegate)
            channel.join { (errorCode) in
                switch errorCode {
                case .channelErrorOk:
                    self.log(info: "rtm join channel success", extra: "channel id: \(id)")
                    if let success = success {
                        success()
                    }
                default:
                    let error = AGEError.rtm("join channel fail",
                                             code: errorCode.rawValue,
                                             extra: "channel: \(id)")
                    
                    self.log(error: error)
                    if let fail = fail {
                        fail(error)
                    }
                }
            }
        } catch {
            log(error: error, extra: "create channel fail")
            if let fail = fail {
                fail(error)
            }
        }
    }

美顏與虛擬形象 是通過接入 FaceUnity 的服務來實現的。可以結合 FUClient 這個類的實現與 FaceUnity 的文檔來集成美顏模塊。

typedef void (^FUCompletion)(void);
typedef void (^FUErrorCompletion)(NSError *error);


typedef NS_ENUM(NSUInteger, FUFilterItemType) {
    FUFilterItemTypeSmooth      = 1,
    FUFilterItemTypeBrighten    = 2,
    FUFilterItemTypeThinning    = 3,
    FUFilterItemTypeEye         = 4
};


@interface FUFilterItem : NSObject
@property (nonatomic, assign) FUFilterItemType type;
@property (nonatomic, assign) float defaultValue;
@property (nonatomic, assign) float minValue;
@property (nonatomic, assign) float maxValue;
@property (nonatomic, assign) float value;
@property (nonatomic, copy) NSString *funcName;
@end


@interface FUClient : NSObject
- (void)loadFilterWithSuccess:(FUCompletion)success fail:(FUErrorCompletion)fail;
- (void)setFilterValue:(float)value withType:(FUFilterItemType)type;
- (FUFilterItem *)getFilterItemWithType:(FUFilterItemType)type;


- (void)loadBackgroudWithSuccess:(FUCompletion)success fail:(FUErrorCompletion)fail;
- (void)loadAnimoji:(NSString *)name success:(FUCompletion)success fail:(FUErrorCompletion)fail;
- (void)renderItemsToPixelBuffer:(CVPixelBufferRef)pixelBuffer;
- (void)destoryAllItems;
@end

視頻流從 AVCaptureSession 流出,流入 FaceUnity 進行前處理,然後進入 Agora RTC SDK 發送到遠端。

func camera(_ camera: AGESingleCamera, position: AGECamera.Position, didOutput sampleBuffer: CMSampleBuffer) {
        cameraStreamQueue.async { [unowned self] in
            guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
                return
            }
            
            CVPixelBufferLockBaseAddress(pixelBuffer, .init(rawValue: 0))
            
            let timeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
            
            if self.enhancement.beauty == .on || self.enhancement.appearance != .none {
                self.enhancement.renderItems(to: pixelBuffer)
            }
            
            self.consumer?.consumePixelBuffer(pixelBuffer,
                                              withTimestamp: timeStamp,
                                              rotation: .rotationNone)
            
            CVPixelBufferUnlockBaseAddress(pixelBuffer, .init(rawValue: 0))
        }
    }

項目開源與未來計劃

我們已經在官方 Github「AgoraIO Usecase」中開源了 Agora Live 的代碼。 大家可以直接 fork,替換 AppID 即可使用。 方便大家快速實現多人連麥直播、單主播直播、PK 直播、虛擬主播 4 種實時互動場景。

Github URL:https://github.com/AgoraIO-usecase/agoralive

我們還將在接下來幾個月對 repo 中的代碼進一步梳理、優化,提升源碼的易用性、可讀性。而且,還會在本季度增加新的場景。當然,如果你在這份源碼基礎上,自己實現了更多功能,也歡迎提交 PR。我們也會向社區中更多開發者推薦你的項目。

相關文章