普通IPC设备接入
本文为您介绍如何通过设备SDK将普通IPC设备接入物联网平台。
前提条件
步骤一:创建视频产品和设备
登录物联网平台控制台。
在实例概览页,找到已创建的实例,单击实例名称。
在实例中创建摄像头设备所属产品,详细操作,请参见创建产品。
部分参数说明如下所示:
所属品类需要选择智能生活 > 家居安防 > 摄像头,您也可以在选择品类面板的搜索框中输入摄像头,搜索该品类并选中。
节点类型需要选择直连设备。
在创建产品页面的添加设备区域,单击前往添加。
在设备页面的设备列表页签,单击添加设备,在添加设备对话框中,输入设备信息,单击确认。
参数
描述
DeviceName
设置设备名称。设备名称在产品内具有唯一性。支持英文字母、数字、短划线(-)、下划线(_)、at(@)、英文句号(.)和英文冒号(:),长度限制为4~32个字符。
说明DeviceName可以为空。为空时,由物联网平台生成一个产品内唯一标识符作为设备的DeviceName。
备注名称
设置备注名称。支持中文、英文字母、日文、数字和下划线(_),长度限制为4~64个字符,一个中文或日文占2个字符。
设备创建成功后,在添加完成对话框,单击前往查看。
在设备详情页面,单击查看,您可以查看、复制设备证书信息。设备证书由设备的ProductKey、DeviceName和DeviceSecret组成,是设备与物联网平台进行通信的重要身份认证,建议您妥善保管。
参数
说明
ProductKey
设备所属产品的ProductKey,即物联网平台为产品颁发的全局唯一标识符。
DeviceName
设备在产品内的唯一标识符。DeviceName与设备所属产品的ProductKey组合,作为设备标识,用来与物联网平台进行连接认证和通信。
DeviceSecret
物联网平台为设备颁发的设备密钥,用于认证加密。需与DeviceName成对使用。
步骤二:将设备接入物联网平台
本步骤在Linux系统下,运行设备端C语言版本的LinkVisual SDK Demo。推荐在64位的Ubuntu18.04的环境下使用Demo。
- 重要
下载LinkVisual SDK Demo将默认您同意软件许可协议,下载前请仔细阅读。
登录Linux虚拟机,将下载的Demo包,上传至Linux虚拟机的开发环境。
在Demo包所在目录路径下执行以下命令,解压文件夹。
tar -xf lv_2.1.2-lk_2.3.0-ubuntu.tar.gz
执行以下命令,打开文件夹。
cd lv_2.1.2-lk_2.3.0-ubuntu
文件夹的目录结构如下。
1.jpg avc_aac_1000k avc_aac_1000k.index avc_aac_1000k.meta avc_aac_500k avc_aac_500k.index avc_aac_500k.meta link_visual_ipc
执行以下命令,将设备接入智能视频服务。
./link_visual_ipc -p ${YourProductKey} -n ${YourDeviceName} -s ${YourDeviceSecret}
其中,${YourProductKey}、${YourDeviceName}和${YourDeviceSecret}在上一步创建产品和设备时获取。显示如下日志,表示执行成功。
登录物联网平台控制台。
单击目标企业版实例,在左侧导航栏选择设备管理>设备,查看设备状态。
单击目标设备名称。单击物模型数据页签,在运行状态页签下查看物模型数据。1~3分钟后,单击事件管理页签,查看生成的智能告警事件。
步骤三:获取直播播放地址
将IPC设备接入物联网智能视频服务后,需要实现一个HTTP Web Server供前端调用来获取播放地址。实现HTTP Web Server有很多方法,本文以Netty HTTP Server为例,展示获取直播播放地址的方法。您也可以根据实际情况,搭建HTTP Web Server。
本步骤使用的开发环境如下:
操作系统:Windows 10 64位
JDK版本:JDK8
集成开发环境:IntelliJ IDEA社区版
打开IntelliJ IDEA,新建示例工程Demo。
在工程Demo的
pom.xml
文件中,添加以下的Maven项目依赖。LinkVisual Java SDK的Maven依赖坐标:
<dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-linkvisual</artifactId> <version>1.5.23</version> </dependency>
阿里云Java SDK公共包Maven依赖坐标:
<dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.3</version> </dependency>
集成Netty框架:
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.29.Final</version> </dependency>
在
src/main/java
路径下新建文件SampleHttpServer.java
,内容如下。import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.linkvisual.model.v20180120.QueryLiveStreamingRequest; import com.aliyuncs.linkvisual.model.v20180120.QueryLiveStreamingResponse; import com.aliyuncs.profile.DefaultProfile; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.*; import com.aliyuncs.profile.IClientProfile; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; /** * SampleHttpServer */ public class SampleHttpServer { private static String LIVE_PATH = "/live/stream"; private static String RESPONSE_SUCCESS_CODE = "200"; private static IAcsClient client = null; private int port; public SampleHttpServer(int port) { this.port = port; } class HttpServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (msg instanceof HttpRequest) { QueryStringDecoder decoder = new QueryStringDecoder(((HttpRequest)msg).uri()); if (decoder.path().equals(LIVE_PATH)) { // 从HTTP请求中获取设备ID、实例ID、播放协议等参数。注:此处省略异常处理逻辑 String iotId = decoder.parameters().get("iotId").get(0); String scheme = decoder.parameters().get("scheme").get(0); String instanceId = decoder.parameters().get("instanceId").get(0); // 获取播放地址接口调用 QueryLiveStreamingRequest queryLiveStreamingRequest = new QueryLiveStreamingRequest(); queryLiveStreamingRequest.setIotId(iotId); queryLiveStreamingRequest.setIotInstanceId(instanceId); queryLiveStreamingRequest.setScheme(scheme); QueryLiveStreamingResponse queryLiveStreamingResponse = null; try { queryLiveStreamingResponse = client.getAcsResponse(queryLiveStreamingRequest); } catch (Exception e) { // 执行异常 } if (queryLiveStreamingResponse != null && queryLiveStreamingResponse.getCode().equals(RESPONSE_SUCCESS_CODE)) { // 返回播放地址 FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(queryLiveStreamingResponse.getData().getPath().getBytes())); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, queryLiveStreamingResponse.getData().getPath().length()); response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); ctx.write(response); } else { // 异常处理 } } else { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.EMPTY_BUFFER); ctx.write(response); } } } } class HttpServerInitializer extends ChannelInitializer<SocketChannel> { @Override public void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); p.addLast(new HttpServerCodec()); p.addLast(new HttpServerHandler()); } } public void start() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.option(ChannelOption.SO_BACKLOG, 1024); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new HttpServerInitializer()); try { Channel ch = b.bind(port).sync().channel(); ch.closeFuture().sync(); } catch (InterruptedException e) {} } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) { SampleHttpServer httpServer = new SampleHttpServer(8082); // 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。 // 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。 // 本示例以将AccessKey和AccessKeySecret保存在环境变量为例说明。 String accessKeyID = System.getenv("CC_AK_ENV"); String accessKeySecret = System.getenv("CC_SK_ENV"); //您的设备所属的地域ID,无需修改。 String regionId = "cn-shanghai"; //请求域名,无需修改。 String domain = "linkvisual.cn-shanghai.aliyuncs.com"; //产品Code,无需修改。 String productCode = "Linkvisual"; try { DefaultProfile.addEndpoint(regionId, regionId, productCode, domain); IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyID, accessKeySecret); client = new DefaultAcsClient(profile); } catch (Exception e) { } // 启动HTTP服务 httpServer.start(); } }
参数
说明
accessKeyID
登录物联网平台控制台,将鼠标指针移至账号头像上,然后单击AccessKey管理,获取AccessKey ID和AccessKey Secret。
说明如果使用RAM用户,您需授予该用户管理物联网平台的权限(AliyunIOTFullAccess)和管理物联网智能视频服务的权限(AliyunLinkVisualFullAccess),否则将连接失败。授权方法请参见授权RAM用户访问物联网平台。
accessKeySecret
运行程序文件
SampleHttpServer.java
,获取直播地址并启动HTTP Server。
步骤四:在Web端播放视频
开发Web端播放器后,根据已获取的直播播放地址,您可在Web端观看直播并控制Web端视频播放器。
支持的音频编码协议:AAC
支持的视频编码协议:H.264
支持的浏览器:Chrome、Firefox、Edge、Safari和UC浏览器
Web端直播播放器支持的播放协议:HTTP-FLV和HLS
创建HTML文件
web.html
,内容如下。<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>videojs-contrib-hls embed</title> <link href="//g.alicdn.com/code/lib/video.js/7.9.7/video-js.min.css" rel="stylesheet"> <script src="//g.alicdn.com/code/lib/video.js/7.9.7/video.min.js"></script> <script src="//g.alicdn.com/linkplatform/videojs-plugins/0.0.3?videojs-tech-flv.js,videojs-plugin-hls-compat.js"></script> </head> <body> <div class="container"> <div id="videoEl" class="video-js vjs-default-skin vjs-fluid"></div> </div> </body> <script> if (!videojs.getTech('flv')) { videojs.registerTech('flv', videojsTechFlv); } if (!videojs.getPlugin('hlsCompat')) { videojs.registerPlugin('hlsCompat', videojsPluginHlsCompat); } function getStreamUrl() { //请求播放地址,xx.xx.xx.xx为您的服务器地址,scheme为播放协议类型,iotId为设备ID,instanceId为实例ID return fetch('http://xx.xx.xx.xx:8082/live/stream?iotId=${Your_iotId}&scheme=${Your_scheme}&instanceId=${Your_instanceId}') .then(response => response.text()) .then(data => { console.log(data); return data; }); } function getSourceType(url) { let type = ''; if (/\.flv/.test(url)) { type = 'video/x-flv'; } else if (/\.m3u8/.test(url)) { type = 'application/x-mpegURL'; } else if(/\.mp4/.test(url)) { type = 'video/mp4'; } return type; } function createPlayer(cb) { var videoEl = document.getElementById('videoEl'); var player = videojs(videoEl, { autoplay: false, muted: true, controls: true, preload: 'none', loop: false, techOrder: ['flv', 'html5'], flv: { reconnInterval: 5000, reconnTimes: 10, getStreamUrl, mediaDataSource: { cors: true, withCredentials: true }, flvConfig: { lazyLoadMaxDuration: 24 * 60 * 60, }, }, html5: { hls: { cacheEncryptionKeys: true, }, }, }, cb); player.on('error', (e) => { console.error('videojs error: ', e); }); player.on('flvError', (e) => { console.error('flv error: ', e.errorInfo); }); var wrappedPlayer = { play: function(loadSource) { if (loadSource) { if (!player.paused()) { player.pause(); } player.reset(); player.removeClass('vjs-paused'); player.addClass('vjs-waiting'); return getStreamUrl().then((url) => { var source = { src: url, type: getSourceType(url) }; player.src(source); player.autoplay(true); player.load(); }); } return player.play(); }, pause: function() { return player.pause(); } } return wrappedPlayer; } if (!videojs.getTech('flv')) { videojs.registerTech('flv', videojsTechFlv); } if (!videojs.getPlugin('hlsCompat')) { videojs.registerPlugin('hlsCompat', videojsPluginHlsCompat); } const player = createPlayer(function () { player.play(true); }); </script>
执行以下命令,获取视频播放地址。
return fetch('http://xx.xx.xx.xx:8082/live/stream?iotId=${Your_iotId}&scheme=${Your_scheme}&instanceId=${Your_instanceId}')
参数
描述
xx.xx.xx.xx
您的服务器IP地址。
${Your_iotId}
用于直播的IPC设备的设备ID,即物联网平台为该设备颁发的ID,设备的唯一标识符。可调用物联网平台QueryDeviceDetail查询。
${Your_scheme}
直播播放协议:
flv:FLV播放协议。
hls:HLS播放协议。
${Your_instanceId}
实例ID。您可在物联网平台控制台的实例概览页面,查看当前实例的ID。实例的更多信息,请参见实例概述。
重要若有ID值,必须传入该ID值,否则调用会失败。若无ID值,则无需传入。
将
web.html
静态页面托管到Web服务器,查看播放效果。请您根据实际情况托管HTML页面,本地Web服务器可选用Apache或Nginx等服务器。在浏览器中观看直播视频。同时,可单击页面上的功能按钮,控制播放器。
- 本页导读 (1)