use super::kind::{DtmfSource, MessageKind};
fn is_valid_dtmf_digit(c: char) -> bool {
matches!(c, '0'..='9' | '*' | '#' | 'A'..='D' | 'F')
}
fn parse_digit_duration(rest: &str) -> Option<(char, u32)> {
let colon = rest.find(':')?;
if colon != 1 {
return None;
}
let digit = rest.chars().next()?;
if !is_valid_dtmf_digit(digit) {
return None;
}
let duration_ms = rest[colon + 1..].parse::<u32>().ok()?;
Some((digit, duration_ms))
}
pub(super) fn parse_dtmf(msg: &str) -> Option<MessageKind> {
if let Some(rest) = msg.strip_prefix("RTP RECV DTMF ") {
let (digit, duration_ms) = parse_digit_duration(rest)?;
return Some(MessageKind::Dtmf {
source: DtmfSource::Rtp,
digit,
duration_ms: Some(duration_ms),
});
}
if let Some(rest) = msg.strip_prefix("RECV DTMF ") {
let (digit, duration_ms) = parse_digit_duration(rest)?;
return Some(MessageKind::Dtmf {
source: DtmfSource::Channel,
digit,
duration_ms: Some(duration_ms),
});
}
if let Some(rest) = msg.strip_prefix("INFO DTMF(") {
let close = rest.find(')')?;
if close != 1 {
return None;
}
let digit = rest.chars().next()?;
if !is_valid_dtmf_digit(digit) {
return None;
}
return Some(MessageKind::Dtmf {
source: DtmfSource::SipInfo,
digit,
duration_ms: None,
});
}
None
}