Browse Source

/*完成SIP协议SUBSCIBE,NOTIFY,INVITE,ACK的逻辑*/

master
htjcAdmin 4 weeks ago
parent
commit
22fddc9cff
1 changed files with 167 additions and 7 deletions
  1. +167
    -7
      src/main/java/com/inspect/tcpserver/sip/service/SipClientService.java

+ 167
- 7
src/main/java/com/inspect/tcpserver/sip/service/SipClientService.java View File

@ -20,6 +20,7 @@ import javax.sip.message.MessageFactory;
import javax.sip.message.Request; import javax.sip.message.Request;
import javax.sip.message.Response; import javax.sip.message.Response;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.*; import java.net.*;
@ -777,6 +778,14 @@ public class SipClientService implements SipListener {
return; return;
} }
// 200 OK -> SIP Server
ServerTransaction st = requestEvent.getServerTransaction();
if (st == null) {
st = sipProvider.getNewServerTransaction(request);
}
Response ok = messageFactory.createResponse(Response.OK, request);
st.sendResponse(ok);
SipXmlEnvelope<?> envelope = SipXmlParser.parse(xml, itemClass); SipXmlEnvelope<?> envelope = SipXmlParser.parse(xml, itemClass);
//handleSipEvent(envelope); //handleSipEvent(envelope);
} }
@ -804,20 +813,29 @@ public class SipClientService implements SipListener {
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(ExpiresHeader.NAME); ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(ExpiresHeader.NAME);
int expires = (expiresHeader != null) ? expiresHeader.getExpires() : 0; int expires = (expiresHeader != null) ? expiresHeader.getExpires() : 0;
log.info("Received SUBSCRIBE expires: {}, XML:\n{}", expires, xml); log.info("Received SUBSCRIBE expires: {}, XML:\n{}", expires, xml);
String eventType = SipXmlParser.peekEventType(xml);
log.info("SUBSCRIBE EventType: {}", eventType);
ServerTransaction transaction = sipProvider.getNewServerTransaction(request); ServerTransaction transaction = sipProvider.getNewServerTransaction(request);
// 对应协议B.9.1.2 F2 前端系统返回200 OK响应指示已经接受订阅请求
Response response = messageFactory.createResponse(Response.OK, request); Response response = messageFactory.createResponse(Response.OK, request);
response.setExpires(expiresHeader); response.setExpires(expiresHeader);
transaction.sendResponse(response); transaction.sendResponse(response);
if (expires > 0) { if (expires > 0) {
saveSubscription(request, expires); saveSubscription(request, expires);
// 对应协议B.9.1.2 F3 SIP客户端(前端系统)发送没有消息体的NOTIFY给平台其中Subscription-State头部字段值为active, 指示订阅关系建立
sendInitialNotify(request, transaction, "initial"); sendInitialNotify(request, transaction, "initial");
} else { } else {
removeSubscription(request); removeSubscription(request);
} }
} else if (Request.INVITE.equals(request.getMethod())) {
handleInvite(requestEvent);
} else if(Request.ACK.equals(request.getMethod())) {
// RFC 3261: The ACK request does not generate a response.
// ACK 事务内请求不是普通 SIP 方法,不生成任何 Response,ACK 事务内请求不是普通 SIP 方法
startRtspToRtp();
} }
else { else {
Response notImpl = messageFactory.createResponse(Response.NOT_IMPLEMENTED, request); Response notImpl = messageFactory.createResponse(Response.NOT_IMPLEMENTED, request);
requestEvent.getServerTransaction().sendResponse(notImpl); requestEvent.getServerTransaction().sendResponse(notImpl);
log.info("Method {} not implemented, replied 501", method); log.info("Method {} not implemented, replied 501", method);
@ -833,6 +851,100 @@ public class SipClientService implements SipListener {
} }
} }
private Process ffmpegProcess;
private void startRtspToRtp() {
try {
String cmd =
"ffmpeg -rtsp_transport tcp " +
"-i \"rtsp://admin:wd19216811@192.168.1.244:554/h264/ch1/sub/av_stream\" " +
"-an -vcodec copy " +
"-f rtp -payload_type 96 " +
"\"rtp://192.168.1.116:50000?tcp\"";
ProcessBuilder pb = new ProcessBuilder(
"bash", "-c", cmd
);
pb.redirectErrorStream(true);
ffmpegProcess = pb.start();
new Thread(() -> {
try (BufferedReader br =
new BufferedReader(new InputStreamReader(
ffmpegProcess.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println("[FFmpeg] " + line);
}
} catch (IOException ignored) {}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
private void handleInvite(RequestEvent requestEvent) throws Exception {
Request request = requestEvent.getRequest();
log.info("Received INVITE:\n{}", request);
SipProvider provider = (SipProvider) requestEvent.getSource();
ServerTransaction st = requestEvent.getServerTransaction();
if (st == null) {
st = provider.getNewServerTransaction(request);
}
// 100 Trying非常推荐
Response trying = messageFactory.createResponse(Response.TRYING, request);
st.sendResponse(trying);
// 解析对方 SDP可先只打印
byte[] raw = request.getRawContent();
if (raw != null) {
String sdp = new String(raw, StandardCharsets.UTF_8);
log.info("INVITE SDP:\n{}", sdp);
}
// 构造 200 OK + SDP
Response ok = messageFactory.createResponse(Response.OK, request);
String localSipId = "29001002120107000001";
int localRtpPort = 554;
// Contact 必须
Address contactAddress = addressFactory.createAddress(
"sip:" + localSipId + "@" + localIp + ":" + localPort
);
ContactHeader contactHeader = headerFactory.createContactHeader(contactAddress);
ok.addHeader(contactHeader);
// Content-Type
ContentTypeHeader contentType =
headerFactory.createContentTypeHeader("application", "sdp");
// 返回 SDP示例
String sdp =
"v=0\r\n" +
"o=" + localSipId + " 0 0 IN IP4 " + localIp + "\r\n" +
"s=Play\r\n" +
"c=IN IP4 " + localIp + "\r\n" +
"t=0 0\r\n" +
"m=video " + localRtpPort + " TCP/RTP/AVP 96\r\n" +
"a=sendonly\r\n" +
"a=setup:active\r\n" +
"a=connection:new\r\n" +
"a=rtpmap:96 PS/90000\r\n";
ok.setContent(sdp, contentType);
// 发送 200 OK
st.sendResponse(ok);
log.info("INVITE handled: 200 OK sent");
}
@Override @Override
public void processTimeout(TimeoutEvent timeoutEvent) { public void processTimeout(TimeoutEvent timeoutEvent) {
log.warn("SIP timeout: {}", timeoutEvent); log.warn("SIP timeout: {}", timeoutEvent);
@ -977,12 +1089,12 @@ public class SipClientService implements SipListener {
notifyRequest.addHeader(ssHeader); notifyRequest.addHeader(ssHeader);
// 消息体 // 消息体
String xmlBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<SIP_XML>\n" +
" <Type>" + bodyText + "</Type>\n" +
"</SIP_XML>";
ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("application", "xml");
notifyRequest.setContent(xmlBody, contentTypeHeader);
// String xmlBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
// "<SIP_XML>\n" +
// " <Type>" + bodyText + "</Type>\n" +
// "</SIP_XML>";
// ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("application", "xml");
// notifyRequest.setContent(xmlBody, contentTypeHeader);
// 发送 // 发送
ClientTransaction ct = sipProvider.getNewClientTransaction(notifyRequest); ClientTransaction ct = sipProvider.getNewClientTransaction(notifyRequest);
@ -995,6 +1107,54 @@ public class SipClientService implements SipListener {
} }
} }
private void sendSubscribeNotifyToSipServer(Request subscribeRequest) {
try {
// 获取必要头字段
CallIdHeader callIdHeader = (CallIdHeader) subscribeRequest.getHeader(CallIdHeader.NAME);
CSeqHeader cseqHeader = (CSeqHeader) subscribeRequest.getHeader(CSeqHeader.NAME);
FromHeader fromHeader = (FromHeader) subscribeRequest.getHeader(FromHeader.NAME);
ToHeader toHeader = (ToHeader) subscribeRequest.getHeader(ToHeader.NAME);
EventHeader eventHeader = (EventHeader) subscribeRequest.getHeader(EventHeader.NAME);
ContactHeader contactHeader = (ContactHeader) subscribeRequest.getHeader(ContactHeader.NAME);
List<ViaHeader> viaHeaders = new ArrayList<>();
ViaHeader viaHeader = headerFactory.createViaHeader(localIp, localPort, transport.toUpperCase(), null);
viaHeaders.add(viaHeader);
// 创建 NOTIFY 请求
Request notifyRequest = messageFactory.createRequest(
subscribeRequest.getRequestURI(),
Request.NOTIFY,
callIdHeader,
headerFactory.createCSeqHeader(cseqHeader.getSeqNumber() + 1, Request.NOTIFY),
fromHeader,
toHeader,
viaHeaders,
headerFactory.createMaxForwardsHeader(70)
);
// 加入 Contact
notifyRequest.addHeader(contactHeader);
// 必须的事件头
notifyRequest.addHeader(eventHeader);
// Subscription-State
SubscriptionStateHeader ssHeader = headerFactory.createSubscriptionStateHeader("active");
ssHeader.setExpires(3600);
notifyRequest.addHeader(ssHeader);
ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("application", "xml");
notifyRequest.setContent(null, contentTypeHeader);
// 发送
ClientTransaction ct = sipProvider.getNewClientTransaction(notifyRequest);
ct.sendRequest();
log.info("sendSubscribeNotifyToSipServer: callId: {}", callIdHeader.getCallId());
} catch (Exception e) {
e.printStackTrace();
}
}
private void removeSubscription(Request request) { private void removeSubscription(Request request) {
CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);


Loading…
Cancel
Save