]> git.basschouten.com Git - openhab-addons.git/blob
e08c091e8dc339e0778a18983e7549066a31d9fa
[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  *
47  * @author Matthew Skinner - Initial contribution
48  */
49 @NonNullByDefault
50 public class RtspConnection {
51     private final Logger logger = LoggerFactory.getLogger(getClass());
52     private @Nullable Bootstrap rtspBootstrap;
53     private EventLoopGroup mainEventLoopGroup = new NioEventLoopGroup();
54     private IpCameraHandler ipCameraHandler;
55     String username, password;
56
57     public RtspConnection(IpCameraHandler ipCameraHandler, String username, String password) {
58         this.ipCameraHandler = ipCameraHandler;
59         this.username = username;
60         this.password = password;
61     }
62
63     public void connect() {
64         sendRtspRequest(getRTSPoptions());
65     }
66
67     public void processMessage(Object msg) {
68         logger.info("reply from RTSP is {}", msg);
69         if (msg.toString().contains("DESCRIBE")) {// getRTSPoptions
70             // Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, RECORD, PAUSE, TEARDOWN, SET_PARAMETER, GET_PARAMETER
71             sendRtspRequest(getRTSPdescribe());
72         } else if (msg.toString().contains("CSeq: 2")) {// getRTSPdescribe
73             // returns this:
74             // RTSP/1.0 200 OK
75             // CSeq: 2
76             // x-Accept-Dynamic-Rate: 1
77             // Content-Base:
78             // rtsp://192.168.xx.xx:554/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif/
79             // Cache-Control: must-revalidate
80             // Content-Length: 582
81             // Content-Type: application/sdp
82             sendRtspRequest(getRTSPsetup());
83         } else if (msg.toString().contains("CSeq: 3")) {
84             sendRtspRequest(getRTSPplay());
85         }
86     }
87
88     HttpRequest getRTSPoptions() {
89         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS,
90                 ipCameraHandler.rtspUri);
91         request.headers().add(RtspHeaderNames.CSEQ, "1");
92         return request;
93     }
94
95     HttpRequest getRTSPdescribe() {
96         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.DESCRIBE,
97                 ipCameraHandler.rtspUri);
98         request.headers().add(RtspHeaderNames.CSEQ, "2");
99         return request;
100     }
101
102     HttpRequest getRTSPsetup() {
103         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.SETUP, ipCameraHandler.rtspUri);
104         request.headers().add(RtspHeaderNames.CSEQ, "3");
105         request.headers().add(RtspHeaderNames.TRANSPORT, "RTP/AVP;unicast;client_port=5000-5001");
106         return request;
107     }
108
109     HttpRequest getRTSPplay() {
110         HttpRequest request = new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.PLAY, ipCameraHandler.rtspUri);
111         request.headers().add(RtspHeaderNames.CSEQ, "4");
112         // need session to match response from getRTSPsetup()
113         request.headers().add(RtspHeaderNames.SESSION, "12345678");
114         return request;
115     }
116
117     private RtspConnection getHandle() {
118         return this;
119     }
120
121     @SuppressWarnings("null")
122     public void sendRtspRequest(HttpRequest request) {
123         if (rtspBootstrap == null) {
124             rtspBootstrap = new Bootstrap();
125             rtspBootstrap.group(mainEventLoopGroup);
126             rtspBootstrap.channel(NioSocketChannel.class);
127             rtspBootstrap.option(ChannelOption.SO_KEEPALIVE, true);
128             rtspBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 4500);
129             rtspBootstrap.option(ChannelOption.SO_SNDBUF, 1024 * 8);
130             rtspBootstrap.option(ChannelOption.SO_RCVBUF, 1024 * 1024);
131             rtspBootstrap.option(ChannelOption.TCP_NODELAY, true);
132             rtspBootstrap.handler(new ChannelInitializer<SocketChannel>() {
133
134                 @Override
135                 public void initChannel(SocketChannel socketChannel) throws Exception {
136                     socketChannel.pipeline().addLast(new IdleStateHandler(18, 0, 0));
137                     socketChannel.pipeline().addLast(new RtspDecoder());
138                     socketChannel.pipeline().addLast(new RtspEncoder());
139                     // Need to update the authhandler to work for multiple use cases, before this works.
140                     // socketChannel.pipeline().addLast(new MyNettyAuthHandler(username, password, ipCameraHandler));
141                     socketChannel.pipeline().addLast(new NettyRtspHandler(getHandle()));
142                 }
143             });
144         }
145
146         rtspBootstrap.connect(new InetSocketAddress(ipCameraHandler.cameraConfig.getIp(), 554))
147                 .addListener(new ChannelFutureListener() {
148
149                     @Override
150                     public void operationComplete(@Nullable ChannelFuture future) {
151                         if (future == null) {
152                             return;
153                         }
154                         if (future.isDone() && future.isSuccess()) {
155                             Channel ch = future.channel();
156                             ch.writeAndFlush(request);
157                         } else { // an error occured
158                             logger.debug("Could not reach cameras rtsp on port 554.");
159                         }
160                     }
161                 });
162     }
163 }