mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-06-22 02:57:49 +08:00
支持通用通道对讲,支持全双工对讲
This commit is contained in:
parent
f6ca930492
commit
6ade3060b5
@ -574,9 +574,9 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
|
||||
@Override
|
||||
public boolean removeCatalogSubscribe(@NotNull Device device, CommonCallback<Boolean> callback) {
|
||||
log.info("[移除目录订阅]: {}", device.getDeviceId());
|
||||
String key = SubscribeTaskForCatalog.getKey(device);
|
||||
if (subscribeTaskRunner.containsKey(key)) {
|
||||
log.info("[移除目录订阅]: {}", device.getDeviceId());
|
||||
SipTransactionInfo transactionInfo = subscribeTaskRunner.getTransactionInfo(key);
|
||||
if (transactionInfo == null) {
|
||||
log.warn("[移除目录订阅] 未找到事务信息,{}", device.getDeviceId());
|
||||
@ -638,9 +638,9 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
|
||||
@Override
|
||||
public boolean removeMobilePositionSubscribe(Device device, CommonCallback<Boolean> callback) {
|
||||
log.info("[移除移动位置订阅]: {}", device.getDeviceId());
|
||||
String key = SubscribeTaskForMobilPosition.getKey(device);
|
||||
if (subscribeTaskRunner.containsKey(key)) {
|
||||
log.info("[移除移动位置订阅]: {}", device.getDeviceId());
|
||||
SipTransactionInfo transactionInfo = subscribeTaskRunner.getTransactionInfo(key);
|
||||
if (transactionInfo == null) {
|
||||
log.warn("[移除移动位置订阅] 未找到事务信息,{}", device.getDeviceId());
|
||||
@ -703,9 +703,9 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
|
||||
@Override
|
||||
public boolean removeAlarmSubscribe(Device device, CommonCallback<Boolean> callback) {
|
||||
log.info("[移除报警订阅]: {}", device.getDeviceId());
|
||||
String key = SubscribeTaskForAlarm.getKey(device);
|
||||
if (subscribeTaskRunner.containsKey(key)) {
|
||||
log.info("[移除报警订阅]: {}", device.getDeviceId());
|
||||
SipTransactionInfo transactionInfo = subscribeTaskRunner.getTransactionInfo(key);
|
||||
if (transactionInfo == null) {
|
||||
log.warn("[移除报警订阅] 未找到事务信息,{}", device.getDeviceId());
|
||||
|
||||
@ -1229,6 +1229,12 @@ public class PlayServiceImpl implements IPlayService {
|
||||
audioBroadcastResult.setApp(app);
|
||||
audioBroadcastResult.setStream(stream);
|
||||
audioBroadcastResult.setStreamInfo(new StreamContent(mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null, false)));
|
||||
if (!broadcastMode) {
|
||||
audioBroadcastResult.setPlayStreamInfo(new StreamContent(
|
||||
mediaServerService.getStreamInfoByAppAndStream(mediaServerItem,
|
||||
MediaStreamUtil.GB28181_TALK, stream + "_talk",
|
||||
null, null, null, true)));
|
||||
}
|
||||
audioBroadcastResult.setCodec("G.711");
|
||||
return audioBroadcastResult;
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
@ -11,12 +9,9 @@ import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IDeviceService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IPlayService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.ISourceBroadcastService;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.AudioTalkResult;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -34,12 +29,6 @@ public class SourceBroadcastServiceForGbImpl implements ISourceBroadcastService
|
||||
@Autowired
|
||||
private IDeviceChannelService deviceChannelService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Override
|
||||
public AudioTalkResult startBroadcast(CommonGBChannel channel) {
|
||||
Device device = deviceService.getDevice(channel.getDataDeviceId());
|
||||
@ -79,14 +68,9 @@ public class SourceBroadcastServiceForGbImpl implements ISourceBroadcastService
|
||||
}
|
||||
AudioBroadcastResult abResult = playService.audioBroadcast(
|
||||
device.getDeviceId(), deviceChannel.getDeviceId(), false);
|
||||
MediaServer mediaServer = mediaServerService.getMediaServerForMinimumLoad(null);
|
||||
StreamContent playStream = new StreamContent(
|
||||
mediaServerService.getStreamInfoByAppAndStream(mediaServer,
|
||||
MediaStreamUtil.GB28181_TALK, abResult.getStream() + "_talk",
|
||||
null, null, null, false));
|
||||
AudioTalkResult result = new AudioTalkResult();
|
||||
result.setPushStream(abResult.getStreamInfo());
|
||||
result.setPlayStream(playStream);
|
||||
result.setPlayStream(abResult.getPlayStreamInfo());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -496,7 +496,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
if (!mediaServerItem.isRtpEnable()) {
|
||||
// 单端口暂不支持语音喊话
|
||||
log.info("[语音喊话] 单端口暂不支持此操作");
|
||||
log.warn("[语音喊话] 单端口暂不支持此操作");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
package com.genersoft.iot.vmp.vmanager.bean;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author lin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AudioBroadcastResult {
|
||||
/**
|
||||
* 推流的各个方式流地址
|
||||
@ -24,36 +29,10 @@ public class AudioBroadcastResult {
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 播放流地址(设备音频通过ZLM播放给浏览器),对讲时设置
|
||||
*/
|
||||
private StreamContent playStreamInfo;
|
||||
|
||||
public StreamContent getStreamInfo() {
|
||||
return streamInfo;
|
||||
}
|
||||
|
||||
public void setStreamInfo(StreamContent streamInfo) {
|
||||
this.streamInfo = streamInfo;
|
||||
}
|
||||
|
||||
public String getCodec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
public void setCodec(String codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void setStream(String stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,7 +355,9 @@ export default {
|
||||
|
||||
this.talkAudioRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, (s) => {
|
||||
console.warn('[ChAudioTalk] 音频播放连接状态:', s)
|
||||
if (s === 'disconnected' || s === 'failed' || s === 'closed') {
|
||||
if (s === 'connected') {
|
||||
this.playConnected = true
|
||||
} else if (s === 'disconnected' || s === 'failed' || s === 'closed') {
|
||||
this.playConnected = false
|
||||
this.talkAudioFailed = true
|
||||
if (this.talkStatus === 1) {
|
||||
|
||||
@ -51,9 +51,19 @@
|
||||
/>
|
||||
<p style="margin-top: 16px; color: #606266;">
|
||||
<span v-if="talkStatus === -2">正在释放资源</span>
|
||||
<span v-if="talkStatus === -1">点击开始{{ talkMode ? '对讲' : '喊话' }}</span>
|
||||
<span v-if="talkStatus === -1">点击开始{{ talkMode ? '喊话' : '对讲' }}</span>
|
||||
<span v-if="talkStatus === 0">等待接通中...</span>
|
||||
<span v-if="talkStatus === 1">请说话</span>
|
||||
<span v-if="talkStatus === 1 && talkMode">喊话中</span>
|
||||
<span v-if="talkStatus === 1 && !talkMode && !playConnected">等待接通中...</span>
|
||||
<span v-if="talkStatus === 1 && !talkMode && playConnected">对讲中</span>
|
||||
</p>
|
||||
<p v-if="talkStatus === 1 && !talkMode && talkAudioFailed" style="margin-top: 8px;">
|
||||
<el-button
|
||||
type="warning"
|
||||
size="mini"
|
||||
icon="el-icon-refresh"
|
||||
@click="retryTalkAudio"
|
||||
>重试音频</el-button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -129,7 +139,10 @@ export default {
|
||||
if (this.talkStatus === -2) return 'primary'
|
||||
if (this.talkStatus === -1) return 'primary'
|
||||
if (this.talkStatus === 0) return 'warning'
|
||||
if (this.talkStatus === 1) return 'danger'
|
||||
if (this.talkStatus === 1) {
|
||||
if (!this.talkMode && !this.playConnected) return 'warning'
|
||||
return 'danger'
|
||||
}
|
||||
},
|
||||
async talkButtonClick() {
|
||||
if (this.talkStatus === -1) {
|
||||
@ -145,6 +158,13 @@ export default {
|
||||
const si = data.streamInfo
|
||||
const url = document.location.protocol.includes('https') ? si.rtcs : si.rtc
|
||||
this.startWebrtcPush(url)
|
||||
|
||||
const playStreamInfo = data?.playStreamInfo
|
||||
if (!this.talkMode && playStreamInfo) {
|
||||
this.talkAudioPlayStream = playStreamInfo
|
||||
this.startTalkAudioPlay(playStreamInfo)
|
||||
this.muteVideoPlayer()
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message({ showClose: true, message: e, type: 'error' })
|
||||
this.talkStatus = -1
|
||||
@ -181,6 +201,105 @@ export default {
|
||||
})
|
||||
.catch(() => { this.talkStatus = -1 })
|
||||
},
|
||||
muteVideoPlayer() {
|
||||
const player = this.$refs.playerTabs
|
||||
if (!player) return
|
||||
if (player.mute) {
|
||||
player.mute()
|
||||
}
|
||||
},
|
||||
unmuteVideoPlayer() {
|
||||
const player = this.$refs.playerTabs
|
||||
if (!player) return
|
||||
if (player.cancelMute) {
|
||||
player.cancelMute()
|
||||
}
|
||||
},
|
||||
startTalkAudioPlay(playStreamInfo) {
|
||||
if (this.talkAudioRtc) {
|
||||
this.talkAudioRtc.close()
|
||||
}
|
||||
if (this.talkAudioRetryTimer) {
|
||||
clearTimeout(this.talkAudioRetryTimer)
|
||||
}
|
||||
|
||||
const url = location.protocol === 'https:' ? playStreamInfo.rtcs : playStreamInfo.rtc
|
||||
if (!url) {
|
||||
console.warn('[AudioTalk] 无可用的设备音频播放地址')
|
||||
return
|
||||
}
|
||||
this.talkAudioRetryTimer = setTimeout(() => {
|
||||
this.pollMediaInfoAndPlay(playStreamInfo)
|
||||
}, 800)
|
||||
},
|
||||
async pollMediaInfoAndPlay(playStreamInfo) {
|
||||
try {
|
||||
const data = await this.$store.dispatch('server/getMediaInfo', {
|
||||
app: playStreamInfo.app,
|
||||
stream: playStreamInfo.stream,
|
||||
mediaServerId: playStreamInfo.mediaServerId
|
||||
})
|
||||
if (data) {
|
||||
const url = location.protocol === 'https:' ? playStreamInfo.rtcs : playStreamInfo.rtc
|
||||
this.startTalkAudioByRtc(url)
|
||||
} else {
|
||||
throw new Error('no data')
|
||||
}
|
||||
} catch (e) {
|
||||
if (this.talkStatus === 1 || this.talkStatus === 0) {
|
||||
this.talkAudioRetryTimer = setTimeout(() => {
|
||||
this.pollMediaInfoAndPlay(playStreamInfo)
|
||||
}, 800)
|
||||
}
|
||||
}
|
||||
},
|
||||
startTalkAudioByRtc(url) {
|
||||
this.talkAudioFailed = false
|
||||
this.talkAudioRtc = new ZLMRTCClient.Endpoint({
|
||||
debug: false,
|
||||
element: document.getElementById('audioTalkVideo'),
|
||||
zlmsdpUrl: url,
|
||||
simulecast: false,
|
||||
useCamera: false,
|
||||
audioEnable: true,
|
||||
videoEnable: false,
|
||||
recvOnly: true,
|
||||
usedatachannel: false
|
||||
})
|
||||
|
||||
this.talkAudioRtc.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {
|
||||
console.warn('[AudioTalk] 播放流offer失败:', e?.code, e?.msg)
|
||||
if (e && e.code == -400 && e.msg == '流不存在') {
|
||||
this.talkAudioRetryTimer = setTimeout(() => {
|
||||
this.startTalkAudioByRtc(url)
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
|
||||
this.talkAudioRtc.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, () => {
|
||||
console.warn('[AudioTalk] 设备音频流到达')
|
||||
this.playConnected = true
|
||||
})
|
||||
|
||||
this.talkAudioRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, () => {
|
||||
console.error('[AudioTalk] 音频播放ICE协商失败')
|
||||
})
|
||||
|
||||
this.talkAudioRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, (s) => {
|
||||
console.warn('[AudioTalk] 音频播放连接状态:', s)
|
||||
if (s === 'connected') {
|
||||
this.playConnected = true
|
||||
} else if (s === 'disconnected' || s === 'failed' || s === 'closed') {
|
||||
this.playConnected = false
|
||||
this.talkAudioFailed = true
|
||||
if (this.talkStatus === 1) {
|
||||
this.talkAudioRetryTimer = setTimeout(() => {
|
||||
this.startTalkAudioByRtc(url)
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
async stopTalk() {
|
||||
this.talkStatus = -2
|
||||
if (this.broadcastRtc) {
|
||||
@ -198,6 +317,7 @@ export default {
|
||||
this.talkAudioFailed = false
|
||||
this.talkAudioPlayStream = null
|
||||
this.playConnected = false
|
||||
this.unmuteVideoPlayer()
|
||||
try {
|
||||
await this.$store.dispatch('play/broadcastStop', [this.deviceId, this.channelId])
|
||||
} catch (e) {
|
||||
@ -205,6 +325,11 @@ export default {
|
||||
}
|
||||
this.talkStatus = -1
|
||||
},
|
||||
retryTalkAudio() {
|
||||
if (this.talkAudioPlayStream) {
|
||||
this.startTalkAudioPlay(this.talkAudioPlayStream)
|
||||
}
|
||||
},
|
||||
close() {
|
||||
if (this.showPlayer && this.$refs.playerTabs) {
|
||||
this.$refs.playerTabs.stop()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user