Skip to content

Commit cfe4e59

Browse files
committed
Refactor DTMF code
1 parent f59296f commit cfe4e59

2 files changed

Lines changed: 40 additions & 26 deletions

File tree

src/call-session/index.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Buffer } from "node:buffer";
44

55
import { RtpHeader, RtpPacket, SrtpSession } from "werift-rtp";
66

7-
import DTMF from "../dtmf.js";
7+
import DTMF, { type DTMFChar, isDTMFChar } from "../dtmf.js";
88
import {
99
type InboundMessage,
1010
RequestMessage,
@@ -94,9 +94,7 @@ abstract class CallSession extends EventEmitter {
9494
await this.softphone.send(requestMessage);
9595
}
9696

97-
public sendDTMF(
98-
char: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "*" | "#",
99-
) {
97+
public sendDTMF(char: DTMFChar) {
10098
const payloads = DTMF.charToPayloads(char);
10199
const timestamp = this.timestamp;
102100
let first = true;
@@ -128,7 +126,12 @@ abstract class CallSession extends EventEmitter {
128126

129127
public async sendDTMFs(s: string, delay = 500) {
130128
for (const c of s) {
131-
this.sendDTMF(c as any);
129+
if (!isDTMFChar(c)) {
130+
throw new Error(
131+
`Invalid DTMF character: "${c}". Valid characters are 0-9, *, #`,
132+
);
133+
}
134+
this.sendDTMF(c);
132135
await waitFor({ interval: delay });
133136
}
134137
}

src/dtmf.ts

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
import { Buffer } from "node:buffer";
22

3+
const PHONE_CHARS = [
4+
"0",
5+
"1",
6+
"2",
7+
"3",
8+
"4",
9+
"5",
10+
"6",
11+
"7",
12+
"8",
13+
"9",
14+
"*",
15+
"#",
16+
] as const;
17+
18+
export type DTMFChar = (typeof PHONE_CHARS)[number];
19+
20+
const VALID_DTMF_SET = new Set<string>(PHONE_CHARS);
21+
22+
export function isDTMFChar(char: string): char is DTMFChar {
23+
return VALID_DTMF_SET.has(char);
24+
}
25+
326
class DTMF {
4-
public static readonly phoneChars = [
5-
"0",
6-
"1",
7-
"2",
8-
"3",
9-
"4",
10-
"5",
11-
"6",
12-
"7",
13-
"8",
14-
"9",
15-
"*",
16-
"#",
17-
];
27+
public static readonly phoneChars = PHONE_CHARS;
28+
1829
private static readonly payloads = [
1930
0x00060000,
2031
0x000600a0,
@@ -24,11 +35,8 @@ class DTMF {
2435
0x00860320,
2536
];
2637

27-
public static charToPayloads = (char: string) => {
28-
const index = DTMF.phoneChars.indexOf(char[0]);
29-
if (index === -1) {
30-
throw new Error("invalid phone char");
31-
}
38+
public static charToPayloads = (char: DTMFChar) => {
39+
const index = DTMF.phoneChars.indexOf(char);
3240
return DTMF.payloads.map((payload) => {
3341
const temp = payload + index * 0x01000000;
3442
const buffer = Buffer.alloc(4);
@@ -37,9 +45,12 @@ class DTMF {
3745
});
3846
};
3947

40-
public static payloadToChar = (payload: Buffer) => {
48+
public static payloadToChar = (payload: Buffer): DTMFChar | undefined => {
4149
const intBE = payload.readIntBE(0, 4);
42-
const index = (intBE - 0x00060000) / 0x01000000;
50+
const index = Math.floor((intBE - 0x00060000) / 0x01000000);
51+
if (index < 0 || index >= DTMF.phoneChars.length) {
52+
return undefined;
53+
}
4354
return DTMF.phoneChars[index];
4455
};
4556
}

0 commit comments

Comments
 (0)