優酷鴻蒙開發實踐|多屏互動開發實踐

阿里巴巴移動技術發表於2021-11-02

作者:玉追 & 以繩

優酷與華為長期保持著良好的戰略合作關係,旨在為消費者帶來優質的影音娛樂體驗。鴻蒙作業系統的流轉特性為多屏互動帶來了全新的玩法,本文以優酷播放中心的技術儲備為切入點,結合鴻蒙系統的映象和流轉特性,詳細介紹了普通流轉、自由視角和zoom 等核心能力在鴻蒙上的實踐之路。

背景介紹

鴻蒙分散式體驗

華為定義的分散式體驗主要包含連續性體驗和協同體驗兩種。

連續性體驗

當使用者在一個裝置上發起操作,並切換到另一個裝置上繼續操作時,使用者能夠馬上在新的裝置上繼續當前的操作。連續性體驗包括任務接續和音視訊接續。

協同體驗

多個裝置上的軟體和硬體能力相互協同,作為一個整體為使用者提供比單裝置更加高效、沉浸的體驗。協同體驗包括軟體協同和硬體協同。

對於優酷而言,我們已經向使用者提供瞭如下的多屏互動功能。

  • 使用者用手機觀看視訊到某一個時間點,然後切換到平板裝置從剛才的中斷時間點繼續看視訊
  • 使用者用手機或者平板開啟一個視訊,然後使用投屏功能將視訊投射到智慧屏或者電視盒子上,在大屏上繼續觀看
  • 使用者在大屏上遇到登入或者支付等不方便使用大屏側客戶端完成的功能,他可以使用手機直接掃描大屏上的二維碼登入或者支付。

上述功能,都是優酷客戶端利用現有的“華為一碰傳”,“華為HiPlay”等功能可以直接實現的。我們希望藉助鴻蒙OS提供的特色功能,實現若干當前優酷客戶端所不具備的“新功能”,開發出若干“純鴻蒙”專有特性,然後與Android優酷主客相融合。鴻蒙程式碼與Android程式碼相互聯動,共同為消費者提供各種酷炫的影音娛樂功能。

優酷客戶端橫跨Android,iOS,iPad,OTT等多種軟硬體平臺,彼此之前可以通過投屏等功能相互聯動,天然具有多屏互動的場景。

而HarmonyOS採用了多種分散式技術,使得應用程式的開發實現與不同終端裝置的形態差異無關。這能夠讓開發者聚焦上層業務邏輯,更加便捷、高效地開發應用。

在優酷鴻蒙版本中,我們基於HarmonyOS提供的分散式匯流排能力,與優酷端既有的投屏功能相結合,開發出全新的HarmonyOS多屏互動FA,提供多臺鴻蒙裝置之間多屏互動的功能。

這個FA也是100%利用鴻蒙API編寫的,使用者可以通過優酷鴻蒙版的播放頁“視訊流轉”按鈕,將手機端正在播放的視訊流轉到其它鴻蒙裝置上(鴻蒙智慧屏,平板等),並可以將手機作為遙控器對大屏裝置進行播控控制。

不僅能對大屏的音量、快進快退、播放速度、清晰度、劇集進行控制,還可以旋轉大屏上的自由視角視訊的角度。

“基於HarmonyOS的多屏互動”與傳統投屏的最大區別是,我們是利用HarmonyOS提供的“裝置/服務發現機制”來搜尋對端裝置,使用HarmonyOS的“建立連線”功能來建立裝置之間的雙向通訊。

由於HarmonyOSOS的 “裝置/服務發現機制”“建立連線”功能經過高度優化,我們自己的使用體驗是“HarmonyOS多屏互動”相比傳統DLNA或者Miracast映象功能,裝置發現快,連線建立快,且連線建立之後非常穩定,不容易斷連。

而且,我們可以通過此連線進行高速的資料傳輸,直接從操控側streaming視訊到大屏端。

下面,我們簡單介紹下HarmonyOS的分散式匯流排能力是如何與優酷既有的投屏功能相結合的。

投屏業務概覽

投屏技術在我們日常生活和工作中得到了越來越多的應用,手機、平板、個人電腦等無線屏顯和擴充套件功能也給家庭、企業會議、產品釋出、遠端培訓帶來了更加便捷、更加高效的模式變革。市場上相應的產品解決方案也是百花齊放,例如蘋果公司的 Airplay 無線投屏解決方案、WiFi 聯盟的 Miracast 無線投屏解決方案、谷歌公司的 ChromeCast 無線投屏解決方案、英特爾公司的 WIDI 無線投屏解決方案等,都在不同程度上推動了家庭和辦公場合多屏互動產品的升級演化。

無線投屏技術和網路環境的改善其實已經標誌著高效智慧時代的來臨,人們可以使用手機上網、看電視、娛樂、辦公,智慧電視除了看電視外,更趨向於智慧屏、螢幕的概念。大家希望能在電視上瀏覽資訊、購物、玩遊戲等等。人們更希望在大屏上享受看電視的沉浸感。未來的發展趨勢同樣也很明顯,市場巨大的潛在需求是投屏技術的最大推動力,將會呈現一個百花齊放的“盛景”。

作為國內網際網路視訊巨頭之一,優酷在投屏業務場景積累了豐富的技術和產品經驗,並取得了非常迅速的發展;另外,優酷獨有的播放能力,例如自由視角、zoom、AI超分、幀享4K等,也給多屏互動場景提供了強有力的擴充套件空間。整體而言,不管是優酷的投屏業務還是播放能力,都為同華為的合作打下了堅實的基礎。

鴻蒙流轉場景

HarmonyOS 是新一代的智慧終端作業系統,為不同裝置的智慧化、互聯與協同提供了統一的語言,並帶來簡潔、流暢、連續、安全可靠的全場景互動體驗。HarmonyOS 自誕生之初就以 “萬物互聯” 為使命,通過一套程式碼和核心的分散式技術,滿足了不同平臺上各種硬體的需求,打通了手機、平板、電腦、汽車和智慧穿戴等多種裝置,完美實現了不同裝置之間的流轉。可以說,“流轉” 是鴻蒙生態最為核心的特性之一。

隨著智慧時代的到來,流轉無處不在,不管是車機上的雙向控制,還是智慧家居間的一觸即連;不管是辦公室的檔案一碰投,還是手機和智慧屏的超級聯結,有螢幕的地方就能實現流轉。另一方面,5G 時代重新定義了大眾的文化娛樂方式,更大的螢幕、更高的位元速率、更智慧的流轉成為了核心訴求,在這個背景下,鴻蒙跟優酷自然而然走到了一起。

優酷投屏能力版圖

優酷投屏能力不僅能覆蓋傳統的區域網協議,如 DLNA、AirPlay 等,還全新自研了雲投屏協議,徹底打破了區域網組播的限制,提高了裝置發現成功率。此外,為了增加全新玩法,最新的魔屏裝置附贈了 NFC 貼紙,實現了一碰投功能,引入了全新的玩法。接下來詳細介紹下優酷投屏的能力版圖。

能力版圖

無線投屏有三個最基本的要素:內容、裝置和協議。其中,內容可以是非實時的資料檔案,例如電影、圖片、音樂等,也可以是實時的資料流,例如螢幕映象、直播流等。裝置包括髮起投屏的內容提供方(簡稱“傳送端”)和接收投屏的內容呈現方(簡稱“接收端”),其中常見的傳送端包括手機、平板等移動裝置,負責獲取遠端或本地儲存的媒體資源,並傳輸給接收端;接收端則負責響應來自傳送端的內容和播控指令,並完成後續的內容呈現。協議則提供了傳送端和接收端之間的互動規約,覆蓋了包括裝置發現、資料傳輸、播放控制等核心鏈路,比較有代表性的協議包括區域網投屏場景的 SSDP 和 SOAP 協議、雲投屏場景的 MTOP 和 ACCS 協議等。

多屏互動業務複雜度高,互動鏈路長,橫跨大小屏兩條業務線,涉及到包括廣告、會員、運營商、播放、硬體、媒資等非常多的業務方。

經過大量需求的長期打磨,優酷最終形成了如下的多屏互動版圖,可以分為投屏協議層,投屏播控層,業務適配層等核心組成部分:

投屏協議層

1、區域網投屏。包括 DLNA 和 AirPlay,通用性較強,但受限於組播能力,常會出現發現不了裝置的問題;

2、雲投屏。雲投屏是為了解決區域網協議無法發現裝置而自研的新協議,能有效提升裝置發現成功率,但受限於自營的大屏端應用,通用性受到了較大的限制;

3、NFC投屏。作為魔屏新硬體宣推的新特性之一,NFC投屏配合附帶的貼紙,縮短了移動端投屏的操作鏈路,實現了優酷視訊的 “一碰投”。

投屏播控層

  1. DRM管理。負責投屏裝置的管理和校驗,保證版權視訊的正確投放;
  2. 格式處理。適配和相容不同的大屏裝置,保證投屏後的播放體驗;
  3. 清晰度管理。負責多路清晰度的自適應和異常降級,兼顧廣告等業務場景;
  4. 輔助排程。基於投屏的專屬域名,具備針對不同區域、運營商、裝置資訊的動態流管理和排程能力。

業務適配層

  1. 投屏廣告。包括內投內、內投外、外投內三種組合。此外,大小屏端上投屏廣告的投放系統也在開發中;
  2. 點直短融合。將點播、直播、短視訊三個場景的播放適配模組下沉至投屏內部維護,這對於後期監控鏈路的統一和投屏能力的外發,都有重要意義。

鴻蒙系統初實踐

普通流轉

“鴻蒙流轉” 指利用了鴻蒙作業系統特性的多屏互動方式,與傳統投屏協議最大的區別在於對鴻蒙作業系統的依賴。具體而言,鴻蒙作業系統不僅提供了 “裝置/服務發現機制” 作為裝置發現的協議,還提供了 “裝置連線能力” 支援裝置之間進行雙向通訊。

類似傳統的投屏協議,鴻蒙流轉包括基於URL的普通流轉和基於流傳輸的流轉。普通流轉是指基於鴻蒙傳輸能力的多屏互動方式,不同於 DLNA 等通用協議,鴻蒙提供了包括裝置發現、資料傳輸、應用查詢、檔案分享等核心能力,不僅能提供較原生協議而言更穩定的連線,還能按照業務訴求,將自研的APK(例如酷喵)通過小屏傳輸至大屏並喚起,實現一系列定製化操作。

先圍繞普通流轉進行介紹,其時序圖如下所示。

如上圖所示,對其中部分核心流程的實現進行簡單介紹。

鴻蒙裝置發現

跟 DLNA 投屏和雲投屏發現流程完全一致,鴻蒙的發現協議在 DlnaDevs 的 search 方法中實現:

// 鴻蒙search
    if (HarmonyCastMgr.haveInst()) {
        HarmonyCastMgr.getInst().searchDevs();
        // 自由視角search
        if (HarmonyCastMgr.getInst().hasMirr()){
            HarmonyCastMgr.getInst().searchHarmonyMirrorDevs();
        }
    }

再來看看鴻蒙發現流程的實現細節:

    // 搜尋裝置(非同步方式)
    public boolean searchDevs() {
        boolean ret = false;
        if (isHarmonyEnable()) {
            Intent intent = new Intent();
            ComponentName componentName = new ComponentName(PackageContant.PACKAGE_YOUKU, "com.youku.feature.MiddlewareAbility");
            intent.setComponent(componentName);
            intent.putExtra(AbilityUtils.PARAM_KEY_INSTALL_ON_DEMAND, true);
            intent.setAction("action.videoplayer.getdevicelist");
            try {
                mActivity = YoukuContext.getTopActivity();
                ret = AbilityUtils.connectAbility(mActivity, intent, mServiceConnection);
            } catch (RuntimeException e) {
                e.printStackTrace();
                ret = false;
            }
        }
        return ret;
    }

鴻蒙發現協議通過 AIDL 依賴了 FA 的通道,其中 mServiceConnection 內部對 IBinder 物件進行了解析,對映為多屏互動定義的 Device 型別,並回撥裝置列表的更新介面,核心實現如下:

   public ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LogEx.d(tag(), "onServiceConnected");
            HarmonyRCS rcs = new HarmonyRCS(service);
            String[] devices = null;

            try {
                devices = rcs.getDeviceList();
            } catch (RemoteException e) {
                e.printStackTrace();
            }

            // 裝置ID和名稱陣列,以適應鴻蒙AIDL查詢格式
            List<String> deviceIdList = new ArrayList<>();
            List<String> deviceNameList = new ArrayList<>();

            for (int i = 0; i < devices.length; i++) {
                if ((i & 1) == 0) {
                    deviceIdList.add(devices[i]);
                } else {
                    deviceNameList.add(devices[i]);
                }
            }

            // 原始資料對映為Client格式
            if (deviceNameList.size() >= deviceIdList.size()) {
                mHarmonyDevs.clear();
                for (int i = 0; i < deviceIdList.size(); i++) {
                    String deviceId = deviceIdList.get(i);
                    String deviceName = deviceNameList.get(i);
                    if (StringUtils.isNotBlank(deviceId) && StringUtils.isNotBlank(deviceName)) {
                        Client client = new Client();
                        
                        ...

                        mHarmonyDevs.put(deviceId, client);
                    }
                }

                // 判斷大屏裝置是否線上,如果不線上,則停止投屏
                if (DlnaApiBu.api().proj().stat() == DlnaPublic.DlnaProjStat.PLAYING) {
                    Client currentDev = DlnaApiBu.api().proj().req().mDev;
                    if (currentDev != null && currentDev.isHarmonyDev() && !mHarmonyDevs.containsKey(currentDev.getDeviceUuid())) {
                        stopProjEx();
                    }
                }

                // 回撥呼叫方獲取裝置列表
                if (null != mRcsCallback) {
                    mRcsCallback.onHarmonyDevsChanged();
                }
            }

            try {
                if (mActivity != null) {
                    AbilityUtils.disconnectAbility(mActivity, mServiceConnection);
                }
            } catch (Exception pE) {
                pE.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            LogEx.d(tag(), "onServiceConnected");
        }
    };

選擇裝置並啟動FA

類似雲投屏自研協議,鴻蒙普通流轉依賴單獨的發現流程,類似於其他協議,建立 HarmonyCastTrunkBiz 以作為鴻蒙協議管理類,並實現瞭如下基礎介面:

    // 開始投屏
    void start();
  
    // 停止投屏
    void stop();

    // 傳送播放指令
    void play();

    // 傳送暫停指令
    void pause();

    // 傳送seek指令
    void seek(int prog);

    // 傳送設定音量指令
    void setVolume(int volume);

由於鴻蒙 FA 提供了定製的遙控器介面和雙向資料傳輸通道,因此所有傳送指令的任務均由鴻蒙 FA 接管,上述負責傳送指令的介面僅僅同步了小屏端的播放狀態。使用者點選選中鴻蒙裝置後,觸發 start 方法並啟動鴻蒙協議入口,由 HarmonyCastMgr 的 startHarmony 負責同鴻蒙 FA 之間的資料互動:

    // 投屏所需的播放資料
    HarmonyCastData castData = new HarmonyCastData();
    castData.mDev = req.mDev;
    castData.mUrl = req.mUrl;
    castData.metaData = DlnaMetadata.getInst().getMetadataWithReq(req);
    castData.isFromNowbar = isFromNowbar;

    // FA遙控器所需的UI資料
    HarmonyParameterBean parameterBean = new HarmonyParameterBean();
    parameterBean.deviceUuid = req.mDev.getDeviceUuid();
    parameterBean.mShowTitle = req.mShowTitle;
    parameterBean.projSource = "";
    parameterBean.isYoukuApp = req.mDev.isYoukuApp;
    String parameterData = JSON.toJSONString(parameterBean);
    
    // 按FA資料格式進行封裝
    String touchuanData = JSON.toJSONString(castData);
    HarmonyPaBean paBean = new HarmonyPaBean();
    paBean.touchuanData = touchuanData;
    paBean.parameterData = parameterData;
  
    final String harmonyJson = JSON.toJSONString(paBean);
    Activity activity = YoukuContext.getTopActivity();
    Intent jIntent = new Intent();
    ComponentName component = new ComponentName(PackageContant.PACKAGE_YOUKU, "com.youku.feature.MainAbility");
    jIntent.putExtra(AbilityUtils.PARAM_KEY_INSTALL_ON_DEMAND, true);
    jIntent.putExtra("harmonyJson", harmonyJson);
    jIntent.setComponent(component);

    try {
        // 每次開始投屏前檢測一次遠端是否線上,避免因大屏掉線導致的投屏失敗
        boolean remoteValid = true;
        if (HarmonyCastMgr.haveInst()) {
        remoteValid = HarmonyCastMgr.getInst().searchDevs();
    }

        if (remoteValid) {
            AbilityUtils.startAbility(activity, jIntent);
        } else {
            stopProjEx();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

自由視角

自由視角由阿里文娛摩酷實驗室研發,是一種可以隨意滑動視訊、自由切換觀看視角的播放技術。自由視角視訊是多視角直播的進一步發展,帶給使用者更多的主動性。使用者可以在觀看球賽時旋轉視角,並放大區域性畫面,近距離觀看偶像球員的灌籃動作,實現堪比跨次元的真實觀影體驗。

以下是 “這就是街舞” 綜藝的自由視角效果:

視訊請見原文中:優酷鴻蒙開發實踐|多屏互動開發實踐

不同於普通視訊,自由視角視訊的位元速率普遍偏高。例如上述街舞錄製現場,總共安裝了超過 40 臺專用相機,形成的陣列採集畫面全方位記錄了每個精彩瞬間,並實現毫秒級同步和遠端協同控制,採集到的畫面經過焦點矯正和3D重建,再基於各機位採集到的紋理、深度、姿態等引數資訊,最終將多角度分散的畫面拼接成一個高達6K、8K的高清視訊檔案。

因此,自由視角視訊在提升使用者觀感的同時,也對播放端的網路環境和解碼效能提出了非常高的要求。最初的自由視角實現方案是基於流轉特性,小屏端將自由視角視訊的 M3U8 地址或播控指令,通過上述流轉能力傳遞給大屏側,由大屏側完成資料的下載、解碼和渲染等後續流程。但考慮到華為智慧屏的硬體效能不足以支撐這種規模的計算量,傳統的流轉方案不得不被叫停。

為此,開發團隊對比了鴻蒙系統上現存的所有投屏協議,得到如下表的結論:

鴻蒙投屏協議優點缺點
DLNA標準成熟協議,通用性強原生擴充套件能力較弱
雲投屏不依賴區域網,擴充套件性強通用性較差
鴻蒙協議系統適配度高,擴充套件能力強依賴鴻蒙系統
Cast+協議系統適配度高,相容性強,滿足流傳輸需要依賴華為生態

經過內部評估以及同華為研發團隊的討論,開發團隊最終決定放棄傳統的基於URL的投屏方式,採用基於華為 Cast+ 的映象投屏方案,具體而言,是在手機端正常播放和操控自由視角視訊,並把播放器檢視通過Cast+映象到電視端。

簡單介紹下華為 Cast+ 協議的實現細節。如下圖所示,華為 Cast+ Kit 是華為自研的、以手機為中心的多屏協同元件,業務方可據此實現多裝置之間快速、穩定、低時延的映象傳輸。

基於華為 Cast+ 協議,自由視角場景的投屏鏈路跟普通投屏協議大體保持一致,重疊的部分包括裝置搜尋、選擇裝置和建連,不同之處在於,自由視角視訊最後一步並沒有投放播放地址到大屏,而是建立虛擬屏並完成顯示,虛擬屏的建立時機和方式是實踐過程中的重中之重。

自由視角流轉方案的本質,可以概括為兩個方面:首先,將遙控器頁面作為主螢幕,打通其與播放頁之間的雙向資料通道,以實現播放控制和狀態同步;其次,在虛擬屏上啟動播放相關的檢視,作為映象和傳輸到大屏的內容。

主螢幕的方案基本確定,輪到虛擬屏的時候卻踩了坑。最初能想到的虛擬屏渲染物件,自然而然是全屏播放頁,然而試了才發現,直接將全屏播放頁渲染到虛擬屏,會存在如下兩個問題,附帶分析報告如下:

問題1:主螢幕上的遙控器頁面首先被映象到大屏。

  • 原因:Cast+ 會在建連成功後、裝置處於 PLAYING 狀態時,開始抓取虛擬屏的內容,如果虛擬屏尚未載入,會擷取主螢幕內容作為兜底。經過測試,這個時間差大概在 100ms 左右,而期間播放頁無法完成初始化,因此會存在主螢幕內容佔用的問題。

問題2:播放頁進入後存在橫豎屏切換邏輯,導致映象後螢幕會經歷一次轉屏。

  • 原因:屬於播放頁自適應邏輯,初始進入時為豎屏,在映象後會觸發橫屏切換邏輯,從而導致大屏側的轉屏。

內部綜合評估後,決定採用更加輕量的方式實現虛擬屏。我們發現,播放器 Dialog 中只包含 SurfaceView 和 Loading 狀態等內容,如果僅僅映象 Dialog 級別,雖然增加了較多的播放器處理邏輯,但保證了上屏速度和更快的響應效率。調整後的方案結構如下圖所示。

該方案具備如下優勢:

  1. 優化了播放器的生命週期,每次在自由視角流轉和小屏播放之間切換時,僅僅切換 SurfaceView,並不重建播放器,此時播放器只是處於 STOPPED 狀態,切到小屏播放後,跳過了初始化和播放地址請求等過程,保證快速起播;
  2. 將啟動 Presentation 的時機提前,在收到 onDisplayAdded 時就進行頁面啟動和播放器續播,大大縮短了上屏時間。

綜上所示,最終的效果如下視訊所示。

視訊請見原文中:優酷鴻蒙開發實踐|多屏互動開發實踐

線上表現

網友們對鴻蒙系統的特性和優酷鴻蒙版本的表現,也表現出了強烈的興趣,我們摘取了網上的一些體驗視訊,列舉如下:

隨後,經過兩個版本的持續迭代,優酷鴻蒙版的穩定性和體驗得到了極大改善。另一方面,伴隨著鴻蒙系統的自我完善,優酷鴻蒙版的二期需求版本已經開始排期,相信在雙方強強聯合之下,會持續給市場和使用者帶來驚喜。

總結

在優酷鴻蒙版多屏互動專項的開發過程中,各參與方在鴻蒙介面和除錯環境尚不完善的時候介入,克服了重重困難,不斷探索試錯,在極短的時間內掌握了鴻蒙開發技術棧,不僅順利完成了大大小小的開發任務,還反饋給華為技術團隊不少遺留問題和改進建議。這是雙方再一次的深度合作,也是一次非常成功的實踐。

對於華為而言,優酷鴻蒙版不僅給鴻蒙生態帶來了開創性的視訊新互動形式,讓新使用者大呼過癮;而且完美適配了鴻蒙系統流轉特性、為後續更豐富的新玩法鋪平了道路。對於優酷而言,鴻蒙上的多屏互動實踐,大大擴充套件了現有的多屏互動能力版圖,為鴻蒙新時代積累了重要經驗。

關注我們,每週 3 篇移動技術實踐&乾貨給你思考!

相關文章