mirror of
https://github.com/coral/sipcord-bridge.git
synced 2026-06-29 09:23:14 -06:00
trying to get intercom working
This commit is contained in:
parent
6e416573e5
commit
46c6907f59
|
|
@ -7,7 +7,7 @@ RTP_PUBLIC_IP=192.168.0.100
|
|||
# DISCORD_OUTBOUND_SIP_HOST=192.168.0.25
|
||||
# DISCORD_OUTBOUND_SIP_PORT=5060
|
||||
# DISCORD_OUTBOUND_SIP_TRANSPORT=udp
|
||||
# DISCORD_OUTBOUND_EXTENSION_PREFIX=*80
|
||||
# DISCORD_OUTBOUND_EXTENSION_PREFIX=
|
||||
# DATA_DIR=/var/lib/sipcord
|
||||
# CONFIG_PATH=./config.toml
|
||||
# SOUNDS_DIR=./wav
|
||||
|
|
|
|||
21
README.md
21
README.md
|
|
@ -73,7 +73,7 @@ RTP_PUBLIC_IP=192.168.0.100
|
|||
DISCORD_OUTBOUND_SIP_HOST=192.168.0.25
|
||||
DISCORD_OUTBOUND_SIP_PORT=5060
|
||||
DISCORD_OUTBOUND_SIP_TRANSPORT=udp
|
||||
DISCORD_OUTBOUND_EXTENSION_PREFIX=*80
|
||||
DISCORD_OUTBOUND_EXTENSION_PREFIX=
|
||||
```
|
||||
|
||||
Set both IPs to the address other SIP devices use to reach the bridge. For
|
||||
|
|
@ -86,10 +86,11 @@ Set `DISCORD_OUTBOUND_SIP_HOST` to the PBX or SIP server that should receive
|
|||
Discord-originated extension calls. For a FreePBX box at `192.168.0.25`, that
|
||||
means `DISCORD_OUTBOUND_SIP_HOST=192.168.0.25`.
|
||||
|
||||
By default, Discord-originated calls prepend `*80` to the requested extension so
|
||||
FreePBX intercom/auto-answer targets work out of the box. Set
|
||||
`DISCORD_OUTBOUND_EXTENSION_PREFIX=` to an empty string if you want plain
|
||||
extension dialing instead.
|
||||
Discord-originated calls dial the requested extension directly by default. The
|
||||
bridge also attaches common auto-answer headers (`Call-Info:
|
||||
<uri>;answer-after=0` and `Alert-Info: Ring Answer`) to Discord-originated
|
||||
outbound calls so auto-answer phones can behave more like FreePBX intercom
|
||||
targets.
|
||||
|
||||
Create a `docker-compose.yml`:
|
||||
|
||||
|
|
@ -212,10 +213,10 @@ Behavior:
|
|||
- The user running `/call` must already be in a Discord voice channel.
|
||||
- The bot uses that voice channel as the bridge destination.
|
||||
- The bridge dials the requested extension through the configured PBX target.
|
||||
- By default it prepends `*80`, so `/call extension:1101` becomes something like
|
||||
`sip:*801101@192.168.0.25:5060;transport=udp`.
|
||||
- Set `DISCORD_OUTBOUND_EXTENSION_PREFIX=` to empty if you want `/call
|
||||
extension:1101` to dial `1101` directly instead.
|
||||
- It dials the requested extension directly, for example
|
||||
`sip:1101@192.168.0.25:5060;transport=udp`.
|
||||
- Discord-originated outbound calls also include common auto-answer headers so
|
||||
phones configured for that behavior can answer immediately.
|
||||
- When the SIP side answers, the phone call is connected to the Discord voice
|
||||
channel where the command was run.
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ Dial `1000` (or whatever you put in `dialplan.toml`) and you should hear the bot
|
|||
| `DISCORD_OUTBOUND_SIP_HOST` | *(disabled if unset)* | PBX/SIP host used by Discord `/call` |
|
||||
| `DISCORD_OUTBOUND_SIP_PORT` | `5060` | Port for Discord-originated outbound SIP calls |
|
||||
| `DISCORD_OUTBOUND_SIP_TRANSPORT` | `udp` | Transport for Discord-originated outbound SIP calls: `udp`, `tcp`, or `tls` |
|
||||
| `DISCORD_OUTBOUND_EXTENSION_PREFIX` | `*80` | Prefix prepended before the requested extension for Discord-originated calls; set empty for direct dialing |
|
||||
| `DISCORD_OUTBOUND_EXTENSION_PREFIX` | `""` | Optional prefix prepended before the requested extension for Discord-originated calls |
|
||||
| `CONFIG_PATH` | `./config.toml` | Path to config.toml |
|
||||
| `DIALPLAN_PATH` | `./dialplan.toml` | Path to dialplan.toml |
|
||||
| `SOUNDS_DIR` | `./wav` | Path to sound files directory |
|
||||
|
|
|
|||
|
|
@ -553,6 +553,7 @@ impl BridgeCoordinator {
|
|||
tracking_id: req.call_id.clone(),
|
||||
sip_uri,
|
||||
caller_display_name: Some(req.caller_username.clone()),
|
||||
auto_answer: true,
|
||||
fork_total,
|
||||
});
|
||||
outbound_backend.report_call_status(&req.call_id, "ringing");
|
||||
|
|
@ -585,6 +586,7 @@ impl BridgeCoordinator {
|
|||
tracking_id: req.call_id.clone(),
|
||||
sip_uri,
|
||||
caller_display_name: Some(req.caller_username.clone()),
|
||||
auto_answer: false,
|
||||
fork_total,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ fn default_discord_outbound_sip_transport() -> String {
|
|||
"udp".to_string()
|
||||
}
|
||||
fn default_discord_outbound_extension_prefix() -> String {
|
||||
"*80".to_string()
|
||||
String::new()
|
||||
}
|
||||
|
||||
/// All environment variables consumed by the bridge, deserialized once at startup.
|
||||
|
|
@ -546,7 +546,7 @@ mod tests {
|
|||
discord_outbound_sip_host: None,
|
||||
discord_outbound_sip_port: 5060,
|
||||
discord_outbound_sip_transport: "udp".to_string(),
|
||||
discord_outbound_extension_prefix: "*80".to_string(),
|
||||
discord_outbound_extension_prefix: String::new(),
|
||||
};
|
||||
assert_eq!(env.resolved_data_dir(), ".");
|
||||
}
|
||||
|
|
@ -574,7 +574,7 @@ mod tests {
|
|||
discord_outbound_sip_host: None,
|
||||
discord_outbound_sip_port: 5060,
|
||||
discord_outbound_sip_transport: "udp".to_string(),
|
||||
discord_outbound_extension_prefix: "*80".to_string(),
|
||||
discord_outbound_extension_prefix: String::new(),
|
||||
};
|
||||
assert_eq!(env.resolved_data_dir(), "/tmp");
|
||||
}
|
||||
|
|
@ -602,7 +602,7 @@ mod tests {
|
|||
discord_outbound_sip_host: None,
|
||||
discord_outbound_sip_port: 5060,
|
||||
discord_outbound_sip_transport: "udp".to_string(),
|
||||
discord_outbound_extension_prefix: "*80".to_string(),
|
||||
discord_outbound_extension_prefix: String::new(),
|
||||
};
|
||||
let tls = env.to_tls_config();
|
||||
assert_eq!(tls.cert_dir, PathBuf::from("/data/certs"));
|
||||
|
|
@ -646,13 +646,13 @@ mod tests {
|
|||
discord_outbound_sip_host: Some("192.168.0.25".to_string()),
|
||||
discord_outbound_sip_port: 5060,
|
||||
discord_outbound_sip_transport: "udp".to_string(),
|
||||
discord_outbound_extension_prefix: "*80".to_string(),
|
||||
discord_outbound_extension_prefix: String::new(),
|
||||
};
|
||||
|
||||
let outbound = env.discord_outbound_sip_config().unwrap();
|
||||
assert_eq!(
|
||||
outbound.build_sip_uri("1101"),
|
||||
"sip:*801101@192.168.0.25:5060;transport=udp"
|
||||
"sip:1101@192.168.0.25:5060;transport=udp"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ pub enum SipCommand {
|
|||
tracking_id: String,
|
||||
sip_uri: String,
|
||||
caller_display_name: Option<String>,
|
||||
auto_answer: bool,
|
||||
/// Total number of fork legs for this tracking_id (for multi-contact forking)
|
||||
fork_total: usize,
|
||||
},
|
||||
|
|
@ -407,13 +408,14 @@ fn process_sip_command(cmd: SipCommand, calls: &Arc<DashMap<CallId, CallState>>)
|
|||
tracking_id,
|
||||
sip_uri,
|
||||
caller_display_name,
|
||||
auto_answer,
|
||||
fork_total,
|
||||
} => {
|
||||
info!(
|
||||
"Making outbound call: tracking_id={}, uri={}, caller={:?}, fork={}/{}",
|
||||
tracking_id, sip_uri, caller_display_name, fork_total, fork_total
|
||||
"Making outbound call: tracking_id={}, uri={}, caller={:?}, auto_answer={}, fork={}/{}",
|
||||
tracking_id, sip_uri, caller_display_name, auto_answer, fork_total, fork_total
|
||||
);
|
||||
match make_outbound_call(&sip_uri, caller_display_name.as_deref()) {
|
||||
match make_outbound_call(&sip_uri, caller_display_name.as_deref(), auto_answer) {
|
||||
Ok(call_id) => {
|
||||
// Store tracking_id -> call_id mapping
|
||||
let outbound_calls = OUTBOUND_CALL_TRACKING.get_or_init(DashMap::new);
|
||||
|
|
@ -524,8 +526,10 @@ pub fn remove_outbound_tracking(call_id: CallId) -> Option<String> {
|
|||
fn make_outbound_call(
|
||||
sip_uri: &str,
|
||||
caller_display_name: Option<&str>,
|
||||
auto_answer: bool,
|
||||
) -> Result<CallId, SipCallError> {
|
||||
unsafe {
|
||||
use self::ffi::pj_str::make_string_hdr;
|
||||
let uri =
|
||||
std::ffi::CString::new(sip_uri).map_err(|source| SipCallError::InvalidString {
|
||||
field: "sip_uri",
|
||||
|
|
@ -548,6 +552,27 @@ fn make_outbound_call(
|
|||
::pjsua::pjsua_msg_data_init(msg_data.as_mut_ptr());
|
||||
let msg_data_ptr = msg_data.assume_init_mut();
|
||||
|
||||
if auto_answer {
|
||||
let pool = ::pjsua::pjsua_pool_create(c"outbound_call".as_ptr(), 512, 512);
|
||||
if pool.is_null() {
|
||||
return Err(SipCallError::MakeCall(-1));
|
||||
}
|
||||
|
||||
let call_info = make_string_hdr(pool, c"Call-Info", "<uri>;answer-after=0")
|
||||
.map_err(|_| SipCallError::MakeCall(-1))?;
|
||||
::pjsua::pj_list_insert_before(
|
||||
&mut msg_data_ptr.hdr_list as *mut _ as *mut ::pjsua::pj_list_type,
|
||||
call_info as *mut ::pjsua::pj_list_type,
|
||||
);
|
||||
|
||||
let alert_info = make_string_hdr(pool, c"Alert-Info", "Ring Answer")
|
||||
.map_err(|_| SipCallError::MakeCall(-1))?;
|
||||
::pjsua::pj_list_insert_before(
|
||||
&mut msg_data_ptr.hdr_list as *mut _ as *mut ::pjsua::pj_list_type,
|
||||
alert_info as *mut ::pjsua::pj_list_type,
|
||||
);
|
||||
}
|
||||
|
||||
// Build the From URI with display name: "name" <sip:sipcord@host>
|
||||
// The local_uri field overrides the From header in the outgoing INVITE
|
||||
let from_uri_cstring;
|
||||
|
|
|
|||
Loading…
Reference in a new issue