Kurento应用开发指南(以Kurento 6.0为模板) 之八: Kurento协议

14.1 Kurento协议
Kurento媒体服务器可以被两种外部Kurento客户端控制,如Java或JavaScript。
这些客户端使用Kuernto协议来和KMS通信。
Kurento协议是基于WebSocket协议,并使用了JSON-RPC V2.0 消息来提交请求和发送响应。

14.1.1 JSON-RPC 消息格式

Kurento协议使用JSON-RPC V2.0 编码它的消息,下面的章节将讨论如何在JSON消息中使用这种格式。


>>> Request 消息
一个RPC调用可以表示为向服务端发送一个Request消息,Request消息有下列成员变量:
 . jsonrpc: 
   指定JSON-RPC协议的版本的字符串,它必须是"2.0".
 . id: 
   由客户端建立的唯一标识符,包含一个字符串或数字。
   服务端必须在Response消息中以相同的值回复。
   这个成员变量被用于在两个消息间地内容进行关联。
 . method: 
   被激活方法名
 . params: 
   a structured value that holds the parameter values to be used during the invocation of the method.
   用于被激活方法的结构体,它包含了参数值。


下面的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"
    }
}




14.1.2 JSON-RPC之上的Kurento API 

如在Kurento API章节所述,Kurento媒体服务器提供了一套完整成熟的API,让应用程序以多种方式处理媒体。


为了使用这些丰富的API, Kurento客户端要求在客户端和服务端之间实现全双式通信。
基于这个原因,Kurento协议是基于WebSocket传输的。


在发出命令之前,Kurento客户端需要先请求和Kurento媒体服务器的URL: ws://hostname:port/kurento建立WebSocket连接。
一旦这个WebSocket连接已建立,Kurento协议提供了五种不同的类型的请求/响应消息:
 . create:
   实例化一个新的媒体对象,如管道或媒体元件。
 . invoke:
   调用已创建对象的方法。
 . subscribe: 
   创建对象中的事件订阅。
 . unsubscribe: 
   移除一个事件的订阅。
 . release: 
   删除对象并释放其资源。


Kurento协议还允许Kurento媒体服务器向客户端发送请求:
 . onEvent: 
   这个请求是在事件发生时,Kurento媒体服务器向客户端发送请求。


>>> Create messages
Create消息请求Kurento API的对象的创建。
参数 type 指定了被创建对象的类型。
参数 constructorParams 包含了创建该对象需要的所有信息。
每个消息都需要不同的 constructorParams来创建对象,这些参数是在Kurento API章节中定义的。


最后,参数sessionId为当前session的标识符。
这个参数的值是由Kurento Media Server在每次响应时发送给客户端。
只有第一次的从客户端到服务端的请求不需要这个‘sessionId’(因为这时候客户端还未收到这个值)。


下面的示例显示了一个Request消息,
它请求创建一个类型为PlayerEndpoint的对象,它的管道为6829986 ,参数uri: http://host/app/video.mp4,
sessionId为c93e5bf0-4fd0-4888-9411-765ff5d89b93:
{
    "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"
    }
}


响应消息中, 在域value中包含了新对象的id。
消息id还会要被用在协议的其它请求中。
在前面已经讲过,sessionId要在每个响应中返回。
 
下面的示例显示了一个创建消息的典型响应:
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "value": "442352747",
        "sessionId": "c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


>>> Invoke messages
Invoke 消息请求对指定对象调用一个操作。
参数 object    指示了被调用操作的对象的id,
参数 operation 指示了被调用操作的名称。
参数 operationParams 包含了执行操作需要的参数。 


下面的示例显示了一个请求消息,它请求对对象 442352747  执行连接操作,它的参数为 sink 6829986。
sessionId和session中的所有请求一致:
{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "invoke",
    "params": {
        "object": "442352747", 
        "operation": "connect",
        "operationParams": {
            "sink": "6829986"
        },
        "sessionId": "c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


当对象中的操作初成功执行后,响应消息将会包含有返回值 。
如果操作失败,则不会有任何返回值。


下面的示例显示了当连接操作执行后的典型响应消息:
{
    "jsonrpc": "2.0",
    "result": {
        "sessionId": "c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    },
    "id": 2
}


>>> Release messages
Release 消息请求释放指定对象。
参数 object 指定了要释放的对象的id。
{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "release",
    "params": {
        "object": "442352747",
        "sessionId": "c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


响应消息只包含sessionID, 下面是一个示例:
{
    "jsonrpc":"2.0",
    "id":3,
    "result": {
        "sessionId":"c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


>>> Subscribe messages
Subscribe消息请求订阅指定对象的某种类型的事件。
参数 object 指定了要订阅事件的对象id. 
参数 type   指定了事件的类型。
如果客户端订阅了一个对象的某种事件,每次对象的这个事件发生后,
Kurento Media Server就会使用 onEvent 方法发送一个请求到客户端。
这种类型的请求会在后面的章节再讲解。


下面的示例显示了请求订阅对象311861480的 EndOfStream事件,当然,sessionId是必须包括的:


{
    "jsonrpc":"2.0",
    "id":4,
    "method":"subscribe",
    "params":{
        "object":"311861480",
        "type":"EndOfStream",
        "sessionId":"c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


响应消息包含了订阅标识符,这个值会在后面的解除订阅中要用到。


下面的示例显示一个订阅请求的响应消息,属性 value 的值包含了订阅id:
{
    "jsonrpc":"2.0",
    "id":4,
    "result": {
        "value":"353be312-b7f1-4768-9117-5c2f5a087429",
        "sessionId":"c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


>>> Unsubscribe messages
Unsubscribe 消息请求解除前面事件的订阅。
参数 subscription 包含了从服务端收到的成功订阅后的订阅id.


下面的示例显示了解决订阅353be312-b7f1-4768-9117-5c2f5a087429的请求:
{
    "jsonrpc":"2.0",
    "id":5,
    "method":"unsubscribe",
    "params": {
        "subscription":"353be312-b7f1-4768-9117-5c2f5a087429",
        "sessionId":"c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


响应消息包含了sessionId.
下面的示例显示了一个解除订阅请求的响应:
{
    "jsonrpc":"2.0",
    "id":5,
    "result": {
        "sessionId":"c93e5bf0-4fd0-4888-9411-765ff5d89b93"
    }
}


>>> OnEvent Message
当客户端订阅了对象的某类事件后,每当对象的这类事件发生时,服务端都会发送一个onEvent请求。
这也是为什么Kurento协议要使用Websocket并要在客户端和服务端间使用全双工的工作模式。
服务端发送到客户端的请求包含了事件的所有信息:
 . data: 
   这类事件的特定信息。
 . source: 
   事件的对象源。
 . type: 
   事件的类型。
 . subscription:
   事件被触发的订阅id.


下面的显示了服务端发送到客户端的提醒: 
对象311861480 中,订阅号 353be312-b7f1-4768-9117-5c2f5a087429 发生了EndOfStream 事件。
{
    "jsonrpc": "2.0",
    "id": 6,
    "method": "onEvent",
    "params": {
        "value": {
            "data":{
                "source":"311861480",
                "type":"EndOfStream"
            },
            "object":"311861480",
            "subscription":"353be312-b7f1-4768-9117-5c2f5a087429",
            "type":"EndOfStream",
        },
        "sessionId":"4f5255d5-5695-4e1c-aa2b-722e82db5260"
    }
}


响应消息不包含任何有效信息,只是简单的消息模板。
下面显示了一个典型的 onEvent请求的响应:


{
    "jsonrpc":"2.0",
    "id":6,
    "result": ""
}


14.1.3 网络问题

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"
}




14.1.4 Kurento API

为了实现一个Kurento客户端,你需要仔细阅读本文档。


而知道所有细节的最好的方式是查看IDL文件,它定义了Kurento元件的接口。
我们已经定义了基于JSON的通用IDL格式。
从它开始,我们为Java和JavaScript生成了客户端代码。
Kurento API定义了下列IDL文件:
 . KMS core :     https://github.com/Kurento/kms-core/blob/develop/src/server/interface/core.kmd.json
 . KMS elements : https://github.com/Kurento/kms-elements/tree/master/src/server/interface
 . KMS filters  : https://github.com/Kurento/kms-filters/tree/master/src/server/interface


14.1.5 Example: WebRTC in loopback

本章节描述了Kurento客户端和Kurento Media Server实现了下WebRTC回话功能的消息交互。
它完整地展示了教程中的过程 ,步骤如下:


step1. 客户端发送一个创建媒体管道的请求消息:
{
    "id":1,
    "method":"create",
    "params":{
        "type":"MediaPipeline",
        "constructorParams":{}
    },
    "jsonrpc":"2.0"
}


step2. KMS回应一个包含有媒体管道ID和媒体会话ID(sessionId)的响应消息:
{
    "id":1,
    "result":{
        "value":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline",
        "sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"
    },
    "jsonrpc":"2.0"
}


step3. 客户端发送一个创建WebRtcEndpoint的请求:
{
    "id":2,
    "method":"create",
    "params":{
        "type":"WebRtcEndpoint",
        "constructorParams":{
        "mediaPipeline":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline"
    },
    "sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"
    "jsonrpc":"2.0"
}


step4. KMS创建一个WebRtcEndpoint,并回给客户端这个媒体元件的标识符:
{
    "id":2,
    "result":{
    "value":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_"sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"
    },
    "jsonrpc":"2.0"
}


step5. 客户端调用WebRtcEndpoint的连接原语来创建一个回放:
{
    "id":3,
    "method":"invoke",
    "params":{
        "object":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_"operation":"connect",
        "operationParams":{
            "sink":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_},
            "sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"
        },
    "jsonrpc":"2.0"
}


step6. KMS执行连接并回应这个操作:
{
    "id":3,
    "result":{
    "sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"
    },
    "jsonrpc":"2.0"
}


step7. 客户端调用WebRtcEndpoint的processOffer原语来进行WebRTC的SDP协商:
{
    "id":4,
    "method":"invoke",
    "params":{
        "object":"c4a84b47-1acd-4930-9f6d-008c10782dfe_MediaPipeline/e72a1ff5-e416-48ff-99ef-02f7fadabaf7_"operation":"processOffer",
        "operationParams":{
            "offer":"SDP"
        },
        "sessionId":"ba4be2a1-2b09-444e-a368-f81825a6168c"
    },
    "jsonrpc":"2.0"
}


step8. KMS执行SDP协商并返回SDP回答:
{
    "id":4,
    "result":{
    "value":"SDP"
    },
    "jsonrpc":"2.0"
}


14.1.6 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:
   A space separated list of Kurento Media Element Description (kmd) files or folders containing this files. 
   As an example, you can take a look to the kmd files within the Kurento Media Server source code.
   包含这个文件的 Kurento Media Element Description (kmd)文件列表或文件夹的空间划分。
 . TEMPLATES_DIR: 
   Directory that contains template files. 
   As an example, you can take a look to the internal Java and JavaScript templates.



你可能感兴趣的:(Kurento应用开发指南(以Kurento 6.0为模板) 之八: Kurento协议)