Jelajahi Sumber

临时上传版本,调整语音对讲部分代码

kindring 2 tahun lalu
induk
melakukan
082f4d9040

+ 47 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/BroadcastItem.java

@@ -1,5 +1,9 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
+import gov.nist.javax.sip.message.SIPRequest;
+
+import java.util.Vector;
+
 /**
  * @author
  * @date :Created in 2022/8/24 15:17
@@ -34,6 +38,49 @@ public class BroadcastItem {
     private String app;
     private String stream;
 
+    private String mediaId;
+
+    private SIPRequest request;
+
+    private Vector audioFormats;
+
+    public String getMediaId() {
+        return mediaId;
+    }
+
+    public void setMediaId(String mediaId) {
+        this.mediaId = mediaId;
+    }
+
+    public SIPRequest getRequest() {
+        return request;
+    }
+
+    public void setRequest(SIPRequest request) {
+        this.request = request;
+    }
+
+    public Vector getAudioFormats() {
+        return audioFormats;
+    }
+
+    public void setAudioFormats(Vector audioFormats) {
+        this.audioFormats = audioFormats;
+    }
+
+    public String getAudioCoded() {
+        return audioCoded;
+    }
+
+    public void setAudioCoded(String audioCoded) {
+        this.audioCoded = audioCoded;
+    }
+
+    private String audioCoded;
+
+
+
+
     public String getDeviceId() {
         return deviceId;
     }

+ 5 - 4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java

@@ -48,6 +48,7 @@ import javax.sip.header.CallIdHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
 import java.time.Instant;
+import java.util.Objects;
 import java.util.Random;
 import java.util.Vector;
 
@@ -905,10 +906,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                     MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
                     Media media = mediaDescription.getMedia();
                     Vector mediaFormats = media.getMediaFormats(false);
-                    logger.info("mediaFormats {}",mediaFormats);
-                    logger.info("getMediaType {}",media.getMediaType());
-                    if(media.getMediaType() == "audio"){
-                        logger.info("audio mediaFormats {}",mediaFormats);
+//                    logger.info("mediaFormats {}",mediaFormats);
+//                    logger.info("getMediaType {}",media.getMediaType());
+                    if(Objects.equals(media.getMediaType(), "audio")){
+//                        logger.info("audio mediaFormats {}",mediaFormats);
                         audioFormats.addAll(mediaFormats);
                     }
                     if (mediaFormats.contains("8")) {

+ 9 - 0
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.exception.ServiceException;
 import com.genersoft.iot.vmp.gb28181.HookSubscribeForKey;
+import com.genersoft.iot.vmp.gb28181.bean.BroadcastItem;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
 import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
@@ -64,4 +65,12 @@ public interface IPlayService {
     void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
 
     void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
+
+    void broadcast(
+            MediaServerItem mediaServerItem,
+            Device device,
+            BroadcastItem broadcastItem,
+            int waitTime,
+            BroadcastCallback callback
+    );
 }

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java

@@ -1046,4 +1046,14 @@ public class PlayServiceImpl implements IPlayService {
         Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
         cmder.playResumeCmd(device, streamInfo);
     }
+
+    public void broadcast(
+            MediaServerItem mediaServerItem,
+            Device device,
+            BroadcastItem broadcastItem,
+            int waitTime,
+            BroadcastCallback callback
+    ){
+
+    };
 }

+ 3 - 0
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java

@@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
 import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
+import gov.nist.javax.sip.message.SIPRequest;
 
 import java.util.List;
 import java.util.Map;
@@ -289,4 +290,6 @@ public interface IRedisCatchStorage {
     boolean deleteBroadcastItem(String deviceId);
 
     boolean isBroadcastItem(String deviceId);
+
+
 }

+ 8 - 2
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java

@@ -20,6 +20,7 @@ import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.utils.JsonUtil;
 import com.genersoft.iot.vmp.utils.SystemInfoUtils;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
+import gov.nist.javax.sip.message.SIPRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -925,13 +926,16 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
     @Override
     public boolean addBroadcastItem(String deviceId, BroadcastItem broadcastItem) {
         String key = VideoManagerConstants.WVP_BROADCAST_FLAG + deviceId;
-
-        return RedisUtil.set(key, broadcastItem);
+        return RedisUtil.set(key, broadcastItem,15);
     }
 
+
+
     @Override
     public BroadcastItem queryBroadcastItem(String deviceId) {
         String key = VideoManagerConstants.WVP_BROADCAST_FLAG + deviceId;
+        // 更新过期时间,设置为半小时移除
+        RedisUtil.expire(key,60*30);
         return (BroadcastItem) RedisUtil.get(key);
     }
 
@@ -947,4 +951,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
         BroadcastItem broadcastItem = (BroadcastItem) RedisUtil.get(key);
         return broadcastItem != null && broadcastItem.getIpcAudioPort() != null;
     }
+
+
 }

+ 90 - 9
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java

@@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
 import com.genersoft.iot.vmp.gb28181.GBEventSubscribe;
 import com.genersoft.iot.vmp.gb28181.GBHookSubscribeFactory;
 import com.genersoft.iot.vmp.gb28181.HookSubscribeForKey;
+import com.genersoft.iot.vmp.gb28181.bean.BroadcastItem;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@@ -45,10 +46,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.sip.InvalidArgumentException;
 import javax.sip.SipException;
 import java.text.ParseException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
 
 @Tag(name  = "国标设备点播")
 @CrossOrigin
@@ -268,7 +266,7 @@ public class PlayController {
 	@Parameter(name = "deviceId", description = "设备国标编号", required = true)
 	@Parameter(name = "app", description = "推流app", required = true)
 	@Parameter(name = "stream", description = "音频推流编号", required = true)
-    @GetMapping("/broadcast")
+    @GetMapping("/broadcastOld")
 //    @PostMapping("/broadcast/{deviceId}")
     public DeferredResult<WVPResult<String>> broadcastApi(
 			HttpServletRequest request,
@@ -364,7 +362,7 @@ public class PlayController {
 	@Parameter(name = "channelId", description = "设备国标编号", required = true)
 	@Parameter(name = "waitTime", description = "设备国标编号", required = false)
 	@GetMapping("/startBroadcast")
-	public DeferredResult<WVPResult<String>> getWebRtcAddr(@RequestParam String deviceId,
+	public DeferredResult<WVPResult<String>> startBroadcast(@RequestParam String deviceId,
 								   @RequestParam("channelId") String channelId,
 									@RequestParam(value = "waitTime",
 											required = false,
@@ -431,7 +429,17 @@ public class PlayController {
 						wvpResult.setMsg((String) json.get("msg"));
 					} else if (code == 0) {
 						logger.info("收到设备invite信息: {}",json);
-						// todo 存储invite信息和request信息至redis中
+
+						BroadcastItem broadcastItem = new BroadcastItem();
+						broadcastItem.setMediaId(mediaServerItem.getId());
+						broadcastItem.setDeviceId(deviceId);
+						broadcastItem.setApp(app);
+						broadcastItem.setStream(stream);
+						broadcastItem.setIpcIp((String) json.get("addr"));
+						broadcastItem.setIpcAudioPort((Integer) json.get("port"));
+						broadcastItem.setSsrc((String) json.get("ssrc"));
+						broadcastItem.setRequest(request);
+						broadcastItem.setAudioFormats((Vector) json.get("audioFormats"));
 						// 获取id
 						resultData.put("mediaId",mediaServerItem.getId());
 						resultData.put("app",app);
@@ -439,21 +447,94 @@ public class PlayController {
 						resultData.put("type",type);
 						resultData.put("sign",sign);
 						resultData.put("webRtcPushUrl", webRtcPushUrl);
+						resultData.put("audioFormats",json.get("audioFormats"));
 						logger.info("获取webrtc推流地址:{}",webRtcPushUrl);
+						//存储invite信息和request信息至redis中
+						if(redisCatchStorage.addBroadcastItem(
+								deviceId,
+								broadcastItem
+						)){
+							logger.info("语音对讲信息存储成功");
+						}else{
+							logger.warn("无法存储数据至zlm");
+						}
+						//设置过期时间
 						wvpResult.setCode(ErrorCode.SUCCESS.getCode());
 						wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
 						wvpResult.setData(resultData);
 					}
-					logger.warn("结束");
 					msg.setData(wvpResult);
 					resultHolder.invokeAllResult(msg);
-					logger.warn("结束2");
 //					return result;
 				}
 		);
 		return result;
 	}
 
+	@Operation(summary = "开始建立语音广播连接")
+	@Parameter(name = "deviceId", description = "设备国标编号", required = true)
+	@Parameter(name = "audioCoded", description = "音频编码信息", required = false)
+	@GetMapping("/broadcast")
+	public DeferredResult<WVPResult<String>> broadcast(
+			@RequestParam("deviceId") String deviceId,
+			@RequestParam(value = "audioCoded",required = false) String audioCoded
+	){
+		RequestMessage msg = new RequestMessage();
+		// 返回invite信息给设备
+		String key  = DeferredResultHolder.CALLBACK_CMD_BROADCAST_INVITE + deviceId;
+		msg.setKey(key);
+		String uuid = UUID.randomUUID().toString();
+		msg.setId(uuid);
+		DeferredResult<WVPResult<String>> result = new DeferredResult<>(10*1000l);
+		WVPResult wvpResult = new WVPResult();
+		resultHolder.put(key, uuid, result);
+
+
+		// 从redis中拉取语音对讲数据
+		BroadcastItem broadcastItem = redisCatchStorage.queryBroadcastItem(deviceId);
+		if(broadcastItem == null){
+			logger.info("[语音对讲 invite] invite交互超时");
+			wvpResult.setCode(ErrorCode.ERROR404.getCode());
+			wvpResult.setMsg("无法找到设备invite信息,可能是交互超时");
+			msg.setData(wvpResult);
+			resultHolder.invokeAllResult(msg);
+		}
+		// 检查设备是否存在
+		Device device = storager.queryVideoDevice(deviceId);
+		if (device == null){
+			// 无法找到设备
+			wvpResult.setCode(ErrorCode.ERROR404.getCode());
+			wvpResult.setMsg("无法找到设备");
+			msg.setData(wvpResult);
+			resultHolder.invokeAllResult(msg);
+		}
+		// 获取对应的媒体服务
+		MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
+		logger.info("[语言广播] 分配的流媒体服务器为 {}",mediaServerItem.getId());
+		if (mediaServerItem == null) {
+			logger.warn("[语音广播] 无法连接至ZLM服务器");
+			wvpResult.setCode(ErrorCode.ERR_NOTFOUND_STREAM.getCode());
+			wvpResult.setMsg("无法连接至流媒体服务器");
+			msg.setData(wvpResult);
+			resultHolder.invokeAllResult(msg);
+		}else{
+			playService.broadcast(
+				mediaServerItem,
+				device,
+				broadcastItem,
+				5000,
+				(int code, JSONObject json, SIPRequest request)->{
+					// todo 处理并返回语音广播请求,应该有一个ack
+				}
+			);
+		}
+		// 获取zlm推流端口
+		// todo 回复 invite 200 给设备
+
+		return result;
+	}
+
+
 	@Operation(summary = "获取所有的ssrc")
 	@GetMapping("/ssrc")
 	public JSONObject getSSRC() {