@tomgiee/tsdp 1.0.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/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/src/builder/media-builder.d.ts +221 -0
- package/dist/src/builder/media-builder.d.ts.map +1 -0
- package/dist/src/builder/media-builder.js +385 -0
- package/dist/src/builder/session-builder.d.ts +195 -0
- package/dist/src/builder/session-builder.d.ts.map +1 -0
- package/dist/src/builder/session-builder.js +366 -0
- package/dist/src/index.d.ts +67 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +250 -0
- package/dist/src/parser/attribute-parser.d.ts +100 -0
- package/dist/src/parser/attribute-parser.d.ts.map +1 -0
- package/dist/src/parser/attribute-parser.js +217 -0
- package/dist/src/parser/field-parser.d.ts +124 -0
- package/dist/src/parser/field-parser.d.ts.map +1 -0
- package/dist/src/parser/field-parser.js +335 -0
- package/dist/src/parser/media-parser.d.ts +45 -0
- package/dist/src/parser/media-parser.d.ts.map +1 -0
- package/dist/src/parser/media-parser.js +157 -0
- package/dist/src/parser/primitive-parser.d.ts +138 -0
- package/dist/src/parser/primitive-parser.d.ts.map +1 -0
- package/dist/src/parser/primitive-parser.js +316 -0
- package/dist/src/parser/scanner.d.ts +142 -0
- package/dist/src/parser/scanner.d.ts.map +1 -0
- package/dist/src/parser/scanner.js +284 -0
- package/dist/src/parser/session-parser.d.ts +35 -0
- package/dist/src/parser/session-parser.d.ts.map +1 -0
- package/dist/src/parser/session-parser.js +207 -0
- package/dist/src/parser/time-parser.d.ts +74 -0
- package/dist/src/parser/time-parser.d.ts.map +1 -0
- package/dist/src/parser/time-parser.js +168 -0
- package/dist/src/serializer/attribute-serializer.d.ts +18 -0
- package/dist/src/serializer/attribute-serializer.d.ts.map +1 -0
- package/dist/src/serializer/attribute-serializer.js +34 -0
- package/dist/src/serializer/field-serializer.d.ts +112 -0
- package/dist/src/serializer/field-serializer.d.ts.map +1 -0
- package/dist/src/serializer/field-serializer.js +212 -0
- package/dist/src/serializer/media-serializer.d.ts +31 -0
- package/dist/src/serializer/media-serializer.d.ts.map +1 -0
- package/dist/src/serializer/media-serializer.js +83 -0
- package/dist/src/serializer/session-serializer.d.ts +29 -0
- package/dist/src/serializer/session-serializer.d.ts.map +1 -0
- package/dist/src/serializer/session-serializer.js +99 -0
- package/dist/src/serializer/time-serializer.d.ts +46 -0
- package/dist/src/serializer/time-serializer.d.ts.map +1 -0
- package/dist/src/serializer/time-serializer.js +86 -0
- package/dist/src/types/attributes.d.ts +318 -0
- package/dist/src/types/attributes.d.ts.map +1 -0
- package/dist/src/types/attributes.js +225 -0
- package/dist/src/types/errors.d.ts +129 -0
- package/dist/src/types/errors.d.ts.map +1 -0
- package/dist/src/types/errors.js +186 -0
- package/dist/src/types/fields.d.ts +100 -0
- package/dist/src/types/fields.d.ts.map +1 -0
- package/dist/src/types/fields.js +48 -0
- package/dist/src/types/media.d.ts +148 -0
- package/dist/src/types/media.d.ts.map +1 -0
- package/dist/src/types/media.js +137 -0
- package/dist/src/types/network.d.ts +136 -0
- package/dist/src/types/network.d.ts.map +1 -0
- package/dist/src/types/network.js +130 -0
- package/dist/src/types/primitives.d.ts +193 -0
- package/dist/src/types/primitives.d.ts.map +1 -0
- package/dist/src/types/primitives.js +195 -0
- package/dist/src/types/session.d.ts +122 -0
- package/dist/src/types/session.d.ts.map +1 -0
- package/dist/src/types/session.js +81 -0
- package/dist/src/types/time.d.ts +129 -0
- package/dist/src/types/time.d.ts.map +1 -0
- package/dist/src/types/time.js +84 -0
- package/dist/src/utils/address-parser.d.ts +100 -0
- package/dist/src/utils/address-parser.d.ts.map +1 -0
- package/dist/src/utils/address-parser.js +338 -0
- package/dist/src/utils/format-validators.d.ts +77 -0
- package/dist/src/utils/format-validators.d.ts.map +1 -0
- package/dist/src/utils/format-validators.js +504 -0
- package/dist/src/utils/line-reader.d.ts +84 -0
- package/dist/src/utils/line-reader.d.ts.map +1 -0
- package/dist/src/utils/line-reader.js +169 -0
- package/dist/src/utils/time-converter.d.ts +99 -0
- package/dist/src/utils/time-converter.d.ts.map +1 -0
- package/dist/src/utils/time-converter.js +195 -0
- package/dist/src/validator/media-validator.d.ts +27 -0
- package/dist/src/validator/media-validator.d.ts.map +1 -0
- package/dist/src/validator/media-validator.js +241 -0
- package/dist/src/validator/semantic-validator.d.ts +47 -0
- package/dist/src/validator/semantic-validator.d.ts.map +1 -0
- package/dist/src/validator/semantic-validator.js +207 -0
- package/dist/src/validator/session-validator.d.ts +36 -0
- package/dist/src/validator/session-validator.d.ts.map +1 -0
- package/dist/src/validator/session-validator.js +280 -0
- package/dist/tests/integration/round-trip.test.d.ts +5 -0
- package/dist/tests/integration/round-trip.test.d.ts.map +1 -0
- package/dist/tests/integration/round-trip.test.js +320 -0
- package/dist/tests/integration/voip-examples.test.d.ts +5 -0
- package/dist/tests/integration/voip-examples.test.d.ts.map +1 -0
- package/dist/tests/integration/voip-examples.test.js +361 -0
- package/dist/tests/unit/builder/media-builder.test.d.ts +5 -0
- package/dist/tests/unit/builder/media-builder.test.d.ts.map +1 -0
- package/dist/tests/unit/builder/media-builder.test.js +524 -0
- package/dist/tests/unit/builder/session-builder.test.d.ts +5 -0
- package/dist/tests/unit/builder/session-builder.test.d.ts.map +1 -0
- package/dist/tests/unit/builder/session-builder.test.js +367 -0
- package/dist/tests/unit/parser/attribute-parser.test.d.ts +5 -0
- package/dist/tests/unit/parser/attribute-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/attribute-parser.test.js +319 -0
- package/dist/tests/unit/parser/field-parser.test.d.ts +5 -0
- package/dist/tests/unit/parser/field-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/field-parser.test.js +355 -0
- package/dist/tests/unit/parser/media-parser.test.d.ts +5 -0
- package/dist/tests/unit/parser/media-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/media-parser.test.js +241 -0
- package/dist/tests/unit/parser/primitive-parser.test.d.ts +5 -0
- package/dist/tests/unit/parser/primitive-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/primitive-parser.test.js +261 -0
- package/dist/tests/unit/parser/scanner.test.d.ts +5 -0
- package/dist/tests/unit/parser/scanner.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/scanner.test.js +241 -0
- package/dist/tests/unit/parser/session-parser.test.d.ts +5 -0
- package/dist/tests/unit/parser/session-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/session-parser.test.js +346 -0
- package/dist/tests/unit/parser/time-parser.test.d.ts +5 -0
- package/dist/tests/unit/parser/time-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/parser/time-parser.test.js +173 -0
- package/dist/tests/unit/serializer/attribute-serializer.test.d.ts +5 -0
- package/dist/tests/unit/serializer/attribute-serializer.test.d.ts.map +1 -0
- package/dist/tests/unit/serializer/attribute-serializer.test.js +78 -0
- package/dist/tests/unit/serializer/field-serializer.test.d.ts +5 -0
- package/dist/tests/unit/serializer/field-serializer.test.d.ts.map +1 -0
- package/dist/tests/unit/serializer/field-serializer.test.js +159 -0
- package/dist/tests/unit/serializer/media-serializer.test.d.ts +5 -0
- package/dist/tests/unit/serializer/media-serializer.test.d.ts.map +1 -0
- package/dist/tests/unit/serializer/media-serializer.test.js +155 -0
- package/dist/tests/unit/serializer/session-serializer.test.d.ts +5 -0
- package/dist/tests/unit/serializer/session-serializer.test.d.ts.map +1 -0
- package/dist/tests/unit/serializer/session-serializer.test.js +317 -0
- package/dist/tests/unit/serializer/time-serializer.test.d.ts +5 -0
- package/dist/tests/unit/serializer/time-serializer.test.d.ts.map +1 -0
- package/dist/tests/unit/serializer/time-serializer.test.js +115 -0
- package/dist/tests/unit/types/errors.test.d.ts +5 -0
- package/dist/tests/unit/types/errors.test.d.ts.map +1 -0
- package/dist/tests/unit/types/errors.test.js +127 -0
- package/dist/tests/unit/types/network.test.d.ts +5 -0
- package/dist/tests/unit/types/network.test.d.ts.map +1 -0
- package/dist/tests/unit/types/network.test.js +132 -0
- package/dist/tests/unit/types/primitives.test.d.ts +5 -0
- package/dist/tests/unit/types/primitives.test.d.ts.map +1 -0
- package/dist/tests/unit/types/primitives.test.js +108 -0
- package/dist/tests/unit/utils/address-parser.test.d.ts +5 -0
- package/dist/tests/unit/utils/address-parser.test.d.ts.map +1 -0
- package/dist/tests/unit/utils/address-parser.test.js +203 -0
- package/dist/tests/unit/utils/format-validators.test.d.ts +5 -0
- package/dist/tests/unit/utils/format-validators.test.d.ts.map +1 -0
- package/dist/tests/unit/utils/format-validators.test.js +224 -0
- package/dist/tests/unit/utils/line-reader.test.d.ts +5 -0
- package/dist/tests/unit/utils/line-reader.test.d.ts.map +1 -0
- package/dist/tests/unit/utils/line-reader.test.js +157 -0
- package/dist/tests/unit/utils/time-converter.test.d.ts +5 -0
- package/dist/tests/unit/utils/time-converter.test.d.ts.map +1 -0
- package/dist/tests/unit/utils/time-converter.test.js +190 -0
- package/dist/tests/unit/validator/media-validator.test.d.ts +5 -0
- package/dist/tests/unit/validator/media-validator.test.d.ts.map +1 -0
- package/dist/tests/unit/validator/media-validator.test.js +313 -0
- package/dist/tests/unit/validator/semantic-validator.test.d.ts +5 -0
- package/dist/tests/unit/validator/semantic-validator.test.d.ts.map +1 -0
- package/dist/tests/unit/validator/semantic-validator.test.js +262 -0
- package/dist/tests/unit/validator/session-validator.test.d.ts +5 -0
- package/dist/tests/unit/validator/session-validator.test.d.ts.map +1 -0
- package/dist/tests/unit/validator/session-validator.test.js +447 -0
- package/package.json +50 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration tests with real-world VoIP/SIP SDP examples
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const src_1 = require("../../src");
|
|
7
|
+
describe('VoIP/SIP SDP examples', () => {
|
|
8
|
+
describe('SIP INVITE SDP', () => {
|
|
9
|
+
it('should parse and validate typical SIP INVITE offer', () => {
|
|
10
|
+
const sipInviteSdp = [
|
|
11
|
+
'v=0',
|
|
12
|
+
'o=alice 2890844526 2890844526 IN IP4 192.168.1.100',
|
|
13
|
+
's=Phone Call',
|
|
14
|
+
'c=IN IP4 192.168.1.100',
|
|
15
|
+
't=0 0',
|
|
16
|
+
'm=audio 49170 RTP/AVP 0 8 101',
|
|
17
|
+
'a=rtpmap:0 PCMU/8000',
|
|
18
|
+
'a=rtpmap:8 PCMA/8000',
|
|
19
|
+
'a=rtpmap:101 telephone-event/8000',
|
|
20
|
+
'a=fmtp:101 0-15',
|
|
21
|
+
'a=ptime:20',
|
|
22
|
+
'a=sendrecv',
|
|
23
|
+
'',
|
|
24
|
+
].join('\r\n');
|
|
25
|
+
const parsed = (0, src_1.parseSessionDescription)(sipInviteSdp);
|
|
26
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
27
|
+
expect(validationResult.valid).toBe(true);
|
|
28
|
+
expect(parsed.mediaDescriptions).toHaveLength(1);
|
|
29
|
+
expect(parsed.mediaDescriptions[0].media.type).toBe('audio');
|
|
30
|
+
expect(parsed.mediaDescriptions[0].media.formats).toContain('101');
|
|
31
|
+
});
|
|
32
|
+
it('should parse and validate SIP 200 OK answer', () => {
|
|
33
|
+
const sip200Sdp = [
|
|
34
|
+
'v=0',
|
|
35
|
+
'o=bob 2890844527 2890844527 IN IP4 10.0.0.50',
|
|
36
|
+
's=Phone Call',
|
|
37
|
+
'c=IN IP4 10.0.0.50',
|
|
38
|
+
't=0 0',
|
|
39
|
+
'm=audio 5004 RTP/AVP 0 101',
|
|
40
|
+
'a=rtpmap:0 PCMU/8000',
|
|
41
|
+
'a=rtpmap:101 telephone-event/8000',
|
|
42
|
+
'a=fmtp:101 0-15',
|
|
43
|
+
'a=ptime:20',
|
|
44
|
+
'a=sendrecv',
|
|
45
|
+
'',
|
|
46
|
+
].join('\r\n');
|
|
47
|
+
const parsed = (0, src_1.parseSessionDescription)(sip200Sdp);
|
|
48
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
49
|
+
expect(validationResult.valid).toBe(true);
|
|
50
|
+
expect(parsed.mediaDescriptions[0].media.port.kind).toBe('simple');
|
|
51
|
+
expect(parsed.mediaDescriptions[0].media.port.value).toBe(5004);
|
|
52
|
+
});
|
|
53
|
+
it('should build SIP offer SDP using builders', () => {
|
|
54
|
+
const session = new src_1.SessionBuilder()
|
|
55
|
+
.origin('alice', '2890844526', '2890844526', '192.168.1.100')
|
|
56
|
+
.sessionName('Phone Call')
|
|
57
|
+
.connection('192.168.1.100')
|
|
58
|
+
.addMediaBuilder((b) => b
|
|
59
|
+
.type('audio')
|
|
60
|
+
.port(49170)
|
|
61
|
+
.protocol('RTP/AVP')
|
|
62
|
+
.formats(['0', '8', '101'])
|
|
63
|
+
.rtpmap(0, 'PCMU', 8000)
|
|
64
|
+
.rtpmap(8, 'PCMA', 8000)
|
|
65
|
+
.rtpmap(101, 'telephone-event', 8000)
|
|
66
|
+
.fmtp(101, '0-15')
|
|
67
|
+
.ptime(20)
|
|
68
|
+
.sendrecv())
|
|
69
|
+
.build();
|
|
70
|
+
const validationResult = (0, src_1.validateSdp)(session);
|
|
71
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
72
|
+
expect(validationResult.valid).toBe(true);
|
|
73
|
+
expect(serialized).toContain('m=audio 49170 RTP/AVP 0 8 101');
|
|
74
|
+
expect(serialized).toContain('a=rtpmap:101 telephone-event/8000');
|
|
75
|
+
expect(serialized).toContain('a=fmtp:101 0-15');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('SIP re-INVITE for hold', () => {
|
|
79
|
+
it('should parse hold SDP with sendonly direction', () => {
|
|
80
|
+
const holdSdp = [
|
|
81
|
+
'v=0',
|
|
82
|
+
'o=alice 2890844526 2890844527 IN IP4 192.168.1.100',
|
|
83
|
+
's=Phone Call',
|
|
84
|
+
'c=IN IP4 0.0.0.0',
|
|
85
|
+
't=0 0',
|
|
86
|
+
'm=audio 49170 RTP/AVP 0',
|
|
87
|
+
'a=rtpmap:0 PCMU/8000',
|
|
88
|
+
'a=sendonly',
|
|
89
|
+
'',
|
|
90
|
+
].join('\r\n');
|
|
91
|
+
const parsed = (0, src_1.parseSessionDescription)(holdSdp);
|
|
92
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
93
|
+
expect(validationResult.valid).toBe(true);
|
|
94
|
+
expect(parsed.mediaDescriptions[0].attributes).toContainEqual({
|
|
95
|
+
kind: 'property',
|
|
96
|
+
name: 'sendonly',
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
it('should build hold SDP using builders', () => {
|
|
100
|
+
const session = new src_1.SessionBuilder()
|
|
101
|
+
.origin('alice', '2890844526', '2890844527', '192.168.1.100')
|
|
102
|
+
.sessionName('Phone Call')
|
|
103
|
+
.connection('0.0.0.0') // Hold address
|
|
104
|
+
.addMediaBuilder((b) => b.type('audio').port(49170).protocol('RTP/AVP').formats(['0']).rtpmap(0, 'PCMU', 8000).sendonly())
|
|
105
|
+
.build();
|
|
106
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
107
|
+
expect(serialized).toContain('c=IN IP4 0.0.0.0');
|
|
108
|
+
expect(serialized).toContain('a=sendonly');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('Audio/Video call SDP', () => {
|
|
112
|
+
it('should parse and validate A/V SDP', () => {
|
|
113
|
+
const avSdp = [
|
|
114
|
+
'v=0',
|
|
115
|
+
'o=alice 2890844526 2890844526 IN IP4 192.168.1.100',
|
|
116
|
+
's=Video Call',
|
|
117
|
+
'c=IN IP4 192.168.1.100',
|
|
118
|
+
'b=CT:1500',
|
|
119
|
+
't=0 0',
|
|
120
|
+
'm=audio 49170 RTP/AVP 0 8',
|
|
121
|
+
'b=AS:128',
|
|
122
|
+
'a=rtpmap:0 PCMU/8000',
|
|
123
|
+
'a=rtpmap:8 PCMA/8000',
|
|
124
|
+
'a=sendrecv',
|
|
125
|
+
'm=video 51372 RTP/AVP 96',
|
|
126
|
+
'b=AS:1000',
|
|
127
|
+
'a=rtpmap:96 H264/90000',
|
|
128
|
+
'a=fmtp:96 profile-level-id=42e01f',
|
|
129
|
+
'a=sendrecv',
|
|
130
|
+
'',
|
|
131
|
+
].join('\r\n');
|
|
132
|
+
const parsed = (0, src_1.parseSessionDescription)(avSdp);
|
|
133
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
134
|
+
expect(validationResult.valid).toBe(true);
|
|
135
|
+
expect(parsed.mediaDescriptions).toHaveLength(2);
|
|
136
|
+
expect(parsed.mediaDescriptions[0].media.type).toBe('audio');
|
|
137
|
+
expect(parsed.mediaDescriptions[1].media.type).toBe('video');
|
|
138
|
+
expect(parsed.bandwidths[0].type).toBe('CT');
|
|
139
|
+
expect(parsed.bandwidths[0].value).toBe(1500);
|
|
140
|
+
});
|
|
141
|
+
it('should build A/V SDP using builders', () => {
|
|
142
|
+
const session = new src_1.SessionBuilder()
|
|
143
|
+
.origin('alice', '2890844526', '2890844526', '192.168.1.100')
|
|
144
|
+
.sessionName('Video Call')
|
|
145
|
+
.connection('192.168.1.100')
|
|
146
|
+
.addBandwidth('CT', 1500)
|
|
147
|
+
.addMediaBuilder((b) => b
|
|
148
|
+
.type('audio')
|
|
149
|
+
.port(49170)
|
|
150
|
+
.protocol('RTP/AVP')
|
|
151
|
+
.formats(['0', '8'])
|
|
152
|
+
.bandwidth(128)
|
|
153
|
+
.rtpmap(0, 'PCMU', 8000)
|
|
154
|
+
.rtpmap(8, 'PCMA', 8000)
|
|
155
|
+
.sendrecv())
|
|
156
|
+
.addMediaBuilder((b) => b
|
|
157
|
+
.type('video')
|
|
158
|
+
.port(51372)
|
|
159
|
+
.protocol('RTP/AVP')
|
|
160
|
+
.formats(['96'])
|
|
161
|
+
.bandwidth(1000)
|
|
162
|
+
.rtpmap(96, 'H264', 90000)
|
|
163
|
+
.fmtp(96, 'profile-level-id=42e01f')
|
|
164
|
+
.sendrecv())
|
|
165
|
+
.build();
|
|
166
|
+
const validationResult = (0, src_1.validateSdp)(session);
|
|
167
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
168
|
+
expect(validationResult.valid).toBe(true);
|
|
169
|
+
expect(serialized).toContain('b=CT:1500');
|
|
170
|
+
expect(serialized).toContain('m=audio 49170 RTP/AVP 0 8');
|
|
171
|
+
expect(serialized).toContain('m=video 51372 RTP/AVP 96');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe('Disabled media stream', () => {
|
|
175
|
+
it('should parse SDP with disabled media (port 0)', () => {
|
|
176
|
+
const disabledMediaSdp = [
|
|
177
|
+
'v=0',
|
|
178
|
+
'o=alice 2890844526 2890844527 IN IP4 192.168.1.100',
|
|
179
|
+
's=Call',
|
|
180
|
+
'c=IN IP4 192.168.1.100',
|
|
181
|
+
't=0 0',
|
|
182
|
+
'm=audio 49170 RTP/AVP 0',
|
|
183
|
+
'a=rtpmap:0 PCMU/8000',
|
|
184
|
+
'a=sendrecv',
|
|
185
|
+
'm=video 0 RTP/AVP 96',
|
|
186
|
+
'a=rtpmap:96 H264/90000',
|
|
187
|
+
'',
|
|
188
|
+
].join('\r\n');
|
|
189
|
+
const parsed = (0, src_1.parseSessionDescription)(disabledMediaSdp);
|
|
190
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
191
|
+
expect(validationResult.valid).toBe(true);
|
|
192
|
+
expect(parsed.mediaDescriptions[1].media.port).toEqual({ kind: 'simple', value: 0 });
|
|
193
|
+
});
|
|
194
|
+
it('should build SDP with disabled video using builders', () => {
|
|
195
|
+
const session = new src_1.SessionBuilder()
|
|
196
|
+
.origin('alice', '123', '456', '192.168.1.100')
|
|
197
|
+
.sessionName('Audio Only')
|
|
198
|
+
.connection('192.168.1.100')
|
|
199
|
+
.addMediaBuilder((b) => b.type('audio').port(49170).protocol('RTP/AVP').formats(['0']).rtpmap(0, 'PCMU', 8000).sendrecv())
|
|
200
|
+
.addMediaBuilder((b) => b.type('video').disabled().protocol('RTP/AVP').formats(['96']).rtpmap(96, 'H264', 90000))
|
|
201
|
+
.build();
|
|
202
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
203
|
+
expect(serialized).toContain('m=audio 49170 RTP/AVP 0');
|
|
204
|
+
expect(serialized).toContain('m=video 0 RTP/AVP 96');
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe('SRTP secure media', () => {
|
|
208
|
+
it('should parse SRTP SDP', () => {
|
|
209
|
+
const srtpSdp = [
|
|
210
|
+
'v=0',
|
|
211
|
+
'o=alice 2890844526 2890844526 IN IP4 192.168.1.100',
|
|
212
|
+
's=Secure Call',
|
|
213
|
+
'c=IN IP4 192.168.1.100',
|
|
214
|
+
't=0 0',
|
|
215
|
+
'm=audio 49170 RTP/SAVP 0',
|
|
216
|
+
'a=rtpmap:0 PCMU/8000',
|
|
217
|
+
'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WVNfX19zZW1NjCrHcF',
|
|
218
|
+
'a=sendrecv',
|
|
219
|
+
'',
|
|
220
|
+
].join('\r\n');
|
|
221
|
+
const parsed = (0, src_1.parseSessionDescription)(srtpSdp);
|
|
222
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
223
|
+
expect(validationResult.valid).toBe(true);
|
|
224
|
+
expect(parsed.mediaDescriptions[0].media.proto).toBe('RTP/SAVP');
|
|
225
|
+
});
|
|
226
|
+
it('should build SRTP SDP using builders', () => {
|
|
227
|
+
const session = new src_1.SessionBuilder()
|
|
228
|
+
.origin('alice', '123', '456', '192.168.1.100')
|
|
229
|
+
.sessionName('Secure Call')
|
|
230
|
+
.connection('192.168.1.100')
|
|
231
|
+
.addMediaBuilder((b) => b
|
|
232
|
+
.type('audio')
|
|
233
|
+
.port(49170)
|
|
234
|
+
.protocol('RTP/SAVP')
|
|
235
|
+
.formats(['0'])
|
|
236
|
+
.rtpmap(0, 'PCMU', 8000)
|
|
237
|
+
.addValueAttribute('crypto', '1 AES_CM_128_HMAC_SHA1_80 inline:WVNfX19zZW1NjCrHcF')
|
|
238
|
+
.sendrecv())
|
|
239
|
+
.build();
|
|
240
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
241
|
+
expect(serialized).toContain('m=audio 49170 RTP/SAVP 0');
|
|
242
|
+
expect(serialized).toContain('a=crypto:');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
describe('IPv6 SDP', () => {
|
|
246
|
+
it('should parse IPv6 SDP', () => {
|
|
247
|
+
var _a;
|
|
248
|
+
const ipv6Sdp = [
|
|
249
|
+
'v=0',
|
|
250
|
+
'o=alice 2890844526 2890844526 IN IP6 2001:db8::1',
|
|
251
|
+
's=IPv6 Call',
|
|
252
|
+
'c=IN IP6 2001:db8::100',
|
|
253
|
+
't=0 0',
|
|
254
|
+
'm=audio 49170 RTP/AVP 0',
|
|
255
|
+
'a=rtpmap:0 PCMU/8000',
|
|
256
|
+
'',
|
|
257
|
+
].join('\r\n');
|
|
258
|
+
const parsed = (0, src_1.parseSessionDescription)(ipv6Sdp);
|
|
259
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
260
|
+
expect(validationResult.valid).toBe(true);
|
|
261
|
+
expect(parsed.origin.addrType).toBe('IP6');
|
|
262
|
+
expect((_a = parsed.connection) === null || _a === void 0 ? void 0 : _a.addrType).toBe('IP6');
|
|
263
|
+
});
|
|
264
|
+
it('should build IPv6 SDP using builders', () => {
|
|
265
|
+
const session = new src_1.SessionBuilder()
|
|
266
|
+
.origin('alice', '123', '456', '2001:db8::1')
|
|
267
|
+
.sessionName('IPv6 Call')
|
|
268
|
+
.connection('2001:db8::100')
|
|
269
|
+
.addMediaBuilder((b) => b.type('audio').port(49170).protocol('RTP/AVP').formats(['0']).rtpmap(0, 'PCMU', 8000))
|
|
270
|
+
.build();
|
|
271
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
272
|
+
expect(serialized).toContain('IN IP6 2001:db8::1');
|
|
273
|
+
expect(serialized).toContain('c=IN IP6 2001:db8::100');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
describe('WebRTC-style SDP', () => {
|
|
277
|
+
it('should parse WebRTC-style SDP with ICE and DTLS', () => {
|
|
278
|
+
const webrtcSdp = [
|
|
279
|
+
'v=0',
|
|
280
|
+
'o=- 123456789 2 IN IP4 127.0.0.1',
|
|
281
|
+
's=-',
|
|
282
|
+
't=0 0',
|
|
283
|
+
'a=group:BUNDLE audio video',
|
|
284
|
+
'm=audio 9 UDP/TLS/RTP/SAVPF 111',
|
|
285
|
+
'c=IN IP4 0.0.0.0',
|
|
286
|
+
'a=rtcp:9 IN IP4 0.0.0.0',
|
|
287
|
+
'a=ice-ufrag:abcd',
|
|
288
|
+
'a=ice-pwd:efghijklmnopqrstuvwxyz',
|
|
289
|
+
'a=fingerprint:sha-256 AB:CD:EF:12:34:56:78:90',
|
|
290
|
+
'a=setup:actpass',
|
|
291
|
+
'a=mid:audio',
|
|
292
|
+
'a=rtpmap:111 opus/48000/2',
|
|
293
|
+
'a=fmtp:111 minptime=10;useinbandfec=1',
|
|
294
|
+
'a=rtcp-mux',
|
|
295
|
+
'a=sendrecv',
|
|
296
|
+
'm=video 9 UDP/TLS/RTP/SAVPF 96',
|
|
297
|
+
'c=IN IP4 0.0.0.0',
|
|
298
|
+
'a=rtcp:9 IN IP4 0.0.0.0',
|
|
299
|
+
'a=ice-ufrag:abcd',
|
|
300
|
+
'a=ice-pwd:efghijklmnopqrstuvwxyz',
|
|
301
|
+
'a=fingerprint:sha-256 AB:CD:EF:12:34:56:78:90',
|
|
302
|
+
'a=setup:actpass',
|
|
303
|
+
'a=mid:video',
|
|
304
|
+
'a=rtpmap:96 VP8/90000',
|
|
305
|
+
'a=rtcp-mux',
|
|
306
|
+
'a=sendrecv',
|
|
307
|
+
'',
|
|
308
|
+
].join('\r\n');
|
|
309
|
+
const parsed = (0, src_1.parseSessionDescription)(webrtcSdp);
|
|
310
|
+
const validationResult = (0, src_1.validateSdp)(parsed);
|
|
311
|
+
expect(validationResult.valid).toBe(true);
|
|
312
|
+
expect(parsed.mediaDescriptions).toHaveLength(2);
|
|
313
|
+
expect(parsed.mediaDescriptions[0].media.proto).toBe('UDP/TLS/RTP/SAVPF');
|
|
314
|
+
});
|
|
315
|
+
it('should build WebRTC-style SDP using builders', () => {
|
|
316
|
+
const session = new src_1.SessionBuilder()
|
|
317
|
+
.origin('-', '123456789', '2', '127.0.0.1')
|
|
318
|
+
.sessionName('-')
|
|
319
|
+
.addValueAttribute('group', 'BUNDLE audio video')
|
|
320
|
+
.addMediaBuilder((b) => b
|
|
321
|
+
.type('audio')
|
|
322
|
+
.port(9)
|
|
323
|
+
.protocol('UDP/TLS/RTP/SAVPF')
|
|
324
|
+
.formats(['111'])
|
|
325
|
+
.connection('0.0.0.0')
|
|
326
|
+
.rtcp(9, '0.0.0.0')
|
|
327
|
+
.iceUfrag('abcd')
|
|
328
|
+
.icePwd('efghijklmnopqrstuvwxyz')
|
|
329
|
+
.fingerprint('sha-256', 'AB:CD:EF:12:34:56:78:90')
|
|
330
|
+
.setup('actpass')
|
|
331
|
+
.mid('audio')
|
|
332
|
+
.rtpmap(111, 'opus', 48000, 2)
|
|
333
|
+
.fmtp(111, 'minptime=10;useinbandfec=1')
|
|
334
|
+
.rtcpMux()
|
|
335
|
+
.sendrecv())
|
|
336
|
+
.addMediaBuilder((b) => b
|
|
337
|
+
.type('video')
|
|
338
|
+
.port(9)
|
|
339
|
+
.protocol('UDP/TLS/RTP/SAVPF')
|
|
340
|
+
.formats(['96'])
|
|
341
|
+
.connection('0.0.0.0')
|
|
342
|
+
.rtcp(9, '0.0.0.0')
|
|
343
|
+
.iceUfrag('abcd')
|
|
344
|
+
.icePwd('efghijklmnopqrstuvwxyz')
|
|
345
|
+
.fingerprint('sha-256', 'AB:CD:EF:12:34:56:78:90')
|
|
346
|
+
.setup('actpass')
|
|
347
|
+
.mid('video')
|
|
348
|
+
.rtpmap(96, 'VP8', 90000)
|
|
349
|
+
.rtcpMux()
|
|
350
|
+
.sendrecv())
|
|
351
|
+
.build();
|
|
352
|
+
const validationResult = (0, src_1.validateSdp)(session);
|
|
353
|
+
const serialized = (0, src_1.serializeSessionDescription)(session);
|
|
354
|
+
expect(validationResult.valid).toBe(true);
|
|
355
|
+
expect(serialized).toContain('a=group:BUNDLE audio video');
|
|
356
|
+
expect(serialized).toContain('a=ice-ufrag:abcd');
|
|
357
|
+
expect(serialized).toContain('a=fingerprint:sha-256 AB:CD:EF:12:34:56:78:90');
|
|
358
|
+
expect(serialized).toContain('a=rtcp-mux');
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-builder.test.d.ts","sourceRoot":"","sources":["../../../../tests/unit/builder/media-builder.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|