]> git.basschouten.com Git - openhab-addons.git/blob
e21f50de4dc4912b24e7b2878b419b2c3c05bee2
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ipcamera.internal.rtsp;
14
15 import java.net.InetSocketAddress;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.ipcamera.internal.handler.IpCameraHandler;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import io.netty.bootstrap.Bootstrap;
24 import io.netty.channel.Channel;
25 import io.netty.channel.ChannelFuture;
26 import io.netty.channel.ChannelFutureListener;
27 import io.netty.channel.ChannelInitializer;
28 import io.netty.channel.ChannelOption;
29 import io.netty.channel.EventLoopGroup;
30 import io.netty.channel.nio.NioEventLoopGroup;
31 import io.netty.channel.socket.SocketChannel;
32 import io.netty.channel.socket.nio.NioSocketChannel;
33 import io.netty.handler.codec.http.DefaultHttpRequest;
34 import io.netty.handler.codec.http.HttpRequest;
35 import io.netty.handler.codec.rtsp.RtspDecoder;
36 import io.netty.handler.codec.rtsp.RtspEncoder;
37 import io.netty.handler.codec.rtsp.RtspHeaderNames;
38 import io.netty.handler.codec.rtsp.RtspMethods;
39 import io.netty.handler.codec.rtsp.RtspVersions;
40 import io.netty.handler.timeout.IdleStateHandler;
41
42 /**
43  * The {@link RtspConnection} is a WIP and not currently used, but will talk directly to RTSP and collect information
44  * about the camera and streams.
45  *
46  * @author Matthew Skinner - Initial contribution
47  */
48 @NonNullByDefault
49 public class RtspConnection {
50     private final Logger logger = LoggerFactory.getLogger(getClass());
51     private @Nullable Bootstrap rtspBootstrap;
52     private EventLoopGroup mainEventLoopGroup = new NioEventLoopGroup();
53     private IpCameraHandler ipCameraHandler;
54     String username, password;
55
56     public RtspConnection(IpCameraHandler ipCameraHandler, String username, String password) {
57         this.ipCameraHandler = ipCameraHandler;
58         this.username = username;
59         this.password = password;
60     }
61
62     public void connect() {
63         sendRtspRequest(getRTSPoptions());
64     }
65
66     public void processMessage(Object msg) {
67         logger.info("reply from RTSP is {}", msg);
68         if (msg.toString().contains("DESCRIBE")) {// getRTSPoptions
69             // Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, RECORD, PAUSE, TEARDOWN, SET_PARAMETER, GET_PARAMETER
70             sendRtspRequest(getRTSPdescribe());
71         } else if (msg.toString().contains("CSeq: 2")) {// getRTSPdescribe
72             // returns this:
73             // RTSP/1.0 200 OK
74             // CSeq: 2
75             // x-Accept-Dynamic-Rate: 1
76             // Content-Base:
77             // rtsp://192.168.xx.xx:554/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif/
78             // Cache-Control: must-revalidate
79             // Content-Length: 582
80             // Content-Type: application/sdp
81             sendRtspRequest(getRTSPsetup());
82         } else if (msg.toString().contains("CSeq: 3")) {
83             sendRtspRequest(getRTSPplay());
84         }
85     }
86
87     HttpRequest getRTSPoptions() {
88         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS,
89                 ipCameraHandler.rtspUri);
90         request.headers().add(RtspHeaderNames.CSEQ, "1");
91         return request;
92     }
93
94     HttpRequest getRTSPdescribe() {
95         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.DESCRIBE,
96                 ipCameraHandler.rtspUri);
97         request.headers().add(RtspHeaderNames.CSEQ, "2");
98         return request;
99     }
100
101     HttpRequest getRTSPsetup() {
102         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.SETUP, ipCameraHandler.rtspUri);
103         request.headers().add(RtspHeaderNames.CSEQ, "3");
104         request.headers().add(RtspHeaderNames.TRANSPORT, "RTP/AVP;unicast;client_port=5000-5001");
105         return request;
106     }
107
108     HttpRequest getRTSPplay() {
109         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.PLAY, ipCameraHandler.rtspUri);
110         request.headers().add(RtspHeaderNames.CSEQ, "4");
111         // need session to match response from getRTSPsetup()
112         request.headers().add(RtspHeaderNames.SESSION, "12345678");
113         return request;
114     }
115
116     private RtspConnection getHandle() {
117         return this;
118     }
119
120     @SuppressWarnings("null")
121     public void sendRtspRequest(HttpRequest request) {
122         if (rtspBootstrap == null) {
123             rtspBootstrap = new Bootstrap();
124             rtspBootstrap.group(mainEventLoopGroup);
125             rtspBootstrap.channel(NioSocketChannel.class);
126             rtspBootstrap.option(ChannelOption.SO_KEEPALIVE, true);
127             rtspBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 4500);
128             rtspBootstrap.option(ChannelOption.SO_SNDBUF, 1024 * 8);
129             rtspBootstrap.option(ChannelOption.SO_RCVBUF, 1024 * 1024);
130             rtspBootstrap.option(ChannelOption.TCP_NODELAY, true);
131             rtspBootstrap.handler(new ChannelInitializer<SocketChannel>() {
132
133                 @Override
134                 public void initChannel(SocketChannel socketChannel) throws Exception {
135                     socketChannel.pipeline().addLast(new IdleStateHandler(18, 0, 0));
136                     socketChannel.pipeline().addLast(new RtspDecoder());
137                     socketChannel.pipeline().addLast(new RtspEncoder());
138                     // Need to update the authhandler to work for multiple use cases, before this works.
139                     // socketChannel.pipeline().addLast(new MyNettyAuthHandler(username, password, ipCameraHandler));
140                     socketChannel.pipeline().addLast(new NettyRtspHandler(getHandle()));
141                 }
142             });
143         }
144
145         rtspBootstrap.connect(new InetSocketAddress(ipCameraHandler.cameraConfig.getIp(), 554))
146                 .addListener(new ChannelFutureListener() {
147
148                     @Override
149                     public void operationComplete(@Nullable ChannelFuture future) {
150                         if (future == null) {
151                             return;
152                         }
153                         if (future.isDone() && future.isSuccess()) {
154                             Channel ch = future.channel();
155                             ch.writeAndFlush(request);
156                         } else { // an error occured
157                             logger.debug("Could not reach cameras rtsp on port 554.");
158                         }
159                     }
160                 });
161     }
162 }