-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 913c9fb
Showing
8 changed files
with
1,157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
<p align="center"> | ||
<h2 align="center"> Webex Outbound Dialer</h2> | ||
|
||
<p align="center"> | ||
As of Q4 2021, it isn't possible to <i>natively</i> add a non-Webex registered SIP endpoint to a Webex Meeting ad-hoc. This proof of concept solves that issue! | ||
<br /> | ||
<a href="https://youtu.be/Kj53KW4ECNk"><strong>Video Demo</strong></a> | ||
· | ||
<a href="https://github.com/WXSD-Sales/WebexOutboundDialer/issues"><strong>Report Bug</strong></a> | ||
· | ||
<a href="https://github.com/WXSD-Sales/WebexOutboundDialer/issues"><strong>Request Feature</strong></a> | ||
</p> | ||
</p> | ||
|
||
## About The Project | ||
|
||
### Video Demo | ||
|
||
[](https://www.youtube.com/watch?v=Kj53KW4ECNk) | ||
|
||
|
||
### Flow Diagram | ||
|
||
 | ||
**Figure A:** | ||
I. **1** is the ```initialToken``` user who dials into the group meeting without any local media. This can be a guest user, bot, or licensed user. | ||
II. **1** receives the remote stream from the group meeting, and passes it as the local stream for **2**. | ||
III. **2** is the ```endpointToken``` user who dials the SIP endpoint (interpreter service). | ||
* ```endpointToken``` cannot be a guest token AND cannot be the same as initialToken. | ||
|
||
IV. **2** receives the remote stream from the SIP endpoint and passes it as the local stream for **3**. | ||
* if provided, **3** will use the optional ```meetingToken```, but otherwise uses the ```endpointToken```. | ||
|
||
V. **3** dials into the group meeting and receives another remote stream. | ||
|
||
**Figure B:** | ||
I. It was necessary for **3** to dial into the meeting, because **1**'s local media cannot be updated because it had no local media initially. | ||
|
||
* This is a limitation of the SDK. | ||
* This now creates a loop where the SIP device user can see and hear themself in the meeting. | ||
II. **2**'s local media can be updated, because it had initial media (provided by **1**). | ||
|
||
III. Therefore, **3** uses its remote stream to update the local stream of **2**. | ||
|
||
**Figure C:** | ||
I. **1** is no longer needed, so it can be dropped, solving the loop problem, and creating the bridge. | ||
|
||
### Built With | ||
|
||
Each of these is required: | ||
- MacOS 10.15 (Catalina) | ||
- node.js (>= v12.0) | ||
- playwright | ||
- express | ||
|
||
<!-- GETTING STARTED --> | ||
|
||
### Installation | ||
|
||
1. Clone the repo | ||
```sh | ||
git clone repo | ||
``` | ||
2. Set Environment Variable `PORT` | ||
``` | ||
export PORT=12345 #(the port your server listener will expose) | ||
``` | ||
If you set ```PORT=12345``` in a file named ```.env``` in the root directory, this variable will be loaded in server.js at runtime. | ||
3. Install the packages. | ||
``` | ||
npm i -D playwright | ||
npm install dotenv | ||
npm install express | ||
``` | ||
4. Start the server | ||
``` | ||
>$ node server.js | ||
Your app is listening on port 12345 | ||
``` | ||
|
||
### Usage | ||
Once your server is running, you can test it with HTTPS POST requests with a JSON payload to the /bridge path. Example: | ||
``` | ||
POST http://localhost:12345/bridge | ||
``` | ||
|
||
JSON Data Parameters | ||
|
||
| Key | Required | Type | Description | | ||
| --- | --- | --- | --- | | ||
| `initialToken` | **required** | String | The Webex Account Bearer token for the 'operator' user that joins the meeting first. This can be a guest user. | | ||
| `endpointToken` | **required** | String | The Webex Account Bearer token for the **licensed** user that places the outbound call to endpointSIP. | | ||
| `meetingToken` | optional | String | The Webex Account Bearer token for the user that joins the meeting *after* the 'operator' has connected and *after* the endpointSIP call has been placed. If null or not provided, endpointToken will be used. | | ||
| `meeting` | **required** | String | The sip address, meeting URL, or roomId of the main meeting to join. | | ||
| `endpointSIP` | **required** | String | The sip address of the device to be added to the meeting. | | ||
| `wait` | optional | Boolean | Defaults to false. If true, the POST request will **not** return immediately, but wait for e full bridge to be established before returning the result. Will wait for a max of about 1 minute. Example: if the 'operator' or endpoint user has to be let in to the meeting, and is let in quickly, the response will contain the result of the bridge setup. If the 'operator' or endpoint user are not let in to the meeting within 1 minute, the request will return with the last known state of the bridge setup. If false, null or not provided, the POST request will respond immediately with an acknowledgement, but the bridge setup result will not be known. | | ||
|
||
Sample: | ||
``` | ||
{"initialToken":"MTM1NzlkMjUtOABCDEFGHIJKLMNOPQRSTUVWXYZ_AB12_abcdef-1234-1111-a1b2-abcdefghijk", "endpointToken":"ZWM3YmMzNzktOWYABCDEFGHIJKLMNOPQRSTUVWXYZ_CD34_zyxwvut-3456-4444-5555-10987654321", "meeting":"[email protected]", "endpointSIP":"[email protected]", "wait":true} | ||
``` | ||
|
||
Postman Sample: | ||
<img width="904" alt="Screen Shot 2021-06-16 at 12 41 32 PM" src="https://user-images.githubusercontent.com/19175490/122259497-3f7a4900-cea0-11eb-9024-a0a542cf185d.png"> | ||
|
||
|
||
### Serve | ||
If you want to serve this at system startup, I recommend using [pm2](https://pm2.keymetrics.io/docs/usage/quick-start/). | ||
1. ```npm install -g pm2``` | ||
*Note: You may run into an issue where pm2 throws an error when it tries to access a directory that does not exist. You can simply make the directory in that case. For example* | ||
``` | ||
mkdir -p /Users/<username>/Library/LaunchAgents/ | ||
``` | ||
2. ```pm2 startup``` | ||
*Note: Follow the instructions from pm2 - run the command it provides to you.* | ||
3. Start the server with pm2 | ||
``` | ||
pm2 start path/to/bridgeCall/server.js --watch | ||
``` | ||
4. ```pm2 save``` | ||
5. Unfortunately, this will only start the server once ```<username>``` logs into the mac. We want it to start at boot, so what I had to do was move the .plist file that was created in ```~/Library/LaunchAgents``` and move it to the system root directory ```/Library/LaunchDaemons``` | ||
*Note: this is not the Library directory that exists under the users directory i.e.* | ||
``` | ||
cd /Users/<username>/Library/LaunchAgents/ | ||
mv pm2.<username>.plist /Library/LaunchDaemons | ||
``` | ||
6. I then also had to manually change the UserName in the .plist file to root: | ||
``` | ||
<key>UserName</key> | ||
<string>root</string> | ||
``` | ||
|
||
## License | ||
|
||
Distributed under the MIT License. See `LICENSE` for more information. | ||
|
||
<!-- CONTACT --> | ||
|
||
## Contact | ||
Please contact us at [email protected] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
</head> | ||
<title>Webex Connect Demo</title> | ||
<body> | ||
Hello World | ||
<!--<script crossorigin src="https://unpkg.com/webex@^1/umd/webex.min.js"></script>--> | ||
<script src="public/webex.js"></script> | ||
<script src="public/bridge.js"></script> | ||
</body> | ||
</html> |
Oops, something went wrong.