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文件:
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-r -r
在这里 :
-
CODEGEN_DIR: 生成文件的目的路径
-
ROM_FILE: 包含这个文件的 Kurento Media Element Description (kmd)文件列表或文件夹的空间划分。例如: 你可以看下 内部源代码。
-
TEMPLATES_DIR: 包含模版文件的目录。例如:你可以看一下内部 和 的模版。