sip-lab 1.32.0 → 1.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/binding.gyp +1 -0
- package/build_deps.sh +3 -1
- package/package.json +1 -1
- package/prebuilds/linux-x64/node.abi102.node +0 -0
- package/prebuilds/linux-x64/node.abi108.node +0 -0
- package/prebuilds/linux-x64/node.abi111.node +0 -0
- package/prebuilds/linux-x64/node.abi115.node +0 -0
- package/prebuilds/linux-x64/node.abi120.node +0 -0
- package/prebuilds/linux-x64/node.abi88.node +0 -0
- package/prebuilds/linux-x64/node.abi93.node +0 -0
- package/samples/100_calls.js +6 -4
- package/samples/g729.js +20 -0
- package/samples/opus.narrowband.js +236 -0
- package/samples/{send_and_receive_bfsk.js.future → send_and_receive_bfsk.js} +24 -27
- package/samples/stop_with_cleanup.js +8 -1
- package/src/pjmedia/include/pjmedia/bfsk_det2.h +23 -0
- package/src/pjmedia/src/pjmedia/bfsk_det.c +124 -131
- package/src/pjmedia/src/pjmedia/bfsk_det2.c +226 -0
- package/src/pjmedia/src/pjmedia/ws_speech_port.cpp +16 -1
- package/src/sip.cpp +25 -2
- /package/samples_extra/{ws_speech_server.start_bfsk_detection.js.future → ws_speech_server.start_bfsk_detection.js} +0 -0
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ It uses pjproject for SIP and media processing.
|
|
|
8
8
|
It permits to:
|
|
9
9
|
- make audio calls using UDP, TCP and TLS transports
|
|
10
10
|
- send/receive DTMF inband/RFC2833/INFO.
|
|
11
|
+
- send/receive [BFSK](https://en.wikipedia.org/wiki/Frequency-shift_keying) bits.
|
|
11
12
|
- play/record audio on a call from/to a wav file
|
|
12
13
|
- send/receive fax (T.30 only)
|
|
13
14
|
- send/receive MRCPv2 messages (TCP only, no TLS)
|
|
@@ -87,4 +88,8 @@ Although the code in written in *.cpp/*.hpp named files, this is not actually a
|
|
|
87
88
|
|
|
88
89
|
It is mostly written in C using some C++ facilities.
|
|
89
90
|
|
|
91
|
+
### Release Notes
|
|
92
|
+
|
|
93
|
+
[ReleaseNotes](https://github.com/MayamaTakeshi/sip-lab/blob/master/RELEASE_NOTES.md)
|
|
94
|
+
|
|
90
95
|
|
package/binding.gyp
CHANGED
|
@@ -120,6 +120,7 @@
|
|
|
120
120
|
'src/addon.cpp',
|
|
121
121
|
'src/pjmedia/src/pjmedia/dtmfdet.c',
|
|
122
122
|
'src/pjmedia/src/pjmedia/bfsk_det.c',
|
|
123
|
+
'src/pjmedia/src/pjmedia/bfsk_det2.c',
|
|
123
124
|
'src/pjmedia/src/pjmedia/fax_port.c',
|
|
124
125
|
'src/pjmedia/src/pjmedia/flite_port.c',
|
|
125
126
|
'src/pjmedia/src/pjmedia/pocketsphinx_port.c',
|
package/build_deps.sh
CHANGED
|
@@ -39,7 +39,7 @@ then
|
|
|
39
39
|
git clone https://github.com/MayamaTakeshi/bcg729
|
|
40
40
|
cd bcg729
|
|
41
41
|
git checkout faaa895862165acde6df8add722ba4f85a25007d
|
|
42
|
-
cmake .
|
|
42
|
+
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .
|
|
43
43
|
make
|
|
44
44
|
mkdir -p lib
|
|
45
45
|
cp -f src/libbcg729.a lib
|
|
@@ -70,6 +70,8 @@ EOF
|
|
|
70
70
|
#define PJSUA_MAX_ACC (20000)
|
|
71
71
|
#define PJ_IOQUEUE_MAX_HANDLES (1024)
|
|
72
72
|
#define PJSUA_MAX_CALLS (20000)
|
|
73
|
+
|
|
74
|
+
#define PJMEDIA_HAS_OPUS_CODEC 1
|
|
73
75
|
EOF
|
|
74
76
|
make dep && make clean && make
|
|
75
77
|
fi
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/samples/100_calls.js
CHANGED
|
@@ -80,6 +80,11 @@ async function test() {
|
|
|
80
80
|
|
|
81
81
|
await z.wait(events, 50000)
|
|
82
82
|
|
|
83
|
+
ocs.forEach(oc => {
|
|
84
|
+
sip.call.start_inband_dtmf_detection(oc.id)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// first send RFC2833 DTMF digits
|
|
83
88
|
ocs.forEach(oc => {
|
|
84
89
|
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
|
|
85
90
|
})
|
|
@@ -92,10 +97,7 @@ async function test() {
|
|
|
92
97
|
media_id: 0,
|
|
93
98
|
})).value(), 50000)
|
|
94
99
|
|
|
95
|
-
|
|
96
|
-
sip.call.start_inband_dtmf_detection(oc.id)
|
|
97
|
-
})
|
|
98
|
-
|
|
100
|
+
// now send inband DTMF digits
|
|
99
101
|
z.store.ic_ids.forEach(ic_id => {
|
|
100
102
|
sip.call.send_dtmf(ic_id, {digits: '4321', mode: 1})
|
|
101
103
|
})
|
package/samples/g729.js
CHANGED
|
@@ -77,6 +77,23 @@ async function test() {
|
|
|
77
77
|
},
|
|
78
78
|
], 1000)
|
|
79
79
|
|
|
80
|
+
sip.call.start_record_wav(oc.id, {file: './oc.wav'})
|
|
81
|
+
sip.call.start_record_wav(ic.id, {file: './ic.wav'})
|
|
82
|
+
|
|
83
|
+
sip.call.start_play_wav(oc.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true, no_loop: true})
|
|
84
|
+
sip.call.start_play_wav(ic.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true, no_loop: true})
|
|
85
|
+
|
|
86
|
+
await z.wait([
|
|
87
|
+
{
|
|
88
|
+
event: 'end_of_file',
|
|
89
|
+
call_id: oc.id,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
event: 'end_of_file',
|
|
93
|
+
call_id: ic.id,
|
|
94
|
+
},
|
|
95
|
+
], 3000)
|
|
96
|
+
|
|
80
97
|
sip.call.reinvite(oc.id)
|
|
81
98
|
|
|
82
99
|
await z.wait([
|
|
@@ -173,6 +190,9 @@ async function test() {
|
|
|
173
190
|
assert(oc_stat.CodecInfo == 'G729/8000/1')
|
|
174
191
|
assert(ic_stat.CodecInfo == 'G729/8000/1')
|
|
175
192
|
|
|
193
|
+
sip.call.stop_record_wav(oc.id)
|
|
194
|
+
sip.call.stop_record_wav(ic.id)
|
|
195
|
+
|
|
176
196
|
sip.call.terminate(oc.id)
|
|
177
197
|
|
|
178
198
|
await z.wait([
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
var sip = require ('../index.js')
|
|
2
|
+
var Zeq = require('@mayama/zeq')
|
|
3
|
+
var z = new Zeq()
|
|
4
|
+
var m = require('data-matching')
|
|
5
|
+
var sip_msg = require('sip-matching')
|
|
6
|
+
var sdp = require('sdp-matching')
|
|
7
|
+
|
|
8
|
+
var assert = require('assert')
|
|
9
|
+
|
|
10
|
+
async function test() {
|
|
11
|
+
//sip.set_log_level(6)
|
|
12
|
+
sip.dtmf_aggregation_on(500)
|
|
13
|
+
|
|
14
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
15
|
+
var e = evt.args[0]
|
|
16
|
+
return e
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
20
|
+
|
|
21
|
+
t1 = sip.transport.create({address: "127.0.0.1", type: 'udp'})
|
|
22
|
+
t2 = sip.transport.create({address: "127.0.0.1", type: 'udp'})
|
|
23
|
+
|
|
24
|
+
console.log("t1", t1)
|
|
25
|
+
console.log("t2", t2)
|
|
26
|
+
|
|
27
|
+
console.log(sip.get_codecs())
|
|
28
|
+
sip.set_codecs("opus/48000/2:128")
|
|
29
|
+
|
|
30
|
+
flags = 0
|
|
31
|
+
|
|
32
|
+
oc = sip.call.create(t1.id, {from_uri: 'sip:alice@test.com', to_uri: `sip:bob@${t2.address}:${t2.port}`})
|
|
33
|
+
|
|
34
|
+
await z.wait([
|
|
35
|
+
{
|
|
36
|
+
event: "incoming_call",
|
|
37
|
+
call_id: m.collect("call_id"),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
event: 'response',
|
|
41
|
+
call_id: oc.id,
|
|
42
|
+
method: 'INVITE',
|
|
43
|
+
msg: sip_msg({
|
|
44
|
+
$rs: '100',
|
|
45
|
+
$rr: 'Trying',
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
], 1000)
|
|
49
|
+
|
|
50
|
+
ic = {
|
|
51
|
+
id: z.store.call_id,
|
|
52
|
+
sip_call_id: z.store.sip_call_id,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK'})
|
|
56
|
+
|
|
57
|
+
await z.wait([
|
|
58
|
+
{
|
|
59
|
+
event: 'media_update',
|
|
60
|
+
call_id: oc.id,
|
|
61
|
+
status: 'ok',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
event: 'media_update',
|
|
65
|
+
call_id: ic.id,
|
|
66
|
+
status: 'ok',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
event: 'response',
|
|
70
|
+
call_id: oc.id,
|
|
71
|
+
method: 'INVITE',
|
|
72
|
+
msg: sip_msg({
|
|
73
|
+
$rs: '200',
|
|
74
|
+
$rr: 'OK',
|
|
75
|
+
'hdr_content_type': 'application/sdp',
|
|
76
|
+
$rb: '!{_}a=sendrecv',
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
], 1000)
|
|
80
|
+
|
|
81
|
+
sip.call.start_record_wav(oc.id, {file: './oc.wav'})
|
|
82
|
+
sip.call.start_record_wav(ic.id, {file: './ic.wav'})
|
|
83
|
+
|
|
84
|
+
sip.call.start_play_wav(oc.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true, no_loop: true})
|
|
85
|
+
sip.call.start_play_wav(ic.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true, no_loop: true})
|
|
86
|
+
|
|
87
|
+
await z.wait([
|
|
88
|
+
{
|
|
89
|
+
event: 'end_of_file',
|
|
90
|
+
call_id: oc.id,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
event: 'end_of_file',
|
|
94
|
+
call_id: ic.id,
|
|
95
|
+
},
|
|
96
|
+
], 3000)
|
|
97
|
+
|
|
98
|
+
sip.call.reinvite(oc.id)
|
|
99
|
+
|
|
100
|
+
await z.wait([
|
|
101
|
+
{
|
|
102
|
+
event: 'reinvite',
|
|
103
|
+
call_id: ic.id
|
|
104
|
+
},
|
|
105
|
+
], 1000)
|
|
106
|
+
|
|
107
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK'})
|
|
108
|
+
|
|
109
|
+
await z.wait([
|
|
110
|
+
{
|
|
111
|
+
event: 'response',
|
|
112
|
+
call_id: oc.id,
|
|
113
|
+
method: 'INVITE',
|
|
114
|
+
msg: sip_msg({
|
|
115
|
+
$rs: '100',
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
event: 'response',
|
|
120
|
+
call_id: oc.id,
|
|
121
|
+
method: 'INVITE',
|
|
122
|
+
msg: sip_msg({
|
|
123
|
+
$rs: '200',
|
|
124
|
+
$rr: 'OK',
|
|
125
|
+
$rb: '!{_}a=sendrecv',
|
|
126
|
+
}),
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
event: 'media_update',
|
|
130
|
+
call_id: oc.id,
|
|
131
|
+
status: 'ok',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
event: 'media_update',
|
|
135
|
+
call_id: ic.id,
|
|
136
|
+
status: 'ok',
|
|
137
|
+
},
|
|
138
|
+
], 500)
|
|
139
|
+
|
|
140
|
+
sip.call.reinvite(oc.id, false, 0)
|
|
141
|
+
|
|
142
|
+
await z.wait([
|
|
143
|
+
{
|
|
144
|
+
event: 'reinvite',
|
|
145
|
+
call_id: ic.id
|
|
146
|
+
},
|
|
147
|
+
], 1000)
|
|
148
|
+
|
|
149
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK'})
|
|
150
|
+
|
|
151
|
+
await z.wait([
|
|
152
|
+
{
|
|
153
|
+
event: 'response',
|
|
154
|
+
call_id: oc.id,
|
|
155
|
+
method: 'INVITE',
|
|
156
|
+
msg: sip_msg({
|
|
157
|
+
$rs: '100',
|
|
158
|
+
}),
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
event: 'response',
|
|
162
|
+
call_id: oc.id,
|
|
163
|
+
method: 'INVITE',
|
|
164
|
+
msg: sip_msg({
|
|
165
|
+
$rs: '200',
|
|
166
|
+
$rr: 'OK',
|
|
167
|
+
$rb: '!{_}a=sendrecv',
|
|
168
|
+
}),
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
event: 'media_update',
|
|
172
|
+
call_id: oc.id,
|
|
173
|
+
status: 'ok',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
event: 'media_update',
|
|
177
|
+
call_id: ic.id,
|
|
178
|
+
status: 'ok',
|
|
179
|
+
},
|
|
180
|
+
], 500)
|
|
181
|
+
|
|
182
|
+
oc_stat = sip.call.get_stream_stat(oc.id, {media_id: 0})
|
|
183
|
+
ic_stat = sip.call.get_stream_stat(ic.id, {media_id: 0})
|
|
184
|
+
|
|
185
|
+
console.log(oc_stat)
|
|
186
|
+
console.log(ic_stat)
|
|
187
|
+
|
|
188
|
+
oc_stat = JSON.parse(oc_stat)
|
|
189
|
+
ic_stat = JSON.parse(ic_stat)
|
|
190
|
+
|
|
191
|
+
assert(oc_stat.CodecInfo == 'opus/8000/1')
|
|
192
|
+
assert(ic_stat.CodecInfo == 'opus/8000/1')
|
|
193
|
+
|
|
194
|
+
await z.sleep(100)
|
|
195
|
+
|
|
196
|
+
sip.call.send_dtmf(oc.id, {digits: '12', mode: 1})
|
|
197
|
+
sip.call.send_dtmf(ic.id, {digits: '21', mode: 1})
|
|
198
|
+
|
|
199
|
+
await z.sleep(1000)
|
|
200
|
+
|
|
201
|
+
sip.call.stop_record_wav(oc.id)
|
|
202
|
+
sip.call.stop_record_wav(ic.id)
|
|
203
|
+
|
|
204
|
+
sip.call.terminate(oc.id)
|
|
205
|
+
|
|
206
|
+
await z.wait([
|
|
207
|
+
{
|
|
208
|
+
event: 'call_ended',
|
|
209
|
+
call_id: oc.id,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
event: 'call_ended',
|
|
213
|
+
call_id: ic.id,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
event: 'response',
|
|
217
|
+
call_id: oc.id,
|
|
218
|
+
method: 'BYE',
|
|
219
|
+
msg: sip_msg({
|
|
220
|
+
$rs: '200',
|
|
221
|
+
$rr: 'OK',
|
|
222
|
+
}),
|
|
223
|
+
},
|
|
224
|
+
], 1000)
|
|
225
|
+
|
|
226
|
+
console.log("Success")
|
|
227
|
+
|
|
228
|
+
sip.stop()
|
|
229
|
+
process.exit(0)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
test()
|
|
233
|
+
.catch(e => {
|
|
234
|
+
console.error(e)
|
|
235
|
+
process.exit(1)
|
|
236
|
+
})
|
|
@@ -71,11 +71,9 @@ async function test() {
|
|
|
71
71
|
{
|
|
72
72
|
type: 'audio',
|
|
73
73
|
local: {
|
|
74
|
-
port: 10000,
|
|
75
74
|
mode: 'sendrecv'
|
|
76
75
|
},
|
|
77
76
|
remote: {
|
|
78
|
-
port: 10002,
|
|
79
77
|
mode: 'sendrecv'
|
|
80
78
|
},
|
|
81
79
|
},
|
|
@@ -89,11 +87,9 @@ async function test() {
|
|
|
89
87
|
{
|
|
90
88
|
type: 'audio',
|
|
91
89
|
local: {
|
|
92
|
-
port: 10002,
|
|
93
90
|
mode: 'sendrecv'
|
|
94
91
|
},
|
|
95
92
|
remote: {
|
|
96
|
-
port: 10000,
|
|
97
93
|
mode: 'sendrecv'
|
|
98
94
|
},
|
|
99
95
|
}
|
|
@@ -104,33 +100,34 @@ async function test() {
|
|
|
104
100
|
sip.call.start_record_wav(oc.id, {file: 'oc.wav'})
|
|
105
101
|
sip.call.start_record_wav(ic.id, {file: 'ic.wav'})
|
|
106
102
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
sip.call.start_bfsk_detection(oc.id, {freq_zero: 880, freq_one: 1280})
|
|
110
|
-
//sip.call.start_bfsk_detection(ic.id, {freq_zero: 880, freq_one: 1280})
|
|
103
|
+
sip.call.start_bfsk_detection(oc.id, {freq_zero: 500, freq_one: 2000})
|
|
104
|
+
sip.call.start_bfsk_detection(ic.id, {freq_zero: 500, freq_one: 2000})
|
|
111
105
|
|
|
112
106
|
oc_bits = '1010'
|
|
113
107
|
ic_bits = '1100'
|
|
114
108
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
109
|
+
// wait a little for voice path to open
|
|
110
|
+
await z.sleep(50)
|
|
111
|
+
|
|
112
|
+
for(var i=0 ; i<5 ; i++) {
|
|
113
|
+
sip.call.send_bfsk(ic.id, {bits: ic_bits, freq_zero: 500, freq_one: 2000})
|
|
114
|
+
sip.call.send_bfsk(oc.id, {bits: oc_bits, freq_zero: 500, freq_one: 2000})
|
|
115
|
+
|
|
116
|
+
await z.wait([
|
|
117
|
+
{
|
|
118
|
+
event: 'bfsk',
|
|
119
|
+
call_id: ic.id,
|
|
120
|
+
bits: oc_bits,
|
|
121
|
+
media_id: 0
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
event: 'bfsk',
|
|
125
|
+
call_id: oc.id,
|
|
126
|
+
bits: ic_bits,
|
|
127
|
+
media_id: 0
|
|
128
|
+
},
|
|
129
|
+
], 10000)
|
|
130
|
+
}
|
|
134
131
|
|
|
135
132
|
sip.call.stop_record_wav(oc.id)
|
|
136
133
|
sip.call.stop_record_wav(ic.id)
|
|
@@ -122,6 +122,13 @@ test()
|
|
|
122
122
|
.catch(e => {
|
|
123
123
|
console.error(e)
|
|
124
124
|
sip.stop(true)
|
|
125
|
-
|
|
125
|
+
|
|
126
|
+
if(e == "SOME ERROR") {
|
|
127
|
+
console.log("Expected error catched")
|
|
128
|
+
process.exit(0)
|
|
129
|
+
} else {
|
|
130
|
+
console.log("Unexpected error catched")
|
|
131
|
+
process.exit(1)
|
|
132
|
+
}
|
|
126
133
|
})
|
|
127
134
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#ifndef __PJMEDIA_BFSK_DET2_H__
|
|
2
|
+
#define __PJMEDIA_BFSK_DET2_H__
|
|
3
|
+
|
|
4
|
+
#include <pjmedia/port.h>
|
|
5
|
+
|
|
6
|
+
PJ_BEGIN_DECL
|
|
7
|
+
|
|
8
|
+
PJ_DEF(pj_status_t) pjmedia_bfsk_det2_create( pj_pool_t *pool,
|
|
9
|
+
unsigned clock_rate,
|
|
10
|
+
unsigned channel_count,
|
|
11
|
+
unsigned samples_per_frame,
|
|
12
|
+
unsigned bits_per_sample,
|
|
13
|
+
void (*cb)(pjmedia_port*,
|
|
14
|
+
void *user_data,
|
|
15
|
+
int bit),
|
|
16
|
+
void *user_data,
|
|
17
|
+
int freq_zero,
|
|
18
|
+
int freq_one,
|
|
19
|
+
pjmedia_port **p_port);
|
|
20
|
+
|
|
21
|
+
PJ_END_DECL
|
|
22
|
+
|
|
23
|
+
#endif /* __PJMEDIA_BFSK_DET2_H__ */
|
|
@@ -36,88 +36,106 @@
|
|
|
36
36
|
# define TRACE_(expr)
|
|
37
37
|
#endif
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
#include <math.h>
|
|
40
|
+
#include <stdio.h>
|
|
41
|
+
#include <stdlib.h>
|
|
42
|
+
#include <stdbool.h>
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
// Converted by ChatGPT from https://github.com/hackergrrl/goertzel/blob/master/index.js
|
|
42
45
|
|
|
43
46
|
typedef struct {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
double sine;
|
|
49
|
-
double cosine;
|
|
47
|
+
int freq;
|
|
48
|
+
int sampleRate;
|
|
49
|
+
int samplesPerFrame;
|
|
50
|
+
double targetMagnitude; // Store the precomputed magnitude
|
|
50
51
|
} goertzel_t;
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
int ONE_16 = 1 << 16;
|
|
53
|
+
#define CHUNK_SIZE 16
|
|
54
|
+
#define THRESHOLD 0.9
|
|
55
55
|
|
|
56
|
-
int
|
|
57
|
-
|
|
56
|
+
double precalcMagnitude(int freq, double rate) {
|
|
57
|
+
double t = 0.0;
|
|
58
|
+
double tstep = 1.0 / rate;
|
|
59
|
+
double samples[CHUNK_SIZE];
|
|
60
|
+
for (int i = 0; i < CHUNK_SIZE; i++) {
|
|
61
|
+
samples[i] = sin(2 * M_PI * freq * t);
|
|
62
|
+
t += tstep;
|
|
63
|
+
}
|
|
58
64
|
|
|
59
|
-
int
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
int k = (int)(0.5 + (CHUNK_SIZE * freq) / rate);
|
|
66
|
+
double w = (2 * M_PI / CHUNK_SIZE) * k;
|
|
67
|
+
double c = cos(w);
|
|
68
|
+
double s = sin(w);
|
|
69
|
+
double coeff = 2.0 * c;
|
|
70
|
+
|
|
71
|
+
double q0 = 0.0, q1 = 0.0, q2 = 0.0;
|
|
72
|
+
for (int i = 0; i < CHUNK_SIZE; i++) {
|
|
73
|
+
q0 = coeff * q1 - q2 + samples[i];
|
|
74
|
+
q2 = q1;
|
|
75
|
+
q1 = q0;
|
|
76
|
+
}
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
double real = q1 - q2 * c;
|
|
79
|
+
double imaginary = q2 * s;
|
|
80
|
+
double magSquared = real * real + imaginary * imaginary;
|
|
67
81
|
|
|
68
|
-
|
|
69
|
-
return fix >> FIXED_POINT;
|
|
82
|
+
return magSquared;
|
|
70
83
|
}
|
|
71
84
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
85
|
+
void goertzel_det_init(goertzel_t *g, int freq, int sample_rate) {
|
|
86
|
+
g->freq = freq;
|
|
87
|
+
g->sampleRate = sample_rate;
|
|
88
|
+
g->samplesPerFrame = CHUNK_SIZE;
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
void goertzel_det_init(goertzel_t *g, float frequency, float sampling_rate, int samples_per_frame)
|
|
86
|
-
{
|
|
87
|
-
int k;
|
|
88
|
-
double floatN;
|
|
89
|
-
double omega;
|
|
90
|
-
floatN = (double)samples_per_frame;
|
|
91
|
-
k = (int)(0.5 + ((floatN * frequency) / sampling_rate));
|
|
92
|
-
omega = (2.0 * PI * k) / floatN;
|
|
93
|
-
g->sine = sin(omega);
|
|
94
|
-
g->cosine = cos(omega);
|
|
95
|
-
g->coeff = 2.0 * g->cosine;
|
|
96
|
-
g->fix_coeff = toFix(g->coeff, ONE_30);
|
|
97
|
-
printf("For sampling_rate = %f", sampling_rate);
|
|
98
|
-
printf("samples_per_frame = %d", samples_per_frame);
|
|
99
|
-
printf(" and frequency = %f,\n", frequency);
|
|
100
|
-
printf("k = %d and coeff = %f\n\n", k, g->coeff);
|
|
101
|
-
goertzel_det_reset(g);
|
|
90
|
+
assert(g->sampleRate >= g->freq * 2);
|
|
91
|
+
|
|
92
|
+
g->samplesPerFrame = (int)floor(g->samplesPerFrame);
|
|
93
|
+
|
|
94
|
+
// Precompute the target magnitude and store it in the struct
|
|
95
|
+
g->targetMagnitude = precalcMagnitude(g->freq, g->sampleRate);
|
|
96
|
+
// printf("Target Magnitude: %f\n", g->targetMagnitude);
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
float goertzel_mag(goertzel_t *g,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
g->Q1 = Q0;
|
|
99
|
+
float goertzel_mag(goertzel_t *g, void *samples) {
|
|
100
|
+
// Allocate an array of floats to hold normalized samples
|
|
101
|
+
float float_samples[CHUNK_SIZE];
|
|
102
|
+
uint8_t *byteBuffer = (uint8_t *)samples; // Cast the void* to a byte array (uint8_t *)
|
|
103
|
+
for (int i = 0; i < CHUNK_SIZE ; i++) {
|
|
104
|
+
// Combine two consecutive bytes into a 16-bit signed integer (little-endian)
|
|
105
|
+
int16_t sample = byteBuffer[i * 2] | (byteBuffer[i * 2 + 1] << 8);
|
|
106
|
+
float_samples[i] = sample * 2.0f / 0x7FFF;
|
|
113
107
|
}
|
|
114
108
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
/*
|
|
110
|
+
for (int i = 0; i < CHUNK_SIZE; i++) {
|
|
111
|
+
printf("%f,", float_samples[i]);
|
|
112
|
+
}
|
|
113
|
+
printf("\n");
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
int k = (int)(0.5f + (CHUNK_SIZE * g->freq) / g->sampleRate);
|
|
118
|
+
float w = (2.0f * M_PI / CHUNK_SIZE) * k;
|
|
119
|
+
float c = cosf(w);
|
|
120
|
+
float s = sinf(w);
|
|
121
|
+
float coeff = 2.0f * c;
|
|
122
|
+
|
|
123
|
+
float q0 = 0.0f, q1 = 0.0f, q2 = 0.0f;
|
|
124
|
+
|
|
125
|
+
for (int i = 0; i < CHUNK_SIZE; i++) {
|
|
126
|
+
q0 = coeff * q1 - q2 + float_samples[i];
|
|
127
|
+
q2 = q1;
|
|
128
|
+
q1 = q0;
|
|
129
|
+
}
|
|
120
130
|
|
|
131
|
+
float real = q1 - q2 * c;
|
|
132
|
+
float imaginary = q2 * s;
|
|
133
|
+
float magSquared = real * real + imaginary * imaginary;
|
|
134
|
+
|
|
135
|
+
float per = magSquared / g->targetMagnitude;
|
|
136
|
+
//printf("(freq=%i) MagSquared=%f targetMagnitude=%f per=%f\n", g->freq, magSquared, g->targetMagnitude, per);
|
|
137
|
+
return per;
|
|
138
|
+
}
|
|
121
139
|
|
|
122
140
|
|
|
123
141
|
static pj_status_t bfsk_det_put_frame(pjmedia_port *this_port,
|
|
@@ -141,24 +159,6 @@ struct bfsk_det
|
|
|
141
159
|
void *bfsk_cb_user_data;
|
|
142
160
|
};
|
|
143
161
|
|
|
144
|
-
/*
|
|
145
|
-
static void bfsk_det_bit_callback(void *user_data, int bit)
|
|
146
|
-
{
|
|
147
|
-
printf("bfsk_det_bit_callback got bit=%i\n", bit);
|
|
148
|
-
if(bit != 0 && bit != 1) return;
|
|
149
|
-
|
|
150
|
-
struct bfsk_det *dport = (struct bfsk_det*)user_data;
|
|
151
|
-
|
|
152
|
-
TRACE_((THIS_FILE, "bfsk_det bit detected: %c", bit));
|
|
153
|
-
|
|
154
|
-
if(!dport->bfsk_cb) return;
|
|
155
|
-
|
|
156
|
-
dport->bfsk_cb((pjmedia_port*)dport,
|
|
157
|
-
dport->bfsk_cb_user_data,
|
|
158
|
-
bit);
|
|
159
|
-
}
|
|
160
|
-
*/
|
|
161
|
-
|
|
162
162
|
PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
|
|
163
163
|
unsigned clock_rate,
|
|
164
164
|
unsigned channel_count,
|
|
@@ -172,10 +172,9 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
|
|
|
172
172
|
int freq_one,
|
|
173
173
|
pjmedia_port **p_port)
|
|
174
174
|
{
|
|
175
|
-
printf("pjmedia_bfsk_det_create\n");
|
|
175
|
+
//printf("pjmedia_bfsk_det_create\n");
|
|
176
176
|
struct bfsk_det *det;
|
|
177
177
|
|
|
178
|
-
printf("p1\n");
|
|
179
178
|
const pj_str_t name = pj_str("bfsk_det");
|
|
180
179
|
|
|
181
180
|
PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
|
|
@@ -184,11 +183,8 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
|
|
|
184
183
|
|
|
185
184
|
PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
|
|
186
185
|
|
|
187
|
-
printf("p2\n");
|
|
188
|
-
|
|
189
186
|
det = PJ_POOL_ZALLOC_T(pool, struct bfsk_det);
|
|
190
187
|
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
|
|
191
|
-
printf("p3\n");
|
|
192
188
|
|
|
193
189
|
pjmedia_port_info_init(&det->base.info, &name, SIGNATURE, clock_rate,
|
|
194
190
|
channel_count, bits_per_sample, samples_per_frame);
|
|
@@ -196,13 +192,9 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
|
|
|
196
192
|
det->base.put_frame = &bfsk_det_put_frame;
|
|
197
193
|
det->base.on_destroy = &bfsk_det_on_destroy;
|
|
198
194
|
|
|
199
|
-
printf("p5\n");
|
|
200
|
-
|
|
201
195
|
det->bfsk_cb = cb;
|
|
202
196
|
det->bfsk_cb_user_data = user_data;
|
|
203
197
|
|
|
204
|
-
printf("p6\n");
|
|
205
|
-
|
|
206
198
|
det->clock_rate = clock_rate;
|
|
207
199
|
det->freq_zero = freq_zero;
|
|
208
200
|
det->freq_one = freq_one;
|
|
@@ -217,15 +209,10 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
|
|
|
217
209
|
|
|
218
210
|
int sample_rate = clock_rate;
|
|
219
211
|
|
|
220
|
-
|
|
221
|
-
goertzel_det_init(det->goertzel_one, det->freq_one, sample_rate, samples_per_frame);
|
|
222
|
-
|
|
223
|
-
printf("p7\n");
|
|
224
|
-
|
|
225
|
-
TRACE_((THIS_FILE, "bfsk_det created: clock_rate=%u channel_count=%u samples_per_frame=%u bits_per_frame=%u", clock_rate,
|
|
226
|
-
channel_count, samples_per_frame, bits_per_sample));
|
|
212
|
+
//printf("bfsk_det: clock_rate=%u channel_count=%u samples_per_frame=%u bits_per_frame=%u", clock_rate, channel_count, samples_per_frame, bits_per_sample);
|
|
227
213
|
|
|
228
|
-
|
|
214
|
+
goertzel_det_init(det->goertzel_zero, det->freq_zero, sample_rate);
|
|
215
|
+
goertzel_det_init(det->goertzel_one, det->freq_one, sample_rate);
|
|
229
216
|
|
|
230
217
|
*p_port = &det->base;
|
|
231
218
|
return PJ_SUCCESS;
|
|
@@ -234,50 +221,56 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
|
|
|
234
221
|
static pj_status_t bfsk_det_put_frame(pjmedia_port *this_port,
|
|
235
222
|
pjmedia_frame *frame)
|
|
236
223
|
{
|
|
237
|
-
printf("
|
|
224
|
+
//printf("bfsk_det put_frame\n");
|
|
238
225
|
if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
|
|
239
226
|
|
|
240
227
|
struct bfsk_det *dport = (struct bfsk_det*) this_port;
|
|
241
228
|
|
|
242
|
-
int size =
|
|
229
|
+
int size = frame->size;
|
|
243
230
|
int bps = PJMEDIA_PIA_BITS(&dport->base.info);
|
|
244
231
|
|
|
245
|
-
printf("p=%x, size=%i clock_rate=%i bits_per_sample=%i\n", frame->buf, size, dport->clock_rate, bps);
|
|
232
|
+
//printf("p=%x, size=%i clock_rate=%i bits_per_sample=%i\n", frame->buf, size, dport->clock_rate, bps);
|
|
246
233
|
|
|
247
234
|
int16_t * samples = (int16_t*)frame->buf;
|
|
248
235
|
|
|
236
|
+
/*
|
|
249
237
|
printf("Buffer contents:\n");
|
|
250
238
|
for (int i = 0; i < size; i++) {
|
|
251
|
-
printf("%
|
|
239
|
+
printf("%02x", samples[i] & 0xFF);
|
|
240
|
+
printf("%02x", samples[i] >> 8 & 0xFF);
|
|
252
241
|
}
|
|
253
242
|
printf("\n");
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
dport->zero_in_progress
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
dport->one_in_progress
|
|
279
|
-
|
|
280
|
-
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
for(int i=0 ; i<size/2/CHUNK_SIZE; i++) {
|
|
246
|
+
double zero_power = goertzel_mag(dport->goertzel_zero, &frame->buf[i*2*CHUNK_SIZE]);
|
|
247
|
+
double one_power = goertzel_mag(dport->goertzel_one, &frame->buf[i*2*CHUNK_SIZE]);
|
|
248
|
+
|
|
249
|
+
int zero = zero_power > THRESHOLD;
|
|
250
|
+
int one = one_power > THRESHOLD;
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
printf("zero_power=%f zero_in_progress=%i zero=%i threshold=%f\n", zero_power, dport->zero_in_progress, zero, THRESHOLD);
|
|
254
|
+
printf(" one_power=%f one_in_progress=%i one=%i threshold=%f\n", one_power, dport->one_in_progress, one, THRESHOLD);
|
|
255
|
+
*/
|
|
256
|
+
|
|
257
|
+
// Check for zero signal extinction
|
|
258
|
+
if(dport->zero_in_progress && zero == 0) {
|
|
259
|
+
printf("notifying bit=0\n");
|
|
260
|
+
dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 0);
|
|
261
|
+
dport->zero_in_progress = 0;
|
|
262
|
+
} else {
|
|
263
|
+
dport->zero_in_progress = zero;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Check for one signal extinction
|
|
267
|
+
if(dport->one_in_progress && one == 0) {
|
|
268
|
+
printf("notifying bit=1\n");
|
|
269
|
+
dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 1);
|
|
270
|
+
dport->one_in_progress = 0;
|
|
271
|
+
} else {
|
|
272
|
+
dport->one_in_progress = one;
|
|
273
|
+
}
|
|
281
274
|
}
|
|
282
275
|
|
|
283
276
|
return PJ_SUCCESS;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/* $Id: bfsk_det2.c 0000 2024-09-29 09:41:55Z mayamatakeshi $ */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
|
|
4
|
+
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
|
|
5
|
+
*
|
|
6
|
+
* This program is free software; you can redistribute it and/or modify
|
|
7
|
+
* it under the terms of the GNU General Public License as published by
|
|
8
|
+
* the Free Software Foundation; either version 2 of the License, or
|
|
9
|
+
* (at your option) any later version.
|
|
10
|
+
*
|
|
11
|
+
* This program is distributed in the hope that it will be useful,
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
* GNU General Public License for more details.
|
|
15
|
+
*
|
|
16
|
+
* You should have received a copy of the GNU General Public License
|
|
17
|
+
* along with this program; if not, write to the Free Software
|
|
18
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
#include <pjmedia/bfsk_det2.h>
|
|
22
|
+
#include <pjmedia/errno.h>
|
|
23
|
+
#include <pjmedia/port.h>
|
|
24
|
+
#include <pj/assert.h>
|
|
25
|
+
#include <pj/pool.h>
|
|
26
|
+
#include <pj/string.h>
|
|
27
|
+
|
|
28
|
+
#include <spandsp.h>
|
|
29
|
+
#include <spandsp/expose.h>
|
|
30
|
+
#include <spandsp/tone_detect.h>
|
|
31
|
+
|
|
32
|
+
#include <math.h>
|
|
33
|
+
|
|
34
|
+
#define SIGNATURE PJMEDIA_SIGNATURE('b', 'f', 'd', '2')
|
|
35
|
+
#define THIS_FILE "bfsk_det2.c"
|
|
36
|
+
|
|
37
|
+
#if 0
|
|
38
|
+
# define TRACE_(expr) PJ_LOG(4,expr)
|
|
39
|
+
#else
|
|
40
|
+
# define TRACE_(expr)
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
#include <stdio.h>
|
|
44
|
+
#include <stdlib.h>
|
|
45
|
+
#include <stdbool.h>
|
|
46
|
+
|
|
47
|
+
static pj_status_t bfsk_det2_put_frame(pjmedia_port *this_port,
|
|
48
|
+
pjmedia_frame *frame);
|
|
49
|
+
static pj_status_t bfsk_det2_on_destroy(pjmedia_port *this_port);
|
|
50
|
+
|
|
51
|
+
struct bfsk_det2
|
|
52
|
+
{
|
|
53
|
+
struct pjmedia_port base;
|
|
54
|
+
int clock_rate;
|
|
55
|
+
int freq_zero;
|
|
56
|
+
int freq_one;
|
|
57
|
+
|
|
58
|
+
int zero_in_progress;
|
|
59
|
+
int one_in_progress;
|
|
60
|
+
|
|
61
|
+
int32_t threshold;
|
|
62
|
+
int32_t energy;
|
|
63
|
+
|
|
64
|
+
goertzel_descriptor_t desc_zero;
|
|
65
|
+
goertzel_descriptor_t desc_one;
|
|
66
|
+
|
|
67
|
+
goertzel_state_t *goertzel_zero;
|
|
68
|
+
goertzel_state_t *goertzel_one;
|
|
69
|
+
|
|
70
|
+
void (*bfsk_cb)(pjmedia_port*, void*, int);
|
|
71
|
+
void *bfsk_cb_user_data;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
#define DTMF_SAMPLES_PER_BLOCK 102
|
|
75
|
+
|
|
76
|
+
PJ_DEF(pj_status_t) pjmedia_bfsk_det2_create( pj_pool_t *pool,
|
|
77
|
+
unsigned clock_rate,
|
|
78
|
+
unsigned channel_count,
|
|
79
|
+
unsigned samples_per_frame,
|
|
80
|
+
unsigned bits_per_sample,
|
|
81
|
+
void (*cb)(pjmedia_port*,
|
|
82
|
+
void *user_data,
|
|
83
|
+
int bit),
|
|
84
|
+
void *user_data,
|
|
85
|
+
int freq_zero,
|
|
86
|
+
int freq_one,
|
|
87
|
+
pjmedia_port **p_port)
|
|
88
|
+
{
|
|
89
|
+
//printf("pjmedia_bfsk_det2_create\n");
|
|
90
|
+
struct bfsk_det2 *det;
|
|
91
|
+
|
|
92
|
+
const pj_str_t name = pj_str("bfsk_det2");
|
|
93
|
+
|
|
94
|
+
PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
|
|
95
|
+
samples_per_frame && bits_per_sample == 16 &&
|
|
96
|
+
p_port != NULL, PJ_EINVAL);
|
|
97
|
+
|
|
98
|
+
PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
|
|
99
|
+
|
|
100
|
+
det = PJ_POOL_ZALLOC_T(pool, struct bfsk_det2);
|
|
101
|
+
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
|
|
102
|
+
|
|
103
|
+
pjmedia_port_info_init(&det->base.info, &name, SIGNATURE, clock_rate,
|
|
104
|
+
channel_count, bits_per_sample, samples_per_frame);
|
|
105
|
+
|
|
106
|
+
det->base.put_frame = &bfsk_det2_put_frame;
|
|
107
|
+
det->base.on_destroy = &bfsk_det2_on_destroy;
|
|
108
|
+
|
|
109
|
+
det->bfsk_cb = cb;
|
|
110
|
+
det->bfsk_cb_user_data = user_data;
|
|
111
|
+
|
|
112
|
+
det->clock_rate = clock_rate;
|
|
113
|
+
det->freq_zero = freq_zero;
|
|
114
|
+
det->freq_one = freq_one;
|
|
115
|
+
|
|
116
|
+
make_goertzel_descriptor(&det->desc_zero, freq_zero, DTMF_SAMPLES_PER_BLOCK);
|
|
117
|
+
make_goertzel_descriptor(&det->desc_one, freq_one, DTMF_SAMPLES_PER_BLOCK);
|
|
118
|
+
|
|
119
|
+
goertzel_init(&det->goertzel_zero, &det->desc_zero);
|
|
120
|
+
goertzel_init(&det->goertzel_one, &det->desc_one);
|
|
121
|
+
|
|
122
|
+
int sample_rate = clock_rate;
|
|
123
|
+
|
|
124
|
+
//printf("bfsk_det2: clock_rate=%u channel_count=%u samples_per_frame=%u bits_per_frame=%u", clock_rate, channel_count, samples_per_frame, bits_per_sample);
|
|
125
|
+
|
|
126
|
+
goertzel_det_init(&det->goertzel_zero, det->freq_zero, sample_rate);
|
|
127
|
+
goertzel_det_init(&det->goertzel_one, det->freq_one, sample_rate);
|
|
128
|
+
|
|
129
|
+
*p_port = &det->base;
|
|
130
|
+
return PJ_SUCCESS;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static pj_status_t bfsk_det2_put_frame(pjmedia_port *this_port,
|
|
134
|
+
pjmedia_frame *frame)
|
|
135
|
+
{
|
|
136
|
+
//printf("bfsk_det2 put_frame\n");
|
|
137
|
+
if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
|
|
138
|
+
|
|
139
|
+
struct bfsk_det2 *dport = (struct bfsk_det2*) this_port;
|
|
140
|
+
|
|
141
|
+
int size = frame->size;
|
|
142
|
+
int bps = PJMEDIA_PIA_BITS(&dport->base.info);
|
|
143
|
+
|
|
144
|
+
//printf("p=%x, size=%i clock_rate=%i bits_per_sample=%i\n", frame->buf, size, dport->clock_rate, bps);
|
|
145
|
+
|
|
146
|
+
int16_t * samples = (int16_t*)frame->buf;
|
|
147
|
+
int16_t * num_samples = frame->size/2;
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
printf("Buffer contents:\n");
|
|
151
|
+
for (int i = 0; i < size; i++) {
|
|
152
|
+
printf("%02x", samples[i] & 0xFF);
|
|
153
|
+
printf("%02x", samples[i] >> 8 & 0xFF);
|
|
154
|
+
}
|
|
155
|
+
printf("\n");
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
159
|
+
int32_t row_energy[4];
|
|
160
|
+
int32_t col_energy[4];
|
|
161
|
+
int16_t xamp;
|
|
162
|
+
float famp;
|
|
163
|
+
#else
|
|
164
|
+
float row_energy[4];
|
|
165
|
+
float col_energy[4];
|
|
166
|
+
float xamp;
|
|
167
|
+
float famp;
|
|
168
|
+
#endif
|
|
169
|
+
|
|
170
|
+
float v1;
|
|
171
|
+
int i;
|
|
172
|
+
int j;
|
|
173
|
+
int sample;
|
|
174
|
+
int limit;
|
|
175
|
+
uint8_t hit;
|
|
176
|
+
|
|
177
|
+
for (sample = 0; sample < num_samples; sample = limit)
|
|
178
|
+
{
|
|
179
|
+
limit = num_samples;
|
|
180
|
+
for (j = sample; j < limit; j++)
|
|
181
|
+
{
|
|
182
|
+
xamp = samples[j];
|
|
183
|
+
xamp = goertzel_preadjust_amp(xamp);
|
|
184
|
+
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
185
|
+
dport->energy += ((int32_t) xamp*xamp);
|
|
186
|
+
#else
|
|
187
|
+
dport->energy += xamp*xamp;
|
|
188
|
+
#endif
|
|
189
|
+
goertzel_samplex(&dport->goertzel_zero, xamp);
|
|
190
|
+
goertzel_samplex(&dport->goertzel_one, xamp);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
int32_t zero_power = goertzel_result(&dport->goertzel_zero);
|
|
194
|
+
int32_t one_power = goertzel_result(&dport->goertzel_one);
|
|
195
|
+
|
|
196
|
+
int zero = zero_power > dport->threshold;
|
|
197
|
+
int one = one_power > dport->threshold;
|
|
198
|
+
|
|
199
|
+
printf("zero_power=%f zero_in_progress=%i zero=%i threshold=%f\n", zero_power, dport->zero_in_progress, zero, dport->threshold);
|
|
200
|
+
printf(" one_power=%f one_in_progress=%i one=%i threshold=%f\n", one_power, dport->one_in_progress, one, dport->threshold);
|
|
201
|
+
|
|
202
|
+
// Check for zero signal extinction
|
|
203
|
+
if(dport->zero_in_progress && zero == 0) {
|
|
204
|
+
printf("notifying bit=0\n");
|
|
205
|
+
dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 0);
|
|
206
|
+
dport->zero_in_progress = 0;
|
|
207
|
+
} else {
|
|
208
|
+
dport->zero_in_progress = zero;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Check for one signal extinction
|
|
212
|
+
if(dport->one_in_progress && one == 0) {
|
|
213
|
+
printf("notifying bit=1\n");
|
|
214
|
+
dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 1);
|
|
215
|
+
dport->one_in_progress = 0;
|
|
216
|
+
} else {
|
|
217
|
+
dport->one_in_progress = one;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return PJ_SUCCESS;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static pj_status_t bfsk_det2_on_destroy(pjmedia_port *this_port)
|
|
224
|
+
{
|
|
225
|
+
return PJ_SUCCESS;
|
|
226
|
+
}
|
|
@@ -338,10 +338,25 @@ PJ_DEF(pj_status_t) pjmedia_ws_speech_port_create(pj_pool_t *pool,
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
static pj_status_t put_frame(pjmedia_port *this_port, pjmedia_frame *frame) {
|
|
341
|
+
printf("ws_speech_port put_frame\n");
|
|
341
342
|
if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
|
|
342
343
|
|
|
343
344
|
struct ws_speech_t *port = (struct ws_speech_t*) this_port;
|
|
344
345
|
|
|
346
|
+
int size = PJMEDIA_PIA_SPF(&port->base.info);
|
|
347
|
+
int bps = PJMEDIA_PIA_BITS(&port->base.info);
|
|
348
|
+
|
|
349
|
+
printf("p=%x, size=%i bits_per_sample=%i\n", frame->buf, size, bps);
|
|
350
|
+
|
|
351
|
+
int16_t * samples = (int16_t*)frame->buf;
|
|
352
|
+
|
|
353
|
+
printf("Buffer contents:\n");
|
|
354
|
+
for (int i = 0; i < size; i++) {
|
|
355
|
+
printf("%02x", samples[i] & 0xFF);
|
|
356
|
+
printf("%02x", samples[i] >> 8 & 0xFF);
|
|
357
|
+
}
|
|
358
|
+
printf("\n");
|
|
359
|
+
|
|
345
360
|
if(port->wc && port->connected) {
|
|
346
361
|
pj_websock_send(port->wc, PJ_WEBSOCK_OP_BIN, PJ_TRUE, PJ_TRUE, frame->buf, frame->size);
|
|
347
362
|
}
|
|
@@ -364,7 +379,7 @@ static pj_status_t get_frame(pjmedia_port *this_port, pjmedia_frame *frame) {
|
|
|
364
379
|
int len = PJMEDIA_PIA_SPF(&this_port->info)*2;
|
|
365
380
|
|
|
366
381
|
if(port->buffering_count >= MINIMAl_BUFFERING && port->buffer_top > 0 && port->buffer_top >= len) {
|
|
367
|
-
printf("get_frame top=%i\n", port->buffer_top);
|
|
382
|
+
//printf("get_frame top=%i\n", port->buffer_top);
|
|
368
383
|
memcpy(frame->buf, port->buffer, len);
|
|
369
384
|
port->buffer_top -= len;
|
|
370
385
|
memcpy(port->buffer, port->buffer + len, port->buffer_top);
|
package/src/sip.cpp
CHANGED
|
@@ -267,7 +267,7 @@ int ms_timestamp();
|
|
|
267
267
|
bool g_shutting_down;
|
|
268
268
|
|
|
269
269
|
int g_dtmf_inter_digit_timer = 0;
|
|
270
|
-
int g_bfsk_inter_bit_timer =
|
|
270
|
+
int g_bfsk_inter_bit_timer = 50;
|
|
271
271
|
|
|
272
272
|
pj_str_t g_sip_ipaddress;
|
|
273
273
|
|
|
@@ -1558,6 +1558,29 @@ int __pjw_init() {
|
|
|
1558
1558
|
addon_log(L_DBG, "pjmedia_codec_opus_init failed\n");
|
|
1559
1559
|
return 1;
|
|
1560
1560
|
}
|
|
1561
|
+
pjmedia_codec_param param;
|
|
1562
|
+
pjmedia_codec_opus_config opus_cfg;
|
|
1563
|
+
|
|
1564
|
+
pjmedia_codec_mgr *codec_mgr;
|
|
1565
|
+
codec_mgr = pjmedia_endpt_get_codec_mgr(g_med_endpt);
|
|
1566
|
+
|
|
1567
|
+
unsigned cnt = 1;
|
|
1568
|
+
const pjmedia_codec_info *pci;
|
|
1569
|
+
|
|
1570
|
+
pj_str_t codec_id = pj_str((char*)"opus/48000/2");
|
|
1571
|
+
pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, &codec_id, &cnt, &pci, NULL);
|
|
1572
|
+
pjmedia_codec_mgr_get_default_param(codec_mgr, pci, ¶m);
|
|
1573
|
+
pjmedia_codec_opus_get_config(&opus_cfg);
|
|
1574
|
+
|
|
1575
|
+
opus_cfg.sample_rate = 8000;
|
|
1576
|
+
opus_cfg.channel_cnt = 1;
|
|
1577
|
+
opus_cfg.bit_rate = 8000;
|
|
1578
|
+
status = pjmedia_codec_opus_set_default_param(&opus_cfg, ¶m);
|
|
1579
|
+
if(status != PJ_SUCCESS)
|
|
1580
|
+
{
|
|
1581
|
+
addon_log(L_DBG, "pjmedia_codec_opus_set_default_param failed\n");
|
|
1582
|
+
return 1;
|
|
1583
|
+
}
|
|
1561
1584
|
#endif
|
|
1562
1585
|
|
|
1563
1586
|
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
|
|
@@ -6642,7 +6665,7 @@ int pjw_enable_telephone_event() {
|
|
|
6642
6665
|
}
|
|
6643
6666
|
|
|
6644
6667
|
int __pjw_shutdown(int clean_up) {
|
|
6645
|
-
addon_log(L_DBG, "pjw_shutdown thread_id=%i\n", syscall(SYS_gettid));
|
|
6668
|
+
//addon_log(L_DBG, "pjw_shutdown thread_id=%i\n", syscall(SYS_gettid));
|
|
6646
6669
|
|
|
6647
6670
|
g_shutting_down = true;
|
|
6648
6671
|
|
|
File without changes
|