Merge branch 'master' of gitlab.inria.fr:qdufour/donar
This commit is contained in:
commit
d715ee2f34
5 changed files with 546 additions and 5 deletions
|
@ -49,11 +49,13 @@ add_executable(torecho ${CSOURCES} src/tor_echo.c)
|
||||||
add_executable(capdiff ${CSOURCES} src/capdiff.c)
|
add_executable(capdiff ${CSOURCES} src/capdiff.c)
|
||||||
add_executable(capreplay ${CSOURCES} src/capreplay.c)
|
add_executable(capreplay ${CSOURCES} src/capreplay.c)
|
||||||
add_executable(donar_unit_test ${CSOURCES} src/test.c)
|
add_executable(donar_unit_test ${CSOURCES} src/test.c)
|
||||||
add_executable(dcall src/call.c)
|
|
||||||
|
add_executable(dcall src/dcall.c)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_search_module(GLIB REQUIRED glib-2.0)
|
pkg_search_module(GLIB REQUIRED glib-2.0)
|
||||||
pkg_check_modules(GST REQUIRED gstreamer-1.0>=1.16)
|
pkg_search_module(GST REQUIRED gstreamer-1.0 >= 1.14)
|
||||||
|
>>>>>>> 22c07f1e26d7ad8bd76249bf690e437f27e25529
|
||||||
|
|
||||||
target_include_directories(donar PRIVATE ${GLIB_INCLUDE_DIRS})
|
target_include_directories(donar PRIVATE ${GLIB_INCLUDE_DIRS})
|
||||||
target_link_libraries(donar ${GLIB_LDFLAGS})
|
target_link_libraries(donar ${GLIB_LDFLAGS})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM fedora:30 as builder
|
FROM fedora:31 as builder
|
||||||
RUN dnf install -y \
|
RUN dnf install -y \
|
||||||
coreutils \
|
coreutils \
|
||||||
cmake \
|
cmake \
|
||||||
|
@ -14,7 +14,8 @@ RUN dnf install -y \
|
||||||
automake \
|
automake \
|
||||||
libzstd-devel \
|
libzstd-devel \
|
||||||
xz-devel \
|
xz-devel \
|
||||||
git
|
git \
|
||||||
|
gstreamer1-devel
|
||||||
|
|
||||||
WORKDIR /home/donar-build
|
WORKDIR /home/donar-build
|
||||||
RUN chown -R 1000 /home/donar-build
|
RUN chown -R 1000 /home/donar-build
|
||||||
|
@ -41,7 +42,7 @@ RUN mkdir out && \
|
||||||
|
|
||||||
#####
|
#####
|
||||||
|
|
||||||
FROM fedora:30
|
FROM fedora:31
|
||||||
RUN dnf install -y \
|
RUN dnf install -y \
|
||||||
glib2 \
|
glib2 \
|
||||||
procps-ng \
|
procps-ng \
|
||||||
|
@ -69,6 +70,7 @@ COPY --from=builder /home/donar-build/out/donar /usr/local/bin
|
||||||
COPY --from=builder /home/donar-build/out/measlat /usr/local/bin
|
COPY --from=builder /home/donar-build/out/measlat /usr/local/bin
|
||||||
COPY --from=builder /home/donar-build/out/udpecho /usr/local/bin
|
COPY --from=builder /home/donar-build/out/udpecho /usr/local/bin
|
||||||
COPY --from=builder /home/donar-build/out/torecho /usr/local/bin
|
COPY --from=builder /home/donar-build/out/torecho /usr/local/bin
|
||||||
|
COPY --from=builder /home/donar-build/out/dcall /usr/local/bin
|
||||||
COPY --from=builder /home/donar-build/tor2/src/app/tor /usr/local/bin/tor2
|
COPY --from=builder /home/donar-build/tor2/src/app/tor /usr/local/bin/tor2
|
||||||
COPY --from=builder /home/donar-build/tor3/src/app/tor /usr/local/bin/tor3
|
COPY --from=builder /home/donar-build/tor3/src/app/tor /usr/local/bin/tor3
|
||||||
COPY ./scripts/container/* /usr/local/bin/
|
COPY ./scripts/container/* /usr/local/bin/
|
||||||
|
|
300
README.more.md
Normal file
300
README.more.md
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
# Donar
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
The following steps are provided for [Fedora 29 Workstation](https://getfedora.org/fr/workstation/download/).
|
||||||
|
We assume you have two containers or two virtual machines or two physical machines.
|
||||||
|
|
||||||
|
To setup each machine, you should do:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo dnf install --refresh -y cmake gcc gcc-c++ ninja-build glib2-devel glib2 tor valgrind git net-tools nmap-ncat
|
||||||
|
git clone https://gitlab.inria.fr/qdufour/donar.git
|
||||||
|
cd donar
|
||||||
|
mkdir out && cd out && cmake -GNinja .. && ninja && sudo ninja install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
Now your machine is ready and you will be able to use the following commads:
|
||||||
|
|
||||||
|
* `donar` is our main binary. It can be run as a client or a server.
|
||||||
|
* `udpecho` is a simple udp server that send back the data sent to him.
|
||||||
|
* `torecho` is a simple tcp server that send back the data sent to him + configure the tor daemon to generate a hidden service URL and be accessible on the Tor network.
|
||||||
|
* `measlat` can be used in conjunction with `udpecho` or `torecho` to measure a Round Trip Time (RTT)
|
||||||
|
|
||||||
|
Try to run the previous commands in your terminal without any option, you will see their help.
|
||||||
|
|
||||||
|
At any moment, you can use the following commands that are not part of the project to understand what you are doing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
netstat -ulpn # Show programs that listen on an UDP port
|
||||||
|
netstat -tlpn # Show prograns that listen on a TCP port
|
||||||
|
nc 127.0.0.1 8000 # Connect via TCP on server 127.0.0.1 listening on port 8000
|
||||||
|
nc -u 127.0.0.1 8000 # Connect via UDP on server 127.0.0.1 listening on port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Introduction to the debug tools `udpecho` and `measlat`
|
||||||
|
|
||||||
|
Now let's start simple, we will launch our udp echo server and access it locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
udpecho -p 8000 &
|
||||||
|
nc 127.0.0.1 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done!
|
||||||
|
|
||||||
|
Now, instead of using `nc`, we will use `measlat` to use this echo server to measure latencies (make sure that `udpecho` is still running):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
measlat -h 127.0.0.1 -p 8000 -t udp
|
||||||
|
```
|
||||||
|
|
||||||
|
`measlat` will send one packet to our udpecho server and wait to receive it back, measure the time it took, display it and exit.
|
||||||
|
|
||||||
|
You can use `measlat` more extensively by defining the number of measures to do, an interval and the size of the packet:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
measlat -h 127.0.0.1 -p 8000 -t udp -c 10 -i 100 -s 150
|
||||||
|
```
|
||||||
|
|
||||||
|
### Introduction to `donar`
|
||||||
|
|
||||||
|
Now, let's introduce our main project.
|
||||||
|
First, kill all the remaining processes `killall udpecho measlat nc`.
|
||||||
|
|
||||||
|
*On both machine*
|
||||||
|
Move to the donar repository root where you will see the `torrc_simple` file.
|
||||||
|
We will need to start by launching tor in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tor -f ./torrc_simple
|
||||||
|
```
|
||||||
|
|
||||||
|
*On machine A*
|
||||||
|
Launch Donar server in a second terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
donar -s -a naive -e 3000 -r 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
In a third terminal, launch your echo service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
udpecho -p 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
Display the content of the file `onion_services.pub` that has been created in your working directory.
|
||||||
|
|
||||||
|
*On machine B*
|
||||||
|
Copy the content of the file `onion_services.pub` that is on *machine A* to *machine B* in a file named `machine_a.pub`.
|
||||||
|
Now, run Donar client in a second terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
donar -c -a naive -o machine_a.pub -r 3000 -e 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
In a third terminal, launch your echo service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
udpecho -p 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
*On machine A*
|
||||||
|
You can access to the echo service from *machine B* by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nc 127.13.3.7 3001
|
||||||
|
# or
|
||||||
|
measlat -h 127.13.3.7 -p 3001 -t udp
|
||||||
|
```
|
||||||
|
|
||||||
|
*On machine B*
|
||||||
|
You can access to the echo service from *machine A* by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nc 127.13.3.7 3000
|
||||||
|
# or
|
||||||
|
measlat -h 127.13.3.7 -p 3000 -t udp
|
||||||
|
```
|
||||||
|
|
||||||
|
If it works, that's all! You are now mastering Donar!
|
||||||
|
|
||||||
|
## Linphone configuration
|
||||||
|
|
||||||
|
Choose a SIP UDP, Audio RTP/UDP and Video RTP/UDP that is different between your clients.
|
||||||
|
Go to manage account.
|
||||||
|
Add a new SIP proxy.
|
||||||
|
|
||||||
|
```
|
||||||
|
Username: <username>@127.13.3.7:5061
|
||||||
|
Proxy: 127.13.3.7:5060
|
||||||
|
Leave the rest empty.
|
||||||
|
Uncheck all the checkboxes.
|
||||||
|
```
|
||||||
|
|
||||||
|
You also need to say to Linphone that you are behind a NAT and put `127.13.3.7` as your public IP address.
|
||||||
|
|
||||||
|
## Docker build
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo docker build -t registry.gitlab.inria.fr/qdufour/donar .
|
||||||
|
sudo docker push registry.gitlab.inria.fr/qdufour/donar
|
||||||
|
sudo docker pull registry.gitlab.inria.fr/qdufour/donar
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p ./{xp1-shared,xp1-res}
|
||||||
|
sudo chown -R 1000 ./{xp1-shared,xp1-res}
|
||||||
|
|
||||||
|
sudo docker run -t -i \
|
||||||
|
--privileged \
|
||||||
|
-v `pwd`/xp1-shared:/home/donar/shared \
|
||||||
|
registry.gitlab.inria.fr/qdufour/donar \
|
||||||
|
xp1-server
|
||||||
|
|
||||||
|
sudo docker run -t -i \
|
||||||
|
--privileged \
|
||||||
|
-v `pwd`/xp1-res:/home/donar/res \
|
||||||
|
-v `pwd`/xp1-shared:/home/donar/shared \
|
||||||
|
registry.gitlab.inria.fr/qdufour/donar \
|
||||||
|
xp1-client 1000 100 100
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run an XP instance
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo ./scripts/xp1 1000 100 100
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run instances in parallel
|
||||||
|
|
||||||
|
We generate the name of the algorithm to run on the right side of the parallel command.
|
||||||
|
The idea is to generate a sequence like the following: `orig naive rr rrh orig naive rr rrh orig...`.
|
||||||
|
|
||||||
|
```
|
||||||
|
parallel -j 12 bash -c './xp-instance-runner $1 6000 100 100' -- `xp0=orig xp1=naive xp2=rr xp3=rrh xp4=witness; for i in {0..99}; do q='xp'$((i % 5)); echo ${!q}; done`
|
||||||
|
parallel.moreutils -j 16 bash -c './xp-instance-runner $0 6000 100 100' -- `xp0=orig xp1=naive xp2=rr xp3=rrh xp4=witness; for i in {0..274}; do q='xp'$((i % 5)); echo ${!q}; done`
|
||||||
|
parallel.moreutils -j 16 bash -c './xp-instance-runner $0 6000 100 100' -- `for i in {0..55}; do echo -n 'orig naive rr rrh witness '; done`
|
||||||
|
```
|
||||||
|
|
||||||
|
Tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
parallel.moreutils -j 16 bash -c './xp-instance-runner rr 6000 100 100' -- `seq 0 15`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Helpers
|
||||||
|
|
||||||
|
Track measures that didn't finish:
|
||||||
|
|
||||||
|
```
|
||||||
|
ls | grep -P '^naive-|^rrh-|^rr-|^orig-' | while read n; do echo -n "$n "; tail -n1 $n/res/*.csv ; done | grep -v "Measurement done"
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if timer's bug occured:
|
||||||
|
|
||||||
|
```
|
||||||
|
ls | grep -P '^naive-|^rrh-|^rr-|^orig-' | while read n; do echo "$n "; grep 'bug' $n/log/client-measlat-stderr.log; done
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if a free() invalid pointer bug occured:
|
||||||
|
|
||||||
|
```
|
||||||
|
grep 'free' naive-*/log/*-donar-*.log
|
||||||
|
grep -rn 'free()' .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use a Linphone container
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -f linphone.dockerfile -t superboum/linphone .
|
||||||
|
```
|
||||||
|
|
||||||
|
Run it:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run \
|
||||||
|
-ti \
|
||||||
|
-e DISPLAY=$DISPLAY \
|
||||||
|
-v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||||
|
--ipc=host \
|
||||||
|
superboum/linphone \
|
||||||
|
bash
|
||||||
|
```
|
||||||
|
|
||||||
|
http://gstreamer-devel.966125.n4.nabble.com/Need-help-with-using-OPUS-over-RTP-td4661409.html
|
||||||
|
|
||||||
|
```
|
||||||
|
# some sources
|
||||||
|
audiotestsrc
|
||||||
|
pulsesrc
|
||||||
|
|
||||||
|
# some sinks
|
||||||
|
pulsesink
|
||||||
|
|
||||||
|
# sender
|
||||||
|
gst-launch-1.0 \
|
||||||
|
pulsesrc ! \
|
||||||
|
audioconvert ! \
|
||||||
|
opusenc audio-type=voice inband-fec=false frame-size=20 ! \
|
||||||
|
rtpopuspay ! \
|
||||||
|
udpsink host=127.0.0.1 port=5000
|
||||||
|
|
||||||
|
# receiver
|
||||||
|
gst-launch-1.0 \
|
||||||
|
udpsrc port=5000 caps="application/x-rtp" ! \
|
||||||
|
rtpjitterbuffer do-lost=true do-retransmission=false ! \
|
||||||
|
rtpopusdepay ! \
|
||||||
|
opusdec plc=true use-inband-fec=false ! \
|
||||||
|
pulsesink
|
||||||
|
|
||||||
|
# both sides
|
||||||
|
export TARGET=192.168.1.1
|
||||||
|
gst-launch-1.0 \
|
||||||
|
autoaudiosrc ! \
|
||||||
|
queue ! \
|
||||||
|
audioresample ! \
|
||||||
|
opusenc audio-type=voice inband-fec=FALSE frame-size=20 bitrate=64000 dtx=TRUE ! \
|
||||||
|
rtpopuspay ! \
|
||||||
|
udpsink host=$TARGET port=5000 async=FALSE \
|
||||||
|
udpsrc port=5000 caps="application/x-rtp" ! \
|
||||||
|
rtpjitterbuffer do-lost=TRUE do-retransmission=FALSE latency=10 ! \
|
||||||
|
rtpopusdepay ! \
|
||||||
|
opusdec plc=TRUE use-inband-fec=FALSE ! \
|
||||||
|
audioresample ! \
|
||||||
|
autoaudiosink
|
||||||
|
|
||||||
|
# both sides with echo cancellation
|
||||||
|
export TARGET=192.168.1.1
|
||||||
|
gst-launch-1.0 \
|
||||||
|
autoaudiosrc ! \
|
||||||
|
webrtcdsp ! \
|
||||||
|
queue ! \
|
||||||
|
audioresample ! \
|
||||||
|
opusenc audio-type=voice inband-fec=FALSE frame-size=20 bitrate=64000 dtx=TRUE ! \
|
||||||
|
rtpopuspay ! \
|
||||||
|
udpsink host=$TARGET port=5000 async=FALSE \
|
||||||
|
udpsrc port=5000 caps="application/x-rtp" ! \
|
||||||
|
rtpjitterbuffer do-lost=TRUE do-retransmission=FALSE latency=10 ! \
|
||||||
|
rtpopusdepay ! \
|
||||||
|
opusdec plc=TRUE use-inband-fec=FALSE ! \
|
||||||
|
audioresample ! \
|
||||||
|
webrtcechoprobe ! \
|
||||||
|
autoaudiosink
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo docker run \
|
||||||
|
--rm \
|
||||||
|
-it \
|
||||||
|
-e PULSE_SERVER=unix:/run/user/1000/pulse/native \
|
||||||
|
-v ${XDG_RUNTIME_DIR}/pulse/native:/run/user/1000/pulse/native \
|
||||||
|
-v ~/.config/pulse/cookie:/root/.config/pulse/cookie \
|
||||||
|
--group-add $(getent group audio | cut -d: -f3) \
|
||||||
|
registry.gitlab.inria.fr/qdufour/donar
|
||||||
|
```
|
13
create_binaries.sh
Executable file
13
create_binaries.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
mkdir -p release
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
-it \
|
||||||
|
-v `pwd`/release:/tmp/release \
|
||||||
|
registry.gitlab.inria.fr/qdufour/donar \
|
||||||
|
cp \
|
||||||
|
/usr/local/bin/{tor2,tor3,dcall,donar,measlat} \
|
||||||
|
/etc/{torrc_guard_12,torrc_guard_2,torrc_single_hop_12} \
|
||||||
|
/tmp/release
|
||||||
|
zip -r donar.zip release/
|
224
src/dcall.c
Normal file
224
src/dcall.c
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <glib-2.0/glib.h>
|
||||||
|
#include <glib-2.0/gmodule.h>
|
||||||
|
#include <glib-2.0/glib-object.h>
|
||||||
|
#include <glib-2.0/glib-unix.h>
|
||||||
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
|
|
||||||
|
struct dcall_elements {
|
||||||
|
GstElement *pipeline;
|
||||||
|
GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_echocancel, *rx_sink;
|
||||||
|
GstElement *tx_tap, *tx_echocancel, *tx_queue, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink;
|
||||||
|
char* remote_host;
|
||||||
|
guint bus_watch_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
int create_rx_chain(struct dcall_elements* de) {
|
||||||
|
de->rx_tap = gst_element_factory_make("udpsrc", "rx-tap");
|
||||||
|
de->rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer");
|
||||||
|
de->rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay");
|
||||||
|
de->rx_opusdec = gst_element_factory_make("opusdec", "rx-opusdec");
|
||||||
|
de->rx_resample = gst_element_factory_make("audioresample", "rx-audioresample");
|
||||||
|
de->rx_echocancel = gst_element_factory_make("webrtcechoprobe", "rx-echocancel");
|
||||||
|
de->rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink");
|
||||||
|
|
||||||
|
if (!de->rx_tap || !de->rx_jitterbuffer || !de->rx_depay || !de->rx_opusdec || !de->rx_resample || !de->rx_echocancel || !de->rx_sink) {
|
||||||
|
g_printerr ("One element of the rx chain could not be created. Exiting.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT (de->rx_tap), "port", 5000, NULL);
|
||||||
|
//g_object_set(G_OBJECT (rx_tap), "address", "127.0.0.1", NULL);
|
||||||
|
g_object_set(G_OBJECT (de->rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), NULL);
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT (de->rx_jitterbuffer), "do-lost", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT (de->rx_jitterbuffer), "do-retransmission", FALSE, NULL);
|
||||||
|
g_object_set(G_OBJECT (de->rx_jitterbuffer), "latency", 50, NULL);
|
||||||
|
g_object_set(G_OBJECT (de->rx_jitterbuffer), "drop-on-latency", TRUE, NULL);
|
||||||
|
//g_object_set(G_OBJECT (de->rx_jitterbuffer), "post-drop-messages", TRUE, NULL);
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT (de->rx_opusdec), "plc", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT (de->rx_opusdec), "use-inband-fec", FALSE, NULL);
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (de->pipeline), de->rx_tap, de->rx_jitterbuffer, de->rx_depay, de->rx_opusdec, de->rx_resample, de->rx_echocancel, de->rx_sink, NULL);
|
||||||
|
gst_element_link_many (de->rx_tap, de->rx_jitterbuffer, de->rx_depay, de->rx_opusdec, de->rx_resample, de->rx_echocancel, de->rx_sink, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_tx_chain(struct dcall_elements* de) {
|
||||||
|
de->tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap");
|
||||||
|
de->tx_echocancel = gst_element_factory_make("webrtcdsp", "tx-echocancel");
|
||||||
|
//tx_queue = gst_element_factory_make("queue", "tx-queue");
|
||||||
|
de->tx_resample = gst_element_factory_make("audioresample", "tx-resample");
|
||||||
|
de->tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc");
|
||||||
|
de->tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay");
|
||||||
|
de->tx_sink = gst_element_factory_make("udpsink", "tx-sink");
|
||||||
|
|
||||||
|
if (!de->tx_tap || !de->tx_echocancel || /*!de->tx_queue ||*/ !de->tx_resample || !de->tx_opusenc || !de->tx_pay || !de->tx_sink) {
|
||||||
|
g_printerr("One element of the tx chain could not be created. Exiting.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_util_set_object_arg(G_OBJECT(de->tx_opusenc), "audio-type", "voice");
|
||||||
|
g_object_set(G_OBJECT(de->tx_opusenc), "inband-fec", FALSE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_opusenc), "frame-size", 40, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_opusenc), "bitrate", 32000, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_opusenc), "dtx", FALSE, NULL); // gstreamer dtx opus implem. is broken
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT(de->tx_sink), "host", de->remote_host, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_sink), "port", 5000, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_sink), "async", FALSE, NULL);
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "echo-cancel", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "extended-filter", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "gain-control", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "high-pass-filter", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "limiter", FALSE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "noise-suppression", TRUE, NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "probe", "rx-echocancel", NULL);
|
||||||
|
g_object_set(G_OBJECT(de->tx_echocancel), "voice-detection", FALSE, NULL);
|
||||||
|
|
||||||
|
gst_bin_add_many(GST_BIN(de->pipeline), de->tx_tap, de->tx_echocancel, /*tx_queue,*/ de->tx_resample, de->tx_opusenc, de->tx_pay, de->tx_sink, NULL);
|
||||||
|
gst_element_link_many(de->tx_tap, de->tx_echocancel, /*tx_queue,*/ de->tx_resample, de->tx_opusenc, de->tx_pay, de->tx_sink, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPadProbeReturn jitter_buffer_sink_event(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
|
||||||
|
struct dcall_elements *de = user_data;
|
||||||
|
GstEvent *event = NULL;
|
||||||
|
|
||||||
|
g_print("Entering rtpjitterbuffer sink pad handler for events...\n");
|
||||||
|
|
||||||
|
event = gst_pad_probe_info_get_event (info);
|
||||||
|
if (event == NULL) return GST_PAD_PROBE_OK;
|
||||||
|
g_print("We successfully extracted an event from the pad... \n");
|
||||||
|
|
||||||
|
const GstStructure *struc = NULL;
|
||||||
|
struc = gst_event_get_structure(event);
|
||||||
|
if (struc == NULL) return GST_PAD_PROBE_OK;
|
||||||
|
g_print("We successfully extracted a structure from the event... \n");
|
||||||
|
|
||||||
|
const gchar* struc_name = NULL;
|
||||||
|
struc_name = gst_structure_get_name(struc);
|
||||||
|
if (struc_name == NULL) return GST_PAD_PROBE_OK;
|
||||||
|
g_print("We extracted the structure \"%s\"...\n", struc_name);
|
||||||
|
|
||||||
|
if (strcmp(struc_name, "GstRTPPacketLost") != 0) return GST_PAD_PROBE_OK;
|
||||||
|
g_print("And that's the structure we want !\n");
|
||||||
|
|
||||||
|
guint seqnum = 0, retry = 0;
|
||||||
|
guint64 timestamp = 0, duration = 0;
|
||||||
|
gst_structure_get_uint(struc, "seqnum", &seqnum);
|
||||||
|
gst_structure_get_uint(struc, "retry", &retry);
|
||||||
|
gst_structure_get_uint64(struc, "timestamp", ×tamp);
|
||||||
|
gst_structure_get_uint64(struc, "duration", &duration);
|
||||||
|
g_print("GstRTPPacketLost{seqnum=%d, retry=%d, duration=%ld, timestamp=%ld}\n", seqnum, retry, duration, timestamp);
|
||||||
|
|
||||||
|
return GST_PAD_PROBE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPadProbeReturn jitter_buffer_sink_buffer(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
|
||||||
|
//g_print("Entering rtpjitterbuffer sink pad handler for buffers...\n");
|
||||||
|
|
||||||
|
GstBuffer *buffer = NULL;
|
||||||
|
buffer = gst_pad_probe_info_get_buffer (info);
|
||||||
|
if (buffer == NULL) return GST_PAD_PROBE_OK;
|
||||||
|
//if (gst_buffer_get_size (buffer) != 172) g_print("buffer size is %ld\n", gst_buffer_get_size (buffer));
|
||||||
|
|
||||||
|
GstMapInfo gmi;
|
||||||
|
gst_buffer_map(buffer, &gmi, GST_MAP_READ);
|
||||||
|
|
||||||
|
GstRTPBuffer *rtp_buffer;
|
||||||
|
rtp_buffer->
|
||||||
|
|
||||||
|
|
||||||
|
return GST_PAD_PROBE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_pad(struct dcall_elements *de) {
|
||||||
|
GstPad *pad;
|
||||||
|
pad = gst_element_get_static_pad (de->rx_jitterbuffer, "sink");
|
||||||
|
|
||||||
|
//gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, jitter_buffer_sink_event, &de, NULL);
|
||||||
|
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, jitter_buffer_sink_buffer, &de, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean pipeline_bus_handler (GstBus *bus, GstMessage *message, gpointer data) {
|
||||||
|
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
|
||||||
|
|
||||||
|
const GstStructure *struc = NULL;
|
||||||
|
struc = gst_message_get_structure(message);
|
||||||
|
g_print("structure is: %s \n", gst_structure_to_string (struc));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_bus(struct dcall_elements *de) {
|
||||||
|
GstBus *bus;
|
||||||
|
bus = gst_pipeline_get_bus (GST_PIPELINE (de->pipeline));
|
||||||
|
de->bus_watch_id = gst_bus_add_watch (bus, pipeline_bus_handler, de);
|
||||||
|
gst_object_unref(bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean stop_handler(gpointer user_data) {
|
||||||
|
GMainLoop *loop = user_data;
|
||||||
|
g_main_loop_quit(loop);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
GMainLoop *loop;
|
||||||
|
struct dcall_elements de;
|
||||||
|
|
||||||
|
/* Check input arguments */
|
||||||
|
if (argc != 2) {
|
||||||
|
g_printerr ("Usage: %s <Remote host>\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
de.remote_host = argv[1];
|
||||||
|
|
||||||
|
gst_init (&argc, &argv);
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
|
de.pipeline = gst_pipeline_new ("pipeline");
|
||||||
|
if (!de.pipeline) {
|
||||||
|
g_printerr ("Pipeline could not be created. Exiting.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_rx_chain (&de) != 0) return -1;
|
||||||
|
if (create_tx_chain (&de) != 0) return -1;
|
||||||
|
|
||||||
|
register_pad(&de);
|
||||||
|
//register_bus(&de);
|
||||||
|
|
||||||
|
gst_element_set_state (de.pipeline, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
g_unix_signal_add (SIGTERM, stop_handler, loop);
|
||||||
|
g_unix_signal_add (SIGINT, stop_handler, loop);
|
||||||
|
|
||||||
|
g_print ("Running...\n");
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
g_print ("Main loop stopped...\n");
|
||||||
|
|
||||||
|
GstStructure *stats;
|
||||||
|
guint64 num_pushed, num_lost, num_late, num_duplicates;
|
||||||
|
g_object_get(de.rx_jitterbuffer, "stats", &stats, NULL);
|
||||||
|
|
||||||
|
gst_structure_get_uint64(stats, "num-pushed", &num_pushed);
|
||||||
|
gst_structure_get_uint64(stats, "num-lost", &num_lost);
|
||||||
|
gst_structure_get_uint64(stats, "num-late", &num_late);
|
||||||
|
gst_structure_get_uint64(stats, "num-duplicates", &num_duplicates);
|
||||||
|
g_print("pkt_delivered=%ld, pkt_lost=%ld, pkt_late=%ld, pkt_duplicates=%ld\n", num_pushed, num_lost, num_late, num_duplicates);
|
||||||
|
|
||||||
|
gst_element_set_state (de.pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (de.pipeline));
|
||||||
|
// g_source_remove (de.bus_watch_id);
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue