Kurento協議

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

Kurento媒體服務器可以被兩種外部Kurento客戶端控制,如Java或JavaScript。這些客戶端使用Kuernto協議來和KMS通信。Kurento 協議是基于WebSocket協議,并使用了JSON-RPC V2.0 消息來提交請求和發送響應。

JSON-RPC 消息格式

Kurento協議使用JSON-RPC V2.0 編碼它的消息,下面的章節將討論如何在JSON消息中使用這種格式。

Request 消息

一個RPC調用可以表示為向服務端發送一個Request消息,Request消息有下列成員變量:

  • jsonrpc: 指定JSON-RPC 協議的版本的字符串,它必須是"2.0"。

  • id: 由客戶端建立的唯一標識符,包含一個字符串或數字。 服務端必須在Response消息中以相同的值回復。 這個成員變量被用于在兩個消息間地內容進行關聯。

  • method: 被激活方法名 。

  • params: 用于被激活方法的結構體,它包含了參數值。

下面的JSON顯示了一個示例請求的格式:

{"jsonrpc": "2.0","id": 1,"method": "create","params": {"type": "PlayerEndPoint","constructorParams": {"pipeline": "6829986","uri": "http://host/app/video.mp4"},"sessionId": "c93e5bf0-4fd0-4888-9411-765ff5d89b93"}
}

成功的響應消息

當一個RPC調用讓服務端回復一個響應消息時,如果是一個成功的響應,那么響應消息將包含如下成員變量:

  • jsonrpc:指定JSON-RPC協議的版本的字符串,它必須是"2.0".

  • id:它強制性地和請求消息中的id值一致。

  • result: 它的值是由服務端被激活的方法來確定的。如果連接被拒絕,它返回一個拒絕屬性的消息,拒絕屬性包含了消息代碼,以及為什么session被拒絕,并且不會有被定義的sessionId。

下面是一個成功響應示例:

{"jsonrpc": "2.0","id": 1,"result": {"value": "442352747","sessionId": "c93e5bf0-4fd0-4888-9411-765ff5d89b93"}
}

出錯的響應消息

當一個RPC調用讓服務端回復一個響應消息時,如果是一個出錯的響應,那么響應消息將包含如下成員變量:

  • jsonrpc: 指定JSON-RPC協議的版本的字符串,它必須是"2.0".

  • id: 它強制性地和請求消息中的id值一致。如果檢測到請求消息中id是錯誤的(如錯誤或無效的請求),它就為空。

  • error: 一個消息,通過下面成員變量來描述這個錯誤:

    • code: 標識遇到的錯誤類型的整數值

    • message: 錯誤的簡單描述

    • data: 原始或結構體的值,包含了關于錯誤的額外信息。它可以被忽略,它的值是由服務端定義的。

下面顯示了一個典型的出錯響應:

{"jsonrpc": "2.0","id": 1,"error": {"code": "33","message": "Invalid paramter format"}
}

JSON-RPC之上的Kurento API

如在Kurento API章節所述,Kurento媒體服務器提供了一套完整成熟的API,讓應用程序以多種方式處理媒體。

為了使用這些豐富的API, Kurento客戶端要求在客戶端和服務端之間實現全雙式通信。基于這個原因,Kurento協議是基于WebSocket傳輸的。

在發出命令之前,Kurento客戶端需要先請求和Kurento媒體服務器的URL: ws://hostname:port/kurento建立WebSocket連接。一旦這個WebSocket連接已建立,Kurento協議提供了五種不同的類型的請求/響應消息:

  • ping: 客戶端和KMS之間保活。

  • create: 實例化一個新的媒體對象,如管道或媒體元件。

  • invoke: 調用已創建對象的方法。

  • subscribe: 創建對象中的事件訂閱。

  • unsubscribe: 移除一個事件的訂閱。

  • release: 刪除對象并釋放其資源。

Kurento協議還允許Kurento媒體服務器向客戶端發送請求:

  • onEvent: 這個請求是在事件發生時,Kurento媒體服務器向客戶端發送請求。

Ping

為了保證客戶端和Kurento Media Server之間的WebSocket連接,實現了保持活動方法。 此方法基于客戶端發送的ping方法,必須使用來自服務器的pong消息進行回復。 如果在時間間隔內未獲得響應,則客戶端知道與媒體服務器的連接已丟失。參數間隔是從服務器接收Pong消息的超時時間,以毫秒為單位。 默認情況下,此值為240000(即40秒)。 這是ping請求的示例:

{"id": 1,"method": "ping","params": {"interval": 240000},"jsonrpc": "2.0"
}

對ping請求的響應必須包含具有固定名稱為pong的value參數的result對象。 以下片段顯示了對上一個ping請求的pong響應:

{"id": 1,"result": {"value": "pong"},"jsonrpc": "2.0"
}

Create

Create消息請求 Kurento API 對象的創建。參數 type 指定了被創建對象的類型。參數 constructorParams 包含了創建該對象需要的所有信息。每個消息都需要不同的 constructorParams 來創建對象,這些參數是在Kurento API章節中定義的。

最后,參數sessionId為當前session的標識符。這個參數的值是由Kurento Media Server在每次響應時發送給客戶端。只有第一次的從客戶端到服務端的請求不需要這個‘sessionId’(因為這時候客戶端還未收到這個值)。

下面的例子展示了一個request消息請求,它請求創建一個MediaPipeline類型對象:

{"id": 2,"method": "create","params": {"type": "MediaPipeline","constructorParams": {},"properties": {}},"jsonrpc": "2.0"
}

響應消息中, 在域value中包含了媒體管道id。消息id還會要被用在協議的其它請求中,sessionId要在每個響應中返回, 標識當前會話。

{"id": 2,"result": {"value": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline","sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

響應消息包含字段值中包含新對象的標識符。 像往常一樣,消息id必須與請求消息匹配。 每個響應中還返回sessionId。 以下示例顯示請求消息,請求在現有介質管道(由參數mediaPipeline標識)中創建WebRtcEndpoint類型的對象。 請注意,在此請求中,sessionId已存在,而在上一個示例中,它不是(因為在那一點對于客戶端是未知的):

{"id": 3,"method": "create","params": {"type": "WebRtcEndpoint","constructorParams": {"mediaPipeline": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline"},"properties": {},"sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

以下示例顯示請求消息,請求在現有介質管道(由參數mediaPipeline標識)中創建WebRtcEndpoint類型的對象。 請注意,在此請求中,sessionId已存在,而在上一個示例中,它不是(因為在那一點對于客戶端是未知的):

{"id": 3,"result": {"value": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline/087b7777-aab5-4787-816f-f0de19e5b1d9_kurento.WebRtcEndpoint","sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

Invoke

Invoke 消息請求對指定對象調用一個操作。

參數 object 指示了被調用操作的對象的id,

參數 operation 指示了被調用操作的名稱。

參數 operationParams 包含了執行操作需要的參數。

以下示例顯示請求消息,請求調用連接到WebRtcEndpoint的PlayerEndpoint上的操作connect:

{"id": 5,"method": "invoke","params": {"object": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline/76dcb8d7-5655-445b-8cb7-cf5dc91643bc_kurento.PlayerEndpoint","operation": "connect","operationParams": {"sink": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline/087b7777-aab5-4787-816f-f0de19e5b1d9_kurento.WebRtcEndpoint"},"sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

響應消息包含執行對象中調用操作時返回的值,如果操作未返回任何值,則返回空值。

以下示例顯示調用操作connect(不返回任何內容)時的典型響應:

{"id": 5,"result": {"sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

Release

Release 消息請求釋放指定對象。參數 object 指定了要釋放的對象的id:

{"id": 36,"method": "release","params": {"object": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline","sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

響應消息只包含sessionID, 下面是一個示例:

{"id": 36,"result": {"sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

Subscribe

Subscribe消息請求訂閱指定對象的某種類型的事件。參數 object 指定了要訂閱事件的對象id. 參數 type 指定了事件的類型。如果客戶端訂閱了一個對象的某種事件,每次對象的這個事件發生后, Kurento Media Server就會使用 onEvent 方法發送一個請求到客戶端。這種類型的請求會在后面的章節再講解。

以下示例顯示請求消息,請求在PlayerEndpoint對象上預訂事件類型EndOfStream:

{"id": 11,"method": "subscribe","params": {"type": "EndOfStream","object": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline/76dcb8d7-5655-445b-8cb7-cf5dc91643bc_kurento.PlayerEndpoint","sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

響應消息包含了訂閱標識符,這個值會在后面的解除訂閱中要用到。

下面的示例顯示一個訂閱請求的響應消息,屬性 value 的值包含了訂閱id:

{"id": 11,"result": {"value": "052061c1-0d87-4fbd-9cc9-66b57c3e1280","sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

Unsubscribe

Unsubscribe 消息請求解除前面事件的訂閱。參數 subscription 包含了從服務端收到的成功訂閱后的訂閱id。

以下示例顯示請求消息,請求取消給定對象353be312-b7f1-4768-9117-5c2f5a087429的訂閱:

{"id": 38,"method": "unsubscribe","params": {"subscription": "052061c1-0d87-4fbd-9cc9-66b57c3e1280","object": "6ba9067f-cdcf-4ea6-a6ee-d74519585acd_kurento.MediaPipeline/76dcb8d7-5655-445b-8cb7-cf5dc91643bc_kurento.PlayerEndpoint","sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

響應消息包含了sessionId。下面的示例顯示了一個解除訂閱請求的響應:

{"id": 38,"result": {"sessionId": "bd4d6227-0463-4d52-b1c3-c71f0be68466"},"jsonrpc": "2.0"
}

OnEvent

當客戶端訂閱了對象的某類事件后,每當對象的這類事件發生時,服務端都會發送一個onEvent請求。這也是為什么Kurento協議要使用Websocket并要在客戶端和服務端間使用全雙工的工作模式。服務端發送到客戶端的請求包含了事件的所有信息:

  • source: 事件的對象源。

  • type: 事件的類型。

  • timestamp:媒體服務器時間

  • tags: 可以使用setSendTagsInEvents和addTag方法在每個元素中標記媒體元素。 這些標記是鍵值元數據,可供開發人員用于自定義目的。 媒體服務器在此字段中為每個事件返回標簽。

下面的顯示了服務端發送到客戶端的提醒:

{"jsonrpc":"2.0","method":"onEvent","params":{"value":{"data":{"source":"681f1bc8-2d13-4189-a82a-2e2b92248a21_kurento.MediaPipeline/e983997e-ac19-4f4b-9575-3709af8c01be_kurento.PlayerEndpoint","tags":[],"timestamp":"1441277150","type":"EndOfStream"},"object":"681f1bc8-2d13-4189-a82a-2e2b92248a21_kurento.MediaPipeline/e983997e-ac19-4f4b-9575-3709af8c01be_kurento.PlayerEndpoint","type":"EndOfStream"}}
}

通知消息沒有 id 字段是因為響應不是必須的。

網絡問題

KMS處理的資源是高消耗的,因此,KMS實現了一個垃圾收集器。

當客戶端斷開連接后超過4分鐘,媒體元件就會被收集。在這個時間后,這些媒體元件會被自動處理。

因此,客戶端和KMS間的websocket連接可以在任何時間激活。當網絡臨時中斷中,KMS實現了一個和客戶端重連的機制。

有一種基于上面格式特殊類型的消息,這個消息允許客戶端重新連接到前面連接KMS:

{"jsonrpc": "2.0","id": 7,"method": "connect","params": {"sessionId":"4f5255d5-5695-4e1c-aa2b-722e82db5260"}
}

如果KMS回應如下:

{"jsonrpc": "2.0","id": 7,"result": {"sessionId":"4f5255d5-5695-4e1c-aa2b-722e82db5260"}
}

則表示客戶端重新連接到了同一個KMS。如果連接到了其它KMS, 則消息如下:

{"jsonrpc":"2.0","id": 7,"error":{"code":40007,"message":"Invalid session","data":{"type":"INVALID_SESSION"}}
}

在這種情況下,客戶端應該再次調用原始的連接以獲得一個新的sessionId:

{"jsonrpc":"2.0","id": 7,"method":"connect"
}

Kurento API

為了實現一個Kurento客戶端,你需要仔細閱讀本文檔。而知道所有細節的最好的方式是查看IDL文件,它定義了Kurento元件的接口。我們已經定義了基于JSON的通用IDL格式。從它開始,我們為Java和JavaScript生成了客戶端代碼。Kurento API定義了下列IDL文件:

  • KMS core
  • KMS elements
  • KMS filters

Example: WebRTC in loopback

本章節描述了Kurento客戶端和Kurento Media Server實現了下WebRTC回話功能的消息交互。它完整地展示了教程中的過程 ,步驟如下:

[ 1 ] 客戶端發送一個創建媒體管道的請求消息:

{"id":1,"method":"create","params":{"type":"MediaPipeline","constructorParams":{},"properties":{}},"jsonrpc":"2.0"
}

[ 2 ] KMS回應一個包含有媒體管道ID和媒體會話ID(sessionId)的響應消息:

{"id":1,"result":{"value":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline","sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"},"jsonrpc":"2.0"
}

[ 3 ] 這里是列表文本 客戶端發送一個創建WebRtcEndpoint的請求:

{"id":2,"method":"create","params":{"type":"WebRtcEndpoint","constructorParams":{"mediaPipeline":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline"},"properties": {},"sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"},"jsonrpc":"2.0"
}

[ 4 ] KMS創建一個WebRtcEndpoint,并回給客戶端這個媒體元件的標識符:

{"id":2,"result":{"value":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_WebRtcEndpoint","sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"},"jsonrpc":"2.0"
}

[ 5 ] 客戶端調用WebRtcEndpoint的連接原語來創建一個回放:

{"id":3,"method":"invoke","params":{"object":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_WebRtcEndpoint","operation":"connect","operationParams":{"sink":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_WebRtcEndpoint"},"sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"},"jsonrpc":"2.0"
}

[ 6 ] KMS執行連接并回應這個操作:

{"id":3,"result":{"sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"},"jsonrpc":"2.0"
}

[ 7 ] 客戶端調用WebRtcEndpoint的processOffer原語來進行WebRTC的SDP協商:

{"id":4,"method":"invoke","params":{"object":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_WebRtcEndpoint","operation":"processOffer","operationParams":{"offer":"SDP"},"sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"},"jsonrpc":"2.0"
}

[ 8 ] KMS執行SDP協商并返回SDP回答:

{"id":4,"result":{"value":"SDP"},"jsonrpc":"2.0"
}

Kurento Module Creator

默認的Kurento客戶端(java和JavaScript)是使用一個叫作 Kurento Module Creator的工具創建的。因此,這個工具同樣可以被用來創建基于其它語言的定制化客戶端。

Kurento Module Creator在Ubuntu機器上使用如下命令安裝:

sudo apt-get install kurento-module-creator

這個工具的目的是為了生成客戶端代碼,以及生成服務端需要的glue代碼。對于代碼生成,它通常使用Freemarker 作為模板引擎。通常的使用Kurento Module Creater 的方式是運行如下命令:

kurento-module-creator -c <CODEGEN_DIR> -r <ROM_FILE> -r <TEMPLATES_DIR>

在這里 :

  • CODEGEN_DIR: 生成文件的目的路徑

  • ROM_FILE: 包含這個文件的 Kurento Media Element Description (kmd)文件列表或文件夾的空間劃分。例如: 你可以看下 Kurento Media Server內部源代碼。

  • TEMPLATES_DIR: 包含模版文件的目錄。例如:你可以看一下內部 java 和 javascript 的模版。

轉載于:https://my.oschina.net/997155658/blog/840265

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396733.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396733.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396733.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

升級php7_PhpStorm 2019.3 發布,全面支持 PHP 7.4

PhpStorm 2019.3 發布了&#xff0c;這個版本主要集中在性能和質量上&#xff0c;旨在提供一個更穩定、更快的 IDE。PhpStorm 2019.3 全面支持 PHP 7.4&#xff0c;還帶來 PSR-12 代碼樣式&#xff0c;用于遠程解釋器的 WSL&#xff0c;MongoDB 支持&#xff0c;HTTP 客戶端更新…

ftp 客戶端 使用http代理 源碼_代理服務器連接HTTPS過程

說到HTTPS代理很多人瞬間就會聯想到HTTPS的各種證書和各種加密&#xff0c;覺得很高端很復雜的樣子。其實不然&#xff0c;代理服務器不需要配置證書、也不需要處理任何加密。因為HTTPS代理是通過Web隧道(Web tunnel)工作的。Web隧道允許用戶通過HTTP連接發送非HTTP流量(例如FT…

python解zuobiaoxi方程_Python還能解決數學相關問題?大學生:以后就靠他了,事半功倍...

問題背景高等數學應用非常廣&#xff0c;基本上涉及到函數的地方都要用到微積分&#xff0c;還有在幾何方面也是如此&#xff0c;計算機的應用讓我們能簡單快速處理各種高等數學中的計算&#xff0c;比如極限、導數、積分、微分方程等的計算。實驗目的使用 Python 通過計算與作…

Android版:驗證手機號碼的正則表達式 (轉)

/** * 驗證手機格式 */ public static boolean isMobileNO(String mobiles) { /* 移動&#xff1a;134、135、136、137、138、139、150、151、157(TD)、158、159、187、188 聯通&#xff1a;130、131、132、152、155、156、185、186 電信&#xff1a;133、…

基礎正則表達式介紹與練習

基礎正則表達式介紹與練習 一、什么是正則表達式 在做文字處理或編寫程序時&#xff0c;用到查找、替換等功能&#xff0c;使用正則表達式能夠簡單快捷的完成目標。簡單而言&#xff0c;正則表達式通過一些特殊符號的幫助&#xff0c;使用戶可以輕松快捷的完成查找、刪除、替換…

android canvas 網絡圖,【巨坑:toDataURL】canvas合成網絡圖片

不知有沒有小伙伴用過canvas合成圖片&#xff0c;然后爆炸報錯截圖尼瑪&#xff0c;然后各種搜索&#xff0c;不外乎以下幾種坑爹處理方案&#xff1a;后端處理&#xff0c;比如Access-Control-Allow-Origin "*"(要是請求到其他網站的圖片就不適用了&#xff0c;比如…

水晶報表如何查看sql_有了這個報表工具,一鍵生成自定義的各種報表,還可以導出Excel...

EasyReport是一個簡單易用的Web報表工具,它的主要功能是把SQL語句查詢出的數據轉換成報表頁面&#xff0c; 同時支持表格的跨行(RowSpan)與跨列(ColSpan)配置。 同時它還支持報表Excel導出、圖表顯示及固定表頭與左邊列的功能。功能介紹本工具從數據庫(MySQL,Oracle,SQLServer,…

python 三維向量 交互_Blender實現Nature of Code1.5單位向量[Nature of Node 004]

【Nature of Node #004】Blender創意編程進階應用&#xff1a;實現Nature of CodeNature of Code 1.5, Unit Vector (Normalize)背景介紹這個系列“Nature of Node”&#xff0c;是專門用Blender的Node&#xff08;節點&#xff09;方式來實現Nature of Code。用到一個Blender插…

Sitemesh3的使用及配置

1 . Sitemesh 3 簡介 Sitemesh 是一個網頁布局和修飾的框架&#xff0c;基于 Servlet 中的 Filter&#xff0c;類似于 ASP.NET 中的‘母版頁’技術。參考&#xff1a;百度百科&#xff0c;相關類似技術&#xff1a;Apache Tiles。 官網&#xff1a;http://wiki.sitemesh.org/wi…

等保項目流程

等級保護&#xff1a;直屬管理公安局 產品必須通過公安局安全許可證分級保護&#xff1a;直屬管理保密局 產品必須通過保密局銷售許可證等級保護&#xff1a;一般分為5級&#xff0c;目前最高用到是等保4級總概&#xff1a;定級——前期調研——總…

鴻蒙系統r如何升級,高歌猛進,鴻蒙系統升級機型再次確認,花粉:終等到!...

雖然華為手機現在的壓力非常大&#xff0c;但是在前進的道路上&#xff0c;真的充滿了樂觀精神&#xff0c;而且現在也算是一路高歌猛進了&#xff0c;發展路線開始加快了許多&#xff0c;無論是新機還是系統&#xff0c;都有著非常多的新消息。因為華為手機的實力很強&#xf…

Oracle快速備份表數據

Oracle數據庫中備份表數據。 例子&#xff1a; 1 create table table_name_bak as select * from table_name 1 create table table_name_bak as select * from table_name 2 where table_name.date between TO_DATE(2018-09-25,yyyy-MM-dd) and TO_DATE(2018-09-26,yyyy-MM-d…

git pull

今天在服務器上git pull是出現以下錯誤&#xff1a; error: Your local changes to the following files would be overwritten by merge: application/config/config.php application/controllers/home.php Please, commit your changes or stash them before you can merge. …

jq控制div是否展示_jQuery控制多個DIV的顯示和隱藏

問題補充&#xff1a;這是我寫的JSfunction Previous(){for(var i1;i<3;i){if(document.getElementById("d"i).style.display"block"){document.getElementById("d"(i-1)).style.display"block";}document.getElementById("d&…

C# 線程間不能調用剪切板的問題

最近做一個項目&#xff0c;需要用到線程&#xff0c;而且要用到剪切板&#xff0c;創建了一個子線程之后發現在子線程中剪切板上獲取不到數據&#xff0c;當時特別納悶&#xff0c;上網查資料&#xff0c;最后終于搞定&#xff0c;現將解決方法歸納如下&#xff1a; 第一步&am…

android studio背景模糊_[Android翻譯]CameraX:過去、現在和未來的一瞥

CameraX是一個未捆綁的Android Jetpack庫&#xff0c;它可以幫助你在Android應用中輕松添加攝像頭功能。傳統上&#xff0c;由于Android設備種類繁多&#xff0c;編程模型復雜&#xff0c;在Android上構建具有相機功能的應用程序非常困難。現在成千上萬的開發者都在使用CameraX…

html頁面根據分辨率縮放,html2Canvas根據不同分辨率,生成pdf內容自適應

根據屏幕大小不同&#xff0c;頁面內容自適應并一頁展示&#xff0c;應該如何實現// 導出頁面為PDF格式import html2Canvas from html2canvasimport JsPDF from jspdfexport default{install (Vue, options) {Vue.prototype.getPdf function () {setTimeout(() > {var titl…

【agc002f】Leftmost Ball(動態規劃)

【agc002f】Leftmost Ball&#xff08;動態規劃&#xff09; 題面 atcoder洛谷 題解 我們從前往后依次把每個顏色按順序來放&#xff0c;那么如果當前放的是某種顏色的第一個球&#xff0c;那么放的就會變成\(0\)號顏色&#xff0c;所以無論何時&#xff0c;\(0\)號顏色的數量不…

VS2010中的快捷鍵

一. VS2010中的快捷鍵 1&#xff1a; Ctrl Enter &#xff08;在光標指定位置的上 K C &#xff08;注釋&#xff09; Ctrl E U &#xff08;取消注釋&#xff09;  <>  Ctrl K U &#xff08;取消注釋&#xff09; 5&#xff1a; Tab &#xff08;增加縮進&a…

export function函數傳參_04 js高階函數(惰性函數、柯里化函數、compose函數)和單例設計模式...

高階函數的定義在《javascript設計模式和開發實踐》中是這樣定義的。函數可以作為參數被傳遞&#xff1b;函數可以作為返回值輸出。結合這兩個特點&#xff0c;首先想到的肯定是回調函數&#xff0c;回調函數也是高階函數的一種&#xff0c;除了回調函數&#xff0c;還有很多的…