-
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 f6a212a
Showing
19 changed files
with
1,150 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,4 @@ | ||
build | ||
cmake-build-debug | ||
.idea | ||
TODO.md |
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,30 @@ | ||
cmake_minimum_required(VERSION 3.3) | ||
|
||
project(phone VERSION 0.1 LANGUAGES C CXX) | ||
|
||
set(CMAKE_CXX_STANDARD 20) | ||
|
||
set(CMAKE_C_VISIBILITY_PRESET hidden) | ||
set(CMAKE_CXX_VISIBILITY_PRESET hidden) | ||
set(CMAKE_VISIBILITY_INLINES_HIDDEN true) | ||
|
||
include(GNUInstallDirs) | ||
|
||
file(RELATIVE_PATH pathToLibs | ||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR} | ||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) | ||
|
||
list(APPEND CMAKE_MESSAGE_INDENT "🔧 ") | ||
if(APPLE) | ||
message(DEBUG "Configuring for Apple platform") | ||
set(CMAKE_INSTALL_RPATH "@loader_path/${pathToLibs}") | ||
elseif(UNIX) | ||
message(DEBUG "Configuring for UNIX") | ||
set(CMAKE_INSTALL_RPATH "$ORIGIN/${pathToLibs}") | ||
endif() | ||
message(DEBUG "CMAKE_INSTALL_RPATH: ${CMAKE_INSTALL_RPATH}") | ||
list(POP_BACK CMAKE_MESSAGE_INDENT) | ||
|
||
add_subdirectory(src bin) | ||
|
||
install(TARGETS phone_sharedlib) |
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,179 @@ | ||
# libphone | ||
|
||
libphone is a library that sits on top of [PJSIP project](https://github.com/pjsip/pjproject) and tries to make it very simple to build a softphone. libphone provides a C++ and a C-API. Included with the library is a Python script that demonstrates the API [python_cli.py](src/python_cli/python_cli.py). You can download one of the [binaries](#binaries) and just enter your SIP credentials if you want to test things out. | ||
|
||
## Overview | ||
<!-- TOC --> | ||
* [libphone](#libphone) | ||
* [Overview](#overview) | ||
* [Usage](#usage) | ||
* [Callbacks](#callbacks) | ||
* [CLI Demo Phone](#cli-demo-phone) | ||
* [Compatibility with SIP providers](#compatibility-with-sip-providers) | ||
* [Binaries](#binaries) | ||
* [Build instructions for Linux](#build-instructions-for-linux) | ||
* [Build instructions for macOS](#build-instructions-for-macos) | ||
<!-- TOC --> | ||
|
||
## Usage | ||
|
||
You can create a phone with | ||
|
||
```python | ||
phone = phone_create("☎️", ["194.25.0.69","194.25.0.79"], "stun.t-online.de") | ||
``` | ||
|
||
and connect the phone to your server via: | ||
|
||
```python | ||
phone_connect(phone, "tel.t-online.de", "your_sip_username", "your_sip_password") | ||
``` | ||
Now you are ready to make a call: | ||
|
||
```python | ||
phone_make_call(phone, "+491804100100") | ||
``` | ||
|
||
### Callbacks | ||
You can register callback functions for incoming calls and their call states like this: | ||
|
||
```python | ||
phone_register_on_incoming_call_callback(phone, on_incoming_call, None) | ||
phone_register_on_call_state_callback(phone, on_call_state, None) | ||
``` | ||
|
||
The third parameter to the callback functions is required if you want to use the C-API with an object-oriented programming language like Swift: | ||
|
||
```swift | ||
phone_register_on_incoming_call_callback(phone, { callId, ctx in | ||
guard let ctx else { return } | ||
let me = Unmanaged<Model>.fromOpaque(ctx).takeUnretainedValue() | ||
DispatchQueue.main.async { | ||
me.current_call_id = callId | ||
} | ||
}, Unmanaged.passRetained(self).toOpaque()) | ||
``` | ||
|
||
## CLI Demo Phone | ||
|
||
![CLI Demo Phone](python_cli.png) | ||
|
||
Once you have the library installed there is a CLI Demo phone written in Python in the bin directory `libphone/bin/python_cli.py`. If you want to make a phone call you need to update the config section in the beginning of the script: | ||
|
||
```python | ||
useragent = "Python CLI Phone" | ||
nameservers = ["217.237.148.22", "217.237.150.51"] | ||
stunservers = ["stun.t-online.de"] | ||
sipserver = "tel.t-online.de" | ||
username = "+49..." | ||
password = None | ||
opus_channel_count = 1 | ||
opus_complexity = 8 | ||
opus_sample_rate = 16000 | ||
buddy = "+491804100100" | ||
``` | ||
|
||
If you are a customer of DTAG (Deutsche Telekom AG) you can simply put in your username (which is your telephone number) and everything is set up. A password is not required for DTAG since your line-id is used for authentication. | ||
|
||
## Compatibility with SIP providers | ||
|
||
libphone should work with almost every SIP-provider out of the box. It's been tested with: | ||
- DTAG (Deutsche Telekom) | ||
- Starface | ||
- TeamFON | ||
|
||
I'd be very happy if you can test with your provider and give me feedback. I am willing to help. Reach me here [Oliver Epper](https://oliver-epper.de). | ||
|
||
## Binaries | ||
|
||
If you want to try this out I maintain the following binary distributions: | ||
|
||
- [libphone.0.0.1-macos-universal.zip](https://oliver-epper.de/libphone.0.0.1-macos-universal.zip) (signed and notarized, ready to go) | ||
- [libphone.0.0.1-ubuntu22.04-aarch64.tgz](https://oliver-epper.de/libphone.0.0.1-ubuntu22.04-aarch64.tgz) | ||
- [libphone.0.0.1-ubuntu22.04-x86_64.tgz](https://oliver-epper.de/libphone.0.0.1-ubuntu22.04-x86_64.tgz) | ||
|
||
## Build instructions for Linux | ||
|
||
I've tested this on Ubuntu 22.04. | ||
|
||
First install the build-dependencies: | ||
|
||
```shell | ||
apt install build-essential git pkg-config cmake python3-minimal libssl-dev libasound2-dev libopus-dev ninja-build | ||
``` | ||
|
||
Ninja ist not required, but much faster than building with make. | ||
Check out pjproject: | ||
|
||
```shell | ||
git -c advice.detachedHead=false clone --depth 1 --branch "2.13" https://github.com/pjsip/pjproject | ||
``` | ||
|
||
This will give you the 2.13 release of pjproject which I tested. | ||
Build pjproject with the following commands: | ||
|
||
```shell | ||
pushd pjproject | ||
cat << EOF > pjlib/include/pj/config_site.h | ||
#define PJ_HAS_SSL_SOCK 1 | ||
#include <pj/config_site_sample.h> | ||
EOF | ||
cat << EOF > user.mak | ||
export CFLAGS += -fPIC | ||
EOF | ||
./configure --prefix=$(echo ~)/installed/pjproject | ||
make dep && make clean | ||
make | ||
make install | ||
popd | ||
``` | ||
|
||
Once installed into `~/installed/pjproject` you need to change two things: | ||
|
||
```shell | ||
pushd ~/installed/pjproject | ||
ar -rcT lib/libpjproject.a lib/*.a | ||
cp lib/pkgconfig/libpjproject.pc lib/pkgconfig/libpjproject.orig | ||
popd | ||
``` | ||
|
||
Please edit the file `~/installed/pjproject/lib/pkgconfig/libpjproject.pc` to contain the following (example from my build-docker): | ||
|
||
```text | ||
prefix=/home/oliver/installed/pjproject | ||
libdir=${prefix}/lib | ||
includedir=${prefix}/include | ||
Name: libpjproject | ||
Description: Multimedia communication library | ||
URL: http://www.pjsip.org | ||
Version: 2.13 | ||
Libs: -L${libdir} -lpjproject -lcrypto -lssl -lasound -lopus | ||
Cflags: -I${includedir} -DPJ_AUTOCONF=1 -DPJ_IS_BIG_ENDIAN=0 -DPJ_IS_LITTLE_ENDIAN=1 | ||
``` | ||
|
||
This is an example from my build machine. You need the correct path for `prefix`. | ||
|
||
Once that is in place you can start building libphone. I prefer building out of the source tree, so from inside your libphone directory go up on level. | ||
|
||
```shell | ||
cmake -Slibphone -Bbuild-libphone -GNinja -DCMAKE_PREFIX_PATH=$(echo ~)/installed/pjproject -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" -DCMAKE_INSTALL_PREFIX=$(echo ~)/installed/libphone --log-level=DEBUG | ||
cmake --build build-libphone --config Release --target install | ||
``` | ||
|
||
|
||
## Build instructions for macOS | ||
|
||
You can use my already prebuild package `pjproject-apple-platforms`. Install it with the following commands: | ||
|
||
```shell | ||
brew tap oliverepper/made | ||
brew install pjproject-apple-platforms | ||
``` | ||
|
||
libphone can now be build with the following commands: | ||
|
||
```shell | ||
cmake -Slibphone -Bbuild-libphone -GNinja -DCMAKE_INSTALL_PREFIX=$(echo ~)/installed/libphone --log-level=DEBUG | ||
cmake --build build-libphone --config Release --target install | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,4 @@ | ||
add_subdirectory(phone) | ||
add_subdirectory(c_cli) | ||
add_subdirectory(cpp_cli) | ||
add_subdirectory(python_cli) |
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,2 @@ | ||
add_executable(c_cli main.c) | ||
target_link_libraries(c_cli PRIVATE phone_sharedlib) |
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,127 @@ | ||
#include <phone.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <limits.h> | ||
|
||
void die(phone_t instance) { | ||
phone_destroy(instance); | ||
fprintf(stderr, "%s\n", phone_last_error()); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
struct app_state { | ||
int last_call_id; | ||
}; | ||
|
||
void on_incoming_call(int call_id, __attribute__((unused)) void *ctx) { | ||
printf("Incoming call: %d\n", call_id); | ||
} | ||
|
||
void on_call_state(int call_id, int state, void *ctx) { | ||
char buffer[64]; | ||
phone_state_name(buffer, sizeof(buffer), state); | ||
struct app_state *s = (struct app_state*)ctx; | ||
s->last_call_id = call_id; | ||
printf("Call %d – state: %s\n", call_id, buffer); | ||
} | ||
|
||
void clear_input_buffer(void) { | ||
int c; | ||
while ((c = getchar() != '\n') && c != EOF); | ||
} | ||
|
||
int read_int(int *in) { | ||
char input[11]; | ||
long value; | ||
char *endptr; | ||
|
||
clear_input_buffer(); | ||
if (fgets(input, sizeof(input), stdin) == NULL) { | ||
fprintf(stderr, "could not read from stdin"); | ||
return 1; | ||
} | ||
|
||
input[strcspn(input, "\n")] = '\0'; | ||
|
||
value = strtol(input, &endptr, sizeof(input)); | ||
if (*input == '\0' || *endptr != '\0') { | ||
fprintf(stderr, "invalid input.\n"); | ||
return 1; | ||
} | ||
|
||
if (value <= INT_MAX && value >= INT_MIN) { | ||
*in = (int)value; | ||
} else { | ||
fprintf(stderr, "invalid input.\n"); | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
|
||
int main() { | ||
struct app_state *state = malloc(sizeof(struct app_state)); | ||
state->last_call_id = -1; | ||
|
||
const char *nameserver[] = {"217.237.148.22", "217.237.150.51"}; | ||
const char *stunserver[] = {"stun.t-online.de"}; | ||
phone_t phone = phone_create("Cli Phone in C", nameserver, 2, stunserver, 1); | ||
if (!phone) | ||
die(phone); | ||
phone_set_log_level(0); | ||
|
||
phone_register_on_incoming_call_callback(phone, on_incoming_call, NULL); | ||
phone_register_on_call_state_callback(phone, on_call_state, state); | ||
|
||
if (phone_configure_opus(phone, 1, 8, 16000) != PHONE_STATUS_SUCCESS) | ||
die(phone); | ||
if (phone_connect(phone, | ||
"tel.t-online.de", | ||
"+4965191899543", NULL) != PHONE_STATUS_SUCCESS) | ||
die(phone); | ||
|
||
int command; | ||
char uri[128]; | ||
int call_id, level; | ||
do { | ||
printf("last call id: %d\n> ", state->last_call_id); | ||
command = getchar(); | ||
switch (command) { | ||
case 'c': | ||
printf("please enter number: "); | ||
clear_input_buffer(); | ||
if (fgets(uri, sizeof(uri), stdin) == NULL) { | ||
fprintf(stderr, "could not read number\n"); | ||
break; | ||
} | ||
uri[strcspn(uri, "\n")] = '\0'; | ||
if (phone_make_call(phone, uri) != PHONE_STATUS_SUCCESS) die(phone); | ||
break; | ||
case 'C': | ||
if (phone_make_call(phone, "+4915123595397") != PHONE_STATUS_SUCCESS) die(phone); | ||
break; | ||
case 'a': | ||
printf("please enter call id: "); | ||
if (read_int(&call_id) != 0) break; | ||
if (phone_answer_call(phone, call_id) != PHONE_STATUS_SUCCESS) die(phone); | ||
break; | ||
case 'h': | ||
printf("please enter call id: "); | ||
if (read_int(&call_id) != 0) break; | ||
if (phone_hangup_call(phone, call_id) != PHONE_STATUS_SUCCESS) die(phone); | ||
break; | ||
case 'H': | ||
phone_hangup_calls(phone); | ||
break; | ||
case 'l': | ||
printf("please enter new log level 0..6: "); | ||
if (read_int(&level) != 0) break; | ||
phone_set_log_level(level); | ||
break; | ||
default: | ||
break; | ||
} | ||
} while (command != 'q' && command != EOF); | ||
printf("shutting down...\n"); | ||
phone_destroy(phone); | ||
return 0; | ||
} |
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,2 @@ | ||
add_executable(cpp_cli main.cpp) | ||
target_link_libraries(cpp_cli PRIVATE phone_sharedlib) |
Oops, something went wrong.