|
@@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.conf.security.SecurityUtils;
|
|
|
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.GBStore;
|
|
|
import com.genersoft.iot.vmp.gb28181.HookSubscribeForKey;
|
|
|
import com.genersoft.iot.vmp.gb28181.bean.BroadcastItem;
|
|
|
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
|
@@ -92,6 +93,9 @@ public class PlayController {
|
|
|
@Autowired
|
|
|
private IUserService userService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private GBStore gbStore;
|
|
|
+
|
|
|
@Operation(summary = "开始点播")
|
|
|
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
|
|
|
@Parameter(name = "channelId", description = "通道国标编号", required = true)
|
|
@@ -352,132 +356,129 @@ public class PlayController {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 开始语音广播,获取设备invite,音频编码协商 步骤1
|
|
|
+ * 开始语音广播
|
|
|
* @param deviceId
|
|
|
* @param channelId
|
|
|
* @return
|
|
|
*/
|
|
|
- @Operation(summary = "开始语音广播")
|
|
|
+ @Operation(summary = "开始语音广播,获取参数")
|
|
|
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
|
|
|
@Parameter(name = "channelId", description = "设备国标编号", required = true)
|
|
|
@Parameter(name = "waitTime", description = "设备国标编号", required = false)
|
|
|
@GetMapping("/startBroadcast")
|
|
|
- public DeferredResult<WVPResult<String>> startBroadcast(@RequestParam String deviceId,
|
|
|
+ public WVPResult startBroadcast(@RequestParam String deviceId,
|
|
|
@RequestParam("channelId") String channelId,
|
|
|
@RequestParam(value = "waitTime",
|
|
|
required = false,
|
|
|
defaultValue = "5000") int waitTimeStr ) {
|
|
|
|
|
|
- RequestMessage msg = new RequestMessage();
|
|
|
- String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + 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);
|
|
|
|
|
|
+ Device device = storager.queryVideoDevice(deviceId);
|
|
|
+ MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
|
|
|
String app = "audio";
|
|
|
String stream = "rtc_" + deviceId + "_" + channelId;
|
|
|
String type = "push";
|
|
|
-// if(waitTimeStr.isEmpty() || waitTimeStr==""){
|
|
|
-// waitTimeStr = "5000";
|
|
|
-// }
|
|
|
- int waitTime = waitTimeStr;
|
|
|
+ Map<String, Object> resultData = new HashMap<>(16);
|
|
|
+ LoginUser userInfo = SecurityUtils.getUserInfo();
|
|
|
+ String sign = Md5Utils.hash(userService.getUserByUsername(userInfo.getUsername()).getPushKey()); //获取推流鉴权密钥
|
|
|
+ String webRtcPushUrl = String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=%s&sign=%s", mediaServerItem.getIp(), mediaServerItem.getHttpSSlPort(), app, stream, type,sign);
|
|
|
|
|
|
//首先判断设备是否正在对讲
|
|
|
if (redisCatchStorage.isBroadcastItem(deviceId)) {
|
|
|
// 设备正在进行语音对讲
|
|
|
wvpResult.setCode(ErrorCode.ERROR_Device_Busy.getCode());
|
|
|
wvpResult.setMsg(ErrorCode.ERROR_Device_Busy.getMsg());
|
|
|
- msg.setData(wvpResult);
|
|
|
- resultHolder.invokeAllResult(msg);
|
|
|
- return result;
|
|
|
+ return wvpResult;
|
|
|
}
|
|
|
|
|
|
- Device device = storager.queryVideoDevice(deviceId);
|
|
|
- MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
|
|
|
-
|
|
|
if (mediaServerItem == null) {
|
|
|
logger.error("流媒体未找到");
|
|
|
wvpResult.setCode(ErrorCode.ERR_MEDIA.getCode());
|
|
|
wvpResult.setMsg(ErrorCode.ERR_MEDIA.getMsg());
|
|
|
- msg.setData(wvpResult);
|
|
|
- resultHolder.invokeAllResult(msg);
|
|
|
- return result;
|
|
|
+ return wvpResult;
|
|
|
}
|
|
|
- Map<String, Object> resultData = new HashMap<>(16);
|
|
|
- LoginUser userInfo = SecurityUtils.getUserInfo();
|
|
|
- String sign = Md5Utils.hash(userService.getUserByUsername(userInfo.getUsername()).getPushKey()); //获取推流鉴权密钥
|
|
|
+
|
|
|
+ resultData.put("mediaId",mediaServerItem.getId());
|
|
|
+ resultData.put("app",app);
|
|
|
+ resultData.put("stream",stream);
|
|
|
+ resultData.put("type",type);
|
|
|
+ resultData.put("sign",sign);
|
|
|
+ resultData.put("webRtcPushUrl", webRtcPushUrl);
|
|
|
+ resultData.put("audioEncodePt",device.getAudioEncodePt());
|
|
|
+ wvpResult.setCode(ErrorCode.SUCCESS.getCode());
|
|
|
+ wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
|
|
|
+ wvpResult.setData(resultData);
|
|
|
+ return wvpResult;
|
|
|
//示例 https://192.168.126.111:9443/index/api/webrtc?app=live&stream=test&type=play&sign=...
|
|
|
- String webRtcPushUrl = String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=%s&sign=%s", mediaServerItem.getIp(), mediaServerItem.getHttpSSlPort(), app, stream, type,sign);
|
|
|
// 下发broadcast给设备
|
|
|
- playService.openBroadcast(
|
|
|
- mediaServerItem,
|
|
|
- device,
|
|
|
- waitTime,
|
|
|
- (int code, JSONObject json, SIPRequest request)->{
|
|
|
- // 0 ok,1 超时,2 异常
|
|
|
- // invite sdp , message data
|
|
|
- // request , null
|
|
|
- if(code == 1){
|
|
|
- logger.warn("invite超时");
|
|
|
- wvpResult.setCode(ErrorCode.ERR_TIMEOUT.getCode());
|
|
|
- wvpResult.setMsg(ErrorCode.ERR_TIMEOUT.getMsg());
|
|
|
- } else if (code == 2) {
|
|
|
- wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
|
|
- wvpResult.setMsg((String) json.get("msg"));
|
|
|
- } else if (code == 0) {
|
|
|
- logger.info("收到设备invite信息: {}",json);
|
|
|
-
|
|
|
- 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);
|
|
|
- resultData.put("stream",stream);
|
|
|
- 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);
|
|
|
- }
|
|
|
- msg.setData(wvpResult);
|
|
|
- resultHolder.invokeAllResult(msg);
|
|
|
-// return result;
|
|
|
- }
|
|
|
- );
|
|
|
- return result;
|
|
|
+// playService.openBroadcast(
|
|
|
+// mediaServerItem,
|
|
|
+// device,
|
|
|
+// waitTime,
|
|
|
+// (int code, JSONObject json, SIPRequest request)->{
|
|
|
+// // 0 ok,1 超时,2 异常
|
|
|
+// // invite sdp , message data
|
|
|
+// // request , null
|
|
|
+// if(code == 1){
|
|
|
+// logger.warn("invite超时");
|
|
|
+// wvpResult.setCode(ErrorCode.ERR_TIMEOUT.getCode());
|
|
|
+// wvpResult.setMsg(ErrorCode.ERR_TIMEOUT.getMsg());
|
|
|
+// } else if (code == 2) {
|
|
|
+// wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
|
|
+// wvpResult.setMsg((String) json.get("msg"));
|
|
|
+// } else if (code == 0) {
|
|
|
+// logger.info("收到设备invite信息: {}",json);
|
|
|
+//
|
|
|
+// 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
|
|
|
+//
|
|
|
+// //存储invite信息和request信息至redis中
|
|
|
+// gbStore.addBroadcastStore(
|
|
|
+// "broadcast_"+deviceId,
|
|
|
+// broadcastItem
|
|
|
+// );
|
|
|
+//// if(redisCatchStorage.addBroadcastItem(
|
|
|
+//// deviceId,
|
|
|
+//// broadcastItem
|
|
|
+//// )){
|
|
|
+//// logger.info("语音对讲信息存储成功");
|
|
|
+//// }else{
|
|
|
+//// logger.warn("无法存储数据至zlm");
|
|
|
+//// }
|
|
|
+// //设置过期时间
|
|
|
+//
|
|
|
+// }
|
|
|
+// msg.setData(wvpResult);
|
|
|
+// resultHolder.invokeAllResult(msg);
|
|
|
+//// return result;
|
|
|
+// }
|
|
|
+// );
|
|
|
+// return result;
|
|
|
}
|
|
|
|
|
|
@Operation(summary = "开始建立语音广播连接")
|
|
|
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
|
|
|
- @Parameter(name = "audioCoded", description = "音频编码信息", required = false)
|
|
|
+ @Parameter(name = "app", description = "流的app名称")
|
|
|
+ @Parameter(name = "stream", description = "流名称")
|
|
|
+ @Parameter(name = "waitTime", description = "invite等待时长", required = false)
|
|
|
@GetMapping("/broadcast")
|
|
|
public DeferredResult<WVPResult<String>> broadcast(
|
|
|
@RequestParam("deviceId") String deviceId,
|
|
|
- @RequestParam(value = "audioCoded",required = false) String audioCoded
|
|
|
+ @RequestParam(value = "waitTime",
|
|
|
+ required = false,
|
|
|
+ defaultValue = "5000") int waitTime,
|
|
|
+ @RequestParam(value = "app") String app,
|
|
|
+ @RequestParam(value = "stream") String stream
|
|
|
){
|
|
|
logger.info("[语音对讲] web端已经开启推流");
|
|
|
RequestMessage msg = new RequestMessage();
|
|
@@ -491,16 +492,6 @@ public class PlayController {
|
|
|
Map<String, Object> resultData = new HashMap<>(16);
|
|
|
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){
|
|
@@ -510,6 +501,7 @@ public class PlayController {
|
|
|
msg.setData(wvpResult);
|
|
|
resultHolder.invokeAllResult(msg);
|
|
|
}
|
|
|
+
|
|
|
// 获取对应的媒体服务
|
|
|
MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
|
|
|
logger.info("[语言广播] 分配的流媒体服务器为 {}",mediaServerItem.getId());
|
|
@@ -520,15 +512,16 @@ public class PlayController {
|
|
|
msg.setData(wvpResult);
|
|
|
resultHolder.invokeAllResult(msg);
|
|
|
}else{
|
|
|
- playService.broadcast(
|
|
|
+ playService.openBroadcast(
|
|
|
mediaServerItem,
|
|
|
device,
|
|
|
- broadcastItem,
|
|
|
- 5000,
|
|
|
+ waitTime,
|
|
|
(int code, JSONObject json, SIPRequest request)->{
|
|
|
- // todo 处理并返回语音广播请求,应该有一个ack
|
|
|
+ // 0 ok,1 超时,2 异常
|
|
|
+ // invite sdp , message data
|
|
|
+ // request , null
|
|
|
if(code == 1){
|
|
|
- logger.warn("等待设备ack超时");
|
|
|
+ logger.warn("invite超时");
|
|
|
wvpResult.setCode(ErrorCode.ERR_TIMEOUT.getCode());
|
|
|
wvpResult.setMsg(ErrorCode.ERR_TIMEOUT.getMsg());
|
|
|
} else if (code == 2) {
|
|
@@ -536,24 +529,66 @@ public class PlayController {
|
|
|
wvpResult.setMsg((String) json.get("msg"));
|
|
|
} else if (code == 0) {
|
|
|
logger.info("收到设备invite信息: {}",json);
|
|
|
+
|
|
|
+ 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);
|
|
|
-// resultData.put("stream",stream);
|
|
|
-// resultData.put("type",type);
|
|
|
-// resultData.put("sign",sign);
|
|
|
-// resultData.put("webRtcPushUrl", webRtcPushUrl);
|
|
|
-// resultData.put("audioFormats",json.get("audioFormats"));
|
|
|
-// logger.info("获取webrtc推流地址:{}",webRtcPushUrl);
|
|
|
-
|
|
|
- wvpResult.setCode(ErrorCode.SUCCESS.getCode());
|
|
|
- wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
|
|
|
- wvpResult.setData(resultData);
|
|
|
+ playService.broadcast(
|
|
|
+ mediaServerItem,
|
|
|
+ device,
|
|
|
+ broadcastItem,
|
|
|
+ 5000,
|
|
|
+ (int _code, JSONObject _json, SIPRequest _request)->{
|
|
|
+ // todo 处理并返回语音广播请求,应该有一个ack
|
|
|
+ if(_code == 1){
|
|
|
+ logger.warn("等待设备ack超时");
|
|
|
+ wvpResult.setCode(ErrorCode.ERR_TIMEOUT.getCode());
|
|
|
+ wvpResult.setMsg(ErrorCode.ERR_TIMEOUT.getMsg());
|
|
|
+ } else if (_code == 2) {
|
|
|
+ wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
|
|
+ wvpResult.setMsg((String) _json.get("msg"));
|
|
|
+ } else if (_code == 0) {
|
|
|
+ logger.info("收到设备invite信息 开始建立连接: {}",_json);
|
|
|
+ // 获取id
|
|
|
+ resultData.put("mediaId",mediaServerItem.getId());
|
|
|
+ wvpResult.setCode(ErrorCode.SUCCESS.getCode());
|
|
|
+ wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
|
|
|
+ wvpResult.setData(resultData);
|
|
|
+ }
|
|
|
+ msg.setData(wvpResult);
|
|
|
+ resultHolder.invokeAllResult(msg);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ //存储invite信息和request信息至redis中
|
|
|
+ gbStore.addBroadcastStore(
|
|
|
+ "broadcast_"+deviceId,
|
|
|
+ broadcastItem
|
|
|
+ );
|
|
|
+// if(redisCatchStorage.addBroadcastItem(
|
|
|
+// deviceId,
|
|
|
+// broadcastItem
|
|
|
+// )){
|
|
|
+// logger.info("语音对讲信息存储成功");
|
|
|
+// }else{
|
|
|
+// logger.warn("无法存储数据至zlm");
|
|
|
+// }
|
|
|
+ //设置过期时间
|
|
|
+
|
|
|
}
|
|
|
msg.setData(wvpResult);
|
|
|
resultHolder.invokeAllResult(msg);
|
|
|
+// return result;
|
|
|
}
|
|
|
- );
|
|
|
+ );
|
|
|
+
|
|
|
}
|
|
|
// 获取zlm推流端口
|
|
|
// todo 回复 invite 200 给设备
|
|
@@ -561,6 +596,30 @@ public class PlayController {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ @Operation(summary = "停止语音广播")
|
|
|
+ @Parameter(name = "deviceId", description = "设备国标编号", required = true)
|
|
|
+ @Parameter(name = "channelId", description = "设备通道编号", required = true)
|
|
|
+ @GetMapping("/stopBroadcast")
|
|
|
+ public WVPResult stopBroadcast(@RequestParam("deviceId") String deviceId,@RequestParam("channelId") String channelId){
|
|
|
+ BroadcastItem broadcastItem = gbStore.queryBroadcastStore(
|
|
|
+ "broadcast_"+deviceId
|
|
|
+ );
|
|
|
+ WVPResult wvpResult = new WVPResult();
|
|
|
+ Device device = storager.queryVideoDevice(deviceId);
|
|
|
+ // 停止音频流,给设备发送bye
|
|
|
+ try {
|
|
|
+ logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
|
|
|
+ cmder.streamByeCmd(device, channelId, broadcastItem.getStream(), null, null);
|
|
|
+ wvpResult.setCode(ErrorCode.SUCCESS.getCode());
|
|
|
+ } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
|
|
+ logger.error("[命令发送失败] 停止语音广播, 发送BYE: {}", e.getMessage());
|
|
|
+ wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
|
|
+ wvpResult.setMsg("[命令发送失败] 停止语音广播, 发送BYE: {}");
|
|
|
+// throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ return wvpResult;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
@Operation(summary = "获取所有的ssrc")
|
|
|
@GetMapping("/ssrc")
|