Commit 503f891c9e443551309a91b38493ac49413dbe35
1 parent
cf8a22f5
完成向上级联->点播--增加了sdp解析
修复修改平台主键带来的bug
Showing
21 changed files
with
976 additions
and
81 deletions
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -28,6 +28,8 @@ public class VideoManagerConstants { |
| 28 | 28 | |
| 29 | 29 | public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_"; |
| 30 | 30 | |
| 31 | + public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_"; | |
| 32 | + | |
| 31 | 33 | public static final String Pattern_Topic = "VMP_keeplive_platform_"; |
| 32 | 34 | |
| 33 | 35 | public static final String EVENT_ONLINE_REGISTER = "1"; | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
| ... | ... | @@ -45,11 +45,11 @@ public class SipPlatformRunner implements CommandLineRunner { |
| 45 | 45 | ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch(); |
| 46 | 46 | |
| 47 | 47 | parentPlatformCatch.setParentPlatform(parentPlatform); |
| 48 | - parentPlatformCatch.setId(parentPlatform.getDeviceGBId()); | |
| 48 | + parentPlatformCatch.setId(parentPlatform.getServerGBId()); | |
| 49 | 49 | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| 50 | 50 | |
| 51 | 51 | // 发送平台未注册消息 |
| 52 | - publisher.platformNotRegisterEventPublish(parentPlatform.getDeviceGBId()); | |
| 52 | + publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId()); | |
| 53 | 53 | } |
| 54 | 54 | } |
| 55 | 55 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java
| ... | ... | @@ -10,6 +10,8 @@ public class ParentPlatformCatch { |
| 10 | 10 | // 注册未回复次数 |
| 11 | 11 | private int registerAliveReply; |
| 12 | 12 | |
| 13 | + private String callId; | |
| 14 | + | |
| 13 | 15 | private ParentPlatform parentPlatform; |
| 14 | 16 | |
| 15 | 17 | public String getId() { |
| ... | ... | @@ -43,4 +45,12 @@ public class ParentPlatformCatch { |
| 43 | 45 | public void setParentPlatform(ParentPlatform parentPlatform) { |
| 44 | 46 | this.parentPlatform = parentPlatform; |
| 45 | 47 | } |
| 48 | + | |
| 49 | + public String getCallId() { | |
| 50 | + return callId; | |
| 51 | + } | |
| 52 | + | |
| 53 | + public void setCallId(String callId) { | |
| 54 | + this.callId = callId; | |
| 55 | + } | |
| 46 | 56 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/Codec.java
0 → 100755
| 1 | +/* | |
| 2 | + This file is part of Peers, a java SIP softphone. | |
| 3 | + | |
| 4 | + This program is free software: you can redistribute it and/or modify | |
| 5 | + it under the terms of the GNU General Public License as published by | |
| 6 | + the Free Software Foundation, either version 3 of the License, or | |
| 7 | + any later version. | |
| 8 | + | |
| 9 | + This program is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + GNU General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU General Public License | |
| 15 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | |
| 17 | + Copyright 2010 Yohann Martineau | |
| 18 | +*/ | |
| 19 | + | |
| 20 | +package com.genersoft.iot.vmp.gb28181.sdp; | |
| 21 | + | |
| 22 | +public class Codec { | |
| 23 | + | |
| 24 | + private int payloadType; | |
| 25 | + private String name; | |
| 26 | + | |
| 27 | + public int getPayloadType() { | |
| 28 | + return payloadType; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setPayloadType(int payloadType) { | |
| 32 | + this.payloadType = payloadType; | |
| 33 | + } | |
| 34 | + | |
| 35 | + public String getName() { | |
| 36 | + return name; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public void setName(String name) { | |
| 40 | + this.name = name; | |
| 41 | + } | |
| 42 | + | |
| 43 | + @Override | |
| 44 | + public boolean equals(Object obj) { | |
| 45 | + if (!(obj instanceof Codec)) { | |
| 46 | + return false; | |
| 47 | + } | |
| 48 | + Codec codec = (Codec)obj; | |
| 49 | + if (codec.getName() == null) { | |
| 50 | + return name == null; | |
| 51 | + } | |
| 52 | + return codec.getName().equalsIgnoreCase(name); | |
| 53 | + } | |
| 54 | + | |
| 55 | + @Override | |
| 56 | + public String toString() { | |
| 57 | + StringBuffer buf = new StringBuffer(); | |
| 58 | + buf.append(RFC4566_28181.TYPE_ATTRIBUTE).append(RFC4566_28181.SEPARATOR); | |
| 59 | + buf.append(RFC4566_28181.ATTR_RTPMAP).append(RFC4566_28181.ATTR_SEPARATOR); | |
| 60 | + buf.append(payloadType).append(" ").append(name).append("/"); | |
| 61 | + buf.append(9000).append("\r\n"); | |
| 62 | + return buf.toString(); | |
| 63 | + } | |
| 64 | + | |
| 65 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/MediaDescription.java
0 → 100755
| 1 | +/* | |
| 2 | + This file is part of Peers, a java SIP softphone. | |
| 3 | + | |
| 4 | + This program is free software: you can redistribute it and/or modify | |
| 5 | + it under the terms of the GNU General Public License as published by | |
| 6 | + the Free Software Foundation, either version 3 of the License, or | |
| 7 | + any later version. | |
| 8 | + | |
| 9 | + This program is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + GNU General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU General Public License | |
| 15 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | |
| 17 | + Copyright 2007, 2008, 2009, 2010 Yohann Martineau | |
| 18 | + */ | |
| 19 | + | |
| 20 | +package com.genersoft.iot.vmp.gb28181.sdp; | |
| 21 | + | |
| 22 | +import java.net.Inet4Address; | |
| 23 | +import java.net.Inet6Address; | |
| 24 | +import java.net.InetAddress; | |
| 25 | +import java.util.Hashtable; | |
| 26 | +import java.util.List; | |
| 27 | + | |
| 28 | +public class MediaDescription { | |
| 29 | + | |
| 30 | + private String type; | |
| 31 | + private InetAddress ipAddress; | |
| 32 | + // attributes not codec-related | |
| 33 | + private Hashtable<String, String> attributes; | |
| 34 | + private int port; | |
| 35 | + private List<Codec> codecs; | |
| 36 | + | |
| 37 | + public String getType() { | |
| 38 | + return type; | |
| 39 | + } | |
| 40 | + | |
| 41 | + public void setType(String type) { | |
| 42 | + this.type = type; | |
| 43 | + } | |
| 44 | + | |
| 45 | + public Hashtable<String, String> getAttributes() { | |
| 46 | + return attributes; | |
| 47 | + } | |
| 48 | + | |
| 49 | + public void setAttributes(Hashtable<String, String> attributes) { | |
| 50 | + this.attributes = attributes; | |
| 51 | + } | |
| 52 | + | |
| 53 | + public InetAddress getIpAddress() { | |
| 54 | + return ipAddress; | |
| 55 | + } | |
| 56 | + | |
| 57 | + public void setIpAddress(InetAddress ipAddress) { | |
| 58 | + this.ipAddress = ipAddress; | |
| 59 | + } | |
| 60 | + | |
| 61 | + public int getPort() { | |
| 62 | + return port; | |
| 63 | + } | |
| 64 | + | |
| 65 | + public void setPort(int port) { | |
| 66 | + this.port = port; | |
| 67 | + } | |
| 68 | + | |
| 69 | + public List<Codec> getCodecs() { | |
| 70 | + return codecs; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public void setCodecs(List<Codec> codecs) { | |
| 74 | + this.codecs = codecs; | |
| 75 | + } | |
| 76 | + | |
| 77 | + @Override | |
| 78 | + public String toString() { | |
| 79 | + StringBuffer buf = new StringBuffer(); | |
| 80 | + buf.append(RFC4566_28181.TYPE_MEDIA).append(RFC4566_28181.SEPARATOR); | |
| 81 | + buf.append(type).append(" ").append(port); | |
| 82 | + buf.append(" RTP/AVP"); | |
| 83 | + if (codecs != null) { | |
| 84 | + for (Codec codec: codecs) { | |
| 85 | + buf.append(" "); | |
| 86 | + buf.append(codec.getPayloadType()); | |
| 87 | + } | |
| 88 | + buf.append("\r\n"); | |
| 89 | + } | |
| 90 | + if (ipAddress != null) { | |
| 91 | + int ipVersion; | |
| 92 | + if (ipAddress instanceof Inet4Address) { | |
| 93 | + ipVersion = 4; | |
| 94 | + } else if (ipAddress instanceof Inet6Address) { | |
| 95 | + ipVersion = 6; | |
| 96 | + } else { | |
| 97 | + throw new RuntimeException("unknown ip version: " + ipAddress); | |
| 98 | + } | |
| 99 | + buf.append(RFC4566_28181.TYPE_CONNECTION).append(RFC4566_28181.SEPARATOR); | |
| 100 | + buf.append("IN IP").append(ipVersion).append(" "); | |
| 101 | + buf.append(ipAddress.getHostAddress()).append("\r\n"); | |
| 102 | + } | |
| 103 | + if (codecs != null) { | |
| 104 | + for (Codec codec: codecs) { | |
| 105 | + buf.append(codec.toString()); | |
| 106 | + } | |
| 107 | + } | |
| 108 | + | |
| 109 | + if (attributes != null) { | |
| 110 | + for (String attributeName: attributes.keySet()) { | |
| 111 | + buf.append(RFC4566_28181.TYPE_ATTRIBUTE).append(RFC4566_28181.SEPARATOR); | |
| 112 | + buf.append(attributeName); | |
| 113 | + String attributeValue = attributes.get(attributeName); | |
| 114 | + if (attributeValue != null && !"".equals(attributeValue.trim())) { | |
| 115 | + buf.append(":").append(attributeValue); | |
| 116 | + } | |
| 117 | + buf.append("\r\n"); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + return buf.toString(); | |
| 121 | + } | |
| 122 | + | |
| 123 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/RFC4566_28181.java
0 → 100755
| 1 | +/* | |
| 2 | + This file is part of Peers, a java SIP softphone. | |
| 3 | + | |
| 4 | + This program is free software: you can redistribute it and/or modify | |
| 5 | + it under the terms of the GNU General Public License as published by | |
| 6 | + the Free Software Foundation, either version 3 of the License, or | |
| 7 | + any later version. | |
| 8 | + | |
| 9 | + This program is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + GNU General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU General Public License | |
| 15 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | |
| 17 | + Copyright 2007, 2008, 2009, 2010 Yohann Martineau | |
| 18 | +*/ | |
| 19 | + | |
| 20 | +package com.genersoft.iot.vmp.gb28181.sdp; | |
| 21 | + | |
| 22 | +public class RFC4566_28181 { | |
| 23 | + | |
| 24 | + public static final char VERSION = '0'; | |
| 25 | + | |
| 26 | + public static final char TYPE_VERSION = 'v'; | |
| 27 | + public static final char TYPE_ORIGIN = 'o'; | |
| 28 | + public static final char TYPE_SUBJECT = 's'; | |
| 29 | + public static final char TYPE_INFO = 'i'; | |
| 30 | + public static final char TYPE_URI = 'u'; | |
| 31 | + public static final char TYPE_EMAIL = 'e'; | |
| 32 | + public static final char TYPE_PHONE = 'p'; | |
| 33 | + public static final char TYPE_CONNECTION = 'c'; | |
| 34 | + public static final char TYPE_BANDWITH = 'b'; | |
| 35 | + public static final char TYPE_TIME = 't'; | |
| 36 | + public static final char TYPE_REPEAT = 'r'; | |
| 37 | + public static final char TYPE_ZONE = 'z'; | |
| 38 | + public static final char TYPE_KEY = 'k'; | |
| 39 | + public static final char TYPE_ATTRIBUTE = 'a'; | |
| 40 | + public static final char TYPE_MEDIA = 'm'; | |
| 41 | + public static final char TYPE_SSRC = 'y'; | |
| 42 | + public static final char TYPE_MEDIA_DES = 'f'; | |
| 43 | + | |
| 44 | + public static final char SEPARATOR = '='; | |
| 45 | + public static final char ATTR_SEPARATOR = ':'; | |
| 46 | + | |
| 47 | + public static final String MEDIA_AUDIO = "audio"; | |
| 48 | + | |
| 49 | + public static final String ATTR_RTPMAP = "rtpmap"; | |
| 50 | + public static final String ATTR_SENDRECV = "sendrecv"; | |
| 51 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SdpLine.java
0 → 100755
| 1 | +/* | |
| 2 | + This file is part of Peers, a java SIP softphone. | |
| 3 | + | |
| 4 | + This program is free software: you can redistribute it and/or modify | |
| 5 | + it under the terms of the GNU General Public License as published by | |
| 6 | + the Free Software Foundation, either version 3 of the License, or | |
| 7 | + any later version. | |
| 8 | + | |
| 9 | + This program is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + GNU General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU General Public License | |
| 15 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | |
| 17 | + Copyright 2007, 2008, 2009, 2010 Yohann Martineau | |
| 18 | +*/ | |
| 19 | + | |
| 20 | +package com.genersoft.iot.vmp.gb28181.sdp; | |
| 21 | + | |
| 22 | +public class SdpLine { | |
| 23 | + private char type; | |
| 24 | + private String value; | |
| 25 | + public char getType() { | |
| 26 | + return type; | |
| 27 | + } | |
| 28 | + public void setType(char type) { | |
| 29 | + this.type = type; | |
| 30 | + } | |
| 31 | + public String getValue() { | |
| 32 | + return value; | |
| 33 | + } | |
| 34 | + public void setValue(String value) { | |
| 35 | + this.value = value; | |
| 36 | + } | |
| 37 | + | |
| 38 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SdpParser.java
0 → 100755
| 1 | +/* | |
| 2 | + This file is part of Peers, a java SIP softphone. | |
| 3 | + | |
| 4 | + This program is free software: you can redistribute it and/or modify | |
| 5 | + it under the terms of the GNU General Public License as published by | |
| 6 | + the Free Software Foundation, either version 3 of the License, or | |
| 7 | + any later version. | |
| 8 | + | |
| 9 | + This program is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + GNU General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU General Public License | |
| 15 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | |
| 17 | + Copyright 2007, 2008, 2009, 2010 Yohann Martineau | |
| 18 | +*/ | |
| 19 | + | |
| 20 | +package com.genersoft.iot.vmp.gb28181.sdp; | |
| 21 | + | |
| 22 | +import java.io.BufferedReader; | |
| 23 | +import java.io.ByteArrayInputStream; | |
| 24 | +import java.io.IOException; | |
| 25 | +import java.io.InputStreamReader; | |
| 26 | +import java.net.InetAddress; | |
| 27 | +import java.util.ArrayList; | |
| 28 | +import java.util.Hashtable; | |
| 29 | +import java.util.List; | |
| 30 | + | |
| 31 | +public class SdpParser { | |
| 32 | + | |
| 33 | + public SessionDescription parse(byte[] body) throws IOException { | |
| 34 | + if (body == null || body.length == 0) { | |
| 35 | + return null; | |
| 36 | + } | |
| 37 | + ByteArrayInputStream in = new ByteArrayInputStream(body); | |
| 38 | + InputStreamReader inputStreamReader = new InputStreamReader(in); | |
| 39 | + BufferedReader reader = new BufferedReader(inputStreamReader); | |
| 40 | + SessionDescription sessionDescription = new SessionDescription(); | |
| 41 | + | |
| 42 | + //version | |
| 43 | + | |
| 44 | + String line = reader.readLine(); | |
| 45 | + if (line.length() < 3) { | |
| 46 | + return null; | |
| 47 | + } | |
| 48 | + if (line.charAt(0) != RFC4566_28181.TYPE_VERSION | |
| 49 | + || line.charAt(1) != RFC4566_28181.SEPARATOR | |
| 50 | + || line.charAt(2) != RFC4566_28181.VERSION) { | |
| 51 | + return null; | |
| 52 | + } | |
| 53 | + | |
| 54 | + //origin | |
| 55 | + | |
| 56 | + line = reader.readLine(); | |
| 57 | + if (line.length() < 3) { | |
| 58 | + return null; | |
| 59 | + } | |
| 60 | + if (line.charAt(0) != RFC4566_28181.TYPE_ORIGIN | |
| 61 | + || line.charAt(1) != RFC4566_28181.SEPARATOR) { | |
| 62 | + return null; | |
| 63 | + } | |
| 64 | + line = line.substring(2); | |
| 65 | + String[] originArr = line.split(" "); | |
| 66 | + if (originArr == null || originArr.length != 6) { | |
| 67 | + return null; | |
| 68 | + } | |
| 69 | + sessionDescription.setUsername(originArr[0]); | |
| 70 | + sessionDescription.setId(Long.parseLong(originArr[1])); | |
| 71 | + sessionDescription.setVersion(Long.parseLong(originArr[2])); | |
| 72 | + sessionDescription.setIpAddress(InetAddress.getByName(originArr[5])); | |
| 73 | + | |
| 74 | + //name | |
| 75 | + | |
| 76 | + line = reader.readLine(); | |
| 77 | + if (line.length() < 3) { | |
| 78 | + return null; | |
| 79 | + } | |
| 80 | + if (line.charAt(0) != RFC4566_28181.TYPE_SUBJECT | |
| 81 | + || line.charAt(1) != RFC4566_28181.SEPARATOR) { | |
| 82 | + return null; | |
| 83 | + } | |
| 84 | + sessionDescription.setName(line.substring(2)); | |
| 85 | + | |
| 86 | + //session connection and attributes | |
| 87 | + Hashtable<String, String> sessionAttributes = new Hashtable<String, String>(); | |
| 88 | + sessionDescription.setAttributes(sessionAttributes); | |
| 89 | + | |
| 90 | + while ((line = reader.readLine()) != null | |
| 91 | + && line.charAt(0) != RFC4566_28181.TYPE_MEDIA) { | |
| 92 | + if (line.length() > 3 | |
| 93 | + && line.charAt(0) == RFC4566_28181.TYPE_CONNECTION | |
| 94 | + && line.charAt(1) == RFC4566_28181.SEPARATOR) { | |
| 95 | + String connection = parseConnection(line.substring(2)); | |
| 96 | + if (connection == null) { | |
| 97 | + continue; | |
| 98 | + } | |
| 99 | + sessionDescription.setIpAddress(InetAddress.getByName(connection)); | |
| 100 | + } else if (line.length() > 3 | |
| 101 | + && line.charAt(0) == RFC4566_28181.TYPE_ATTRIBUTE | |
| 102 | + && line.charAt(1) == RFC4566_28181.SEPARATOR) { | |
| 103 | + String value = line.substring(2); | |
| 104 | + int pos = value.indexOf(RFC4566_28181.ATTR_SEPARATOR); | |
| 105 | + if (pos > -1) { | |
| 106 | + sessionAttributes.put(value.substring(0, pos), | |
| 107 | + value.substring(pos + 1)); | |
| 108 | + } else { | |
| 109 | + sessionAttributes.put(value, ""); | |
| 110 | + } | |
| 111 | + } | |
| 112 | + } | |
| 113 | + if (line == null) { | |
| 114 | + return null; | |
| 115 | + } | |
| 116 | + //we are at the first media line | |
| 117 | + | |
| 118 | + ArrayList<SdpLine> mediaLines = new ArrayList<SdpLine>(); | |
| 119 | + do { | |
| 120 | + if (line.length() < 2) { | |
| 121 | + return null; | |
| 122 | + } | |
| 123 | + if (line.charAt(1) != RFC4566_28181.SEPARATOR) { | |
| 124 | + return null; | |
| 125 | + } | |
| 126 | + if (line.charAt(0) == RFC4566_28181.TYPE_SSRC) { | |
| 127 | + sessionDescription.setSsrc(line.length() >=2 ?line.substring(2):""); | |
| 128 | + }else if (line.charAt(0) == RFC4566_28181.TYPE_MEDIA_DES) { | |
| 129 | + sessionDescription.setGbMediaDescriptions(line.length() >=2 ?line.substring(2):""); | |
| 130 | + }else { | |
| 131 | + SdpLine mediaLine = new SdpLine(); | |
| 132 | + mediaLine.setType(line.charAt(0)); | |
| 133 | + mediaLine.setValue(line.substring(2)); | |
| 134 | + mediaLines.add(mediaLine); | |
| 135 | + } | |
| 136 | + | |
| 137 | + } | |
| 138 | + while ((line = reader.readLine()) != null ); | |
| 139 | + | |
| 140 | + ArrayList<MediaDescription> mediaDescriptions = new ArrayList<MediaDescription>(); | |
| 141 | + sessionDescription.setMediaDescriptions(mediaDescriptions); | |
| 142 | + | |
| 143 | + for (SdpLine sdpLine : mediaLines) { | |
| 144 | + MediaDescription mediaDescription; | |
| 145 | + if (sdpLine.getType() == RFC4566_28181.TYPE_MEDIA) { | |
| 146 | + String[] mediaArr = sdpLine.getValue().split(" "); | |
| 147 | + if (mediaArr == null || mediaArr.length < 4) { | |
| 148 | + return null; | |
| 149 | + } | |
| 150 | + mediaDescription = new MediaDescription(); | |
| 151 | + mediaDescription.setType(mediaArr[0]); | |
| 152 | + //TODO manage port range | |
| 153 | + mediaDescription.setPort(Integer.parseInt(mediaArr[1])); | |
| 154 | + mediaDescription.setAttributes(new Hashtable<String, String>()); | |
| 155 | + List<Codec> codecs = new ArrayList<Codec>(); | |
| 156 | + for (int i = 3; i < mediaArr.length; ++i) { | |
| 157 | + int payloadType = Integer.parseInt(mediaArr[i]); | |
| 158 | + Codec codec = new Codec(); | |
| 159 | + codec.setPayloadType(payloadType); | |
| 160 | + codec.setName("unsupported"); | |
| 161 | + codecs.add(codec); | |
| 162 | + } | |
| 163 | + mediaDescription.setCodecs(codecs); | |
| 164 | + mediaDescriptions.add(mediaDescription); | |
| 165 | + } else { | |
| 166 | + mediaDescription = mediaDescriptions.get(mediaDescriptions.size() - 1); | |
| 167 | + String sdpLineValue = sdpLine.getValue(); | |
| 168 | + if (sdpLine.getType() == RFC4566_28181.TYPE_CONNECTION) { | |
| 169 | + String ipAddress = parseConnection(sdpLineValue); | |
| 170 | + mediaDescription.setIpAddress(InetAddress.getByName(ipAddress)); | |
| 171 | + } else if (sdpLine.getType() == RFC4566_28181.TYPE_ATTRIBUTE) { | |
| 172 | + Hashtable<String, String> attributes = mediaDescription.getAttributes(); | |
| 173 | + int pos = sdpLineValue.indexOf(RFC4566_28181.ATTR_SEPARATOR); | |
| 174 | + if (pos > -1) { | |
| 175 | + String name = sdpLineValue.substring(0, pos); | |
| 176 | + String value = sdpLineValue.substring(pos + 1); | |
| 177 | + pos = value.indexOf(" "); | |
| 178 | + if (pos > -1) { | |
| 179 | + int payloadType; | |
| 180 | + try { | |
| 181 | + payloadType = Integer.parseInt(value.substring(0, pos)); | |
| 182 | + List<Codec> codecs = mediaDescription.getCodecs(); | |
| 183 | + for (Codec codec: codecs) { | |
| 184 | + if (codec.getPayloadType() == payloadType) { | |
| 185 | + value = value.substring(pos + 1); | |
| 186 | + pos = value.indexOf("/"); | |
| 187 | + if (pos > -1) { | |
| 188 | + value = value.substring(0, pos); | |
| 189 | + codec.setName(value); | |
| 190 | + } | |
| 191 | + break; | |
| 192 | + } | |
| 193 | + } | |
| 194 | + } catch (NumberFormatException e) { | |
| 195 | + attributes.put(name, value); | |
| 196 | + } | |
| 197 | + } else { | |
| 198 | + attributes.put(name, value); | |
| 199 | + } | |
| 200 | + } else { | |
| 201 | + attributes.put(sdpLineValue, ""); | |
| 202 | + } | |
| 203 | + } | |
| 204 | + } | |
| 205 | + } | |
| 206 | + sessionDescription.setMediaDescriptions(mediaDescriptions); | |
| 207 | + | |
| 208 | + for (MediaDescription description : mediaDescriptions) { | |
| 209 | + if (description.getIpAddress() == null) { | |
| 210 | + InetAddress sessionAddress = sessionDescription.getIpAddress(); | |
| 211 | + if (sessionAddress == null) { | |
| 212 | + return null; | |
| 213 | + } | |
| 214 | + description.setIpAddress(sessionAddress); | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + | |
| 219 | + return sessionDescription; | |
| 220 | + } | |
| 221 | + | |
| 222 | + private String parseConnection(String line) { | |
| 223 | + String[] connectionArr = line.split(" "); | |
| 224 | + if (connectionArr == null || connectionArr.length != 3) { | |
| 225 | + return null; | |
| 226 | + } | |
| 227 | + return connectionArr[2]; | |
| 228 | + } | |
| 229 | + | |
| 230 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SessionDescription.java
0 → 100755
| 1 | +/* | |
| 2 | + This file is part of Peers, a java SIP softphone. | |
| 3 | + | |
| 4 | + This program is free software: you can redistribute it and/or modify | |
| 5 | + it under the terms of the GNU General Public License as published by | |
| 6 | + the Free Software Foundation, either version 3 of the License, or | |
| 7 | + any later version. | |
| 8 | + | |
| 9 | + This program is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + GNU General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU General Public License | |
| 15 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | |
| 17 | + Copyright 2007, 2008, 2009, 2010 Yohann Martineau | |
| 18 | +*/ | |
| 19 | + | |
| 20 | +package com.genersoft.iot.vmp.gb28181.sdp; | |
| 21 | + | |
| 22 | +import java.net.Inet4Address; | |
| 23 | +import java.net.Inet6Address; | |
| 24 | +import java.net.InetAddress; | |
| 25 | +import java.util.Hashtable; | |
| 26 | +import java.util.List; | |
| 27 | + | |
| 28 | +public class SessionDescription { | |
| 29 | + | |
| 30 | + private long id; | |
| 31 | + private long version; | |
| 32 | + private String name; | |
| 33 | + private String username; | |
| 34 | + private InetAddress ipAddress; | |
| 35 | + private List<MediaDescription> mediaDescriptions; | |
| 36 | + private Hashtable<String, String> attributes; | |
| 37 | + private String ssrc; | |
| 38 | + private String gbMediaDescriptions; | |
| 39 | + | |
| 40 | + public SessionDescription() { | |
| 41 | + } | |
| 42 | + | |
| 43 | + public long getId() { | |
| 44 | + return id; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public void setId(long id) { | |
| 48 | + this.id = id; | |
| 49 | + } | |
| 50 | + | |
| 51 | + public InetAddress getIpAddress() { | |
| 52 | + return ipAddress; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public void setIpAddress(InetAddress ipAddress) { | |
| 56 | + this.ipAddress = ipAddress; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public List<MediaDescription> getMediaDescriptions() { | |
| 60 | + return mediaDescriptions; | |
| 61 | + } | |
| 62 | + | |
| 63 | + public void setMediaDescriptions(List<MediaDescription> mediaDescriptions) { | |
| 64 | + this.mediaDescriptions = mediaDescriptions; | |
| 65 | + } | |
| 66 | + | |
| 67 | + public String getName() { | |
| 68 | + return name; | |
| 69 | + } | |
| 70 | + | |
| 71 | + public void setName(String name) { | |
| 72 | + this.name = name; | |
| 73 | + } | |
| 74 | + | |
| 75 | + public String getUsername() { | |
| 76 | + return username; | |
| 77 | + } | |
| 78 | + | |
| 79 | + public void setUsername(String username) { | |
| 80 | + this.username = username; | |
| 81 | + } | |
| 82 | + | |
| 83 | + public long getVersion() { | |
| 84 | + return version; | |
| 85 | + } | |
| 86 | + | |
| 87 | + public void setVersion(long version) { | |
| 88 | + this.version = version; | |
| 89 | + } | |
| 90 | + | |
| 91 | + public Hashtable<String, String> getAttributes() { | |
| 92 | + return attributes; | |
| 93 | + } | |
| 94 | + | |
| 95 | + public void setAttributes(Hashtable<String, String> attributes) { | |
| 96 | + this.attributes = attributes; | |
| 97 | + } | |
| 98 | + | |
| 99 | + public String getSsrc() { | |
| 100 | + return ssrc; | |
| 101 | + } | |
| 102 | + | |
| 103 | + public void setSsrc(String ssrc) { | |
| 104 | + this.ssrc = ssrc; | |
| 105 | + } | |
| 106 | + | |
| 107 | + public String getGbMediaDescriptions() { | |
| 108 | + return gbMediaDescriptions; | |
| 109 | + } | |
| 110 | + | |
| 111 | + public void setGbMediaDescriptions(String gbMediaDescriptions) { | |
| 112 | + this.gbMediaDescriptions = gbMediaDescriptions; | |
| 113 | + } | |
| 114 | + | |
| 115 | + @Override | |
| 116 | + public String toString() { | |
| 117 | + StringBuilder buf = new StringBuilder(); | |
| 118 | + buf.append("v=0\r\n"); | |
| 119 | + buf.append("o=").append(username).append(" ").append(id); | |
| 120 | + buf.append(" ").append(version); | |
| 121 | + int ipVersion; | |
| 122 | + if (ipAddress instanceof Inet4Address) { | |
| 123 | + ipVersion = 4; | |
| 124 | + } else if (ipAddress instanceof Inet6Address) { | |
| 125 | + ipVersion = 6; | |
| 126 | + } else { | |
| 127 | + throw new RuntimeException("unknown ip version: " + ipAddress); | |
| 128 | + } | |
| 129 | + buf.append(" IN IP").append(ipVersion).append(" "); | |
| 130 | + String hostAddress = ipAddress.getHostAddress(); | |
| 131 | + buf.append(hostAddress).append("\r\n"); | |
| 132 | + buf.append("s=").append(name).append("\r\n"); | |
| 133 | + buf.append("c=IN IP").append(ipVersion).append(" "); | |
| 134 | + buf.append(hostAddress).append("\r\n"); | |
| 135 | + buf.append("t=0 0\r\n"); | |
| 136 | + if (attributes != null){ | |
| 137 | + for (String attributeName: attributes.keySet()) { | |
| 138 | + String attributeValue = attributes.get(attributeName); | |
| 139 | + buf.append("a=").append(attributeName); | |
| 140 | + if (attributeValue != null && !"".equals(attributeValue.trim())) { | |
| 141 | + buf.append(":"); | |
| 142 | + buf.append(attributeValue); | |
| 143 | + buf.append("\r\n"); | |
| 144 | + } | |
| 145 | + } | |
| 146 | + } | |
| 147 | + if (mediaDescriptions != null){ | |
| 148 | + for (MediaDescription mediaDescription: mediaDescriptions) { | |
| 149 | + buf.append(mediaDescription.toString()); | |
| 150 | + } | |
| 151 | + } | |
| 152 | + | |
| 153 | + if (ssrc != null){ | |
| 154 | + buf.append("y=").append(ssrc).append("\r\n"); | |
| 155 | + } | |
| 156 | + if (gbMediaDescriptions != null){ | |
| 157 | + buf.append("f=").append(gbMediaDescriptions).append("\r\n"); | |
| 158 | + } | |
| 159 | + return buf.toString(); | |
| 160 | + } | |
| 161 | + | |
| 162 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
| ... | ... | @@ -119,6 +119,9 @@ public class SIPProcessorFactory { |
| 119 | 119 | processor.setRequestEvent(evt); |
| 120 | 120 | processor.setTcpSipProvider(getTcpSipProvider()); |
| 121 | 121 | processor.setUdpSipProvider(getUdpSipProvider()); |
| 122 | + | |
| 123 | + processor.setCmderFroPlatform(cmderFroPlatform); | |
| 124 | + processor.setStorager(storager); | |
| 122 | 125 | return processor; |
| 123 | 126 | } else if (Request.REGISTER.equals(method)) { |
| 124 | 127 | RegisterRequestProcessor processor = new RegisterRequestProcessor(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -70,7 +70,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 70 | 70 | @Override |
| 71 | 71 | public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { |
| 72 | 72 | parentPlatform.setExpires("0"); |
| 73 | - ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getDeviceGBId()); | |
| 73 | + ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); | |
| 74 | 74 | if (parentPlatformCatch != null) { |
| 75 | 75 | parentPlatformCatch.setParentPlatform(parentPlatform); |
| 76 | 76 | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| ... | ... | @@ -86,11 +86,21 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 86 | 86 | |
| 87 | 87 | if (www == null ) { |
| 88 | 88 | request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, 1L, null, null); |
| 89 | + // 将 callid 写入缓存, 等注册成功可以更新状态 | |
| 90 | + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); | |
| 91 | + redisCatchStorage.updatePlatformRegisterInfo(callIdHeader.getCallId(), parentPlatform.getServerGBId()); | |
| 92 | + | |
| 93 | + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{ | |
| 94 | + redisCatchStorage.delPlatformRegisterInfo(callIdHeader.getCallId()); | |
| 95 | + if (errorEvent != null) { | |
| 96 | + errorEvent.response(event); | |
| 97 | + } | |
| 98 | + }); | |
| 89 | 99 | }else { |
| 90 | 100 | request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, null, null, callId, www); |
| 91 | 101 | } |
| 92 | 102 | |
| 93 | - transmitRequest(parentPlatform, request, errorEvent, okEvent); | |
| 103 | + transmitRequest(parentPlatform, request, null, okEvent); | |
| 94 | 104 | return true; |
| 95 | 105 | } catch (ParseException e) { |
| 96 | 106 | e.printStackTrace(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.request.impl; |
| 2 | 2 | |
| 3 | +import javax.sip.InvalidArgumentException; | |
| 3 | 4 | import javax.sip.RequestEvent; |
| 5 | +import javax.sip.SipException; | |
| 6 | +import javax.sip.address.SipURI; | |
| 7 | +import javax.sip.header.ContentTypeHeader; | |
| 8 | +import javax.sip.header.FromHeader; | |
| 9 | +import javax.sip.header.SubjectHeader; | |
| 10 | +import javax.sip.message.Request; | |
| 11 | +import javax.sip.message.Response; | |
| 4 | 12 | |
| 13 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 14 | +import com.genersoft.iot.vmp.gb28181.sdp.Codec; | |
| 15 | +import com.genersoft.iot.vmp.gb28181.sdp.MediaDescription; | |
| 16 | +import com.genersoft.iot.vmp.gb28181.sdp.SdpParser; | |
| 17 | +import com.genersoft.iot.vmp.gb28181.sdp.SessionDescription; | |
| 18 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | |
| 19 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | |
| 5 | 20 | import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; |
| 21 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | |
| 22 | +import gov.nist.javax.sip.address.AddressImpl; | |
| 23 | +import gov.nist.javax.sip.address.SipUri; | |
| 24 | +import org.slf4j.Logger; | |
| 25 | +import org.slf4j.LoggerFactory; | |
| 26 | + | |
| 27 | +import java.io.IOException; | |
| 28 | +import java.text.ParseException; | |
| 29 | +import java.util.List; | |
| 6 | 30 | |
| 7 | 31 | /** |
| 8 | 32 | * @Description:处理INVITE请求 |
| 9 | - * @author: swwheihei | |
| 10 | - * @date: 2020年5月3日 下午4:43:52 | |
| 33 | + * @author: panll | |
| 34 | + * @date: 2021年1月14日 | |
| 11 | 35 | */ |
| 12 | 36 | public class InviteRequestProcessor extends SIPRequestAbstractProcessor { |
| 13 | 37 | |
| 38 | + private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); | |
| 39 | + | |
| 40 | + private SIPCommanderFroPlatform cmderFroPlatform; | |
| 41 | + | |
| 42 | + private IVideoManagerStorager storager; | |
| 43 | + | |
| 14 | 44 | /** |
| 15 | 45 | * 处理invite请求 |
| 16 | 46 | * |
| 17 | - * @param request | |
| 47 | + * @param evt | |
| 18 | 48 | * 请求消息 |
| 19 | 49 | */ |
| 20 | 50 | @Override |
| 21 | 51 | public void process(RequestEvent evt) { |
| 22 | - // TODO 优先级99 Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 | |
| 23 | -// Request request = requestEvent.getRequest(); | |
| 24 | -// | |
| 25 | -// try { | |
| 26 | -// // 发送100 Trying | |
| 27 | -// ServerTransaction serverTransaction = getServerTransaction(requestEvent); | |
| 28 | -// // 查询目标地址 | |
| 29 | -// URI reqUri = request.getRequestURI(); | |
| 30 | -// URI contactURI = currUser.get(reqUri); | |
| 31 | -// | |
| 32 | -// System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI); | |
| 33 | -// | |
| 34 | -// // 根据Request uri来路由,后续的响应消息通过VIA来路由 | |
| 35 | -// Request cliReq = messageFactory.createRequest(request.toString()); | |
| 36 | -// cliReq.setRequestURI(contactURI); | |
| 37 | -// | |
| 38 | -// HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory(); | |
| 39 | -// Via callerVia = (Via) request.getHeader(Via.NAME); | |
| 40 | -// Via via = (Via) headerFactory.createViaHeader(SIPMain.ip, SIPMain.port, "UDP", | |
| 41 | -// callerVia.getBranch() + "sipphone"); | |
| 42 | -// | |
| 43 | -// cliReq.removeHeader(Via.NAME); | |
| 44 | -// cliReq.addHeader(via); | |
| 45 | -// | |
| 46 | -// // 更新contact的地址 | |
| 47 | -// ContactHeader contactHeader = headerFactory.createContactHeader(); | |
| 48 | -// Address address = SipFactory.getInstance().createAddressFactory() | |
| 49 | -// .createAddress("sip:sipsoft@" + SIPMain.ip + ":" + SIPMain.port); | |
| 50 | -// contactHeader.setAddress(address); | |
| 51 | -// contactHeader.setExpires(3600); | |
| 52 | -// cliReq.setHeader(contactHeader); | |
| 53 | -// | |
| 54 | -// clientTransactionId = sipProvider.getNewClientTransaction(cliReq); | |
| 55 | -// clientTransactionId.sendRequest(); | |
| 56 | -// | |
| 57 | -// System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString()); | |
| 58 | -// | |
| 59 | -// System.out.println("send invite to callee: " + cliReq); | |
| 60 | -// } catch (TransactionUnavailableException e1) { | |
| 61 | -// e1.printStackTrace(); | |
| 62 | -// } catch (SipException e) { | |
| 63 | -// e.printStackTrace(); | |
| 64 | -// } catch (ParseException e) { | |
| 65 | -// e.printStackTrace(); | |
| 66 | -// } catch (Exception e) { | |
| 67 | -// e.printStackTrace(); | |
| 68 | -// } | |
| 52 | + // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 | |
| 53 | + try { | |
| 54 | + Request request = evt.getRequest(); | |
| 55 | + SipURI sipURI = (SipURI) request.getRequestURI(); | |
| 56 | + String channelId = sipURI.getUser(); | |
| 57 | + String platformId = null; | |
| 58 | +// SubjectHeader subjectHeader = (SubjectHeader)request.getHeader(SubjectHeader.NAME); | |
| 59 | +// // 查询通道是否存在 不存在回复404 | |
| 60 | +// if (subjectHeader != null) { // 存在则从subjectHeader 获取平台信息 | |
| 61 | +// String subject = subjectHeader.getSubject(); | |
| 62 | +// if (subject != null) { | |
| 63 | +// String[] info1 = subject.split(","); | |
| 64 | +// if (info1 != null && info1 .length == 2) { | |
| 65 | +// String[] info2 = info1[1].split(":"); | |
| 66 | +// if (info2 != null && info2.length == 2) { | |
| 67 | +// platformId = info2[0]; | |
| 68 | +// } | |
| 69 | +// } | |
| 70 | +// } | |
| 71 | +// } | |
| 72 | + | |
| 73 | + FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); | |
| 74 | + AddressImpl address = (AddressImpl) fromHeader.getAddress(); | |
| 75 | + SipUri uri = (SipUri) address.getURI(); | |
| 76 | + platformId = uri.getUser(); | |
| 77 | + | |
| 78 | +// if (platformId == null) { // 不存在则从fromHeader 获取平台信息 | |
| 79 | +// FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); | |
| 80 | +// platformId = fromHeader.getName(); | |
| 81 | +// } | |
| 82 | + if (platformId == null || channelId == null) { | |
| 83 | + response400Ack(evt); // 参数不全, 发400,请求错误 | |
| 84 | + return; | |
| 85 | + } | |
| 86 | + // 查询平台下是否有该通道 | |
| 87 | + DeviceChannel channel = storager.queryChannelInParentPlatform(platformId, channelId); | |
| 88 | + if (channel == null) { | |
| 89 | + response404Ack(evt); // 通道不存在,发404,资源不存在 | |
| 90 | + return; | |
| 91 | + }else { | |
| 92 | + response100Ack(evt); // 通道存在,发100,trying | |
| 93 | + } | |
| 94 | + // 解析sdp消息 | |
| 95 | + byte[] sdpByteArray = request.getRawContent(); | |
| 96 | + SdpParser sdpParser = new SdpParser(); // TODO keng | |
| 97 | + SessionDescription sdp = sdpParser.parse(sdpByteArray); | |
| 98 | + // 获取支持的格式 | |
| 99 | + List<MediaDescription> mediaDescriptions = sdp.getMediaDescriptions(); | |
| 100 | + // 查看是否支持PS 负载96 | |
| 101 | + String ip = null; | |
| 102 | + int port = -1; | |
| 103 | + for (MediaDescription mediaDescription : mediaDescriptions) { | |
| 104 | + | |
| 105 | + List<Codec> codecs = mediaDescription.getCodecs(); | |
| 106 | + for (Codec codec : codecs) { | |
| 107 | + if("96".equals(codec.getPayloadType()) || "PS".equals(codec.getName()) || "ps".equals(codec.getName())) { | |
| 108 | + ip = mediaDescription.getIpAddress().getHostName(); | |
| 109 | + port = mediaDescription.getPort(); | |
| 110 | + break; | |
| 111 | + } | |
| 112 | + } | |
| 113 | + } | |
| 114 | + if (ip == null || port == -1) { // TODO 没有合适的视频流格式, 可配置是否使用第一个media信息 | |
| 115 | + if (mediaDescriptions.size() > 0) { | |
| 116 | + ip = mediaDescriptions.get(0).getIpAddress().getHostName(); | |
| 117 | + port = mediaDescriptions.get(0).getPort(); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + | |
| 121 | + if (ip == null || port == -1) { | |
| 122 | + response488Ack(evt); | |
| 123 | + return; | |
| 124 | + } | |
| 125 | + | |
| 126 | + | |
| 127 | + String ssrc = sdp.getSsrc(); | |
| 128 | + // 通知下级推流, | |
| 129 | + // 查找合适的端口推流, | |
| 130 | + // 发送 200ok | |
| 131 | + // 收到ack后调用推流接口 | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 137 | + e.printStackTrace(); | |
| 138 | + } catch (IOException e) { | |
| 139 | + logger.warn("sdp解析错误"); | |
| 140 | + e.printStackTrace(); | |
| 141 | + } | |
| 142 | + | |
| 143 | + } | |
| 144 | + | |
| 145 | + /*** | |
| 146 | + * 回复100 trying | |
| 147 | + * @param evt | |
| 148 | + * @throws SipException | |
| 149 | + * @throws InvalidArgumentException | |
| 150 | + * @throws ParseException | |
| 151 | + */ | |
| 152 | + private void response100Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | |
| 153 | + Response response = getMessageFactory().createResponse(Response.TRYING, evt.getRequest()); | |
| 154 | + getServerTransaction(evt).sendResponse(response); | |
| 155 | + } | |
| 156 | + | |
| 157 | + /*** | |
| 158 | + * 回复404 | |
| 159 | + * @param evt | |
| 160 | + * @throws SipException | |
| 161 | + * @throws InvalidArgumentException | |
| 162 | + * @throws ParseException | |
| 163 | + */ | |
| 164 | + private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | |
| 165 | + Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest()); | |
| 166 | + getServerTransaction(evt).sendResponse(response); | |
| 167 | + } | |
| 168 | + | |
| 169 | + /*** | |
| 170 | + * 回复400 | |
| 171 | + * @param evt | |
| 172 | + * @throws SipException | |
| 173 | + * @throws InvalidArgumentException | |
| 174 | + * @throws ParseException | |
| 175 | + */ | |
| 176 | + private void response400Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | |
| 177 | + Response response = getMessageFactory().createResponse(Response.BAD_REQUEST, evt.getRequest()); | |
| 178 | + getServerTransaction(evt).sendResponse(response); | |
| 69 | 179 | } |
| 70 | 180 | |
| 181 | + /*** | |
| 182 | + * 回复488 | |
| 183 | + * @param evt | |
| 184 | + * @throws SipException | |
| 185 | + * @throws InvalidArgumentException | |
| 186 | + * @throws ParseException | |
| 187 | + */ | |
| 188 | + private void response488Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { | |
| 189 | + Response response = getMessageFactory().createResponse(Response.NOT_ACCEPTABLE_HERE, evt.getRequest()); | |
| 190 | + getServerTransaction(evt).sendResponse(response); | |
| 191 | + } | |
| 192 | + | |
| 193 | + /*** | |
| 194 | + * 回复200 OK | |
| 195 | + * @param evt | |
| 196 | + * @throws SipException | |
| 197 | + * @throws InvalidArgumentException | |
| 198 | + * @throws ParseException | |
| 199 | + */ | |
| 200 | + private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { | |
| 201 | + Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); | |
| 202 | + ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); | |
| 203 | + response.setContent(sdp, contentTypeHeader); | |
| 204 | + getServerTransaction(evt).sendResponse(response); | |
| 205 | + } | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + public SIPCommanderFroPlatform getCmderFroPlatform() { | |
| 217 | + return cmderFroPlatform; | |
| 218 | + } | |
| 219 | + | |
| 220 | + public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) { | |
| 221 | + this.cmderFroPlatform = cmderFroPlatform; | |
| 222 | + } | |
| 223 | + | |
| 224 | + public IVideoManagerStorager getStorager() { | |
| 225 | + return storager; | |
| 226 | + } | |
| 227 | + | |
| 228 | + public void setStorager(IVideoManagerStorager storager) { | |
| 229 | + this.storager = storager; | |
| 230 | + } | |
| 71 | 231 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
| ... | ... | @@ -15,6 +15,8 @@ import com.genersoft.iot.vmp.gb28181.bean.*; |
| 15 | 15 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| 16 | 16 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 17 | 17 | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
| 18 | +import gov.nist.javax.sip.address.AddressImpl; | |
| 19 | +import gov.nist.javax.sip.address.SipUri; | |
| 18 | 20 | import org.dom4j.Document; |
| 19 | 21 | import org.dom4j.DocumentException; |
| 20 | 22 | import org.dom4j.Element; |
| ... | ... | @@ -166,10 +168,15 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 166 | 168 | Element deviceIdElement = rootElement.element("DeviceID"); |
| 167 | 169 | String deviceId = deviceIdElement.getText(); |
| 168 | 170 | Element deviceListElement = rootElement.element("DeviceList"); |
| 171 | + | |
| 172 | + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME); | |
| 173 | + AddressImpl address = (AddressImpl) fromHeader.getAddress(); | |
| 174 | + SipUri uri = (SipUri) address.getURI(); | |
| 175 | + String platformId = uri.getUser(); | |
| 169 | 176 | // if (deviceListElement == null) { // 存在DeviceList则为响应 catalog, 不存在DeviceList则为查询请求 |
| 170 | 177 | if (name == "Query") { // 区分是Response——查询响应,还是Query——查询请求 |
| 171 | 178 | // TODO 后续将代码拆分 |
| 172 | - ParentPlatform parentPlatform = storager.queryParentPlatById(deviceId); | |
| 179 | + ParentPlatform parentPlatform = storager.queryParentPlatById(platformId); | |
| 173 | 180 | if (parentPlatform == null) { |
| 174 | 181 | response404Ack(evt); |
| 175 | 182 | return; |
| ... | ... | @@ -179,9 +186,8 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 179 | 186 | |
| 180 | 187 | Element snElement = rootElement.element("SN"); |
| 181 | 188 | String sn = snElement.getText(); |
| 182 | - FromHeader fromHeader = (FromHeader)evt.getRequest().getHeader(FromHeader.NAME); | |
| 183 | 189 | // 准备回复通道信息 |
| 184 | - List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getDeviceGBId()); | |
| 190 | + List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); | |
| 185 | 191 | if (channelReduces.size() >0 ) { |
| 186 | 192 | for (ChannelReduce channelReduce : channelReduces) { |
| 187 | 193 | DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); |
| ... | ... | @@ -499,7 +505,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 499 | 505 | } |
| 500 | 506 | |
| 501 | 507 | /*** |
| 502 | - * 回复200 OK | |
| 508 | + * 回复404 | |
| 503 | 509 | * @param evt |
| 504 | 510 | * @throws SipException |
| 505 | 511 | * @throws InvalidArgumentException | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java
| ... | ... | @@ -61,10 +61,14 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor { |
| 61 | 61 | public void process(ResponseEvent evt, SipLayer layer, SipConfig config) { |
| 62 | 62 | // TODO Auto-generated method stub |
| 63 | 63 | Response response = evt.getResponse(); |
| 64 | - ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME); | |
| 65 | - SipUri uri = (SipUri)toHeader.getAddress().getURI(); | |
| 66 | - String platformGBId = uri.getAuthority().getUser(); | |
| 64 | + CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME); | |
| 65 | + String callId = callIdHeader.getCallId(); | |
| 67 | 66 | |
| 67 | + String platformGBId = redisCatchStorage.queryPlatformRegisterInfo(callId); | |
| 68 | + if (platformGBId == null) { | |
| 69 | + logger.info(String.format("未找到callId: %s 的注册/注销平台id", callId )); | |
| 70 | + return; | |
| 71 | + } | |
| 68 | 72 | logger.info(String.format("收到 %s 的注册/注销%S响应", platformGBId, response.getStatusCode() )); |
| 69 | 73 | |
| 70 | 74 | ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformGBId); |
| ... | ... | @@ -80,18 +84,13 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor { |
| 80 | 84 | |
| 81 | 85 | if (response.getStatusCode() == 401) { |
| 82 | 86 | WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME); |
| 83 | - | |
| 84 | - | |
| 85 | - CallIdHeader callIdHeader = (CallIdHeader)response.getHeader(CallIdHeader.NAME); | |
| 86 | - String callId = callIdHeader.getCallId(); | |
| 87 | - | |
| 88 | 87 | sipCommanderForPlatform.register(parentPlatform, callId, www, null, null); |
| 89 | 88 | }else if (response.getStatusCode() == 200){ |
| 90 | 89 | // 注册成功 |
| 91 | 90 | logger.info(String.format("%s 注册成功", platformGBId )); |
| 91 | + redisCatchStorage.delPlatformRegisterInfo(callId); | |
| 92 | 92 | parentPlatform.setStatus(true); |
| 93 | 93 | storager.updateParentPlatform(parentPlatform); |
| 94 | - // | |
| 95 | 94 | redisCatchStorage.updatePlatformRegister(parentPlatform); |
| 96 | 95 | |
| 97 | 96 | redisCatchStorage.updatePlatformKeepalive(parentPlatform); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| ... | ... | @@ -73,4 +73,9 @@ public interface IRedisCatchStorage { |
| 73 | 73 | |
| 74 | 74 | void delPlatformRegister(String platformGbId); |
| 75 | 75 | |
| 76 | + void updatePlatformRegisterInfo(String callId, String platformGbId); | |
| 77 | + | |
| 78 | + String queryPlatformRegisterInfo(String callId); | |
| 79 | + | |
| 80 | + void delPlatformRegisterInfo(String callId); | |
| 76 | 81 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
| ... | ... | @@ -24,7 +24,7 @@ public interface ParentPlatformMapper { |
| 24 | 24 | @Update("UPDATE parent_platform " + |
| 25 | 25 | "SET enable=#{enable}, " + |
| 26 | 26 | "name=#{name}," + |
| 27 | - "serverGBId=#{serverGBId}," + | |
| 27 | + "deviceGBId=#{deviceGBId}," + | |
| 28 | 28 | "serverGBDomain=#{serverGBDomain}, " + |
| 29 | 29 | "serverIP=#{serverIP}," + |
| 30 | 30 | "serverPort=#{serverPort}, " + |
| ... | ... | @@ -39,13 +39,13 @@ public interface ParentPlatformMapper { |
| 39 | 39 | "PTZEnable=#{PTZEnable}, " + |
| 40 | 40 | "rtcp=#{rtcp}, " + |
| 41 | 41 | "status=#{status} " + |
| 42 | - "WHERE deviceGBId=#{deviceGBId}") | |
| 42 | + "WHERE serverGBId=#{serverGBId}") | |
| 43 | 43 | int updateParentPlatform(ParentPlatform parentPlatform); |
| 44 | 44 | |
| 45 | - @Delete("DELETE FROM parent_platform WHERE deviceGBId=#{deviceGBId}") | |
| 45 | + @Delete("DELETE FROM parent_platform WHERE serverGBId=#{serverGBId}") | |
| 46 | 46 | int delParentPlatform(ParentPlatform parentPlatform); |
| 47 | 47 | |
| 48 | - @Select("SELECT *,( SELECT count(0) FROM platform_gb_channel pc WHERE pc.platformId = pp.deviceGBId) as channelCount FROM parent_platform pp ") | |
| 48 | + @Select("SELECT *,( SELECT count(0) FROM platform_gb_channel pc WHERE pc.platformId = pp.serverGBId) as channelCount FROM parent_platform pp ") | |
| 49 | 49 | List<ParentPlatform> getParentPlatformList(); |
| 50 | 50 | |
| 51 | 51 | @Select("SELECT * FROM parent_platform WHERE enable=#{enable}") | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PatformChannelMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 3 | 4 | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
| 4 | 5 | import org.apache.ibatis.annotations.Delete; |
| 5 | 6 | import org.apache.ibatis.annotations.Insert; |
| ... | ... | @@ -39,4 +40,9 @@ public interface PatformChannelMapper { |
| 39 | 40 | "DELETE FROM platform_gb_channel WHERE platformId='${platformId}'" + |
| 40 | 41 | "</script>") |
| 41 | 42 | int cleanChannelForGB(String platformId); |
| 43 | + | |
| 44 | + | |
| 45 | + @Select("SELECT * FROM device_channel WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE " + | |
| 46 | + "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'") | |
| 47 | + DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); | |
| 42 | 48 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -169,13 +169,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 169 | 169 | |
| 170 | 170 | @Override |
| 171 | 171 | public void updatePlatformKeepalive(ParentPlatform parentPlatform) { |
| 172 | - String key = VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX + parentPlatform.getDeviceGBId(); | |
| 172 | + String key = VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX + parentPlatform.getServerGBId(); | |
| 173 | 173 | redis.set(key, "", Integer.parseInt(parentPlatform.getKeepTimeout())); |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | 176 | @Override |
| 177 | 177 | public void updatePlatformRegister(ParentPlatform parentPlatform) { |
| 178 | - String key = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + parentPlatform.getDeviceGBId(); | |
| 178 | + String key = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + parentPlatform.getServerGBId(); | |
| 179 | 179 | redis.set(key, "", Integer.parseInt(parentPlatform.getExpires())); |
| 180 | 180 | } |
| 181 | 181 | |
| ... | ... | @@ -198,4 +198,22 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 198 | 198 | public void delPlatformRegister(String platformGbId) { |
| 199 | 199 | redis.del(VideoManagerConstants.PLATFORM_REGISTER_PREFIX + platformGbId); |
| 200 | 200 | } |
| 201 | + | |
| 202 | + | |
| 203 | + @Override | |
| 204 | + public void updatePlatformRegisterInfo(String callId, String platformGbId) { | |
| 205 | + String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId; | |
| 206 | + redis.set(key, platformGbId); | |
| 207 | + } | |
| 208 | + | |
| 209 | + | |
| 210 | + @Override | |
| 211 | + public String queryPlatformRegisterInfo(String callId) { | |
| 212 | + return (String)redis.get(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId); | |
| 213 | + } | |
| 214 | + | |
| 215 | + @Override | |
| 216 | + public void delPlatformRegisterInfo(String callId) { | |
| 217 | + redis.del(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId); | |
| 218 | + } | |
| 201 | 219 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
| ... | ... | @@ -254,7 +254,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 254 | 254 | public boolean deleteParentPlatform(ParentPlatform parentPlatform) { |
| 255 | 255 | int result = platformMapper.delParentPlatform(parentPlatform); |
| 256 | 256 | // 删除关联的通道 |
| 257 | - patformChannelMapper.cleanChannelForGB(parentPlatform.getDeviceGBId()); | |
| 257 | + patformChannelMapper.cleanChannelForGB(parentPlatform.getServerGBId()); | |
| 258 | 258 | return result > 0; |
| 259 | 259 | } |
| 260 | 260 | |
| ... | ... | @@ -329,4 +329,10 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { |
| 329 | 329 | |
| 330 | 330 | return result; |
| 331 | 331 | } |
| 332 | + | |
| 333 | + @Override | |
| 334 | + public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) { | |
| 335 | + DeviceChannel channel = patformChannelMapper.queryChannelInParentPlatform(platformId, channelId); | |
| 336 | + return channel; | |
| 337 | + } | |
| 332 | 338 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java
| ... | ... | @@ -110,7 +110,7 @@ public class PlatformController { |
| 110 | 110 | if (logger.isDebugEnabled()) { |
| 111 | 111 | logger.debug("查询所有上级设备API调用"); |
| 112 | 112 | } |
| 113 | - if (StringUtils.isEmpty(parentPlatform.getDeviceGBId()) | |
| 113 | + if (StringUtils.isEmpty(parentPlatform.getServerGBId()) | |
| 114 | 114 | ){ |
| 115 | 115 | return new ResponseEntity<>("missing parameters", HttpStatus.BAD_REQUEST); |
| 116 | 116 | } |
| ... | ... | @@ -118,14 +118,14 @@ public class PlatformController { |
| 118 | 118 | // 发送离线消息,无论是否成功都删除缓存 |
| 119 | 119 | commanderForPlatform.unregister(parentPlatform, (event -> { |
| 120 | 120 | // 清空redis缓存 |
| 121 | - redisCatchStorage.delPlatformCatchInfo(parentPlatform.getDeviceGBId()); | |
| 122 | - redisCatchStorage.delPlatformKeepalive(parentPlatform.getDeviceGBId()); | |
| 123 | - redisCatchStorage.delPlatformRegister(parentPlatform.getDeviceGBId()); | |
| 121 | + redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); | |
| 122 | + redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); | |
| 123 | + redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId()); | |
| 124 | 124 | }), (event -> { |
| 125 | 125 | // 清空redis缓存 |
| 126 | - redisCatchStorage.delPlatformCatchInfo(parentPlatform.getDeviceGBId()); | |
| 127 | - redisCatchStorage.delPlatformKeepalive(parentPlatform.getDeviceGBId()); | |
| 128 | - redisCatchStorage.delPlatformRegister(parentPlatform.getDeviceGBId()); | |
| 126 | + redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); | |
| 127 | + redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); | |
| 128 | + redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId()); | |
| 129 | 129 | })); |
| 130 | 130 | |
| 131 | 131 | boolean deleteResult = storager.deleteParentPlatform(parentPlatform); | ... | ... |