|  |  |  | 
|---|
|  |  |  | import com.genersoft.iot.vmp.common.StreamInfo; | 
|---|
|  |  |  | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 
|---|
|  |  |  | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 
|---|
|  |  |  | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; | 
|---|
|  |  |  | import com.genersoft.iot.vmp.media.zlm.ZLMUtils; | 
|---|
|  |  |  | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 
|---|
|  |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Value("${media.rtp.enable}") | 
|---|
|  |  |  | private boolean rtpEnable; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private ZLMHttpHookSubscribe subscribe; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 请求预览视频流 | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * @param device  视频设备 | 
|---|
|  |  |  | * @param channelId  预览通道 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public StreamInfo playStreamCmd(Device device, String channelId) { | 
|---|
|  |  |  | public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String ssrc = streamSession.createPlaySsrc(); | 
|---|
|  |  |  | String streamId = null; | 
|---|
|  |  |  | if (rtpEnable) { | 
|---|
|  |  |  | streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId); | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | String streamMode = device.getStreamMode().toUpperCase(); | 
|---|
|  |  |  | MediaServerConfig mediaInfo = storager.getMediaInfo(); | 
|---|
|  |  |  | String mediaPort = null; | 
|---|
|  |  |  | // 使用动态udp端口 | 
|---|
|  |  |  | if (rtpEnable) { | 
|---|
|  |  |  | mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; | 
|---|
|  |  |  | mediaPort = zlmUtils.getNewRTPPort(streamId) + ""; | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | mediaPort = mediaInfo.getRtpProxyPort(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 添加订阅 | 
|---|
|  |  |  | JSONObject subscribeKey = new JSONObject(); | 
|---|
|  |  |  | subscribeKey.put("app", "rtp"); | 
|---|
|  |  |  | subscribeKey.put("id", streamId); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey, event); | 
|---|
|  |  |  | // | 
|---|
|  |  |  | StringBuffer content = new StringBuffer(200); | 
|---|
|  |  |  | content.append("v=0\r\n"); | 
|---|
|  |  |  | content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | 
|---|
|  |  |  | content.append("s=Play\r\n"); | 
|---|
|  |  |  | content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | 
|---|
|  |  |  | content.append("t=0 0\r\n"); | 
|---|
|  |  |  | if("TCP-PASSIVE".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); | 
|---|
|  |  |  | content.append("v=0\r\n"); | 
|---|
|  |  |  | content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | 
|---|
|  |  |  | content.append("s=Play\r\n"); | 
|---|
|  |  |  | content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | 
|---|
|  |  |  | content.append("t=0 0\r\n"); | 
|---|
|  |  |  | if("TCP-PASSIVE".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); | 
|---|
|  |  |  | }else if ("TCP-ACTIVE".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); | 
|---|
|  |  |  | }else if("UDP".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | content.append("a=recvonly\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:96 PS/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:98 H264/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:97 MPEG4/90000\r\n"); | 
|---|
|  |  |  | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 | 
|---|
|  |  |  | content.append("a=setup:passive\r\n"); | 
|---|
|  |  |  | content.append("a=recvonly\r\n"); | 
|---|
|  |  |  | content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:126 H264/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:125 H264S/90000\r\n"); | 
|---|
|  |  |  | content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); | 
|---|
|  |  |  | content.append("a=fmtp:99 profile-level-id=3\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:98 H264/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:97 MPEG4/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:96 PS/90000\r\n"); | 
|---|
|  |  |  | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 | 
|---|
|  |  |  | content.append("a=setup:passive\r\n"); | 
|---|
|  |  |  | content.append("a=connection:new\r\n"); | 
|---|
|  |  |  | }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 | 
|---|
|  |  |  | }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 | 
|---|
|  |  |  | content.append("a=setup:active\r\n"); | 
|---|
|  |  |  | content.append("a=connection:new\r\n"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | content.append("y="+ssrc+"\r\n");//ssrc | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | ClientTransaction transaction = transmitRequest(device, request); | 
|---|
|  |  |  | streamSession.put(ssrc, transaction); | 
|---|
|  |  |  | content.append("y="+ssrc+"\r\n");//ssrc | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | ClientTransaction transaction = transmitRequest(device, request); | 
|---|
|  |  |  | streamSession.put(streamId, transaction); | 
|---|
|  |  |  | DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); | 
|---|
|  |  |  | if (deviceChannel != null) { | 
|---|
|  |  |  | deviceChannel.setSsrc(ssrc); | 
|---|
|  |  |  | deviceChannel.setStreamId(streamId); | 
|---|
|  |  |  | storager.updateChannel(device.getDeviceId(), deviceChannel); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | StreamInfo streamInfo = new StreamInfo(); | 
|---|
|  |  |  | streamInfo.setSsrc(ssrc); | 
|---|
|  |  |  | streamInfo.setCahnnelId(channelId); | 
|---|
|  |  |  | streamInfo.setDeviceID(device.getDeviceId()); | 
|---|
|  |  |  | storager.startPlay(streamInfo); | 
|---|
|  |  |  | return streamInfo; | 
|---|
|  |  |  | // TODO 订阅SIP response,处理对方的错误返回 | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch ( SipException | ParseException | InvalidArgumentException e) { | 
|---|
|  |  |  | e.printStackTrace(); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | 
|---|
|  |  |  | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public StreamInfo playbackStreamCmd(Device device, String channelId, String startTime, String endTime) { | 
|---|
|  |  |  | public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | MediaServerConfig mediaInfo = storager.getMediaInfo(); | 
|---|
|  |  |  | String ssrc = streamSession.createPlayBackSsrc(); | 
|---|
|  |  |  | String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | 
|---|
|  |  |  | // 添加订阅 | 
|---|
|  |  |  | JSONObject subscribeKey = new JSONObject(); | 
|---|
|  |  |  | subscribeKey.put("app", "rtp"); | 
|---|
|  |  |  | subscribeKey.put("id", streamId); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey, event); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // | 
|---|
|  |  |  | StringBuffer content = new StringBuffer(200); | 
|---|
|  |  |  | content.append("v=0\r\n"); | 
|---|
|  |  |  | content.append("o="+sipConfig.getSipId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n"); | 
|---|
|  |  |  | content.append("s=Playback\r\n"); | 
|---|
|  |  |  | content.append("u="+channelId+":0\r\n"); | 
|---|
|  |  |  | content.append("c=IN IP4 "+mediaInfo.getLocalIP()+"\r\n"); | 
|---|
|  |  |  | content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | 
|---|
|  |  |  | content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" " | 
|---|
|  |  |  | +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n"); | 
|---|
|  |  |  | String mediaPort = null; | 
|---|
|  |  |  | // 使用动态udp端口 | 
|---|
|  |  |  | if (rtpEnable) { | 
|---|
|  |  |  | mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; | 
|---|
|  |  |  | mediaPort = zlmUtils.getNewRTPPort(streamId) + ""; | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | mediaPort = mediaInfo.getRtpProxyPort(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | String streamMode = device.getStreamMode().toUpperCase(); | 
|---|
|  |  |  | if("TCP-PASSIVE".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); | 
|---|
|  |  |  | }else if ("TCP-ACTIVE".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); | 
|---|
|  |  |  | }else if("UDP".equals(streamMode)) { | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); | 
|---|
|  |  |  | content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | content.append("a=recvonly\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:96 PS/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:98 H264/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:97 MPEG4/90000\r\n"); | 
|---|
|  |  |  | content.append("a=recvonly\r\n"); | 
|---|
|  |  |  | content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:126 H264/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:125 H264S/90000\r\n"); | 
|---|
|  |  |  | content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); | 
|---|
|  |  |  | content.append("a=fmtp:99 profile-level-id=3\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:98 H264/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:97 MPEG4/90000\r\n"); | 
|---|
|  |  |  | content.append("a=rtpmap:96 PS/90000\r\n"); | 
|---|
|  |  |  | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 | 
|---|
|  |  |  | content.append("a=setup:passive\r\n"); | 
|---|
|  |  |  | content.append("a=connection:new\r\n"); | 
|---|
|  |  |  | 
|---|
|  |  |  | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | ClientTransaction transaction = transmitRequest(device, request); | 
|---|
|  |  |  | streamSession.put(ssrc, transaction); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | StreamInfo streamInfo = new StreamInfo(); | 
|---|
|  |  |  | streamInfo.setSsrc(ssrc); | 
|---|
|  |  |  | streamInfo.setCahnnelId(channelId); | 
|---|
|  |  |  | streamInfo.setDeviceID(device.getDeviceId()); | 
|---|
|  |  |  | boolean b = storager.startPlayback(streamInfo); | 
|---|
|  |  |  | return streamInfo; | 
|---|
|  |  |  | streamSession.put(streamId, transaction); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch ( SipException | ParseException | InvalidArgumentException e) { | 
|---|
|  |  |  | e.printStackTrace(); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | * | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public void streamByeCmd(String ssrc) { | 
|---|
|  |  |  | public void streamByeCmd(String streamId) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | ClientTransaction transaction = streamSession.get(ssrc); | 
|---|
|  |  |  | ClientTransaction transaction = streamSession.get(streamId); | 
|---|
|  |  |  | if (transaction == null) { | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 
|---|
|  |  |  | clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | dialog.sendRequest(clientTransaction); | 
|---|
|  |  |  | streamSession.remove(streamId); | 
|---|
|  |  |  | } catch (TransactionDoesNotExistException e) { | 
|---|
|  |  |  | e.printStackTrace(); | 
|---|
|  |  |  | } catch (SipException e) { | 
|---|