欢迎使用LYCAM+(铼看科技)直播云服务构建直播类应用,通过本指南您将对 LYCAM+ 直播云服务的基本架构有一个清晰的了解 ,并使用我们提供的 SDK 快速集成直播云服务 。

为了顺利接入LYCAM+直播云服务 ,您需要联系我们(028-028-61152581)申请一个开发者账号

本文档将会从以下几个方面来介绍LYCAM+直播云服务:

  1. 功能介绍
  2. 快速入门
  3. 接口与安全
  4. SDK及API参考
功能 描述
创建用户 创建用户,用于API鉴权、登录等功能
用户Token授权 对指定 ID 用户生成Token,用于接口鉴权
视频流创建/修改 终端推流,收看等
按ID搜索视频流 按指定ID查看视频流数据
关键字搜索视频流 按指定关键字搜索视频流
地理位置搜索视频流 按指定地址位置搜索视频流
视频流销毁 删除一条指定ID的视频流
查询在线人数 获取直播流的在线人数
WebHook调用 推流开始或停止时,LYCAM+直播云服务器会对您的业务服务器发起 WebHook 回调
功能 描述
直播推流 主要用于美女秀场直播、活动直播等场景
直播观看 主要用于直播推流过程中,观看直播以及回放的机制
消息服务 主要用于推流过程中,即时通讯功能以及视频流状态监听机制
涂鸦功能 主要用于PDF推流过程中,主播可以勾画PDF等文件上的要点
PDF上传 将电脑上的PDF文件,无线传输到手机客户端
PDF预览 主要用于PDF推流过程中,渲染PDF文件

为了顺利接入LYCAM+直播云服务, 您需要对 LYCAM+ 直播云服务的基本架构有一个清晰的了解,并熟悉业务服务器、推流端和拉流端的工作流程和实现逻辑。我们将从以下几个方面介绍:

  1. LYCAM+直播架构
  2. 业务实现

LYCAM+直播云服务的基本架构图如下:



以上主要分为四部分:

业务服务器

业务服务器由第三方开发者实现。负责自己的业务流程并协调直播业务逻辑 ,比如创建视频流、 直播房间列表获取、用户管理等相关操作。


LYCAM+直播云服务

负责用户的管理、流媒体的分发、直播流的创建、查询等相关操作 。


推流端

负责采集和推送流媒体 。推流端请求业务服务器获取推流地址 ,业务服务器使用服务端SDK请求LYCAM+直播云服务创建推流地址 ,主播端获取到地址后,使用 RTMP 协议向LYCAM+直播云服务推流 。


拉流端

负责拉取并播放流媒体 。 拉流端请求业务服务器获取收看地址 ,业务服务器查询数据库或向LYCAM+直播云服务请求收看地址 ,拉流端获取到收看地址后,使用 HLS 协议拉流收看 。

服务端业务实现

业务服务器的实现逻辑需要第三方开发者根据自己的业务来实现。例如:在教育直播场景中,可能需要实现用户注册、课程报名收费等功能。

推流端业务实现逻辑图如下:

  1. 推流端向业务服务器发起创建房间的请求 ;
  2. 业务服务器通过LYCAM+直播服务端 SDK 向LYCAM+云服务发起创建直播流的请求 ;
  3. LYCAM+云服务向业务服务器返回创建的直播流数据信息 ;
  4. 业务服务器把LYCAM+云服务返回的直播流数据存储在本地并返回给推流端 ;
  5. 推流端获取到推流地址后 ,使用终端 SDK(Android/IOS)推流给LYCAM+直播云服务 ,业务服务器不需要承担流媒体流量 。

拉流端业务实现逻辑图如下:

  1. 拉流端对业务服务器发起查询房间列表请求 ;
  2. 业务服务器返回给拉流端查询的房间列表详细数据 ;
  3. 拉流端选择某个房间并获取拉流地址字段 ,使用终端 SDK(Android/IOS)开始播放流 ,业务服务器不需要承担流媒体流量 。

我们提供三组推流和拉流测试地址。每个地址每次只能由一个测试用户推流,如当前地址推流不成功,可切换另一条推流地址。

测试地址仅用于体验使用,正式开发需向我们申请开发者账号

第一组:

StreamID : dev-0eef8da1-d881-11e6-9a35-0b98f1f82fb

推流地址 : rtmp://ec2-54-223-160-253.cn-north-1.compute.amazonaws.com.cn/lycam

RTMP拉流地址 : rtmp://rtmp.ws.lycam.tv/lycam/dev-0eef8da1-d881-11e6-9a35-0b98f1f82fb

HLS拉流地址1 : http://hls.ws.lycam.tv/lycam/dev-0eef8da1-d881-11e6-9a35-0b98f1f82fb/playlist.m3u8

HLS拉流地址2 : http://hls.f.lycam.tv/lycam/dev-0eef8da1-d881-11e6-9a35-0b98f1f82fb/playlist.m3u8

第二组:

StreamID : dev-53657e41-d881-11e6-9c2e-db771ef49960

推流地址 : rtmp://ec2-54-223-160-253.cn-north-1.compute.amazonaws.com.cn/lycam

RTMP拉流地址 : rtmp://rtmp.ws.lycam.tv/lycam/dev-53657e41-d881-11e6-9c2e-db771ef49960

HLS拉流地址1 : http://hls.ws.lycam.tv/lycam/dev-53657e41-d881-11e6-9c2e-db771ef49960/playlist.m3u8

HLS拉流地址2 : http://hls.f.lycam.tv/lycam/dev-53657e41-d881-11e6-9c2e-db771ef49960/playlist.m3u8

第三组

StreamID : dev-5675f291-d881-11e6-9a35-0b98f1f82fb4

推流地址 : rtmp://ec2-54-223-160-253.cn-north-1.compute.amazonaws.com.cn/lycam

RTMP拉流地址 : rtmp://rtmp.ws.lycam.tv/lycam/dev-5675f291-d881-11e6-9a35-0b98f1f82fb4

HLS拉流地址1 : http://hls.ws.lycam.tv/lycam/dev-5675f291-d881-11e6-9a35-0b98f1f82fb4/playlist.m3u8

HLS拉流地址2 : http://hls.f.lycam.tv/lycam/dev-5675f291-d881-11e6-9a35-0b98f1f82fb4/playlist.m3u8

为了更方便体验LYCAM+直播云服务,我们提供了以下两种体验方式:

  1. 桌面端推流
  2. SDK推流

OBS安装

OBS官网,下载相应的安装包,按照默认设置进行安装。OBS支持 Windows/Mac/Linux等系统。确认是Open Broadcaster Software。


软件参数设置

1. 打开 OBS 推流软件,在设置——>串流中进行串流配置;



2. 串流类型 选择自定义流媒体服务器,将获取到的推流地址分别填入 URL 和 流密钥,如图:



3. 点击 开始串流,进行推流;



1. 使用 VLC 播放验证

下载VLC,安装按照默认设置即可。 在文件 ——> 打开网络中进行串流配置,填写播放地址,点击播放 。



2. 若拉流成功,出现直播界面



如果您只需要在现有的 APP 里集成直播推流功能,那么按照如下步骤可以快速实现目标

  1. step1:下载 RTMP SDK 开发包(联系我们)
  2. step2:参考对接文档(iOS & Android)完成接入

什么是API接口鉴权 ?

接口鉴权(鉴定权限),就是 APP 在跟后台服务器交互时 ,服务器会检查当前用户是否已经登录过 ?是否有权限完成当前的操作?接口鉴权主要作用是为了检查请求合法。

LYCAM+直播云服务使用 OAuth2 协议对第三方开发者业务服务器和终端(Android/IOS)进行接口鉴权。

本节将介绍以下几个方面:

  1. OAuth2协议描述
  2. 业务服务器鉴权
  3. 终端鉴权

考虑到您会使用自有的用户账号系统 ,LYCAM+直播云服务使用 OAuth2 协议授权模式对您的推流端和业务服务器进行接口鉴权 。OAuth2 定义了四种授权方式 , 我们选择了 OAuth2 中的 password 授权方式 。 password 模式交互流程如下:

 a. 用户向客户端提供用户名,密码。

 b. 客户端用用户名,密码发送给认证服务器,向后者申请令牌。

 c. 认证服务器确认无误后,向客户端提供访问令牌。

OAuth2 协议 password 授权方式客户端请求示例:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w

客户端发出的 HTTP 请求,包含以下参数:

grant_type:表示授权类型,此处的值固定为"password",必选项。
username:表示用户名,必选项。
password:表示用户的密码,必选项。
scope:表示权限范围,可选项。

OAuth2 协议 password 授权方式认证服务器响应示例:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
    "access_token":"2YotnFZFEjr1zCsicMWpAA",
    "token_type":"example",
    "expires_in":3600,
    "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
    "example_parameter":"example_value"
}

认证服务器返回的 HTTP 响应中,包含以下参数:

access_token:表示访问令牌,必选项。
token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

我们提供的服务端 SDK 中已经集成了 OAuth2 鉴权 , 只需要按照说明配置好appKey、appSerect 和 masterSerect即可。

用户在LYCAM+直播云服务控制台创建 APP 应用后,系统会默认创建一个名字叫 master 的用户 , 它的密码为 masterSecret 字段的值。业务服务器与LYCAM+直播云服务鉴权流程如下:

  1. 业务服务器通过 OAuth2 协议为 master 用户申请授权 Token
  2. LYCAM+直播云服务验证通过后,将 master 用户授权 Token 返回给业务服务器
  3. 业务服务器在 HTTP 的 Header 中添加Token , 访问LYCAM+直播云服务API

HTTP 请求中添加Header方法:

Authorization: Bearer <access_token>, 请将 <access_token> 替换为OAUTH2获取的Token对象中的access_token字段

终端用户(Android/IOS)在推流时,会把视频流直接推向LYCAM+直播云服务 ,LYCAM+直播云服务需要对终端用户进行鉴权 ,推流地址中需要带有当前用户被授权的 Token 请求参数。 终端(Android/IOS)与LYCAM+直播云服务鉴权流程如下:

  1. 推流用户向业务服务器请求自己的授权 Token
  2. 业务服务器向LYCAM+直播云服务申请当前推流用户授权 Token
  3. LYCAM+直播云服务向业务服务器返回当前推流用户的授权 Token
  4. 业务服务器向推流用户返回授权 Token
  5. 推流端使用带 Token 参数的推流地址向LYCAM+直播云服务发起推流申请
  6. LYCAM+直播云服务验证 Token 通过后,立即向推流服务器开始推流,否则执行步骤7
  7. Token 校验不成功,返回错误给推流用户

WebHook回调

推流端开始视频直播(推流)或者停止推流的时候,我们的服务器会对您的业务服务器发起一个 POST 类型的 WebHook 回调 。回调 URL 格式如下:

https://your.appserver.com/webhook?clientIp=172.31.8.78&streamId=dev-c9d19f61-0b7b-11e6-b846-134668be52d0&type=stream.unpublish&sign=6F8CE067E88AAF3114D4D3A24615461D

其中https://your.appserver.com/webhook是你在控制台应用设置里设置的 webhook 地址

回调参数如下:

参数名称 数据类型 说明
clientId string 推流用户的IP地址
streamId string 视频流Id
type string 通知类型
sign string 签名,用于验证回调是否合法

其中通知类型(type)又分为以下两种:

类型名称 说明
stream.publish 开始推流
stream.unpublish 停止推流

您的业务服务器 HTTP 响应

当您的服务器收到 WebHook 回调时需要对我们的服务器返回成功接收响应 , 你必须对 WebHook 返回以 200 状态码,body 为 ok 的请求,否者会重试,直到超出重试次数为止 。

HTTP 响应示例, 以 PHP 语言为例:

header('HTTP/1.1 200 OK');
header('Content-type: text/html; charset=utf-8');
echo 'ok';

使用其它程序设计语言开发时, 可用上面示例中的原文进行签名验证, 得到的签名串与例子中的一致即可。

签名合法验证

1. 字段排序(除 sign 字段外)

首先对所有请求参数按参数名做字典序升序排列,所谓字典序升序排列,直观上就如同在字典中排列单词一样排序,按照字母表或数字表里递增顺序的排列次序,即先考虑第一个“字母”,在相同的情况下考虑第二个“字母”,依此类推。您可以借助编程语言中的相关排序函数来实现这一功能,如 php 中的 ksort 函数。上述示例参数的排序结果如下:

{
    'clientId' : '172.31.8.78',
    'streamId' : 'dev-c9d19f61-0b7b-11e6-b846-134668be52d0',
    'type' : 'stream.unpublish'
}

使用其它程序设计语言开发时, 可对上面示例中的参数进行排序,得到的结果一致即可。

2. 拼接请求字符串

将把上一步排序好的请求参数格式化成“参数名称”=“参数值”的形式,如对clientId参数,其参数名称为"clientId",参数值为"172.31.8.78",因此格式化后就为clientId=172.31.8.78

然后将格式化后的各个参数用"&"拼接在一起,生成的请求字符串为:

clientIp=172.31.8.78&streamId=c9d19f61-0b7b-11e6-b846-134668be52d0&type=stream.unpublish

3. 追加 appSecret 到请求字符串

此步骤生成最终请求字符串。 将 appSecret 追加到上一步生成好的请求字符串的末尾。 appSecret 在控制台创建应用时得到,假设我们这里的 appSecret 值为 “ZWGZMLSP6S”。

追加 appSecret, 最终生成的请求字符串为:

clientIp=172.31.8.78&streamId=c9d19f61-0b7b-11e6-b846-134668be52d0&type=stream.unpublish&appSecret=ZWGZMLSP6S

4. MD5 编码

利用32位 MD5 编码算法对生成的最终请求字符串进行签名运算,并将 MD5 编码结果中字母全部转换为大写,从而得到签名结果字符串(该字符串赋值于参数 sign)。

具体代码如下,以 PHP 语言为例:

$srcStr = 'clientIp=172.31.8.78&streamId=c9d19f61-0b7b-11e6-b846-134668be52d0&type=stream.unpublish&appSecret=ZWGZMLSP6S';
$signStr = strtoupper(md5($srcStr));
echo $signStr;

最终得到的签名串为:

33D60296B58C12C8909C79900482D9C9

使用其它程序设计语言开发时, 可用上面示例中的原文进行签名验证, 得到的签名串与例子中的一致即可。

业务服务器与LYCAM+直播云服务器交互使用HTTP协议通信,API是LYCAM+直播云服务器开放的一套通信接口。为了第三方开发者能够快速高效地将自己的服务接入LYCAM+直播云服务,我们提供了服务端 SDK, 服务端 SDK 是对LYCAM+直播云服务 API 的进一步封装。

服务端 SDK 提供用户创建、授权、直播流创建、查询等。服务端 SDK 功能包括但不限于:

-user.create()              # 创建用户
-user.assume()              # 用户token授权
-stream.create()            # 创建视频流
-stream.update()            # 更新视频流
-stream.show()              # 显示指定ID视频流信息
-stream.searchByKeyword()   # 通过关键字查询视频流
-stream.searchByLocation()  # 通过地理位置查询视频流
-stream.listSince()         # 查询指定时间前视频流
-stream.destroy()           # 销毁视频流

目前提供的服务端 SDK 有:Node (其他主流语言SDK版本正在开发中)

  1. JAVA SDK
  2. Node SDK
  3. Golang SDK

如果以上提供的服务端 SDK 缺少您们使用的编程语言,可以联系我们或者根据LYCAM+直播云服务 API 自己集成。

该 SDK 适用于 JAVA 1.6 及其以上版本 ,基于LYCAM+官方直播API构建 。 若您的服务端是一个基于 JAVA 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式接入我们的服务 ,同时也使得您的服务端更加轻盈 。

安装

基于 maven 构建

在项目根目录 pom.xml 文件中添加:

<dependency>
    <groupId>tv.lycam</groupId>
    <artifactId>lycamplus-java-sdk</artifactId>
    <version>1.0.0</version>
</dependency>

基于 gradle 构建

在项目根目录 build.gradle 文件中添加:

compile group:'tv.lycam', name:'lycamplus-java-sdk', version: '1.0.0'

或者

compile 'tv.lycam:lycamplus-java-sdk:1.0.0'

使用

配置参数 并创建 SDK 实例

设置全局参数 ,包括必须的 appKey ,appSecret 和 masterSecret ,配置参数将会延至所有空间 。

String appKey       =  <您申请到的 AppKey>

String appSecret    =  <您申请到的 AppSecret>

String masterSecret =  <您申请到的 masterSecret>

创建 SDK 实例 。

LycamPlus lycamPlus = new LycamPlus(appKey, appSecret, masterSercet);

User 对象

获取 User 对象并进行操作

userInstance = lycamPlus.getUserInstance();

1. 创建用户

创建用户到 LYCAM+ 系统中 ,以便用户操作 API 接口鉴权使用 。

...

UserRequestModel userRequestModel = new UserRequestModel();

userRequestModel.setUsername("lycam-test4");

userRequestModel.setPassword('123456789l');

...

UserResponseModel responseModel = userInstance.create(userRequestModel);

...

请求参数

请求参数传递 UserRequestModel 类型。 UserRequestModel 类型包含以下字段 :

字段名称 是否必须 数据类型 参数说明
Username false string 用户名,长度为6-80位,如果为空将随机生成(唯一)
Password false string 用户密码,长度8-16位,如果为空将随机生成
Email false string 邮件地址
Phone false string 手机号码 11-20 位
Description false string 描述 4-300个字符
DisplayName false string 显示的昵称,2-20位

返回数据

接口返回 UserResponseModel 类型,UserResponseModel标识返回详细数据。UserResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
Username string 用户名
UUID string 用户唯一身份标识
Password string 用户密码(如果密码为随机生成,才返回此字段)
Success bool 成功标志,成功 true,失败 false

2. 用户token获取

用户访问 LYCAM+ 资源操作接口(比如:推流)时需要用户鉴权,我们使用token进行验证 。

...

String uuid = "f6524e90-e055-11e6-9b86-4d1c174d4365";

long expires = 38000;

TokenResponseModel tokenResponseModel = userInstance.assume(uuid, expires);

...

请求参数

请求参数传递两个参数: string 和 long 类型。 string 类型用于标识用户的唯一ID, long 类型标识 token 过期的时间(单位:秒)。

请求参数 是否必须 数据类型 参数说明
uuid true string 用户唯一身份标识( 即uuid )
expires true long token过期时间(单位:秒)

返回数据

接口返回 TokenResponseModel 类型 , TokenResponseModel 标识返回详细数据。TokenResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
Success bool 成功标志,成功 true,失败false
Scope string 授权资源范围,*表示所有资源
Token json object token对象 。包括 access_token,expires_in 字段等…

Stream 对象

获取 Stream 对象并进行操作

...

streamInstance = lycamPlus.getStreamInstance();

...

1. 创建视频流

在 LYCAM+ 后台系统中创建一条视频流 。 用于返回给终端用户或实现您自己的业务 。

...

StreamRequestModel requestModel = new StreamRequestModel();

requestModel.setTitle("java test");

requestModel.setUser("f6524e90-e055-11e6-9b86-4d1c174d4365");

...

StreamResponseModel responseModel = streamInstance.create(requestModel);

...

请求参数

请求参数传递 StreamRequestModel 类型。 StreamRequestModel 类型包含以下字段:

字段名称 是否必须 数据类型 参数说明
User false string 用户唯一身份标识( 即uuid )
Title false string 视频流标题
Description false string 视频流描述
ThumbnailUrl false string 视频流封面地址
StartLat false float 开始视频的维度坐标
StartLon false float 开始视频的经度坐标
Country false string 国家
State false string 省份
City false string 城市
Privacy false bool 是否私有视频( true是,false否 )

返回数据

接口返回 StreamResponseModel 类型,StreamResponseModel 标识返回详细数据。StreamResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
StreamId string stramId ( 视频流标识 )
Status string 直播状态(live, over,ready)
StreamUrls json object 视频播放资源列表
UploadUrl string 推流地址
ChatUrl string 消息服务器地址
ChatChannel string 消息服务器频道
ResourceUrl string 视屏 HTML 主页地址
Title string 视频流标题
Description string 视频流描述
ThumbnailUrl string 视频流封面地址
StartLat float 开始视频的维度坐标
StartLon float 开始视频的经度坐标
Country string 国家
State string 省份
City string 城市
Privacy bool 是否私有视频( true是,false否 )

2. 更新指定ID视频流

在 LYCAM+ 后台系统中更新指定 ID 视频流信息 。

...

String streamID = "775009d0-e06d-11e6-ba8a-a3de0ac619fb";

StreamRequestModel requestModel = new StreamRequestModel();

requestModel.setStartLat(90);

requestModel.setStartLon(90);

requestModel.setEndLat(180);

requestModel.setEndLon(220);

requestModel.setDescription("no description");

...

StreamResponseModel responseModel = streamInstance.update(streamID, requestModel);

...

请求参数

请求参数传递 string 类型 和 StreamRequestModel 类型。string 类型标识被更新的视频流 ID, StreamRequestModel 类型包含以下字段:

字段名称 是否必须 数据类型 参数说明
Title false string 视频流标题
Description false string 视频流描述
ThumbnailUrl false string 视频流封面地址
StartLat false float 开始视频的维度坐标
StartLon false float 开始视频的经度坐标
EndLat false float 视频当前的维度坐标
EndLon false float 视频当前的经度坐标
Country false string 国家
State false string 省份
City false string 城市
Privacy false bool 是否私有视频( true是,false否 )

返回数据

接口返回 StreamResponseModel 类型,StreamResponseModel 标识返回详细数据。StreamResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
StreamId string stramId ( 视频流标识 )
Status string 直播状态(live, over,ready)
StreamUrls json object 视频播放资源列表
UploadUrl string 推流地址
ChatUrl string 消息服务器地址
ChatChannel string 消息服务器频道
ResourceUrl string 视屏 HTML 主页地址
Title string 视频流标题
Description string 视频流描述
ThumbnailUrl string 视频流封面地址
Country string 国家
State string 省份
City string 城市
Privacy bool 是否私有视频( true是,false否 )
其它视频流参数

3. 获取指定ID视频流信息

在 LYCAM+ 后台系统中获取指定 ID 的视频流 。 用于返回给终端用户或实现您自己的业务 。

...

String streamID = "775009d0-e06d-11e6-ba8a-a3de0ac619fb";

StreamResponseModel responseModel =  streamInstance.show(streamID);

...

请求参数

请求参数传递 string 类型 , 用于标识视频流的ID。

请求参数 是否必须 数据类型 参数说明
streamId true string stramId ( 视频流标识 )

返回字段

接口返回 StreamResponseModel 类型,StreamResponseModel 标识返回详细数据。StreamResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
StreamID string stramId ( 视频流标识 )
Status string 直播状态(live, over,ready)
StreamUrls json object 视频播放资源列表
UploadUrl string 推流地址
ChatUrl string 消息服务器地址
ChatChannel string 消息服务器频道
ResourceUrl string 视屏 HTML 主页地址
Title string 视频流标题
Description string 视频流描述
ThumbnailUrl string 视频流封面地址
StartLat float 开始视频的维度坐标
StartLon float 开始视频的经度坐标
Country string 国家
State string 省份
City string 城市
Privacy bool 是否私有视频( true是,false否 )

4. 获取视频流列表

获取 Lycam+ 后台系统中视频流列表 。用于返回给终端用户或实现您自己的业务 。

...

PageModel pageModel = new PageModel();

pageModel.setResultsPerPage(2);

pageModel.setPage(3);

pageModel.setOrder(Order.DESC);

...

StreamResponseListModel listModel = streamInstance.getList(pageModel);

...

请求参数

请求参数传递 PageModel 类型 。 PageModel 包含以下字段:

字段名称 是否必须 数据类型 参数说明
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false Enum 排序字段( id,description,created )
Order false Enum 排序方向( asc,desc )

返回字段

接口返回 StreamResponseListModel 类型,StreamResponseListModel 标识返回详细数据。StreamResponseListModel 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

5. 获取指定时间前视频流列表

在 LYCAM+ 后台系统获取指定时间前的视频流列表 。 用于返回给终端用户或实现您自己的业务 。

...

PageModel pageModel = new PageModel();

pageModel.setResultsPerPage(2);

pageModel.setPage(2);

pageModel.setOrder(Order.DESC);

...

String tsStr = "2016-12-30 11:49:45";

Timestamp timestamp = Timestamp.valueOf(tsStr);


StreamResponseListModel listModel = streamInstance.getListSince(timestamp.getTime(), pageModel);

...

请求参数

请求参数传递 long 类型 和 PageModel 类型 。long 类型标识时间戳(单位:秒), PageModel 类型包含以下字段:

字段名称 是否必须 数据类型 参数说明
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false Enum 排序字段( id,description,created )
Order false Enum 排序方向( asc,desc )

返回字段

接口返回 StreamResponseListModel 类型,StreamResponseListModel 标识返回详细数据。StreamResponseListModel 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

6. 通过关键词搜索视频流

通过关键词在 LYCAM+ 后台系统获取视频流列表 。 用于返回给终端用户或实现您自己的业务 。

...

KeywordModel keywordModel = new KeywordModel();

keywordModel.setKeyword("test");

...

StreamSearchListModel listModel = streamInstance.getListByKeyword(keywordModel);

...

请求参数

请求参数传递 KeywordModel 类型 。 KeywordModel 包含以下字段:

字段名称 是否必须 数据类型 参数说明
Keyword true string 搜索关键词
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false Enum 排序字段( id,description,created )
Order false Enum 排序方向( asc,desc )

返回字段

接口返回 StreamSearchListModel 类型,StreamSearchListModel 标识返回详细数据。StreamSearchListModel 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

7. 通过地理位置搜索视频流

通过地理位置在 LYCAM+ 后台系统获取视频流列表 。 用于返回给终端用户或实现您自己的业务 。

...

LocationModel locationModel = new LocationModel();

locationModel.setLat(90);

locationModel.setLon(90);

locationModel.setRadius(100);

...

StreamSearchListModel listModel = streamInstance.getListByLocation(locationModel);

...

请求参数

请求参数传递 LocationModel 类型 。LocationModel 包含以下字段:

字段名称 是否必须 数据类型 参数说明
Lon true float 经度
Lat true float 纬度
Radius true float 搜索半径
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false Enum 排序字段( id,description,created )
Order false Enum 排序方向( asc,desc )

返回字段

接口返回 StreamSearchListModel 类型,StreamSearchListModel 标识返回详细数据。StreamSearchListModel 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

8. 销毁指定ID视频流

销毁在 LYCAM+ 后台系统中指定ID的视频流 。

...

String streamID = "775009d0-e06d-11e6-ba8a-a3de0ac619fb";

SuccessModel successModel = streamInstance.delete(streamID);

...

请求参数

请求参数传递 string 类型 , 用于标识视频流的ID。

请求参数 是否必须 数据类型 参数说明
streamID true string streamId ( 视频流标识 )

返回字段

接口返回 SuccessModel 类型,SuccessModel 标识返回详细数据。SuccessModel 类型包含以下字段:

字段名称 数据类型 参数说明
Success bool 成功标志 。成功 true,失败 false

安装

您可以从 npm 进行安装

npm install lycamplus-node-sdk

使用

配置 config 并创建 SDK 实例

设置全局参数 ,包括必须的 appKey ,appSecret 和 password ,配置参数将会延至所有空间 。

var config = {
    appKey:     <您申请到的 AppKey>
    appSecret:  <您申请到的 AppSecret>
    password:   <您申请到的 masterSecret>
};

创建 SDK 实例 。

var lycamPlus = new LycamPlus(config);

Stream 对象

// 获取 User 对象并进行操作
var userInstance = lycamPlus.newUser();

1. 创建用户

创建用户到 Lycam+ 系统中 ,以便用户操作 API 接口鉴权使用 。

var params = {
    username: 'admin123',
    password: 'admin123'
};
userInstance.create(params, function(err, result) {
    // 您的代码
});

该 SDK 所有 API ,我们都提供了 callback 和 Promise 两种返回操作 。所以 ,您也可以使用如下方式 :

var params = {
    username: 'admin123',
    password: 'admin123'
};
userInstance.create(params)
            .then(function(result) {
                // 您的逻辑代码
            })
            .catch(function(err) {
                // 您的错误处理代码
            });

请求参数

请求参数 是否必须 数据类型 参数说明
username false string 用户名,长度为6-80位,如果为空将随机生成
password false string 用户密码,长度8-16位,如果为空将随机生成

返回字段

返回字段 数据类型 参数说明
username string 用户名
uuid string 用户唯一身份标识
password string 用户密码(如果密码为随机生成,才返回此字段)
success bool 成功标志,成功 true,失败 false

2. 用户token获取

用户访问Lycam+资源操作接口(比如:推流、收看)时需要用户鉴权,我们使用token进行验证 。

userInstance.assume('uuid', function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
uuid true string 用户唯一身份标识( 即uuid )

返回字段

返回字段 数据类型 参数说明
success bool 成功标志,成功 true,失败false
scope string 授权资源范围,*表示所有资源
token json object token对象 。包括 access_token,expires_in 字段等…

Stream 对象

获取 Stream 对象并进行操作

var streamInstance = lycamPlus.newStream();

1. 创建视频流

在 Lycam+ 后台系统中创建一条视频流 。 用于返回给终端用户或实现您自己的业务 。

var params = {
    user: 'uuid',
    title: 'test',
    ...
};
streamInstance.create(params, function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
uuid false string 用户唯一身份标识( 即uuid )
title false string 视频流标题
description false string 视频流描述
thumbnailUrl false string 视频流封面地址
startLat false float 开始视频的维度坐标
startLon false float 开始视频的经度坐标
country false string 国家
state false string 省份
city false string 城市
privacy false bool 是否私有视频( true是,false否 )
extraInfo false json object 自定义用户信息,格式为 json

返回字段

返回字段 数据类型 参数说明
streamId string stramId ( 视频流标识 )
status string 直播状态(live, over,ready)
streamUrls json object 视频播放资源列表
uploadUrl string 推流地址
chatUrl string 消息服务器地址
chatChannel string 消息服务器频道
resourceUrl string 视屏 HTML 主页地址
title string 视频流标题
description string 视频流描述
thumbnailUrl string 视频流封面地址
startLat float 开始视频的维度坐标
startLon float 开始视频的经度坐标
country string 国家
state string 省份
city string 城市
privacy bool 是否私有视频( true是,false否 )
extraInfo object 自定义用户信息,格式为 json

2. 更新指定ID视频流

在 Lycam+ 后台系统中更新指定ID视频流信息 。

var params = {
    'description': '视频描述',
    ...
};
streamInstance.update('streamId', params, function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
title false string 视频流标题
description false string 视频流描述
thumbnailUrl false string 视频流封面地址
startLat false float 开始视频的维度坐标
startLon false float 开始视频的经度坐标
endLat false float 视频当前的维度坐标
endLon false float 视频当前的经度坐标
country false string 国家
state false string 省份
city false string 城市
privacy false bool 是否私有视频( true是,false否 )
extraInfo false json object 自定义用户信息,格式为 json

返回字段

返回字段 数据类型 参数说明
streamId string stramId ( 视频流标识 )
status string 直播状态(live, over,ready)
streamUrls json object 视频播放资源列表
uploadUrl string 推流地址
chatUrl string 消息服务器地址
chatChannel string 消息服务器频道
resourceUrl string 视屏 HTML 主页地址
title string 视频流标题
description string 视频流描述
thumbnailUrl string 视频流封面地址
country string 国家
state string 省份
city string 城市
privacy bool 是否私有视频( true是,false否 )
其它视频流参数

3. 获取指定ID视频流信息

在 Lycam+ 后台系统中获取指定ID的视频流 。 用于返回给终端用户或实现您自己的业务 。

streamInstance.show('streamId', function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
streamId true string stramId ( 视频流标识 )

返回字段

返回字段 数据类型 参数说明
streamId string stramId ( 视频流标识 )
status string 直播状态(live, over,ready)
streamUrls json object 视频播放资源列表
uploadUrl string 推流地址
chatUrl string 消息服务器地址
chatChannel string 消息服务器频道
resourceUrl string 视屏 HTML 主页地址
title string 视频流标题
description string 视频流描述
thumbnailUrl string 视频流封面地址
startLat float 开始视频的维度坐标
startLon float 开始视频的经度坐标
country string 国家
state string 省份
city string 城市
privacy bool 是否私有视频( true是,false否 )
extraInfo object 自定义用户信息 ,格式为 json

4. 获取视频流列表

获取 Lycam+ 后台系统中视频流列表 。用于返回给终端用户或实现您自己的业务 。

streamInstance.list(function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
resultsPerPage false int 每页返回记录数 ,默认 10 行
page false int 返回第几页 ,默认第 1 页
sort false string 排序字段( id,description,created )
order false string 排序方向( asc,desc )

返回字段

返回字段 数据类型 参数说明
totalItems int 记录总数
resultsPerPage int 每一页数量
nextPageAvailable bool 是否有下一页
items array 视频流清单数组

5. 获取指定时间前视频流列表

在 Lycam+ 后台系统获取指定时间前的视频流列表 。 用于返回给终端用户或实现您自己的业务 。

streamInstance.listSince(timestamp, resultsPerPage, function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
timestamp true long timestamp ( unix timestamp )
resultsPerPage false int 每页返回记录数 ,默认 10 行

返回字段

返回字段 数据类型 参数说明
totalItems int 记录总数
resultsPerPage int 每一页数量
nextPageAvailable bool 是否有下一页
items array 视频流清单数组

6. 通过地理位置搜索视频流

通过地理位置在 Lycam+ 后台系统获取视频流列表 。 用于返回给终端用户或实现您自己的业务 。

var params = {
    lon: '0',
    lat: '0',
    ..
};
streamInstance.searchByLocation(params, function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
lon true float 经度
lat true float 纬度
radius true float 搜索半径
resultsPerPage false int 每页返回记录数 ,默认 10 行
page false int 返回第几页 ,默认第 1 页
sort false string 排序字段( id,description,created )
order false string 排序方向( asc,desc )

返回字段

返回字段 数据类型 参数说明
totalItems int 记录总数
resultsPerPage int 每一页数量
nextPageAvailable bool 是否有下一页
items array 视频流清单数组

7. 销毁指定ID视频流

销毁在 Lycam+ 后台系统中指定ID的视频流 。

streamInstance.destroy('streamId', function(err, result) {
    // 您的代码
});

请求参数

请求参数 是否必须 数据类型 参数说明
streamId true string stramId ( 视频流标识 )

返回字段

返回字段 数据类型 参数说明
success bool 成功标志 。成功 true,失败 false

该 SDK 适用于 Golang 1.5 及其以上版本 ,基于LYCAM+官方直播API构建 。 若您的服务端是一个基于 Golang 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式接入我们的服务 ,同时也使得您的服务端更加轻盈 。

安装

go get github.com/lycam-dev/lycamplus-go-sdk/lycamplus

Demo 参考

https://github.com/lycam-dev/lycamplus-go-sdk/tree/master/example

使用

配置参数 并创建 SDK 实例

设置全局参数 ,包括必须的 appKey ,appSecret 和 masterSecret ,配置参数将会延至所有空间 。

appKey       :=  <您申请到的 AppKey>

appSecret    :=  <您申请到的 AppSecret>

masterSecret :=  <您申请到的 masterSecret>

创建 SDK 实例 。

lycamPlusInstance := NewLycamPlus(appKey, appSecret, masterSecret)

User 对象

获取 User 对象并进行操作

var userInstance = lycamPlusInstance.UserInstance;

1. 创建用户

创建用户到 LYCAM+ 系统中 ,以便用户操作 API 接口鉴权使用 。

userRequestModel := lycamplus.UserRequestModel{
    UserName: "lycamplus_tester",
    Password: "abcdefg123",
    ...
}

userResponseModel, err := userInstance.Create(&userRequestModel)

请求参数

请求参数传递 UserRequestModel 类型。 UserRequestModel 类型包含以下字段 :

字段名称 是否必须 数据类型 参数说明
Username false string 用户名,长度为6-80位,如果为空将随机生成(唯一)
Password false string 用户密码,长度8-16位,如果为空将随机生成
Email false string 邮件地址
Phone false string 手机号码 11-20 位
Description false string 描述 4-300个字符
DisplayName false string 显示的昵称,2-20位

返回数据

接口返回 UserResponseModel 类型 和 error 类型。 error 标识是否出错,UserResponseModel标识返回详细数据。UserResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
Username string 用户名
UUID string 用户唯一身份标识
Password string 用户密码(如果密码为随机生成,才返回此字段)
Success bool 成功标志,成功 true,失败 false

2. 用户token获取

用户访问 LYCAM+ 资源操作接口(比如:推流)时需要用户鉴权,我们使用token进行验证 。

UUID := "3725d420-dc71-11e6-b191-5f7a2ebf06ef"

tokenResponseModel, err := userInstance.Assume(UUID)

请求参数

请求参数传递 string 类型, 用于标识用户的唯一ID。

请求参数 是否必须 数据类型 参数说明
uuid true string 用户唯一身份标识( 即uuid )

返回数据

接口返回 TokenResponseModel 类型 和 error 类型 。 error 标识是否出错,TokenResponseModel 标识返回详细数据。TokenResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
Success bool 成功标志,成功 true,失败false
Scope string 授权资源范围,*表示所有资源
Token json object token对象 。包括 access_token,expires_in 字段等…

Stream 对象

获取 Stream 对象并进行操作

var streamInstance = lycamPlusInstance.StreamInstance;
            

1. 创建视频流

在 LYCAM+ 后台系统中创建一条视频流 。 用于返回给终端用户或实现您自己的业务 。

streamRequestModel := lycamplus.StreamRequestModel{
    Title: "test_stream",
    Description: "test_stream description"
    ...
}

streamResponseModel, err := streamInstance.Create(&streamRequestModel)

请求参数

请求参数传递 StreamRequestModel 类型。 StreamRequestModel 类型包含以下字段:

字段名称 是否必须 数据类型 参数说明
User false string 用户唯一身份标识( 即uuid )
Title false string 视频流标题
Description false string 视频流描述
ThumbnailUrl false string 视频流封面地址
StartLat false float 开始视频的维度坐标
StartLon false float 开始视频的经度坐标
Country false string 国家
State false string 省份
City false string 城市
Privacy false bool 是否私有视频( true是,false否 )

返回数据

接口返回 StreamResponseModel 类型 和 error 类型 。 error 标识是否出错,StreamResponseModel 标识返回详细数据。StreamResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
StreamId string stramId ( 视频流标识 )
Status string 直播状态(live, over,ready)
StreamUrls json object 视频播放资源列表
UploadUrl string 推流地址
ChatUrl string 消息服务器地址
ChatChannel string 消息服务器频道
ResourceUrl string 视屏 HTML 主页地址
Title string 视频流标题
Description string 视频流描述
ThumbnailUrl string 视频流封面地址
StartLat float 开始视频的维度坐标
StartLon float 开始视频的经度坐标
Country string 国家
State string 省份
City string 城市
Privacy bool 是否私有视频( true是,false否 )

2. 更新指定ID视频流

在 LYCAM+ 后台系统中更新指定 ID 视频流信息 。

streamID := "b7d87ea0-dc72-11e6-98af-bb17f4293ffa"

    streamRequestModel := lycamplus.StreamRequestModel{
        Title:       "test_stream",
        Description: "no Description",
        ...
    }

    streamResponseModel, err := streamInstance.Update(streamID, &streamRequestModel)

请求参数

请求参数传递 string 类型 和 StreamRequestModel 类型。string 类型标识被更新的视频流 ID, StreamRequestModel 类型包含以下字段:

字段名称 是否必须 数据类型 参数说明
Title false string 视频流标题
Description false string 视频流描述
ThumbnailUrl false string 视频流封面地址
StartLat false float 开始视频的维度坐标
StartLon false float 开始视频的经度坐标
EndLat false float 视频当前的维度坐标
EndLon false float 视频当前的经度坐标
Country false string 国家
State false string 省份
City false string 城市
Privacy false bool 是否私有视频( true是,false否 )

返回数据

接口返回 StreamResponseModel 类型 和 error 类型 。 error 标识是否出错,StreamResponseModel 标识返回详细数据。StreamResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
StreamId string stramId ( 视频流标识 )
Status string 直播状态(live, over,ready)
StreamUrls json object 视频播放资源列表
UploadUrl string 推流地址
ChatUrl string 消息服务器地址
ChatChannel string 消息服务器频道
ResourceUrl string 视屏 HTML 主页地址
Title string 视频流标题
Description string 视频流描述
ThumbnailUrl string 视频流封面地址
Country string 国家
State string 省份
City string 城市
Privacy bool 是否私有视频( true是,false否 )
其它视频流参数

3. 获取指定ID视频流信息

在 LYCAM+ 后台系统中获取指定 ID 的视频流 。 用于返回给终端用户或实现您自己的业务 。

streamID := "b7d87ea0-dc72-11e6-98af-bb17f4293ffa"

streamResponseModel, err := streamInstance.Show(streamID)

请求参数

请求参数传递 string 类型 , 用于标识视频流的ID。

请求参数 是否必须 数据类型 参数说明
streamId true string stramId ( 视频流标识 )

返回字段

接口返回 StreamResponseModel 类型 和 error 类型 。 error 标识是否出错,StreamResponseModel 标识返回详细数据。StreamResponseModel 类型包含以下字段:

字段名称 数据类型 参数说明
StreamID string stramId ( 视频流标识 )
Status string 直播状态(live, over,ready)
StreamUrls json object 视频播放资源列表
UploadUrl string 推流地址
ChatUrl string 消息服务器地址
ChatChannel string 消息服务器频道
ResourceUrl string 视屏 HTML 主页地址
Title string 视频流标题
Description string 视频流描述
ThumbnailUrl string 视频流封面地址
StartLat float 开始视频的维度坐标
StartLon float 开始视频的经度坐标
Country string 国家
State string 省份
City string 城市
Privacy bool 是否私有视频( true是,false否 )

4. 获取视频流列表

获取 Lycam+ 后台系统中视频流列表 。用于返回给终端用户或实现您自己的业务 。

pageModel := PageModel{
    ResultsPerPage: 2,
}
streamResponseModelList, err := streamInstance.List(&pageModel)

请求参数

请求参数传递 PageModel 类型 。 PageModel 包含以下字段:

字段名称 是否必须 数据类型 参数说明
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false string 排序字段( id,description,created )
Order false string 排序方向( asc,desc )

返回字段

接口返回 StreamResponseModelList 类型 和 error 类型 。 error 标识是否出错,StreamResponseModelList 标识返回详细数据。StreamResponseModelList 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

5. 获取指定时间前视频流列表

在 LYCAM+ 后台系统获取指定时间前的视频流列表 。 用于返回给终端用户或实现您自己的业务 。

pageModel := PageModel{
    ResultsPerPage: 2,
}

response, err := streamInstance.ListSince(time.Now().UnixNano(), &pageModel)

请求参数

请求参数传递 int64 类型 和 PageModel 类型 。int64 类型标识纳秒时间戳, PageModel 类型包含以下字段:

字段名称 是否必须 数据类型 参数说明
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false string 排序字段( id,description,created )
Order false string 排序方向( asc,desc )

返回字段

接口返回 StreamResponseModelList 类型 和 error 类型 。 error 标识是否出错,StreamResponseModelList 标识返回详细数据。StreamResponseModelList 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

6. 通过关键词搜索视频流

通过关键词在 LYCAM+ 后台系统获取视频流列表 。 用于返回给终端用户或实现您自己的业务 。

keywordModel := KeywordModel{
    Keyword: "lycamplus666"
}

response, err := streamInstance.SearchByKeyword(&keywordModel)

请求参数

请求参数传递 KeywordModel 类型 。 KeywordModel 包含以下字段:

字段名称 是否必须 数据类型 参数说明
Keyword true string 搜索关键词
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false string 排序字段( id,description,created )
Order false string 排序方向( asc,desc )

返回字段

接口返回 StreamResponseModelList 类型 和 error 类型 。 error 标识是否出错,StreamResponseModelList 标识返回详细数据。StreamResponseModelList 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

7. 通过地理位置搜索视频流

通过地理位置在 LYCAM+ 后台系统获取视频流列表 。 用于返回给终端用户或实现您自己的业务 。

locationModel := lycamplus.LocationModel {
    Lon:    90,
    Lat:    90,
    Radius: 100,
}

streamResponseModelList, err := streamInstance.SearchByLocation(&locationModel)

请求参数

请求参数传递 LocationModel 类型 。LocationModel 包含以下字段:

字段名称 是否必须 数据类型 参数说明
Lon true float 经度
Lat true float 纬度
Radius true float 搜索半径
ResultsPerPage false int 每页返回记录数 ,默认 10 行
Page false int 返回第几页 ,默认第 1 页
Sort false string 排序字段( id,description,created )
Order false string 排序方向( asc,desc )

返回字段

接口返回 StreamResponseModelList 类型 和 error 类型 。 error 标识是否出错,StreamResponseModelList 标识返回详细数据。StreamResponseModelList 类型包含以下字段:

字段名称 数据类型 参数说明
TotalItems int 记录总数
ResultsPerPage int 每一页数量
NextPageAvailable bool 是否有下一页
Items array 视频流清单数组

8. 销毁指定ID视频流

销毁在 LYCAM+ 后台系统中指定ID的视频流 。

streamID := "b7d87ea0-dc72-11e6-98af-bb17f4293ffa"

successModel, err := streamInstance.Delete(streamID)

请求参数

请求参数传递 string 类型 , 用于标识视频流的ID。

请求参数 是否必须 数据类型 参数说明
streamId true string stramId ( 视频流标识 )

返回字段

接口返回 SuccessModel 类型 和 error 类型 。 error 标识是否出错,SuccessModel 标识返回详细数据。SuccessModel 类型包含以下字段:

字段名称 数据类型 参数说明
Success bool 成功标志 。成功 true,失败 false

下载SDK

下载移动端直播SDK,解压后得到一个LycamPlusCore.framework。目前 直播SDK 所有功能都集成在这一framework中。

Xcode工程设置

一、支持平台

SDK支持iOS 7.0以上系统

二、开发环境

Xcode 7或更高版本

OS X 10.10或更高版本

三、Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

1、拷贝SDK文件

在本例中,新建一个名字叫做ZhiBoSDK的iOS工程,将下载下来的LycamPlusCore.framework拷贝至工程目录。目录结构如下图所示:



2、添加Framework

在工程中添加LycamPlusCore.framework,同时还要添加以下系统依赖库



3、配置info.plist文件



四、注册AppKey、AppSecret

下面在ZhiBoSDK的代码中,调用SDK的接口,获取SDK版本信息,以验证工程设置是否正确。

1、引用头文件

在AppDelegate.m开头引用SDK的头文件:

#import <LycamPlusCore/LCPCoreManager.h>

2、添加调用代码

#define LYCAMPLUS_APP_KEY @"AppKey"
#define LYCAMPLUS_APP_SECRET @"AppSecret"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [[LCPCoreManager shareCoreManager] registAppKey:LYCAMPLUS_APP_KEY withAppSecret:LYCAMPLUS_APP_SECRET withPlusCoreForProduction:NO]; // YES 代表生产环境,NO 代表开发环境(一般向LYCAM+申请的账号为生产环境)。
    return YES;
}

3、编译运行

如果前面各个步骤都操作正确的话,ZhiBoSDK工程应该可以顺利编译通过。

至此,配置工作已完成。

概要描述

本篇攻略主要是面向摄像头直播的解决方案,该方案主要用于美女秀场直播、活动直播等场景。如果您需要实现PDF推流,请参考进阶功能区的PDF推流文档。

准备工作

获取开发包

下载 RTMP SDK 开发包,并按照工程配置指引将 RTMP SDK 嵌入您的 APP 开发工程。

获取测试URL

代码对接

1. 创建LCPVideoCameraInputSource对象,该对象用于手机摄像头视频采集功能。

在ViewController.m开头引入SDK头文件

#import <LycamPlusCore/LCPVideoCameraInputSource.h>

初始化LCPVideoCameraInputSource对象

@interface ViewController ()<LCPVideoCameraInputSourceDelegate>

@property (nonatomic,strong) LCPVideoCameraInputSource * cameraInputSource;
@property (nonatomic, assign) LCPCameraState cameraState;

@end

self.cameraInputSource = [[LCPVideoCameraInputSource alloc] init];
self.cameraInputSource.delegate = self;
[self.cameraInputSource setupCamera:AVCaptureSessionPresetiFrame960x540 cameraState:LCPCameraStateFront interfaceOrientation:(UIInterfaceOrientationPortrait)];

实现LCPVideoCameraInputSource代理,开始采集视频数据

-(void) didSetupCamera:(LCPVideoCameraInputSource *)source{
    [source startCameraCapture];
}

2.创建LCPVCBaseSession对象,该对象用于推流相关功能。

在ViewController.m开头引入SDK头文件

#import <LycamPlusCore/LCPVCBaseSession.h>

初始化LCPVCBaseSession对象,在创建 LCPVCBaseSession 对象之前,还需要您设定推流时各个环节的配置参数,比如推流用多大的分辨率、每秒钟要多少帧画面(FPS)、bitrate(带宽)以及useAdaptiveBitrate(自适应码率)等等。

@interface ViewController ()<LCPVCBaseSessionDelegate>

@property (nonatomic,strong) LCPVCBaseSession *session;

@end

CGSize videoSize =  CGSizeMake(720,1280);
_session = [[LCPVCBaseSession alloc] initWithVideoSize:videoSize frameRate:30 bitrate:2000000 useAdaptiveBitrate:YES source:self.cameraInputSource];
_session.delegate = self;
_session.previewView.frame = self.view.bounds;
[self.view addSubview:_session.previewView];

实现LCPVCBaseSession代理,判断推流状态及参数设置

-(void) didSetupSession:(LCPVCBaseSession *)session{
    [session setMicDryWetMix:0];
    [session setMicGain:0.9];
    [session setBlendScale:1.0];
    [session setBlendMix:1.0];
    [session setBlendOffset:CGPointMake(0.0,0.0)];
    [session setBlendMode:LCPBlendMix];
    [session setMicEnabled:YES];
    [session setAudioOutputEnabled:YES];
    [self.cameraInputSource setFilter:(LCPFilterBeauty)];
}

- (void) connectionStatusChanged:(LCPSessionState) state
{
    switch(state) {
        case LCPSessionStateStarting:
            NSLog(@"session starting");
            break;
        case LCPSessionStateStarted:
            NSLog(@"session started");
            break;
        case LCPSessionStateError:
            NSLog(@"session error");
            break;
        case LCPSessionStateEnded:
            NSLog(@"session stoped");
            break;
        default:
            break;
    }
}

3. 开始推流

//以下参数token、streamKey需从服务器获取
NSString *token = @"token";
NSString *streamKey = @"streamId";

//开始推流
[self.session startRtmpSessionWithToken:token andStreamKey:streamKey completionBlock:^(BOOL success, NSError *error) {
    if (error) {
        NSLog(@"====%@",[error localizedDescription]);
    }
}];

4. 美颜滤镜

对于摄像头直播的场景,美颜是必不可少的一个功能点,本SDK提供了一种简单版实现,包含美白 (level 0 -> level 5)、灰度、高斯模糊、怀旧等。

您可以在您的APP得用户操作界面上使用滑竿等控件来让用户选择美颜效果,或者推荐您也可以先用Demo里的滑竿进行,达到您满意的效果后,将此时的数值固定到程序的设置参数里。

接口函数setFilter可以动态调整美颜级别:

[self.cameraInputSource setFilter:(LCPFilterBeauty)];

5. 控制摄像头

切换前置或后置摄像头

默认是使用前置摄像头(注意切换摄像头前必须保证 LCPVideoCameraInputSource 和LCPVCBaseSession 对象都已经初始化。

// 默认是前置摄像头   
if (self.cameraState != LCPCameraStateBack) {
    self.cameraInputSource.cameraState = LCPCameraStateBack;
} else {
    self.cameraInputSource.cameraState = LCPCameraStateFront;
}

6.后台推流

常规模式下,App一旦切到后台,摄像头的采集能力就会被 iOS 暂时停止掉,这就意味着 SDK 不能再继续采集并编码出音视频数据。如果我们什么都不做,那么故事将按照如下的剧本发展下去:

  • 阶段一(切后台开始 -> 之后的10秒内)- CDN因为没有数据所以无法向观众提供视频流,观众看到画面卡主。
  • 阶段二(10秒 -> 70秒内)- 观众端的播放器因为持续收不到直播流而直接推出,直播间已经人去楼空。
  • 阶段三(70秒以后)- 推流的 RTMP 链路被服务器直接断掉,主播需要重新开启直播才能继续。

主播可能只是短暂接个紧急电话而已,但上述的交互体验显然会让观众全部离开直播间,怎么优化呢?

设置App后台(短暂)运行

App 如果切后台后就彻底被休眠掉,那么 LycamPlusCore.framework 再有本事也无济于事,所以我们使用下面的代码让App在切到后台后还可再跑几分钟,这段时间如果主播应付一下紧急电话,也就算是“功德圆满”。

//先注册后退消息通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleEnterBackground:) 
    name:UIApplicationDidEnterBackgroundNotification object:nil];

//收到通知后,调用beginBackgroundTaskWithExpirationHandler
-(void)handleEnterBackground:(NSNotification *)notification
{
    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    }];
}

切后台处理

推流中,如果App被切了后台,也就是在 8.2 中的 handleEnterBackground 里,调用 LycamPlusCore.framework 的 endRtmpSession 接口函数。

//切后台处理: 在 8.2 的基础上补一句
- (void)handleEnterBackground:(NSNotification *)notification
{
    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    }];
    [self.session endRtmpSession];
}

切前台处理

等待App切回前台之后,调用LycamPlusCore.framework 的开始推流的接口函数,之后,RTMP SDK 会继续采集摄像头的画面进行推流。

//切前台处理
- (void)handleEnterForeground:(NSNotification *)notification
{
    [self.session startRtmpSessionWithToken:token andStreamKey:streamKey completionBlock:^(BOOL success, NSError *error) {
        NSLog(@"-===-%@",[error localizedDescription]);
    }];
}

7.推荐的清晰度

影响画质的主要因素是三个:分辨率、帧率和码率。

  • 分辨率:摄像头直播有三种 9:16 的常规分辨率可供选择:360640,540960,720*1280。
  • 帧率:FPS <=10 会明显感觉到卡顿,摄像头直播推荐设置 20 FPS。
  • 码率:编码器每秒编出的数据大小,单位是kbps,比如800kbps代表编码器每秒产生800kb(或100KB)的数据。

好的画质是分辨率、帧率和码率三者之间的平衡,如下是几种清晰度档位的推荐设置结果:

清晰度 分辨率(videoSize) FPS(videoFPS) 码率(videoBitrate)
标清 AVCaptureSessionPreset640x480 30 700kbps
高清 AVCaptureSessionPreset960x540 30 1000kbps
超清 AVCaptureSessionPreset1280x720 30 1500kbps

娱乐秀场领域,我们的客户一般是选择高清档位,因为它比较平衡:720p超清档拍人像比较浪费,360p的效果又不能在清晰度上跟竞品拉开差距。

8. 提醒主播“网络不好”

当bpsCount < 100 的时候,说明主播的网络环境很差,观众观看已经出现卡顿现象了,这个时候就要主播去换个好点的网络环境了。

- (void)detectedThroughput:(NSInteger)throughputInBytesPerSecond videoRate:(NSInteger)rate {
    NSString * str = [NSString stringWithFormat:@"%ld K/s",(long)(throughputInBytesPerSecond/1024)];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSInteger bpsCount = (NSInteger)(throughputInBytesPerSecond/1024);
        if (bpsCount < 100) {
            [self.bpsLabel setTextColor:[UIColor redColor]];
        }else {
            [self.bpsLabel setTextColor:[UIColor greenColor]];
        }
        [self.bpsLabel setText:str];
    });
}

9. 横屏推流

大多数情况下,用户习惯以“竖屏持握”进行直播拍摄,观看端看到的也是竖屏样式;有时候用户在直播的时候需要更广的视角,则拍摄的时候需要“横屏持握”,这个时候其实是期望观看端能看到横屏画面,就需要做横屏推流,下面两幅示意图分别描述了横竖屏持握进行横竖屏推流在观众端看到的效果。

注意: 横屏推流和竖屏推流,观众端看到的图像的宽高比是不同的,竖屏9:16,横屏16:9。

初始化LCPVideoCameraInputSource对象时,就要选择推流方式,不能在推流过程中进行修改。目前只支持UIInterfaceOrientationLandscapeRight、UIInterfaceOrientationPortrait两种模式。

[self.cameraInputSource setupCamera:AVCaptureSessionPresetiFrame960x540 cameraState:LCPCameraStateFront interfaceOrientation:(UIInterfaceOrientationLandscapeRight)];
            

10. 结束推流

结束推流很简单,不过要做好清理工作,因为用于推流的 LCPVCBaseSession 对象同一时刻只能有一个在运行,所以清理工作不当会导致下次直播遭受不良的影响。

[self.session clean];
            

11. 事件处理

事件监听

RTMP SDK 通过 消息服务功能 来监听推流相关的事件,详情见 消息服务

常规事件

一次成功的推流都会通知的事件

事件ID 数值 含义说明
LCPSessionStateStarting 2 正在连接到LYCAM+云推流服务器
LCPSessionStateStarted 3 已经成功连接到LYCAM+云推流服务器
LCPSessionStateEnded 4 已经断开LYCAM+云推流服务器
LCPSessionStateError 5 连接报错或着推流过程中报错

概要描述

视频播放功能主要用于直播推流过程中,观看直播以及回放的机制。

下载SDK

下载移动端 IJKMediaFramework SDK,解压后得到一个IJKMediaFramework.framework。目前 IJKMediaFramework SDK 所有功能都集成在这一framework中。

Xcode工程设置

一、支持平台

SDK支持iOS 7.0以上系统

二、开发环境

Xcode 7或更高版本
OS X 10.10或更高版本

三、Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

1、拷贝SDK文件

在本例中,新建一个名字叫做CoreDemo的iOS工程,将下载下来的IJKMediaFramework.framework拷贝至工程目录。目录结构如下图所示:

2、SDK添加到工程,同时还要添加以下系统依赖库

功能实现

1.在ViewController.m引入头文件

#import <IJKMediaFramework/IJKMediaFramework.h>

2.初始化IJKFFMoviePlayerController对象

#ifdef DEBUG
    [IJKFFMoviePlayerController setLogReport:YES];
    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];
#else
    [IJKFFMoviePlayerController setLogReport:NO];
    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_INFO];
#endif
                
[IJKFFMoviePlayerController checkIfFFmpegVersionMatch:YES];
// [IJKFFMoviePlayerController checkIfPlayerVersionMatch:YES major:1 minor:0 micro:0];

IJKFFOptions *options = [IJKFFOptions optionsByDefault];

//StreamUrl 需要从服务器获取
self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:@"StreamUrl"] withOptions:options];
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.player.view.frame = self.view.bounds;
self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
self.player.shouldAutoplay = YES;

self.view.autoresizesSubviews = YES;
[self.view addSubview:self.player.view];

3.给播放器添加通知机制,该机制用于监听视频数据的状态信息

/* Register observers for the various movie object notifications. */
-(void)installMovieNotificationObservers
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(loadStateDidChange:)
                                                name:IJKMPMoviePlayerLoadStateDidChangeNotification
                                            object:_player];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(moviePlayBackDidFinish:)
                                                name:IJKMPMoviePlayerPlaybackDidFinishNotification
                                            object:_player];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(mediaIsPreparedToPlayDidChange:)
                                                name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
                                            object:_player];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(moviePlayBackStateDidChange:)
                                                name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
                                            object:_player];
}

#pragma mark == NSNotification methods
- (void)loadStateDidChange:(NSNotification*)notification
{
    //    MPMovieLoadStateUnknown        = 0,
    //    MPMovieLoadStatePlayable       = 1 << 0,
    //    MPMovieLoadStatePlaythroughOK  = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES
    //    MPMovieLoadStateStalled        = 1 << 2, // Playback will be automatically paused in this state, if started
    
    IJKMPMovieLoadState loadState = _player.loadState;
    
    if ((loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) {
        NSLog(@"loadStateDidChange: IJKMPMovieLoadStatePlaythroughOK: %d\n", (int)loadState);
    } else if ((loadState & IJKMPMovieLoadStateStalled) != 0) {
        NSLog(@"loadStateDidChange: IJKMPMovieLoadStateStalled: %d\n", (int)loadState);
    } else {
        NSLog(@"loadStateDidChange: ???: %d\n", (int)loadState);
    }
}

- (void)moviePlayBackDidFinish:(NSNotification*)notification
{
    //    MPMovieFinishReasonPlaybackEnded,
    //    MPMovieFinishReasonPlaybackError,
    //    MPMovieFinishReasonUserExited
    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
    
    switch (reason)
    {
        case IJKMPMovieFinishReasonPlaybackEnded:
            NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackEnded: %d\n", reason);
            break;
            
        case IJKMPMovieFinishReasonUserExited:
            NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonUserExited: %d\n", reason);
            break;
            
        case IJKMPMovieFinishReasonPlaybackError:
            NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackError: %d\n", reason);
            break;
            
        default:
            NSLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
            break;
    }
}

- (void)mediaIsPreparedToPlayDidChange:(NSNotification*)notification
{
    NSLog(@"mediaIsPreparedToPlayDidChange\n");
}

- (void)moviePlayBackStateDidChange:(NSNotification*)notification
{
    //    MPMoviePlaybackStateStopped,
    //    MPMoviePlaybackStatePlaying,
    //    MPMoviePlaybackStatePaused,
    //    MPMoviePlaybackStateInterrupted,
    //    MPMoviePlaybackStateSeekingForward,
    //    MPMoviePlaybackStateSeekingBackward
    
    switch (_player.playbackState)
    {
        case IJKMPMoviePlaybackStateStopped: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: stoped", (int)_player.playbackState);
            break;
        }
        case IJKMPMoviePlaybackStatePlaying: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: playing", (int)_player.playbackState);
            break;
        }
        case IJKMPMoviePlaybackStatePaused: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: paused", (int)_player.playbackState);
            break;
        }
        case IJKMPMoviePlaybackStateInterrupted: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: interrupted", (int)_player.playbackState);
            break;
        }
        case IJKMPMoviePlaybackStateSeekingForward:
        case IJKMPMoviePlaybackStateSeekingBackward: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: seeking", (int)_player.playbackState);
            break;
        }
        default: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: unknown", (int)_player.playbackState);
            break;
        }
    }
}

4.结束播放,同时要移除通知机制

[self.player shutdown];

-(void)removeMovieNotificationObservers
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:IJKMPMoviePlayerLoadStateDidChangeNotification
                                                object:_player];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:IJKMPMoviePlayerPlaybackDidFinishNotification
                                                object:_player];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
                                                object:_player];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
                                                object:_player];
}

概要描述

消息服务主要用于推流过程中,即时通讯功能以及视频流状态监听机制,需要跟推流SDK配套使用。

下载SDK

您可以在 LYCAM+ 官网下载移动端 LycamPlusMessageTool SDK,解压后得到一个LycamPlusMessageTool.framework。目前 消息服务 SDK 所有功能都集成在这一framework中。

Xcode工程设置

一、支持平台

SDK支持iOS 7.0以上系统

二、开发环境

Xcode 7或更高版本
OS X 10.10或更高版本

三、Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

1、拷贝SDK文件

在本例中,新建一个名字叫做MessageToolSDK的iOS工程,将下载下来的LycamPlusMessageTool.framework拷贝至工程目录。目录结构如下图所示:

2.SDK添加到工程,同时还要添加以下系统依赖库

功能实现

1.在ViewController.m引入头文件

#import <LycamPlusMessageTool/LCPMessageManager.h>
            

2.初始化LCPMessageManager对象,初始化LCPMessageManager对象之前,要设置一些必备参数。

//其中kLCPMSGServerHost以及kLCPMSGServerPort需要从服务器获取

NSDictionary * config = @{kLCPMSGAppName:@"",          //appName
                            kLCPMSGServerHost:@"mqtt.lycam.tv", //host
                            kLCPMSGServerPort:@(1883),                 //port
                            kLCPMSGTls:@(NO)                                //NO
                            };
//token也需要从服务器获取
_manager = [[LCPMessageManager alloc] initWithToken:@"token" withConfig:config];
_manager.delegate = self;
[_manager connect];

3.LCPMessageManager 代理回调机制

-(void) managerConnecting:(LCPMessageManager *)manager{
}
//连接成功,订阅房间号,其中房间号streamId需要从服务器获取。
-(void) managerConnected:(LCPMessageManager *)manager{
    NSLog(@"connected");
    [self.manager subscribeChannel:@"streamId"];
}
-(void) manager:(LCPMessageManager *)manager receiveMessage:(NSDictionary * )msg withTopic:(NSString *)topic withRetained:(BOOL)retained{
    NSLog(@"receiveMessage:%@ <-%@",msg,topic);
}
-(void) manager:(LCPMessageManager *)manager error:(NSError *)error{
}

- (void)managerClosing:(LCPMessageManager *)manager {
}

-(void) managerClosed:(LCPMessageManager *)manager{
}

功能介绍

LCPMessageManager对象

/**
初始化,配置相关参数

@param token  认证token
@param config 相关参数

@return <#return value description#>
*/
-(id) initWithToken:(NSString *) token
        withConfig:(NSDictionary*) config;


/**
建立连接
*/
-(void) connect;


/**
断开连接
*/
-(void) disconnect;


/**
重连机制
*/
-(void) reconnect;

/**
订阅频道

@param channel 频道号
*/
-(void) subscribeChannel:(NSString*) channel ;

/**
取消订阅频道

@param chan 频道号
*/
-(void) unsubscribeChannel:(NSString*) chan;


/**
设置频道号

@param channel <#channel description#>

@return <#return value description#>
*/
-(NSString*) makeTopic:(NSString*) channel;


/**
发送消息到指定频道

@param obj     消息内容
@param channel 频道号

@return <#return value description#>
*/
- (NSInteger)send:(NSDictionary* ) obj
    withChannel:(NSString *) channel;

事件处理

事件监听

推流状态监听机制

事件Type 含义说明
stream.publish 直播开始推流
stream.pause 直播暂停推流
stream.unpublish 直播结束推流

概要描述

涂鸦功能主要用于PDF推流过程中,主播可以勾画PDF等文件上的要点,让观众一目了然,大大提高了讲演、培训、授课的目的。

下载SDK

您可以在 LYCAM+ 官网下载移动端 涂鸦SDK,解压后得到一个LycamPlusDrawTool.framework。目前 涂鸦SDK 所有功能都集成在这一framework中。

Xcode工程设置

一、支持平台

SDK支持iOS 7.0以上系统

二、开发环境

Xcode 7或更高版本
OS X 10.10或更高版本

三、Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

1、拷贝SDK文件

在本例中,新建一个名字叫做DrawToolSDK的iOS工程,将下载下来的LycamPlusDrawTool.framework拷贝至工程目录。目录结构如下图所示:

2.SDK添加到工程

功能实现

1.在ViewController.m引入头文件
#import <LycamPlusDrawTool/LCPDrawView.h>
            #import <LycamPlusDrawTool/LCPDrawToolView.h>
            
2.初始化绘图工具类
- (LCPDrawToolView *)toolView {
    if (_toolView == nil) {
        __weak typeof(self)weakSelf = self;
        LCPDrawToolView *toolView = [[LCPDrawToolView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 44) afterSelectColor:^(UIColor *color) {
            //给绘图视图设置颜色
            [weakSelf.drawView setDrawColor:color];
        } afterSelectLineWidth:^(CGFloat lineWidth) {
            //给绘图视图设置线宽
            [weakSelf.drawView setLineWidth:lineWidth];
        } afterSelectUndo:^{
            [weakSelf.drawView undoStep];
        } afterSelectClearScreen:^{
            [weakSelf.drawView clearScreen];
        }];
        _toolView = toolView;
    }
    return _toolView;
}

[self.view addSubview:self.toolView];
3.初始化画板
- (LCPDrawView *)drawView {
    if (_drawView == nil) {
        LCPDrawView *drawView = [[LCPDrawView alloc]initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
        [drawView setBackgroundColor:[UIColor clearColor]];
        _drawView = drawView;
    }
    return _drawView;
}
[self.view addSubview:self.drawView];

功能介绍

LCPDrawToolView对象
//代码块
typedef void(^SelectColorBlock)(UIColor *color);//设置颜色
typedef void(^SelectLineWidthBlock)(CGFloat lineWidth);//设置线宽
typedef void(^ToolViewActionBlock)();

/初始化
- (instancetype)initWithFrame:(CGRect)frame
            afterSelectColor:(SelectColorBlock)afterSelectColor
        afterSelectLineWidth:(SelectLineWidthBlock)afterSelectLineWidth
            afterSelectUndo:(ToolViewActionBlock)afterSelectUndo
    afterSelectClearScreen:(ToolViewActionBlock)afterSelectClearScreen;
LCPDrawView对象
//设置线宽
@property (assign, nonatomic) CGFloat lineWidth;
//设置线条颜色
@property (strong, nonatomic) UIColor *drawColor;

//撤销操作
- (void)undoStep;
//清屏操作
- (void)clearScreen;

概要描述

将电脑上的PDF文件,无线传输到手机客户端

下载SDK

您可以在 LYCAM+ 官网下载移动端 LycamPlusUploadFileToolSDK,解压后得到一个LycamPlusUploadFileTool.framework。目前 LycamPlusUploadFileToolSDK 所有功能都集成在这一framework中。

Xcode工程设置

一、支持平台

SDK支持iOS 7.0以上系统

二、开发环境

Xcode 7或更高版本
OS X 10.10或更高版本

三、Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

1、拷贝SDK文件

在本例中,新建一个名字叫做UploadFileSDK的iOS工程,将下载下来的LycamPlusUploadFileTool.framework拷贝至工程目录。目录结构如下图所示:

2、添加Framework

在工程中添加LycamPlusUploadFileTool.framework

3.添加网页文件包 文件包下载

功能实现

1.在ViewController.m引入头文件
#import <LycamPlusUploadFileTool/LCPCoursewareModel.h>
#import <LycamPlusUploadFileTool/HTTPServiceManager.h>
2.初始化HTTPServiceManager对象,开启手机HTTPService
[[HTTPServiceManager defaultManager] startService];
3.获取手机Wi-Fi环境下的IP地址
[[HTTPServiceManager defaultManager] getWiFiIPAddress]
4、打开电脑浏览器,输入手机的IP地址,端口8080,打开下图所示:

  • 选择文件->电脑中选择上传的PDF文件->上传文件->文件列表

  • 文件可删除、可下载

功能介绍

HTTPServiceManager对象
/**
文件上传成功通知
*/
extern NSString * const kLCPHttpServiceUploadFileSuccessNotification;


/**
文件删除成功通知
*/
extern NSString * const kLCPHttpServiceDeleteFileSuccessNotification;


/**
单例
@return <#return value description#>
*/
+ (instancetype)defaultManager;


/**
开启 HTTP Service 服务
*/
- (void)startService;


/**
关闭 HTTP Service 服务
*/
- (void)stopService;


/**
获取 Wi-Fi 环境下的IP地址
@return IP address
*/
- (NSString *)getWiFiIPAddress;


/**
读取手机沙盒所有上传文件
@return files array
*/
- (NSArray *)reloadCoursewareData;


/**
根据文件名获取文件沙盒路径
@param filename 文件名
@return file path
*/
- (NSString *)getFilePathWithFileName:(NSString *)filename;


/**
根据文件名删除指定沙盒文件
@param filename 文件名
*/
- (void)deleteFileWithFilename:(NSString *)filename;

概要描述

PDF预览功能主要用于PDF推流过程中,渲染PDF文件。

下载SDK

您可以在 LYCAM+ 官网下载移动端 PDF预览SDK,解压后得到一个LycamPlusDrawTool.framework。目前 涂鸦SDK 所有功能都集成在这一framework中。

Xcode工程设置

一、支持平台

SDK支持iOS 7.0以上系统

二、开发环境

Xcode 7或更高版本
OS X 10.10或更高版本

三、Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

1、拷贝SDK文件

在本例中,新建一个名字叫做PDFReaderSDK的iOS工程,将下载下来的LycamPlusPDFReader.framework拷贝至工程目录。目录结构如下图所示:

2.SDK添加到工程,同时还要添加以下系统依赖库

3、配置info.plist文件

功能实现

1.在ViewController.m引入头文件
#import <LycamPlusPDFReader/LCPPDFReadViewController.h>
2.初始化PDFReader对象
//全局变量
@property (nonatomic, strong) LCPPDFReadViewController *pdfReadViewController;

NSString *path = "文件路径";
LCPPDFReadViewController *vc = [[LCPPDFReadViewController alloc] initWithPDFAtPath:filePath];
vc.view.frame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
self.pdfReadViewController = vc;

功能介绍

LCPPDFReadViewController对象
/**
初始化PDF

@param path PDF path

@return <#return value description#>
*/
- (id)initWithPDFAtPath:(NSString *)path;

/**
切换PDF

@param filePath      PDF path
@param callbackBlock result
*/
- (void)exchangeCoursewareWithFilePath:(NSString *)filePath
                    completionBlock:(void((^)(BOOL success, NSError *error)))callbackBlock;

/**
移除PDF
*/
- (void)removeCoursewareFile;

/**
修改PDF位置

@param rect   PDF rect
@param enable PDF UserInteractionEnabled
*/
- (void)changePdfFileViewFrame:(CGRect)rect withPDFUserInteractionEnabled:(BOOL)enable;

打开手机蓝牙,使用配套遥控器,可实现PDF翻页效果。

概要描述

PDF推流功能主要包含PDF预览、涂鸦、文件上传、消息服务系统以及直播推流五大功能的综合体。是第三方开发者快速集成实现手播课相关功能,是你的活动、培训、授课更方便、快捷、有效。

下载SDK

参考 推流功能 涂鸦功能 PDF上传功能 PDF预览功能 消息服务功能 SDK下载。

1、拷贝SDK文件

在本例中,新建一个名字叫做CoreDemo的iOS工程,将下载下来的LycamPlusPDFReader.framework、LycamPlusCore.framework、LycamPlusDrawTool.framework、LycamPlusMessageTool.framework、LycamPlusUploadFileTool.framework拷贝至工程目录。目录结构如下图所示:

2.SDK添加到工程,同时还要添加以下系统依赖库

3、配置info.plist文件

功能实现

1.创建一个ViewController,在实现文件中引入头文件
#pragma mark == LycamPlusCore
#import <LycamPlusCore/LCPViewSnapshotInputSource.h>
#import <LycamPlusCore/LCPVCBaseSession.h>
#import <LycamPlusCore/LCPVideoCameraInputSource.h>

#pragma mark == LycamPlusPDFReader
#import <LycamPlusPDFReader/LCPPDFReadViewController.h>

#pragma mark == LycamPlusDrawTool
#import <LycamPlusDrawTool/LCPDrawView.h>
#import <LycamPlusDrawTool/LCPDrawToolView.h>

#pragma mark == LycamPlusUploadFileTool
#import <LycamPlusUploadFileTool/HTTPServiceManager.h>

#pragma mark == LycamPlusMessageTool
#import <LycamPlusMessageTool/LCPMessageManager.h>
2.在 推流功能 的基础上,初始化LCPViewSnapshotInputSource对象,该对象用于传输PDF文件数据。
CGSize videoSize =  CGSizeMake(1280,720);
_session = [[LCPVCBaseSession alloc] initWithVideoSize:videoSize frameRate:30 bitrate:1000000 useAdaptiveBitrate:YES source:self.cameraInputSource];
_session.delegate = self;

LCPViewSnapshotInputSource * inputSource = [[LCPViewSnapshotInputSource alloc] initWithView:self.view fps:30];
inputSource.afterScreenUpdates = NO;
[_session setInputSource:inputSource atIndex:1];
3.PDF文件跟摄像头预览大小窗口切换
- (void) switchButtonPressed:(UIButton *)sender {
    sender.selected = !sender.selected;
    [self.cameraInputSourceView setHidden:NO];
    if (sender.selected) {
        
        [self.session setBlendOffset:CGPointMake(0.0,0.0)];   //锚点
        [self.session setBlendScale:1.0f];
        [self.session setBlendMode:11];
        
        [self.cameraInputSourceView setFrame:CGRectMake(0,0, SCREEN_WIDTH, SCREEN_HEIGHT)];
        [self.cameraInputSource.previewLayer setFrame:CGRectMake(0,0,SCREEN_WIDTH, SCREEN_HEIGHT)];
        
        CGRect pdfRect = CGRectMake(SCREEN_WIDTH - kLCPSmallViewWidth,SCREEN_HEIGHT - kLCPSmallViewHeight, kLCPSmallViewWidth, kLCPSmallViewHeight);
        if (self.cameraPointX <= 0.5f && self.cameraPointY <= 0.5f) {
            pdfRect = CGRectMake(0,0, kLCPSmallViewWidth, kLCPSmallViewHeight);
        }else if (self.cameraPointX > 0.5 && self.cameraPointY <= 0.5f) {
            pdfRect = CGRectMake(SCREEN_WIDTH - kLCPSmallViewWidth,0, kLCPSmallViewWidth, kLCPSmallViewHeight);
        }else if (self.cameraPointX <= 0.5f && self.cameraPointY > 0.5f) {
            pdfRect = CGRectMake(0,SCREEN_HEIGHT - kLCPSmallViewHeight, kLCPSmallViewWidth, kLCPSmallViewHeight);
        }else if (self.cameraPointX > 0.5f && self.cameraPointY > 0.5) {
            pdfRect = CGRectMake(SCREEN_WIDTH - kLCPSmallViewWidth,SCREEN_HEIGHT - kLCPSmallViewHeight, kLCPSmallViewWidth, kLCPSmallViewHeight);
        }
        
        [self.pdfReadViewController changePdfFileViewFrame:pdfRect withPDFUserInteractionEnabled:NO];
        [self.view insertSubview:self.pdfReadViewController.view aboveSubview:self.cameraInputSourceView];
        
        if (self.drawButton.selected && self.isRecording) {
//            [self.view bringSubviewToFront:self.drawView];
        }else if (self.drawButton.selected && !self.isRecording){
//            [self.view insertSubview:self.drawView aboveSubview:self.pdfReadViewController.view];
        }
    
    }else {
        [self.session setBlendOffset:CGPointMake(self.cameraPointX,self.cameraPointY)];   //锚点
        [self.session setBlendScale:0.25];
        [self.session setBlendMode:20];
        
        if (self.cameraPointX <= 0.5f && self.cameraPointY <= 0.5f) {
            [self.cameraInputSourceView setFrame:CGRectMake(0,0, kLCPSmallViewWidth, kLCPSmallViewHeight)];
        }else if (self.cameraPointX > 0.5 && self.cameraPointY <= 0.5f) {
            [self.cameraInputSourceView setFrame:CGRectMake(SCREEN_WIDTH - kLCPSmallViewWidth,0, kLCPSmallViewWidth, kLCPSmallViewHeight)];
        }else if (self.cameraPointX <= 0.5f && self.cameraPointY > 0.5f) {
            [self.cameraInputSourceView setFrame:CGRectMake(0,SCREEN_HEIGHT - kLCPSmallViewHeight, kLCPSmallViewWidth, kLCPSmallViewHeight)];
        }else if (self.cameraPointX > 0.5f && self.cameraPointY > 0.5) {
            [self.cameraInputSourceView setFrame:CGRectMake(SCREEN_WIDTH - kLCPSmallViewWidth,SCREEN_HEIGHT - kLCPSmallViewHeight, kLCPSmallViewWidth, kLCPSmallViewHeight)];
        }
        
        [self.cameraInputSource.previewLayer setFrame:CGRectMake(0,0, kLCPSmallViewWidth, kLCPSmallViewHeight)];
        [self.pdfReadViewController changePdfFileViewFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) withPDFUserInteractionEnabled:YES];
        [self.view insertSubview:self.cameraInputSourceView aboveSubview:self.pdfReadViewController.view];
    }
}
4.PDF课件切换
- (void) coursewareButtonPressed:(UIButton *)sender {
    sender.selected = ! sender.selected;
    NSString *path = @"文件路径";
    [self.pdfReadViewController exchangeCoursewareWithFilePath:path completionBlock:^(BOOL success, NSError *error) {
        
    }];
}
5.隐藏小窗口
- (void) hideSmallButtonPressed:(UIButton *)sender {
    sender.selected = ! sender.selected;
    
    if (sender.selected) {
        if (self.switchButton.selected) {
            [self.session setBlendMode:11];
            [self.pdfReadViewController.view setFrame:CGRectZero];
        }else {
            [self.session setBlendOffset:CGPointMake(1.0,1.0)];   //锚点
            [self.session setBlendScale:1.0];
            [self.cameraInputSourceView setHidden:YES];
        }
    }else {
        if (self.switchButton.selected) {
            [self.session setBlendMode:11];
            CGRect frame = CGRectMake(SCREEN_WIDTH - kLCPSmallViewWidth, SCREEN_HEIGHT - kLCPSmallViewHeight, kLCPSmallViewWidth, kLCPSmallViewHeight);
            [self.pdfReadViewController.view setFrame:frame];
        }else {
            [self.session setBlendOffset:CGPointMake(self.cameraPointX,self.cameraPointY)];   //锚点
            [self.session setBlendScale:0.25];
            [self.session setBlendMode:20];
            [self.cameraInputSourceView setHidden:NO];
        }
    }
}
6.涂鸦
- (void) drawButtonPressed:(UIButton *)sender {
    sender.selected = !sender.selected;
    if (sender.selected) {
        [self.drawView setAlpha:1.0f];
        [self.toolView setAlpha:0.6f];
        if (self.isRecording) {
            [self.view bringSubviewToFront:self.drawView];
        }
    }else {
        [self.drawView setAlpha:0.0f];
        [self.toolView setAlpha:0.0f];
        [self.drawView clearScreen];
    }
}
7.小窗口就近停靠
- (void) panGestureRecognizerAction:(UIPanGestureRecognizer *)recognizer {
                
    if (self.switchButton.selected) {
        return;
    }
    
    CGPoint translation = [recognizer translationInView:self.view];
    recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                        recognizer.view.center.y + translation.y);
    [recognizer setTranslation:CGPointZero inView:self.view];
    
    if (recognizer.state == UIGestureRecognizerStateEnded) {
        
        CGPoint velocity = [recognizer velocityInView:self.view];
        CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
        CGFloat slideMult = magnitude / 200;
        
        float slideFactor = 0.1 * slideMult; // Increase for more of a slide
        CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor),
                                        recognizer.view.center.y + (velocity.y * slideFactor));
        finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
        finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
        
        if (finalPoint.x <= SCREEN_WIDTH / 2 && finalPoint.y <= SCREEN_HEIGHT / 2) {
            finalPoint.x = kLCPSmallViewWidth / 2;
            finalPoint.y = kLCPSmallViewHeight / 2;
            self.cameraPointX = 0.0f;
            self.cameraPointY = 0.0f;
            
        }else if (finalPoint.x <= SCREEN_WIDTH / 2 && finalPoint.y > SCREEN_HEIGHT / 2) {
            finalPoint.x = kLCPSmallViewWidth / 2;
            finalPoint.y = SCREEN_HEIGHT - kLCPSmallViewHeight / 2;
            
            self.cameraPointX = 0.0f;
            self.cameraPointY = 0.75f;
            
        }else if (finalPoint.x > SCREEN_WIDTH / 2 && finalPoint.y <= SCREEN_HEIGHT / 2) {
            finalPoint.x = SCREEN_WIDTH - kLCPSmallViewWidth / 2;
            finalPoint.y = kLCPSmallViewHeight / 2;
            
            self.cameraPointX = 0.8f;
            self.cameraPointY = 0.0f;
            
        }else if (finalPoint.x > SCREEN_WIDTH / 2 && finalPoint.y > SCREEN_HEIGHT / 2) {
            finalPoint.x = SCREEN_WIDTH - kLCPSmallViewWidth / 2;
            finalPoint.y = SCREEN_HEIGHT - kLCPSmallViewHeight / 2;
            
            self.cameraPointX = 0.8f;
            self.cameraPointY = 0.75f;
        }
        
        [self resetCameraPointWithCGPoint:CGPointMake(self.cameraPointX, self.cameraPointY)];
        [self.session setBlendScale:0.25];
        [self.session setBlendMode:20];
        
        [UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            recognizer.view.center = finalPoint;
        } completion:nil];
    }
}

Android 端暂时只实现了直播观看功能,推流功能我们还在努力完善中。

  1. 播放器使用

介绍

当前项目是基于ijkplayer项目进行的播放器界面UI封装。
是一个适用于 Android 的 RTMP 直播推流 SDK,可高度定制化和二次开发。特色是同时支持 H.264 软编/硬编和 AAC 软编/硬编。主要是支持RTMP、HLS、MP4、M4A等视频格式的播放。

特性

  1. 基于ijkplayer封装的视频播放器界面,支持 RTMP,HLS,MP4,M4A 等;
  2. 可根据需求去定制部分界面样式;
  3. 常用的手势操作左边上下亮度,右边上下声音,左右滑动播放进度调整;
  4. 支持多种分辨率流的切换播放;
  5. 播放出错尝试重连;
  6. 界面裁剪显示样式;

集成(支持android 4.2以上机型)

Maven:

<dependency>
  <groupId>tv.lycam</groupId>
  <artifactId>ijkplayer</artifactId>
  <version>0.2.5</version>
  <type>pom</type>
</dependency>

or Gradle:

compile 'tv.lycam:ijkplayer:0.2.5'

支持多种ABI类型的机型,可以根据需要添加以下依赖:

#armeabi
compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.7.8.1'

# Other ABIs: optional
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.7.8.1'
compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.7.8.1'
compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.7.8.1'
compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.7.8.1'

使用

1.简单的播放器实现

new PlayerView(this)
                .setTitle("标题")//   标题
                .setScaleType(PlayStateParams.fitparent)    // 缩放类型
                .forbidTouch(false) // 禁止触摸
                .showThumbnail(new OnShowThumbnailListener() {
                    @Override
                    public void onShowThumbnail(ImageView ivThumbnail) {
                        // 加载封面(自定义第三方图片加载库)
                        Glide.with(mContext)
                                .load("http://www.lycam.tv/assets/images/Lycam_logo_png.png")
                                .dontTransform()
                                .placeholder(R.color.cl_default)
                                .error(R.color.cl_error)
                                .into(ivThumbnail);
                    }
                })
                .setPlaySource(url, true)   // 设置播放源, true表示直播,false表示回放
                .setPlayerBackListener(new OnPlayerBackListener() {
                    @Override
                    public void onPlayerBack() {
                        //finish(); // 全屏时后退键功能回调
                    }
                });
                // 播放器类型, 根据需求选择
                .setPlayerType(IjkVideoView.PV_PLAYER__IjkMediaPlayer)
        .startPlay();

2.播放器配置

在Activity或Fragment中,添加如下生命周期方法:


    @Override
    protected void onPause() {
        super.onPause();
        if (player != null) {
            player.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (player != null) {
            player.onResume();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (player != null) {
            player.onDestroy();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (player != null) {
            // 自适应屏幕方向
            player.onConfigurationChanged(newConfig);
        }
    }

    @Override
    public void onBackPressed() {
        // 这里是退出播放器全屏操作,如不需要可去除
        if (player != null && player.onBackPressed()) {
            return;
        }
        super.onBackPressed();
    }

3.权限配置

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

播放器类型介绍

public static final int PV_PLAYER__AndroidMediaPlayer = 1;  // android播放器,部分手机有兼容性导致不能播放
public static final int PV_PLAYER__IjkMediaPlayer = 2;  // 可播放直播的ijkplayer
public static final int PV_PLAYER__IjkExoMediaPlayer = 3;   // google播放器

视频界面裁剪介绍

可通过方法setScaleType(int type)去设置

1. PlayStateParams.fitParent:可能会剪裁,保持原视频的大小,显示在中心,当原视频的大小超过view的大小超过部分裁剪处理
2. PlayStateParams.fillParent:可能会剪裁,等比例放大视频,直到填满View为止,超过View的部分作裁剪处理
3. PlayStateParams.wrapcontent:将视频的内容完整居中显示,如果视频大于view,则按比例缩视频直到完全显示在view中
4. PlayStateParams.fitXY:不剪裁,非等比例拉伸画面填满整个View
5. PlayStateParams.f16_9:不剪裁,非等比例拉伸画面到16:9,并完全显示在View中
6. PlayStateParams.f4_3:不剪裁,非等比例拉伸画面到4:3,并完全显示在View中

隐藏不想要的界面

//隐藏返回键,true隐藏,false为显示
PlayerView hideBack(boolean isHide)
//隐藏菜单键,true隐藏,false为显示
PlayerView hideMenu(boolean isHide)
//隐藏分辨率按钮,true隐藏,false为显示
PlayerView hideSteam(boolean isHide)
//隐藏旋转按钮,true隐藏,false为显示
PlayerView hideRotation(boolean isHide)
//隐藏全屏按钮,true隐藏,false为显示
PlayerView hideFullscreen(boolean isHide)
//隐藏中间播放按钮,ture为隐藏,false为不做隐藏处理,但不是显示
PlayerView hideCenterPlayer(boolean isHide)

播放器底部bar播放进度条样式定制

默认的进度样式是竖屏为上下样式,即进度条在播放时长的上面,横屏为左右样式,即进度条在播放时长的中间。样式定制主要是两个方法搭配使用toggleProcessDurationOrientation方法和setProcessDurationOrientation方法,横竖屏切换2中情况,和3种进度条样式

/**上下样式*/
PlayStateParams.PROCESS_PORTRAIT
/**左右样式*/
PlayStateParams.PROCESS_LANDSCAPE
/**中间两边样式*/
PlayStateParams.PROCESS_CENTER

提示

设置播放器类型时**必须在startPlay()之前**,否则无法生效。

业务服务端校验

Token 获取

业务服务器使用 OAuth2 协议中的 Password 模式, 请求 LYCAM+ 直播云获取 Token 。 Token 获取地址为:

https://oauth.lycam.tv/oauth2/token

用户管理

创建用户

请求格式 :

POST https://api.lycam.tv/v1/users

参数说明

请求参数 是否必须 数据类型 参数说明
username false string 用户名,长度为6-80位,如果为空将随机生成
password false string 用户密码,长度8-16位,如果为空将随机生成
email false string 邮件地址
phone false string 手机号码 11-20 位
description false string 描述 4-300个字符
displayName false string 显示的昵称,2-20位
extraInfo false json 自定义用户信息。格式为 json,比如:{ address:“成都市科华北路”,tel:“0288519999”}

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    "username": "tester1",
    "password": "e32c10-8c1",
    "uuid": "03635c10-8d0e-11e5-b7e5-b140b14b271c",
    "success": true
}

返回字段说明

返回字段 数据类型 参数说明
username string 用户名
uuid string 用户唯一身份标识
password string 用户密码(如果密码为随机生成,才返回此字段)
success bool 成功标志,成功 true,失败 false

用户查询

请求格式

POST http://api-dev.lycam.tv/v1/search/user/accurate

参数说明

请求参数 是否必须 数据类型 参数说明
username true string 用户名

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
  "totalItems": 1,
  "resultsPerPage": 10,
  "pageNumber": 1,
  "nextPageAvailable": false,
  "items": [
    {
      "username": "7a1a4490-16ab-11e7-80d6-0366a4445f75",
      "clientId": "58df313577cbb40f005c676a",
      "uuid": "7a1a4490-16ab-11e7-80d6-0366a4445f75",
      "active": true,
      "deleted": false,
      "createdAt": "2017-04-01T07:19:00.191Z",
      "updatedAt": "2017-04-01T07:19:00.274Z",
      "id": "58df546477cbb40f005c6822"
    }
  ]
}

用户 Token 授权

请求格式

POST https://api.lycam.tv/v1/users/<uuid>/assume

uuid 为需要被授权用户的 uuid

参数说明

请求参数 是否必须 数据类型 参数说明
scope false string 授权资源范围,默认*
durationSeconds false integer 令牌时效(秒)

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    success: true,
    scope: '*',
    token:
    {
        token_type: 'bearer',
        access_token: 'YDwRSWICvOTstG4MoAxwMfsPLZr26eHVomtDTO0mtv2WR8waKNTgJGfYUVBhm4HCFso0e21Y2DuGETgPA8Hm1IpIskvUJYKtYjkYtxhbLMu8I2clVcvo7b3hgq0UYa5nYHCm66Zx6BqaKbA5Wx4hwwF0LRrZOe2q5UTVqljL6Xa7qbQT8UKEdIxFHb7MfMx2eKqfnr5Rwvt1y7YkPyMNRw4giDkkRXDZ2w133Es9JLGDQVx2CMw2qhLKcekil2b',
        expires_in: 360000
    }
}

返回字段说明

返回字段 数据类型 参数说明
success bool 成功标志,成功 true,失败false
scope string 授权资源范围,*表示所有资源
token json token对象 。包括 access_token,expires_in 字段等…
token_type string 认证类型
access_token string 访问令牌
expires_in integer 令牌过期时间

视频流管理

创建视频流

请求格式

POST https://api.lycam.tv/v1/streams

参数说明

请求参数 是否必须 数据类型 参数说明
uuid false string 用户唯一身份标识( 即uuid )
title false string 视频流标题
description false string 视频流描述
thumbnailUrl false string 视频流封面地址
startLat false float 开始视频的维度坐标
startLon false float 开始视频的经度坐标
country false string 国家
state false string 省份
city false string 城市
privacy false bool 是否私有视频( true是,false否 )
extraInfo false json object 自定义用户信息,格式为 json

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    streamId: '03b60490-b44d-11e5-a15f-79327a48fd81',
    status: 'ready',
    streamUrls: [
        {
            type: 'RTMP',
            url: 'rtmp://rtmp-pull.lycam.tv/livestream/03b60490-b44d-11e5-a15f-79327a48fd81',
            bitrate: 1000
        },
        {
            type:'HLS',
            url:'http://hls-live.lycam.tv/livestream/03b60490-b44d-11e5-a15f-79327a48fd81.m3u8',
            bitrate: 1000
        },
        { 
            type: 'RTMP/audio',
            url: 'rtmp://rtmp.ws.lycam.tv/lycam/39483dd0-295a-11e6-b429-81501508db8a_audio',
            bitrate: 128
        }
    ],
    thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/03b60490-b44d-11e5-a15f-79327a48fd81/thumb.jpg',
    resourceUrl: 'https://api.lycam.tv/v1/streams/03b60490-b44d-11e5-a15f-79327a48fd81/player',
    streamType: 'RTMP',
    chatUrl: 'im.lycam.tv',
    chatChannel: '441dd3b1-1829-11e6-80a9-7d20416a7de8',
    chatToken: 'M4wFHbwmNPQcOWx12FMI5GiUiMJlpSgE7cM9SGw37ffRpAUc5zH7SXFStTNFJg8F',
    uploadUrl: 'rtmp://rtmp-push.lycam.tv/livestream',
    videoWidth: 640,
    videoHeight: 360,
    videoOrientation: 0,
    timeStarted: '2016-01-06T08:10:57.000Z',
    timeFinished: '2016-01-06T08:10:57.000Z',
    startLat: 30.6186,
    startLon: 104.059,
    endLat: null,
    endLon: null,
    city: '成都',
    state: '四川',
    country: '中国',
    privacy: false,
    title: 'test',
    description: 'this is a test',
    extraInfo: {
        outdoor_temperature:"28℃"
    }
}

返回字段说明

返回字段 数据类型 参数说明
streamId string stramId ( 视频流标识 )
status string 直播状态(live, over,ready)
streamUrls json object 视频播放资源列表
uploadUrl string 推流地址
chatUrl string 消息服务器地址
chatChannel string 消息服务器频道
resourceUrl string 视屏 HTML 主页地址
title string 视频流标题
description string 视频流描述
thumbnailUrl string 视频流封面地址
startLat float 开始视频的维度坐标
startLon float 开始视频的经度坐标
country string 国家
state string 省份
city string 城市
privacy bool 是否私有视频( true是,false否 )
extraInfo object 自定义用户信息,格式为 json

更新视频流

请求格式:

PUT https://api.lycam.tv/v1/streams/<stream_id>

uuid 为需要被授权用户的 uuid

参数说明

请求参数 是否必须 数据类型 参数说明
title false string 视频流标题
description false string 视频流描述
thumbnailUrl false string 视频流封面地址
startLat false float 开始视频的维度坐标
startLon false float 开始视频的经度坐标
endLat false float 视频当前的维度坐标
endLon false float 视频当前的经度坐标
country false string 国家
state false string 省份
city false string 城市
privacy false bool 是否私有视频( true是,false否 )
extraInfo false json object 自定义用户信息,格式为 json

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{}

返回字段说明

返回字段 数据类型 参数说明
streamId string stramId ( 视频流标识 )
status string 直播状态(live, over,ready)
streamUrls json object 视频播放资源列表
uploadUrl string 推流地址
chatUrl string 消息服务器地址
chatChannel string 消息服务器频道
resourceUrl string 视屏 HTML 主页地址
title string 视频流标题
description string 视频流描述
thumbnailUrl string 视频流封面地址
country string 国家
state string 省份
city string 城市
privacy bool 是否私有视频( true是,false否 )
其它视频流参数

获取指定 ID 视频流

请求格式:

GET https://api.lycam.tv/v1/streams/<stream_id>

stream_id 为需要被销毁的 stream_id

参数说明

请求参数 是否必须 数据类型 参数说明
streamId true string stramId ( 视频流标识 )

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    user:
    {
        username: 'tester1',
        displayName: 'tester',
        description: null,
        uuid: 'ce2a8ea0-af78-11e5-bab7-ddd23502f257'
    },
    streamId: '03b60490-b44d-11e5-a15f-79327a48fd81',
    status: 'live',
    streamUrls:
    [
        {
            type: 'RTMP',
            url: 'rtmp://rtmp-pull.lycam.tv/livestream/03b60490-b44d-11e5-a15f-79327a48fd81',
            bitrate: 1000
        },
        {
            type:'HLS',
            url:'http://hls-live.lycam.tv/livestream/03b60490-b44d-11e5-a15f-79327a48fd81.m3u8',
            bitrate: 1000
        }
    ],
    thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/03b60490-b44d-11e5-a15f-79327a48fd81/thumb.jpg',
    resourceUrl: 'https://api.lycam.tv/v1/streams/03b60490-b44d-11e5-a15f-79327a48fd81/player',
    streamType: 'RTMP',
    chatUrl: 'im.lycam.tv',
    videoWidth: 640,
    videoHeight: 360,
    videoOrientation: 0,
    timeStarted: '2016-01-06T08:10:57.000Z',
    timeFinished: '2016-01-06T08:10:57.000Z',
    startLat: 30.6186,
    startLon: 104.059,
    endLat: null,
    endLon: null,
    city: '成都',
    state: '四川',
    country: '中国',
    privacy: false,
    title: 'test',
    description: 'this is a test',
    extraInfo: null
}

返回字段说明

返回字段 数据类型 参数说明
streamId string stramId ( 视频流标识 )
status string 直播状态(live, over,ready)
streamUrls json object 视频播放资源列表
uploadUrl string 推流地址
chatUrl string 消息服务器地址
chatChannel string 消息服务器频道
resourceUrl string 视屏 HTML 主页地址
title string 视频流标题
description string 视频流描述
thumbnailUrl string 视频流封面地址
startLat float 开始视频的维度坐标
startLon float 开始视频的经度坐标
country string 国家
state string 省份
city string 城市
privacy bool 是否私有视频( true是,false否 )
extraInfo object 自定义用户信息 ,格式为 json

获取视频流列表

请求格式:

GET https://api.lycam.tv/v1/search/

参数说明

请求参数 是否必须 数据类型 参数说明
keyword(模糊匹配) false string 视频标题
status false string 视频状态(ready, live, over)
resultsPerPage false int 每页返回记录数 ,默认 10 行
page false int 返回第几页 ,默认第 1 页
sort false string 排序字段(id,description,created)
order false string 排序方向( asc,desc )

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    totalItems: 2,
    resultsPerPage: 10,
    pageNumber: 1,
    nextPageAvailable: false,
    items:
    [ 
        { 
            streamId: '41acd410-b45a-11e5-a6b7-1bd1c8f0b971',
            status: 'live',
            streamUrl: 'rtmp://rtmp-pull.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971',
            thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/41acd410-b45a-11e5-a6b7-1bd1c8f0b971/thumb.jpg',
            resourceUrl: 'https://api.lycam.tv/v1/streams/41acd410-b45a-11e5-a6b7-1bd1c8f0b971/player',
            streamResourceRoot: 'http://hls.cd26.com/',
            streamType: 'RTMP',
            chatUrl: 'Not implemented yet',
            videoWidth: null,
            videoHeight: null,
            videoOrientation: null,
            timeStarted: '2016-01-06T09:45:44.000Z',
            timeFinished: '2016-01-06T09:45:44.000Z',
            startLat: 30.6186,
            startLon: 104.059,
            endLat: null,
            endLon: null,
            city: null,
            state: null,
            country: null,
            privacy: null,
            title: null,
            description: 'this is a test',
            extraInfo: null,
            streamUrls: 
            [
                {
                    type:'rtmp',
                    url:'rtmp://rtmp-pull.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971'
                },
                {
                    type:'hls',
                    url:'http://hls-live.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971.m3u8'
                }
            ]
        },
        { 
            streamId: '412135e0-b45a-11e5-a6b7-1bd1c8f0b971',
            status: 'live',
            streamUrl: 'rtmp://rtmp-pull.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971',
            thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/412135e0-b45a-11e5-a6b7-1bd1c8f0b971/thumb.jpg',
            resourceUrl: 'https://api.lycam.tv/v1/streams/412135e0-b45a-11e5-a6b7-1bd1c8f0b971/player',
            streamResourceRoot: 'http://hls.cd26.com/',
            streamType: 'RTMP',
            chatUrl: 'Not implemented yet',
            videoWidth: null,
            videoHeight: null,
            videoOrientation: null,
            timeStarted: '2016-01-06T09:45:43.000Z',
            timeFinished: null,
            startLat: 30.6186,
            startLon: 104.059,
            endLat: null,
            endLon: null,
            city: null,
            state: null,
            country: null,
            privacy: null,
            title: null,
            description: 'test',
            extraInfo: null,
            streamUrls: 
            [
                {
                    type:'rtmp',
                    url:'rtmp://rtmp-pull.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971'
                },
                {
                    type:'hls',
                    url:'http://hls-live.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971.m3u8'
                }
            ],
        }
    ]
}

返回字段说明

返回字段 数据类型 参数说明
totalItems int 记录总数
resultsPerPage int 每一页数量
nextPageAvailable bool 是否有下一页
items array 视频流清单数组

获取指定时间前视频流列表

请求格式:

GET https://api.lycam.tv/v1/streams/since/<timestamp>

<timestamp> 替换为 距1970 年 1 月 1 日之间的毫秒数 , timestamp 为 0 ,则表示为获取最新的视频列表

参数说明

请求参数 是否必须 数据类型 参数说明
timestamp true long timestamp ( unix timestamp )
resultsPerPage false int 每页返回记录数 ,默认 10 行

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    totalItems: 2,
    resultsPerPage: 10,
    pageNumber: 1,
    nextPageAvailable: false,
    items:
    [
        { 
            streamId: '41acd410-b45a-11e5-a6b7-1bd1c8f0b971',
            status: 'live',
            streamUrl: 'rtmp://rtmp-pull.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971',
            thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/41acd410-b45a-11e5-a6b7-1bd1c8f0b971/thumb.jpg',
            resourceUrl: 'https://api.lycam.tv/v1/streams/41acd410-b45a-11e5-a6b7-1bd1c8f0b971/player',
            streamResourceRoot: 'http://hls.cd26.com/',
            streamType: 'RTMP',
            chatUrl: 'Not implemented yet',
            videoWidth: null,
            videoHeight: null,
            videoOrientation: null,
            timeStarted: '2016-01-06T09:45:44.000Z',
            timeFinished: '2016-01-06T09:45:44.000Z',
            startLat: 30.6186,
            startLon: 104.059,
            endLat: null,
            endLon: null,
            city: null,
            state: null,
            country: null,
            privacy: null,
            title: null,
            description: 'this is a test',
            extraInfo: null,
            streamUrl: 
            [
                {
                    type:'rtmp',
                    url:'rtmp://rtmp-pull.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971'
                },
                {
                    type:'hls',
                    url:'http://hls-live.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971.m3u8'
                }
            ]
        },
        { 
            streamId: '412135e0-b45a-11e5-a6b7-1bd1c8f0b971',
            status: 'live',
            streamUrl: 'rtmp://rtmp-pull.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971',
            thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/412135e0-b45a-11e5-a6b7-1bd1c8f0b971/thumb.jpg',
            resourceUrl: 'https://api.lycam.tv/v1/streams/412135e0-b45a-11e5-a6b7-1bd1c8f0b971/player',
            streamResourceRoot: 'http://hls.cd26.com/',
            streamType: 'RTMP',
            chatUrl: 'Not implemented yet',
            videoWidth: null,
            videoHeight: null,
            videoOrientation: null,
            timeStarted: '2016-01-06T09:45:43.000Z',
            timeFinished: null,
            startLat: 30.6186,
            startLon: 104.059,
            endLat: null,
            endLon: null,
            city: null,
            state: null,
            country: null,
            privacy: null,
            title: null,
            description: 'test',
            extraInfo: null,
            streamUrl: 
            [
                {
                    type:'rtmp',
                    url:'rtmp://rtmp-pull.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971'
                },
                {
                    type:'hls',
                    url:'http://hls-live.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971.m3u8'
                }
            ],
        }
    ]
}

返回字段说明

返回字段 数据类型 参数说明
totalItems int 记录总数
resultsPerPage int 每一页数量
nextPageAvailable bool 是否有下一页
items array 视频流清单数组

通过地理位置搜索视频流

请求格式:

POST https://api.lycam.tv/v1/search/location/

参数说明

请求参数 是否必须 数据类型 参数说明
lon true float 经度
lat true float 纬度
radius true float 搜索半径
resultsPerPage false int 每页返回记录数 ,默认 10 行
page false int 返回第几页 ,默认第 1 页
sort false string 排序字段( id,description,created )
order false string 排序方向( asc,desc )

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    totalItems: 2,
    resultsPerPage: 10,
    pageNumber: 1,
    nextPageAvailable: false,
    items:
    [ 
        {
            streamId: '41acd410-b45a-11e5-a6b7-1bd1c8f0b971',
            status: 'live',
            streamUrl: 'rtmp://rtmp-pull.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971',
            thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/41acd410-b45a-11e5-a6b7-1bd1c8f0b971/thumb.jpg',
            resourceUrl: 'https://api.lycam.tv/v1/streams/41acd410-b45a-11e5-a6b7-1bd1c8f0b971/player',
            streamResourceRoot: 'http://hls.cd26.com/',
            streamType: 'RTMP',
            chatUrl: 'Not implemented yet',
            videoWidth: null,
            videoHeight: null,
            videoOrientation: null,
            timeStarted: '2016-01-06T09:45:44.000Z',
            timeFinished: '2016-01-06T09:45:44.000Z',
            startLat: 30.6186,
            startLon: 104.059,
            endLat: null,
            endLon: null,
            city: null,
            state: null,
            country: null,
            privacy: null,
            title: null,
            description: 'this is a test',
            extraInfo: null,
            streamUrl: 
            [
                {
                    type:'rtmp',
                    url:'rtmp://rtmp-pull.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971'
                },
                {
                    type:'hls',
                    url:'http://hls-live.lycam.tv/livestream/41acd410-b45a-11e5-a6b7-1bd1c8f0b971.m3u8'
                }
            ]
        },
        { 
            streamId: '412135e0-b45a-11e5-a6b7-1bd1c8f0b971',
            status: 'live',
            streamUrl: 'rtmp://rtmp-pull.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971',
            thumbnailUrl: 'http://hls.cd26.com/testApp/tester1/412135e0-b45a-11e5-a6b7-1bd1c8f0b971/thumb.jpg',
            resourceUrl: 'https://api.lycam.tv/v1/streams/412135e0-b45a-11e5-a6b7-1bd1c8f0b971/player',
            streamResourceRoot: 'http://hls.cd26.com/',
            streamType: 'RTMP',
            chatUrl: 'Not implemented yet',
            videoWidth: null,
            videoHeight: null,
            videoOrientation: null,
            timeStarted: '2016-01-06T09:45:43.000Z',
            timeFinished: null,
            startLat: 30.6186,
            startLon: 104.059,
            endLat: null,
            endLon: null,
            city: null,
            state: null,
            country: null,
            privacy: null,
            title: null,
            description: 'test',
            extraInfo: null,
            streamUrl:
            [
                {
                    type:'rtmp',
                    url:'rtmp://rtmp-pull.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971'
                },
                {
                    type:'hls',
                    url:'http://hls-live.lycam.tv/livestream/412135e0-b45a-11e5-a6b7-1bd1c8f0b971.m3u8'
                }
            ],
        }
    ]
}

返回字段说明

返回字段 数据类型 参数说明
totalItems int 记录总数
resultsPerPage int 每一页数量
nextPageAvailable bool 是否有下一页
items array 视频流清单数组

销毁指定ID视频流

请求格式:

DELETE https://api.lycam.tv/v1/streams/<stream_id>

stream_id为需要被销毁的 stream_id

参数说明

请求参数 是否必须 数据类型 参数说明
streamId true string streamId ( 视频流标识 )

HTTP 响应

所有的返回都是 JSON 格式, 正常返回 200 状态码。 返回值范例:

{
    success:true
}

返回字段说明

返回字段 数据类型 参数说明
success bool 成功标志 。成功 true,失败 false

地址:成都市武侯区天府软件园B区B7栋412号

邮编:610000

咨询热线:028-61152581 / 18600091039

服务邮箱:service@lycam.tv