From a1a6c6d7ef01a40f902f1f7d0f90f082a2d90d46 Mon Sep 17 00:00:00 2001 From: cheetah Date: Mon, 11 Sep 2023 22:46:10 +0000 Subject: [PATCH] fixed RTP/CMoIP streaming --- common/reginfo.go | 1 + common/rtpenums.go | 21 ++++++++++ common/terminalClient.go | 49 ++++++++++++++++++++++ common/terminalMessage.go | 7 +--- common/terminalMessageResponse.go | 15 +++++++ common/tmkind/tmkind.go | 56 +++++++++++++------------ main.go | 70 ++++++++++++++++++++++++++----- 7 files changed, 177 insertions(+), 42 deletions(-) create mode 100644 common/rtpenums.go diff --git a/common/reginfo.go b/common/reginfo.go index 5a6a628..cc3eef2 100644 --- a/common/reginfo.go +++ b/common/reginfo.go @@ -10,5 +10,6 @@ type RegistrationInfo struct { CallCount byte StreamCount byte RoamingRef uint32 + Description string RTPPorts []uint16 } diff --git a/common/rtpenums.go b/common/rtpenums.go new file mode 100644 index 0000000..01ee429 --- /dev/null +++ b/common/rtpenums.go @@ -0,0 +1,21 @@ +package common + +type TetraFlexCMoIPPayload byte + +const ( + TetraFlexCMoIPPayload_None TetraFlexCMoIPPayload = 0 + TetraFlexCMoIPPayload_Tetra_STCH_U TetraFlexCMoIPPayload = 1 + TetraFlexCMoIPPayload_Tetra_TCH_S TetraFlexCMoIPPayload = 2 + TetraFlexCMoIPPayload_Tetra_TCH_7_2 TetraFlexCMoIPPayload = 3 + TetraFlexCMoIPPayload_Tetra_TCH_4_8 TetraFlexCMoIPPayload = 4 + TetraFlexCMoIPPayload_Tetra_TCH_2_4 TetraFlexCMoIPPayload = 5 + TetraFlexCMoIPPayload_aLaw TetraFlexCMoIPPayload = 7 + TetraFlexCMoIPPayload_uLaw TetraFlexCMoIPPayload = 8 +) + +type TetraFlexRTPPayload byte + +const ( + TetraFlexRTPPayload_uLaw TetraFlexRTPPayload = 0 + TetraFlexRTPPayload_aLaw TetraFlexRTPPayload = 8 +) diff --git a/common/terminalClient.go b/common/terminalClient.go index 4eb3d68..e52826b 100644 --- a/common/terminalClient.go +++ b/common/terminalClient.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "net" + "strings" "git.cheetah.cat/cheetah/opentetraflex-go/common/tmkind" ) @@ -24,6 +25,8 @@ type TerminalClient struct { GroupConfig []GroupConfig RegistrationInfo RegistrationInfo + + udpRTP_TX *net.UDPConn } func NewTerminalClient(address string) (tc *TerminalClient) { @@ -184,6 +187,26 @@ func (tc *TerminalClient) CallConnect(callRef byte) (err error) { return nil } +func (tc *TerminalClient) CallStreamRequest(uint1 uint, callRef byte, streamRef byte, audioChannelType TetraFlexAudioChannelTypes) (err error) { + tfStreamReq, err := NewTMIpApiCallStreamRequest(uint1, callRef, streamRef, audioChannelType) + if err != nil { + return nil + } + fmt.Println(hex.EncodeToString(tfStreamReq.Encode())) + tc.HandlerMap[tfStreamReq.handler] = make(chan HandlerResponse) + + //fmt.Println(hex.EncodeToString(tfAuthReq.Encode())) + err = tc.Send(tfStreamReq) + if err != nil { + return err + } + response := <-tc.HandlerMap[tfStreamReq.handler] + if !response.Success { + return response.Error + } + + return nil +} func (tc *TerminalClient) PTTRequest(callRef byte, identityInfo TetraFlexIdentityInfo, octaStateByte byte) (err error) { // IpApiCallPttRequest tfPTTRequest, err := NewTMIpApiCallPTTRequest(callRef, identityInfo, octaStateByte) @@ -226,6 +249,32 @@ func (tc *TerminalClient) PTTRelease(callRef byte) (err error) { return nil } +func (tc *TerminalClient) RTPConnect() (err error) { + portNum := tc.RegistrationInfo.RTPPorts[0] + localAddress, _ := net.ResolveUDPAddr("udp", fmt.Sprintf("0.0.0.0:%d", portNum)) + + parts := strings.Split(tc.address, ":") + remoteTXAddr := fmt.Sprintf("%s:%d", parts[0], portNum) + remoteAddress, _ := net.ResolveUDPAddr("udp", remoteTXAddr) + + tc.udpRTP_TX, err = net.DialUDP("udp", localAddress, remoteAddress) + if err != nil { + return err + } + return nil +} +func (tc *TerminalClient) RTPSend(data []byte) (err error) { + //parts := strings.Split(tc.address, ":") + //remoteTXAddr := fmt.Sprintf("%s:%d", parts[0], tc.RegistrationInfo.RTPPorts[0]) + //remoteAddress, _ := net.ResolveUDPAddr("udp", remoteTXAddr) + + _, err = tc.udpRTP_TX.Write(data) //WriteToUDP(data, remoteAddress) + if err != nil { + return err + } + return nil +} + /* groupAddr := common.NewAddressFromSSINumber(103) identityNum := common.NewAddressFromSSINumber(1007) diff --git a/common/terminalMessage.go b/common/terminalMessage.go index 3524085..f868dd9 100644 --- a/common/terminalMessage.go +++ b/common/terminalMessage.go @@ -37,11 +37,11 @@ func NewTerminalMessage(length uint16, kind tmkind.TetraFlexTerminalMessageKinds return tm, nil } +// Write Functions func (tm *TerminalMessage) WriteShort(data uint16) (err error) { _, err = tm.data.Write(uint16ToBytes(data)) return err } - func (tm *TerminalMessage) WriteUInt(data uint32) (err error) { _, err = tm.data.Write(uint32ToBytes(data)) return err @@ -150,11 +150,9 @@ func (tm *TerminalMessage) WriteTFAddress(addr TetraFlexAddress) (err error) { //return tm.data.WriteByte(data) return nil } - func (tm *TerminalMessage) WriteIdentityInfoAddress(identityInfo TetraFlexIdentityInfo) (err error) { return tm.WriteTFAddress(identityInfo.Address) } - func (tm *TerminalMessage) WriteIdentityInfoKind(identityInfo TetraFlexIdentityInfo) (err error) { /* case TetraFlexIdentityKind.Mobile: @@ -175,16 +173,15 @@ func (tm *TerminalMessage) WriteIdentityInfoUnfied(identityInfo TetraFlexIdentit } return tm.data.WriteByte(byteVal) } - func (tm *TerminalMessage) FillZero(zeroCount uint32) (err error) { _, err = tm.data.Write(make([]byte, zeroCount)) return err } - func (tm *TerminalMessage) Encode() []byte { return tm.data.Bytes() } +// TerminalMessage Builder for PDUs func NewTMAuthReq(addr TetraFlexAddress, num uint32, randomBytes []byte, terminalTypeID byte, terminalTypeStr string, terminalVersionDate uint32, terminalVersionStr string) (tm *TerminalMessage, err error) { tfAuthReq, err := NewTerminalMessage(256, tmkind.IpApiRegistrationRequest, NextHandlerID()) if err != nil { diff --git a/common/terminalMessageResponse.go b/common/terminalMessageResponse.go index d11e35d..b2dde07 100644 --- a/common/terminalMessageResponse.go +++ b/common/terminalMessageResponse.go @@ -121,6 +121,13 @@ func (tmr *TerminalMessageResponse) readAddress() (result TetraFlexAddress, err return result, nil } +func (tmr *TerminalMessageResponse) readString(count int) (result string, err error) { + textBytes := make([]byte, count) + if _, err = tmr.data.Read(textBytes); err != nil { + return result, err + } + return string(textBytes), nil +} func (tmr *TerminalMessageResponse) AsAuthenticationChallenge() (authChallenge AuthenticationChallenge, err error) { authChallenge.RandomSeed = make([]byte, 10) @@ -181,6 +188,14 @@ func (tmr *TerminalMessageResponse) AsRegistrationInfo() (regInfo RegistrationIn if regInfo.RoamingRef, err = tmr.readUInt32(); err != nil { return regInfo, err } + + if regInfo.Description, err = tmr.readString(64); err != nil { + return regInfo, err + } + + if err != nil { + return regInfo, err + } if regInfo.RemoteVersion > 20120702 { port1, err := tmr.readUInt16() if err != nil { diff --git a/common/tmkind/tmkind.go b/common/tmkind/tmkind.go index 4a856bd..a600bb6 100644 --- a/common/tmkind/tmkind.go +++ b/common/tmkind/tmkind.go @@ -3,23 +3,24 @@ package tmkind type TetraFlexTerminalMessageKinds uint16 const ( - NONE TetraFlexTerminalMessageKinds = 0 - IpApiGeneralConfirm TetraFlexTerminalMessageKinds = 1 - IpApiRegistrationRequest TetraFlexTerminalMessageKinds = 273 - IpApiRegistrationConfirm TetraFlexTerminalMessageKinds = 274 - IpApiAuthenticationChallenge TetraFlexTerminalMessageKinds = 529 - IpApiAuthenticationResponse TetraFlexTerminalMessageKinds = 530 - IpApiNotificationRequest TetraFlexTerminalMessageKinds = 785 - IpApiNotificationConfirm TetraFlexTerminalMessageKinds = 786 - IpApiGroupAttachRequest TetraFlexTerminalMessageKinds = 1041 - IpApiGroupAttachConfirm TetraFlexTerminalMessageKinds = 1042 - IpApiDeregistrationRequest TetraFlexTerminalMessageKinds = 1297 - IpApiKeepAliveChallenge TetraFlexTerminalMessageKinds = 1553 - IpApiKeepAliveResponse TetraFlexTerminalMessageKinds = 1554 - IpApiSubscriberInfoRequest TetraFlexTerminalMessageKinds = 1809 - IpApiSubscriberInfoConfirm TetraFlexTerminalMessageKinds = 1810 - IpApiSoftwareInfoRequest TetraFlexTerminalMessageKinds = 2065 - IpApiSoftwareInfoConfirm TetraFlexTerminalMessageKinds = 2066 + NONE TetraFlexTerminalMessageKinds = 0 + IpApiGeneralConfirm TetraFlexTerminalMessageKinds = 1 + IpApiRegistrationRequest TetraFlexTerminalMessageKinds = 273 + IpApiRegistrationConfirm TetraFlexTerminalMessageKinds = 274 + IpApiAuthenticationChallenge TetraFlexTerminalMessageKinds = 529 + IpApiAuthenticationResponse TetraFlexTerminalMessageKinds = 530 + IpApiNotificationRequest TetraFlexTerminalMessageKinds = 785 + IpApiNotificationConfirm TetraFlexTerminalMessageKinds = 786 + IpApiGroupAttachRequest TetraFlexTerminalMessageKinds = 1041 + IpApiGroupAttachConfirm TetraFlexTerminalMessageKinds = 1042 + IpApiDeregistrationRequest TetraFlexTerminalMessageKinds = 1297 + IpApiKeepAliveChallenge TetraFlexTerminalMessageKinds = 1553 + IpApiKeepAliveResponse TetraFlexTerminalMessageKinds = 1554 + IpApiSubscriberInfoRequest TetraFlexTerminalMessageKinds = 1809 + IpApiSubscriberInfoConfirm TetraFlexTerminalMessageKinds = 1810 + IpApiSoftwareInfoRequest TetraFlexTerminalMessageKinds = 2065 + IpApiSoftwareInfoConfirm TetraFlexTerminalMessageKinds = 2066 + IpApiCallSetupRequest TetraFlexTerminalMessageKinds = 4369 IpApiCallSetupConfirm TetraFlexTerminalMessageKinds = 4370 IpApiCallConnectRequest TetraFlexTerminalMessageKinds = 4625 @@ -28,14 +29,15 @@ const ( IpApiCallStreamRequest TetraFlexTerminalMessageKinds = 5393 IpApiCallUpdateNotification TetraFlexTerminalMessageKinds = 5649 IpApiCallRoamingFinishedNotification TetraFlexTerminalMessageKinds = 5905 - IpApiSdsDataType4Request TetraFlexTerminalMessageKinds = 9233 - IpApiSdsStatusRequest TetraFlexTerminalMessageKinds = 9489 - IpApiSdsTlTransferRequest TetraFlexTerminalMessageKinds = 9745 - IpApiSdsTlReportRequest TetraFlexTerminalMessageKinds = 10001 - IpApiSdsTlShortReportRequest TetraFlexTerminalMessageKinds = 10257 - IpApiSdsDataType4Notification TetraFlexTerminalMessageKinds = 13329 - IpApiSdsStatusNotification TetraFlexTerminalMessageKinds = 13585 - IpApiSdsTlTransferNotification TetraFlexTerminalMessageKinds = 13841 - IpApiSdsTlReportNotification TetraFlexTerminalMessageKinds = 14097 - IpApiSdsTlShortReportNotification TetraFlexTerminalMessageKinds = 14353 + + IpApiSdsDataType4Request TetraFlexTerminalMessageKinds = 9233 + IpApiSdsStatusRequest TetraFlexTerminalMessageKinds = 9489 + IpApiSdsTlTransferRequest TetraFlexTerminalMessageKinds = 9745 + IpApiSdsTlReportRequest TetraFlexTerminalMessageKinds = 10001 + IpApiSdsTlShortReportRequest TetraFlexTerminalMessageKinds = 10257 + IpApiSdsDataType4Notification TetraFlexTerminalMessageKinds = 13329 + IpApiSdsStatusNotification TetraFlexTerminalMessageKinds = 13585 + IpApiSdsTlTransferNotification TetraFlexTerminalMessageKinds = 13841 + IpApiSdsTlReportNotification TetraFlexTerminalMessageKinds = 14097 + IpApiSdsTlShortReportNotification TetraFlexTerminalMessageKinds = 14353 ) diff --git a/main.go b/main.go index 5d011c4..5bd0911 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,13 @@ package main import ( + "bufio" "encoding/hex" "encoding/json" "fmt" "math/rand" + "os" + "strings" "time" "git.cheetah.cat/cheetah/opentetraflex-go/common" @@ -26,7 +29,7 @@ func main() { // myAddr := common.TetraFlexAddress{ Kind: common.UserNo, - UserNo: "1005", + UserNo: "9400001", } err = terminalClient.Authenticate(myAddr) if err != nil { @@ -69,19 +72,17 @@ func main() { } fmt.Println("Groups attached") go func() { - fmt.Println("Test started, waiting 3s") - time.Sleep(3 * time.Second) groupAddr := common.NewAddressFromSSINumber(101) fmt.Println("Test callSetup") callRef, err := terminalClient.CallSetup(*groupAddr, common.CallTypeGroup, common.CallPriorityDefault, false, common.TetraFlexIdentityInfo{ - Description: "Blaa", + Description: "2m/FM Gateway SWM", /* Kind: common.IdentityKindApplication, Address: *common.NewAddressFromSSINumber(1002), UnifiedSSIKinds: common.UnifiedKindExternalNumber, */ Kind: common.IdentityKindTerminal, - Address: *common.NewAddressFromSSINumber(1002), + Address: *common.NewAddressFromSSINumber(9400001), UnifiedSSIKinds: common.UnifiedKindPersonalNumber, }) if err != nil { @@ -89,6 +90,11 @@ func main() { } fmt.Printf("callRef=%d\n", callRef) + err = terminalClient.CallStreamRequest(0, callRef, 0, common.AudioChannel_CMoIP_Tetra) // CMoIP_aLaw + if err != nil { + panic(err) + } + // IpApiCallStreamRequest err = terminalClient.PTTRequest(callRef, common.TetraFlexIdentityInfo{ Description: "Blaa", @@ -104,18 +110,62 @@ func main() { if err != nil { panic(err) } - time.Sleep(3 * time.Second) - // PTT Release - err = terminalClient.PTTRelease(callRef) + time.Sleep(1 * time.Second) + + // Connect RTP + err = terminalClient.RTPConnect() if err != nil { panic(err) } - time.Sleep(3 * time.Second) - err = terminalClient.CallDisconnect(callRef, common.DisconnectReason_CallRejectedByCalled) + file, err := os.Open("./test.tetra.txt") if err != nil { panic(err) } + defer file.Close() + + scanner := bufio.NewScanner(file) + var counter byte = 0 + var voiceArray [][]byte + for scanner.Scan() { + hexData := scanner.Text() + hexData = strings.Trim(hexData, " ") + byteData, _ := hex.DecodeString(hexData) + fmt.Println(hexData) + voiceArray = append(voiceArray, byteData) + } + for { + for _, byteData := range voiceArray { + fmt.Println(byteData) + byteData[8] = counter + err = terminalClient.RTPSend(byteData) + if err != nil { + panic(err) + } + + if counter == 255 { + counter = 128 + } else { + counter++ + } + time.Sleep(20 * time.Millisecond) + } + } + /* + time.Sleep(3 * time.Second) + // PTT Release + err = terminalClient.PTTRelease(callRef) + if err != nil { + panic(err) + } + time.Sleep(3 * time.Second) + + err = terminalClient.CallDisconnect(callRef, common.DisconnectReason_CallRejectedByCalled) + if err != nil { + panic(err) + } + + */ // IpApiCallPttRequest }() // idk send help xD