-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathv1.go
240 lines (207 loc) · 6.75 KB
/
v1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
package main
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"net"
"path/filepath"
"strings"
)
func v1getFilePathForCodePair(modemMode spkModemMode, voiceID spkVoiceID, codePair string) string {
dir := "voices/v1/"
switch voiceID {
default:
dir += "srf-male-en"
case SPK_VOICE_ID_FEMALE_EN:
dir += "srf-female-en"
}
switch modemMode {
case SPK_MODEM_MODE_DMR, SPK_MODEM_MODE_C4FM, SPK_MODEM_MODE_C4FM_HALF_DEVIATION, SPK_MODEM_MODE_NXDN:
dir += "/dmr/"
case SPK_MODEM_MODE_DSTAR:
dir += "/dstar/"
case SPK_MODEM_MODE_P25:
dir += "/p25/"
default:
return ""
}
for filePath := range _bindata {
if filepath.Dir(filePath) != filepath.Clean(dir) || filepath.Ext(filePath) != ".ambe" {
continue
}
fileName := filepath.Base(filePath)
// The requested code pair is stored in the first two characters of the filename.
var fileCodePair = string(fileName[0]) + string(fileName[1])
if fileCodePair == codePair {
return filePath
}
}
return ""
}
func v1StartSendAnswer(udpConn *net.UDPConn, toAddr net.UDPAddr, rp *spkRequestPacketv1) {
defer RequestRemove(rp.SessionID, &toAddr)
codeStr := strings.TrimRight(string(rp.CodeStr[:]), "\x00")
// If the client is requesting a connect announce to a Homebrew server, we try to query a BM status from
// the server's BM HTTP API to get linked talkgroups and reflector.
bmGetClientDataFinished := make(chan bool)
defer close(bmGetClientDataFinished)
bmGetClientDataRunning := false
var bmGetClientDataResult bmClientData
var serverData bmServerData
if rp.ConnectorID == SPK_CONNECTOR_ID_HOMEBREW &&
(rp.AnnounceType == SPK_ANNOUNCE_TYPE_CONNECTED || rp.AnnounceType == SPK_ANNOUNCE_TYPE_CONNECTED_BRANDMEISTER_SHORTENED ||
rp.AnnounceType == SPK_ANNOUNCE_TYPE_CONNECTOR_STATUS) {
serverIP := fmt.Sprintf("%d.%d.%d.%d", rp.AnnounceTypeData[0]>>24, (rp.AnnounceTypeData[0]>>16)&0xff,
(rp.AnnounceTypeData[0]>>8)&0xff, rp.AnnounceTypeData[0]&0xff)
var ok bool
if serverData, ok = BMGetServerDataForServerIP(serverIP); ok {
clientId := rp.AnnounceTypeData[1]
log.Printf("getting bm client data srv:%s cid:%d", serverIP, clientId)
bmGetClientDataRunning = true
go BMGetClientData(clientId, &bmGetClientDataResult, bmGetClientDataFinished)
}
}
var res spkResponsePacket
switch rp.ModemMode {
default:
copy(res.AMBE.Magic[:], SPK_PACKET_MAGIC)
res.AMBE.Version = 1
res.AMBE.PacketType = SPK_PACKET_TYPE_AMBE_RESPONSE
res.AMBE.SessionID = rp.SessionID
case SPK_MODEM_MODE_P25:
copy(res.IMBE.Magic[:], SPK_PACKET_MAGIC)
res.IMBE.Version = 1
res.IMBE.PacketType = SPK_PACKET_TYPE_IMBE_RESPONSE
res.IMBE.SessionID = rp.SessionID
}
// Stepping through each code char pair.
for codeStrPos := 0; codeStrPos < len(codeStr); codeStrPos += 2 {
if bmGetClientDataRunning {
select {
case finished := <-bmGetClientDataFinished:
if finished && codeStrPos < 4 {
toReplace := "HBSV"
if strings.Contains(codeStr, "BMSV") {
toReplace = "BMSV"
}
codeStr = strings.Replace(codeStr, toReplace, BMGenerateCodeStrFromClientData(&bmGetClientDataResult, &serverData,
rp.AnnounceType == SPK_ANNOUNCE_TYPE_CONNECTED_BRANDMEISTER_SHORTENED), 1)
log.Printf("code str modified for %s to %s", toAddr.String(), codeStr)
bmGetClientDataRunning = false
}
default:
break
}
}
if codeStrPos+2 > len(codeStr) {
log.Println("warning: last code pair is broken")
break
}
var codePair = codeStr[codeStrPos : codeStrPos+2]
filePath := v1getFilePathForCodePair(rp.ModemMode, rp.VoiceID, codePair)
if filePath == "" {
log.Printf("warning: file not found for modem mode %d code pair \"%s\", skipping\n", rp.ModemMode, codePair)
continue
}
data, err := Asset(filePath)
if err != nil {
log.Printf("warning: can't find \"%s\", skipping\n", filePath)
continue
}
log.Printf("playing %s to %s\n", filePath, toAddr.String())
reader := bytes.NewReader(data)
var fileFinished = false
// Filling up frames from the file.
for !fileFinished {
switch rp.ModemMode {
default:
for ; res.AMBE.FrameCount < 3; res.AMBE.FrameCount++ {
readBytes, err := reader.Read(res.AMBE.Frames[res.AMBE.FrameCount][:])
if err != nil || readBytes != 9 {
fileFinished = true
break
}
}
// Flushing if needed.
if res.AMBE.FrameCount == 3 {
sendAMBEAnswer(udpConn, &toAddr, &res.AMBE)
res.AMBE.FrameCount = 0
}
case SPK_MODEM_MODE_P25:
for ; res.IMBE.FrameCount < 3; res.IMBE.FrameCount++ {
readBytes, err := reader.Read(res.IMBE.Frames[res.IMBE.FrameCount][:])
if err != nil || readBytes != 18 {
fileFinished = true
break
}
}
// Flushing if needed.
if res.IMBE.FrameCount == 3 {
sendIMBEAnswer(udpConn, &toAddr, &res.IMBE)
res.IMBE.FrameCount = 0
}
}
}
}
switch rp.ModemMode {
default:
res.AMBE.PacketType = SPK_PACKET_TYPE_RESPONSE_TERMINATOR
sendAMBEAnswer(udpConn, &toAddr, &res.AMBE)
case SPK_MODEM_MODE_P25:
res.IMBE.PacketType = SPK_PACKET_TYPE_RESPONSE_TERMINATOR
sendIMBEAnswer(udpConn, &toAddr, &res.IMBE)
}
if bmGetClientDataRunning {
<-bmGetClientDataFinished
}
log.Printf("playing to %s finished\n", toAddr.String())
}
func v1processPacket(udpConn *net.UDPConn, fromAddr *net.UDPAddr, buffer []byte, readBytes int) {
var packetType = buffer[7]
switch packetType {
default:
log.Printf("ignoring packet with type 0x%.2x\n", packetType)
case SPK_PACKET_TYPE_REQUEST:
if readBytes != SPK_REQUEST_PACKET_V1_SIZE {
log.Printf("ignoring packet with size %d\n", readBytes)
return
}
// Reading the packet payload to our request struct.
readBuf := bytes.NewReader(buffer)
var rp spkRequestPacketv1
err := binary.Read(readBuf, binary.BigEndian, &rp)
if err != nil {
log.Println("ignoring packet, binary parse error: ", err)
return
}
switch rp.ModemMode {
case SPK_MODEM_MODE_DMR:
break
case SPK_MODEM_MODE_DSTAR:
break
case SPK_MODEM_MODE_C4FM:
break
case SPK_MODEM_MODE_C4FM_HALF_DEVIATION:
break
case SPK_MODEM_MODE_NXDN:
break
case SPK_MODEM_MODE_P25:
break
default:
log.Printf("ignoring packet, invalid modem mode %.2x\n", rp.ModemMode)
return
}
rp.CodeStr[SPK_ANNOUNCE_DATA_MAX_LENGTH-1] = 0
if RequestIsAdded(rp.SessionID, fromAddr) {
//log.Printf("ignoring packet, request already under processing with sid:0x%.8x\n", rp.SessionID)
return
}
RequestAdd(rp.SessionID, fromAddr)
atStr, atdStr := decodeAnnounceTypeAndDataToStr(rp.AnnounceType, rp.AnnounceTypeData)
log.Printf("sending \"%s\" to %s (sid:0x%.8x t:%s con:%s at:%s %s)\n",
strings.TrimRight(string(rp.CodeStr[:]), "\x00"), fromAddr.String(), rp.SessionID, getModemModeNameStr(rp.ModemMode),
getConnectorIdNameStr(rp.ConnectorID), atStr, atdStr)
go v1StartSendAnswer(udpConn, *fromAddr, &rp)
}
}