From 9d484f7328c1cbb7f014c63b5617ebb376c632bf Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 07:33:04 +0100 Subject: [PATCH 01/18] Add compiling dcall client --- CMakeLists.txt | 7 ++++++- src/dcall.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/dcall.c diff --git a/CMakeLists.txt b/CMakeLists.txt index aac5bdc..75053a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,9 +49,11 @@ add_executable(torecho ${CSOURCES} src/tor_echo.c) add_executable(capdiff ${CSOURCES} src/capdiff.c) add_executable(capreplay ${CSOURCES} src/capreplay.c) add_executable(donar_unit_test ${CSOURCES} src/test.c) +add_executable(dcall src/dcall.c) find_package(PkgConfig REQUIRED) pkg_search_module(GLIB REQUIRED glib-2.0) +pkg_search_module(GST REQUIRED gstreamer-1.0 >= 1.16) target_include_directories(donar PRIVATE ${GLIB_INCLUDE_DIRS}) target_link_libraries(donar ${GLIB_LDFLAGS}) @@ -74,6 +76,9 @@ target_link_libraries(capreplay ${GLIB_LDFLAGS}) target_include_directories(donar_unit_test PRIVATE ${GLIB_INCLUDE_DIRS}) target_link_libraries(donar_unit_test ${GLIB_LDFLAGS}) -install(TARGETS donar measlat udpecho torecho capdiff capreplay donar_unit_test +target_include_directories(dcall PRIVATE ${GST_INCLUDE_DIRS}) +target_link_libraries(dcall ${GST_LDFLAGS}) + +install(TARGETS donar measlat udpecho torecho capdiff capreplay donar_unit_test dcall RUNTIME DESTINATION bin LIBRARY DESTINATION lib) diff --git a/src/dcall.c b/src/dcall.c new file mode 100644 index 0000000..1086de4 --- /dev/null +++ b/src/dcall.c @@ -0,0 +1,39 @@ +#include + +int main(int argc, char *argv[]) { + GMainLoop *loop; + GstElement *rx, *tx; + GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_sink; + + gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); + + rx = gst_pipeline_new ("rx"); + rx_tap = gst_element_factory_make("udpsrc", "rx-tap"); + rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer"); + rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay"); + rx_opusdec = gst_element_factory_make("opusdec", "rx-opusdec"); + rx_resample = gst_element_factory_make("audioresample", "rx-audioresample"); + rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink"); + + if (!rx || !rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_sink) { + g_printerr ("One element could not be created. Exiting.\n"); + return -1; + } + + gst_bin_add_many (GST_BIN (rx), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); + gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); + + gst_element_set_state (rx, GST_STATE_PLAYING); + + g_print ("Running...\n"); + g_main_loop_run (loop); + + g_print ("Returned, stopping playback\n"); + gst_element_set_state (rx, GST_STATE_NULL); + + gst_object_unref (GST_OBJECT (rx)); + g_main_loop_unref (loop); + + return 0; +} From f34135a4a805367a171124e9c221c855900616fb Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 07:48:15 +0100 Subject: [PATCH 02/18] Working audio source... --- src/dcall.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dcall.c b/src/dcall.c index 1086de4..7055d79 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -21,6 +21,16 @@ int main(int argc, char *argv[]) { return -1; } + g_object_set(G_OBJECT (rx_tap), "port", 5000, NULL); + g_object_set(G_OBJECT (rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), NULL); + + g_object_set(G_OBJECT (rx_jitterbuffer), "do-lost", TRUE, NULL); + g_object_set(G_OBJECT (rx_jitterbuffer), "do-retransmission", FALSE, NULL); + g_object_set(G_OBJECT (rx_jitterbuffer), "latency", 50, NULL); + + g_object_set(G_OBJECT (rx_opusdec), "plc", TRUE, NULL); + g_object_set(G_OBJECT (rx_opusdec), "use-inband-fec", FALSE, NULL); + gst_bin_add_many (GST_BIN (rx), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); From 62275e8fdbdd37116437f255fd26cae91d3a1c19 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 08:35:01 +0100 Subject: [PATCH 03/18] Working sound in loopback --- src/dcall.c | 69 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index 7055d79..065f4a7 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -1,14 +1,8 @@ #include -int main(int argc, char *argv[]) { - GMainLoop *loop; - GstElement *rx, *tx; +int create_rx_chain(GstElement *pipeline) { GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_sink; - gst_init (&argc, &argv); - loop = g_main_loop_new (NULL, FALSE); - - rx = gst_pipeline_new ("rx"); rx_tap = gst_element_factory_make("udpsrc", "rx-tap"); rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer"); rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay"); @@ -16,8 +10,8 @@ int main(int argc, char *argv[]) { rx_resample = gst_element_factory_make("audioresample", "rx-audioresample"); rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink"); - if (!rx || !rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_sink) { - g_printerr ("One element could not be created. Exiting.\n"); + if (!rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_sink) { + g_printerr ("One element of the rx chain could not be created. Exiting.\n"); return -1; } @@ -31,18 +25,67 @@ int main(int argc, char *argv[]) { g_object_set(G_OBJECT (rx_opusdec), "plc", TRUE, NULL); g_object_set(G_OBJECT (rx_opusdec), "use-inband-fec", FALSE, NULL); - gst_bin_add_many (GST_BIN (rx), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); - gst_element_set_state (rx, GST_STATE_PLAYING); + return 0; +} + +int create_tx_chain(GstElement *pipeline) { + GstElement *tx_tap, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; + + tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap"); + tx_resample = gst_element_factory_make("audioresample", "tx-resample"); + tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc"); + tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay"); + tx_sink = gst_element_factory_make("udpsink", "tx-sink"); + + if (!tx_tap || !tx_resample || !tx_opusenc || !tx_pay || !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(tx_opusenc), "audio-type", "voice"); + g_object_set(G_OBJECT(tx_opusenc), "inband-fec", FALSE, NULL); + g_object_set(G_OBJECT(tx_opusenc), "frame-size", 40, NULL); + g_object_set(G_OBJECT(tx_opusenc), "bitrate", 32000, NULL); + g_object_set(G_OBJECT(tx_opusenc), "dtx", FALSE, NULL); // gstreamer dtx opus implem. is broken + + g_object_set(G_OBJECT(tx_sink), "host", "127.0.0.1", NULL); + g_object_set(G_OBJECT(tx_sink), "port", 5000, NULL); + g_object_set(G_OBJECT(tx_sink), "async", FALSE, NULL); + + gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + gst_element_link_many(tx_tap, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + + return 0; +} + +int main(int argc, char *argv[]) { + GMainLoop *loop; + GstElement *pipeline; + + gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); + + pipeline = gst_pipeline_new ("pipeline"); + if (!pipeline) { + g_printerr ("Pipeline could not be created. Exiting.\n"); + return -1; + } + + if (create_rx_chain (pipeline) != 0) return -1; + if (create_tx_chain (pipeline) != 0) return -1; + + gst_element_set_state (pipeline, GST_STATE_PLAYING); g_print ("Running...\n"); g_main_loop_run (loop); g_print ("Returned, stopping playback\n"); - gst_element_set_state (rx, GST_STATE_NULL); + gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (rx)); + gst_object_unref (GST_OBJECT (pipeline)); g_main_loop_unref (loop); return 0; From 34bd9d829cec5dfffd62ee39d86bfda3502c5607 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 08:47:47 +0100 Subject: [PATCH 04/18] Parameterize dcall --- src/dcall.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index 065f4a7..8bbe006 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -31,7 +31,7 @@ int create_rx_chain(GstElement *pipeline) { return 0; } -int create_tx_chain(GstElement *pipeline) { +int create_tx_chain(GstElement *pipeline, char* remote_host) { GstElement *tx_tap, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap"); @@ -51,7 +51,7 @@ int create_tx_chain(GstElement *pipeline) { g_object_set(G_OBJECT(tx_opusenc), "bitrate", 32000, NULL); g_object_set(G_OBJECT(tx_opusenc), "dtx", FALSE, NULL); // gstreamer dtx opus implem. is broken - g_object_set(G_OBJECT(tx_sink), "host", "127.0.0.1", NULL); + g_object_set(G_OBJECT(tx_sink), "host", remote_host, NULL); g_object_set(G_OBJECT(tx_sink), "port", 5000, NULL); g_object_set(G_OBJECT(tx_sink), "async", FALSE, NULL); @@ -64,6 +64,14 @@ int create_tx_chain(GstElement *pipeline) { int main(int argc, char *argv[]) { GMainLoop *loop; GstElement *pipeline; + char *remote_host; + + /* Check input arguments */ + if (argc != 2) { + g_printerr ("Usage: %s \n", argv[0]); + return -1; + } + remote_host = argv[1]; gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); @@ -75,7 +83,7 @@ int main(int argc, char *argv[]) { } if (create_rx_chain (pipeline) != 0) return -1; - if (create_tx_chain (pipeline) != 0) return -1; + if (create_tx_chain (pipeline, remote_host) != 0) return -1; gst_element_set_state (pipeline, GST_STATE_PLAYING); From 81e2b122733ac02b3ef57b6535d278c27533e752 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 10:05:16 +0100 Subject: [PATCH 05/18] Create binaries --- CMakeLists.txt | 2 +- Dockerfile | 8 +- README.md | 308 ++++----------------------------------------- README.more.md | 300 +++++++++++++++++++++++++++++++++++++++++++ create_binaries.sh | 9 ++ 5 files changed, 337 insertions(+), 290 deletions(-) create mode 100644 README.more.md create mode 100755 create_binaries.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 75053a2..bf75b83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ add_executable(dcall src/dcall.c) find_package(PkgConfig REQUIRED) pkg_search_module(GLIB REQUIRED glib-2.0) -pkg_search_module(GST REQUIRED gstreamer-1.0 >= 1.16) +pkg_search_module(GST REQUIRED gstreamer-1.0 >= 1.14) target_include_directories(donar PRIVATE ${GLIB_INCLUDE_DIRS}) target_link_libraries(donar ${GLIB_LDFLAGS}) diff --git a/Dockerfile b/Dockerfile index f613418..1f6fa4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:30 as builder +FROM fedora:31 as builder RUN dnf install -y \ coreutils \ cmake \ @@ -14,7 +14,8 @@ RUN dnf install -y \ automake \ libzstd-devel \ xz-devel \ - git + git \ + gstreamer1-devel WORKDIR /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 \ glib2 \ 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/udpecho /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/tor3/src/app/tor /usr/local/bin/tor3 COPY ./scripts/container/* /usr/local/bin/ diff --git a/README.md b/README.md index 67c77b1..d034b6c 100644 --- a/README.md +++ b/README.md @@ -1,300 +1,36 @@ -# Donar +# DONAR -## Quickstart +## 1) Runtime dependencies -### 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: +On Fedora: ```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 +sudo dnf install -y \ + glib2 \ + gstreamer1.0 \ + libevent \ + zlib \ + openssl \ + libzstd \ + xz-libs ``` -### Introduction to the debug tools `udpecho` and `measlat` - -Now let's start simple, we will launch our udp echo server and access it locally: +On Ubuntu: ```bash -udpecho -p 8000 & -nc 127.0.0.1 8000 +sudo apt-get install -y \ + libglib2.0-0 \ + gstreamer1.0 \ + libevent \ + zlib \ + libssl1.1 \ + zstd \ + liblzma5 ``` -If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done! +## 2) Obtain binaries -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 -``` +## 3) Run them -`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: @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 -``` diff --git a/README.more.md b/README.more.md new file mode 100644 index 0000000..67c77b1 --- /dev/null +++ b/README.more.md @@ -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: @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 +``` diff --git a/create_binaries.sh b/create_binaries.sh new file mode 100755 index 0000000..861d6c9 --- /dev/null +++ b/create_binaries.sh @@ -0,0 +1,9 @@ +#!/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} /tmp/release From fa4eae4f04b96a76127e08a422e0af78dbe9cc9b Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 10:33:12 +0100 Subject: [PATCH 06/18] Improve README --- README.md | 50 +++++++++++++++++++++++++++++++++++++++++++++- create_binaries.sh | 6 +++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d034b6c..bb2ebf0 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,55 @@ sudo apt-get install -y \ ## 2) Obtain binaries +Download the version you want here: https://cloud.deuxfleurs.fr/d/612993c04e9d40609242/ -## 3) Run them +And extract the zip file: + +```bash +unzip donar*.zip +cd release +``` + +## 3) Callee + +In a first terminal: + +```bash +./tor2 -f torrc_guard_12 +``` + +In a second terminal: + +```bash +./donar -s -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +``` + +In a third terminal: + +```bash +./dcall 127.13.3.7 +``` + +Your "address" is contained inside the `onion_services.pub`, you must transmit it out of band to people that want to call you. + +## 4) Caller + +In a first terminal: + +```bash +./tor2 -f torrc_guard_12 +``` + +In a second terminal: + +```bash +./donar -c -o onion_service.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +``` + +In a third terminal: + +```bash +./dcall 127.13.3.7 +``` diff --git a/create_binaries.sh b/create_binaries.sh index 861d6c9..8900dda 100755 --- a/create_binaries.sh +++ b/create_binaries.sh @@ -6,4 +6,8 @@ docker run \ -it \ -v `pwd`/release:/tmp/release \ registry.gitlab.inria.fr/qdufour/donar \ - cp /usr/local/bin/{tor2,tor3,dcall,donar,measlat} /tmp/release + cp \ + /usr/local/bin/{tor2,tor3,dcall,donar,measlat} \ + /etc/tor/{torrc_guard_12,torrc_guard_2,torrc_single_hop_12} \ + /tmp/release +zip -r donar.zip release/ From e52f47ce6e047b8fd927aa7da7f83dd74b71ae95 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 10:51:14 +0100 Subject: [PATCH 07/18] Fix guide --- README.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bb2ebf0..65b4624 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,9 @@ sudo dnf install -y \ zlib \ openssl \ libzstd \ - xz-libs + xz-libs \ + wget \ + unzip ``` On Ubuntu: @@ -20,12 +22,19 @@ On Ubuntu: ```bash sudo apt-get install -y \ libglib2.0-0 \ - gstreamer1.0 \ - libevent \ - zlib \ + libgstreamer1.0 \ + gstreamer1.0-alsa \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-ugly \ + gstreamer1.0-pulseaudio \ + libevent-2.1 \ + zlib1g \ libssl1.1 \ zstd \ - liblzma5 + liblzma5 \ + wget \ + unzip ``` ## 2) Obtain binaries From c24f65cd4317d06f5d5efd5968586ea419f1f98e Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 10:58:23 +0100 Subject: [PATCH 08/18] Add echo cancellation --- README.md | 313 +++++++++++++++++++++++++++++++++++++++++++--------- src/dcall.c | 19 ++-- 2 files changed, 271 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 65b4624..67c77b1 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,300 @@ -# DONAR +# Donar -## 1) Runtime dependencies +## Quickstart -On Fedora: +### Installation -```bash -sudo dnf install -y \ - glib2 \ - gstreamer1.0 \ - libevent \ - zlib \ - openssl \ - libzstd \ - xz-libs \ - wget \ - unzip +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 ``` -On Ubuntu: +### 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 -sudo apt-get install -y \ - libglib2.0-0 \ - libgstreamer1.0 \ - gstreamer1.0-alsa \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-pulseaudio \ - libevent-2.1 \ - zlib1g \ - libssl1.1 \ - zstd \ - liblzma5 \ - wget \ - unzip +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 ``` -## 2) Obtain binaries +### Introduction to the debug tools `udpecho` and `measlat` -Download the version you want here: https://cloud.deuxfleurs.fr/d/612993c04e9d40609242/ - -And extract the zip file: +Now let's start simple, we will launch our udp echo server and access it locally: ```bash -unzip donar*.zip -cd release +udpecho -p 8000 & +nc 127.0.0.1 8000 ``` -## 3) Callee +If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done! -In a first terminal: +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 -./tor2 -f torrc_guard_12 +measlat -h 127.0.0.1 -p 8000 -t udp ``` -In a second terminal: +`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 -./donar -s -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +measlat -h 127.0.0.1 -p 8000 -t udp -c 10 -i 100 -s 150 ``` -In a third terminal: +### 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 -./dcall 127.13.3.7 +donar -s -a naive -e 3000 -r 3001 ``` -Your "address" is contained inside the `onion_services.pub`, you must transmit it out of band to people that want to call you. - -## 4) Caller - -In a first terminal: +In a third terminal, launch your echo service: ```bash -./tor2 -f torrc_guard_12 +udpecho -p 3000 ``` -In a second terminal: +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 -o onion_service.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +donar -c -a naive -o machine_a.pub -r 3000 -e 3001 ``` -In a third terminal: +In a third terminal, launch your echo service: ```bash -./dcall 127.13.3.7 +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: @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 +``` diff --git a/src/dcall.c b/src/dcall.c index 8bbe006..d95d0d4 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -1,21 +1,23 @@ #include int create_rx_chain(GstElement *pipeline) { - GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_sink; + GstElement *rx_tap, *rx_jitterbuffer, *rx_depay, *rx_opusdec, *rx_resample, *rx_echocancel, *rx_sink; rx_tap = gst_element_factory_make("udpsrc", "rx-tap"); rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer"); rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay"); rx_opusdec = gst_element_factory_make("opusdec", "rx-opusdec"); rx_resample = gst_element_factory_make("audioresample", "rx-audioresample"); + rx_echocancel = gst_element_factory_make("webrtcechoprobe", "rx-echocancel"); rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink"); - if (!rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_sink) { + if (!rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_echocancel || !rx_sink) { g_printerr ("One element of the rx chain could not be created. Exiting.\n"); return -1; } g_object_set(G_OBJECT (rx_tap), "port", 5000, NULL); + g_object_set(G_OBJECT (rx_tap), "address", "127.0.0.1", NULL); g_object_set(G_OBJECT (rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), NULL); g_object_set(G_OBJECT (rx_jitterbuffer), "do-lost", TRUE, NULL); @@ -25,22 +27,23 @@ int create_rx_chain(GstElement *pipeline) { g_object_set(G_OBJECT (rx_opusdec), "plc", TRUE, NULL); g_object_set(G_OBJECT (rx_opusdec), "use-inband-fec", FALSE, NULL); - gst_bin_add_many (GST_BIN (pipeline), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); - gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_echocancel, rx_sink, NULL); + gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_echocancel, rx_sink, NULL); return 0; } int create_tx_chain(GstElement *pipeline, char* remote_host) { - GstElement *tx_tap, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; + GstElement *tx_tap, *tx_echocancel, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap"); + tx_echocancel = gst_element_factory_make("webrtcdsp", "tx-echocancel"); tx_resample = gst_element_factory_make("audioresample", "tx-resample"); tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc"); tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay"); tx_sink = gst_element_factory_make("udpsink", "tx-sink"); - if (!tx_tap || !tx_resample || !tx_opusenc || !tx_pay || !tx_sink) { + if (!tx_tap || !tx_echocancel || !tx_resample || !tx_opusenc || !tx_pay || !tx_sink) { g_printerr("One element of the tx chain could not be created. Exiting.\n"); return -1; } @@ -55,8 +58,8 @@ int create_tx_chain(GstElement *pipeline, char* remote_host) { g_object_set(G_OBJECT(tx_sink), "port", 5000, NULL); g_object_set(G_OBJECT(tx_sink), "async", FALSE, NULL); - gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); - gst_element_link_many(tx_tap, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_echocancel, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + gst_element_link_many(tx_tap, tx_echocancel, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); return 0; } From 26d2d2f85c7f588d11f95f9b66ad54fc9771f84f Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 11:16:55 +0100 Subject: [PATCH 09/18] Better echo cancel config! --- src/dcall.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index d95d0d4..f261701 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -17,7 +17,7 @@ int create_rx_chain(GstElement *pipeline) { } g_object_set(G_OBJECT (rx_tap), "port", 5000, NULL); - g_object_set(G_OBJECT (rx_tap), "address", "127.0.0.1", NULL); + //g_object_set(G_OBJECT (rx_tap), "address", "127.0.0.1", NULL); g_object_set(G_OBJECT (rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), NULL); g_object_set(G_OBJECT (rx_jitterbuffer), "do-lost", TRUE, NULL); @@ -34,16 +34,17 @@ int create_rx_chain(GstElement *pipeline) { } int create_tx_chain(GstElement *pipeline, char* remote_host) { - GstElement *tx_tap, *tx_echocancel, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; + GstElement *tx_tap, *tx_echocancel, *tx_queue, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap"); tx_echocancel = gst_element_factory_make("webrtcdsp", "tx-echocancel"); + //tx_queue = gst_element_factory_make("queue", "tx-queue"); tx_resample = gst_element_factory_make("audioresample", "tx-resample"); tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc"); tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay"); tx_sink = gst_element_factory_make("udpsink", "tx-sink"); - if (!tx_tap || !tx_echocancel || !tx_resample || !tx_opusenc || !tx_pay || !tx_sink) { + if (!tx_tap || !tx_echocancel || /*!tx_queue ||*/ !tx_resample || !tx_opusenc || !tx_pay || !tx_sink) { g_printerr("One element of the tx chain could not be created. Exiting.\n"); return -1; } @@ -58,8 +59,17 @@ int create_tx_chain(GstElement *pipeline, char* remote_host) { g_object_set(G_OBJECT(tx_sink), "port", 5000, NULL); g_object_set(G_OBJECT(tx_sink), "async", FALSE, NULL); - gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_echocancel, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); - gst_element_link_many(tx_tap, tx_echocancel, tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + g_object_set(G_OBJECT(tx_echocancel), "echo-cancel", TRUE, NULL); + g_object_set(G_OBJECT(tx_echocancel), "extended-filter", TRUE, NULL); + g_object_set(G_OBJECT(tx_echocancel), "gain-control", TRUE, NULL); + g_object_set(G_OBJECT(tx_echocancel), "high-pass-filter", TRUE, NULL); + g_object_set(G_OBJECT(tx_echocancel), "limiter", FALSE, NULL); + g_object_set(G_OBJECT(tx_echocancel), "noise-suppression", TRUE, NULL); + g_object_set(G_OBJECT(tx_echocancel), "probe", "rx-echocancel", NULL); + g_object_set(G_OBJECT(tx_echocancel), "voice-detection", FALSE, NULL); + + gst_bin_add_many(GST_BIN(pipeline), tx_tap, tx_echocancel, /*tx_queue,*/ tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); + gst_element_link_many(tx_tap, tx_echocancel, /*tx_queue,*/ tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); return 0; } From 72199376a661eef136f2bae4b203b27cc5b3ee28 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 12:01:32 +0100 Subject: [PATCH 10/18] Improve dcall --- src/dcall.c | 137 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 55 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index f261701..20d42ac 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -1,83 +1,96 @@ #include +#include +#include +#include +#include -int create_rx_chain(GstElement *pipeline) { +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; +}; - rx_tap = gst_element_factory_make("udpsrc", "rx-tap"); - rx_jitterbuffer = gst_element_factory_make("rtpjitterbuffer", "rx-jitterbuffer"); - rx_depay = gst_element_factory_make("rtpopusdepay", "rx-depay"); - rx_opusdec = gst_element_factory_make("opusdec", "rx-opusdec"); - rx_resample = gst_element_factory_make("audioresample", "rx-audioresample"); - rx_echocancel = gst_element_factory_make("webrtcechoprobe", "rx-echocancel"); - rx_sink = gst_element_factory_make("autoaudiosink", "rx-sink"); +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 (!rx_tap || !rx_jitterbuffer || !rx_depay || !rx_opusdec || !rx_resample || !rx_echocancel || !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 (rx_tap), "port", 5000, NULL); + 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 (rx_tap), "caps", gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio", NULL), 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 (rx_jitterbuffer), "do-lost", TRUE, NULL); - g_object_set(G_OBJECT (rx_jitterbuffer), "do-retransmission", FALSE, NULL); - g_object_set(G_OBJECT (rx_jitterbuffer), "latency", 50, 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 (rx_opusdec), "plc", TRUE, NULL); - g_object_set(G_OBJECT (rx_opusdec), "use-inband-fec", FALSE, 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 (pipeline), rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_echocancel, rx_sink, NULL); - gst_element_link_many (rx_tap, rx_jitterbuffer, rx_depay, rx_opusdec, rx_resample, rx_echocancel, rx_sink, 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(GstElement *pipeline, char* remote_host) { - GstElement *tx_tap, *tx_echocancel, *tx_queue, *tx_resample, *tx_opusenc, *tx_pay, *tx_sink; - - tx_tap = gst_element_factory_make("autoaudiosrc", "tx-tap"); - tx_echocancel = gst_element_factory_make("webrtcdsp", "tx-echocancel"); +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"); - tx_resample = gst_element_factory_make("audioresample", "tx-resample"); - tx_opusenc = gst_element_factory_make("opusenc", "tx-opusenc"); - tx_pay = gst_element_factory_make("rtpopuspay", "tx-rtpopuspay"); - tx_sink = gst_element_factory_make("udpsink", "tx-sink"); + 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 (!tx_tap || !tx_echocancel || /*!tx_queue ||*/ !tx_resample || !tx_opusenc || !tx_pay || !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(tx_opusenc), "audio-type", "voice"); - g_object_set(G_OBJECT(tx_opusenc), "inband-fec", FALSE, NULL); - g_object_set(G_OBJECT(tx_opusenc), "frame-size", 40, NULL); - g_object_set(G_OBJECT(tx_opusenc), "bitrate", 32000, NULL); - g_object_set(G_OBJECT(tx_opusenc), "dtx", FALSE, NULL); // gstreamer dtx opus implem. is broken + 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(tx_sink), "host", remote_host, NULL); - g_object_set(G_OBJECT(tx_sink), "port", 5000, NULL); - g_object_set(G_OBJECT(tx_sink), "async", FALSE, NULL); + 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(tx_echocancel), "echo-cancel", TRUE, NULL); - g_object_set(G_OBJECT(tx_echocancel), "extended-filter", TRUE, NULL); - g_object_set(G_OBJECT(tx_echocancel), "gain-control", TRUE, NULL); - g_object_set(G_OBJECT(tx_echocancel), "high-pass-filter", TRUE, NULL); - g_object_set(G_OBJECT(tx_echocancel), "limiter", FALSE, NULL); - g_object_set(G_OBJECT(tx_echocancel), "noise-suppression", TRUE, NULL); - g_object_set(G_OBJECT(tx_echocancel), "probe", "rx-echocancel", NULL); - g_object_set(G_OBJECT(tx_echocancel), "voice-detection", 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(pipeline), tx_tap, tx_echocancel, /*tx_queue,*/ tx_resample, tx_opusenc, tx_pay, tx_sink, NULL); - gst_element_link_many(tx_tap, tx_echocancel, /*tx_queue,*/ tx_resample, tx_opusenc, tx_pay, tx_sink, 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; } +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; - GstElement *pipeline; char *remote_host; + struct dcall_elements de; /* Check input arguments */ if (argc != 2) { @@ -89,24 +102,38 @@ int main(int argc, char *argv[]) { gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); - pipeline = gst_pipeline_new ("pipeline"); - if (!pipeline) { + de.pipeline = gst_pipeline_new ("pipeline"); + if (!de.pipeline) { g_printerr ("Pipeline could not be created. Exiting.\n"); return -1; } - if (create_rx_chain (pipeline) != 0) return -1; - if (create_tx_chain (pipeline, remote_host) != 0) return -1; + if (create_rx_chain (&de) != 0) return -1; + if (create_tx_chain (&de) != 0) return -1; - gst_element_set_state (pipeline, GST_STATE_PLAYING); + 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 ("Returned, stopping playback\n"); - gst_element_set_state (pipeline, GST_STATE_NULL); + g_print ("Main loop stopped...\n"); - gst_object_unref (GST_OBJECT (pipeline)); + 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_main_loop_unref (loop); return 0; From 32f6256547a1467bf88fd840f450e8adaf16371e Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 12:03:39 +0100 Subject: [PATCH 11/18] Fix bug --- src/dcall.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index 20d42ac..1c4ba5f 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -89,7 +89,6 @@ gboolean stop_handler(gpointer user_data) { int main(int argc, char *argv[]) { GMainLoop *loop; - char *remote_host; struct dcall_elements de; /* Check input arguments */ @@ -97,7 +96,7 @@ int main(int argc, char *argv[]) { g_printerr ("Usage: %s \n", argv[0]); return -1; } - remote_host = argv[1]; + de.remote_host = argv[1]; gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); From 568da4b677e4d5b9c73f5747ef261570e8ad2baf Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 12:05:48 +0100 Subject: [PATCH 12/18] Update building script --- create_binaries.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create_binaries.sh b/create_binaries.sh index 8900dda..6d96de8 100755 --- a/create_binaries.sh +++ b/create_binaries.sh @@ -8,6 +8,6 @@ docker run \ registry.gitlab.inria.fr/qdufour/donar \ cp \ /usr/local/bin/{tor2,tor3,dcall,donar,measlat} \ - /etc/tor/{torrc_guard_12,torrc_guard_2,torrc_single_hop_12} \ + /etc/{torrc_guard_12,torrc_guard_2,torrc_single_hop_12} \ /tmp/release zip -r donar.zip release/ From 3d8ec86c3b9fb8c045a06902cf235a7eb472177b Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 12:09:07 +0100 Subject: [PATCH 13/18] Fix wrong README --- README.md | 309 +++++++++--------------------------------------------- 1 file changed, 51 insertions(+), 258 deletions(-) diff --git a/README.md b/README.md index 67c77b1..65b4624 100644 --- a/README.md +++ b/README.md @@ -1,300 +1,93 @@ -# Donar +# DONAR -## Quickstart +## 1) Runtime dependencies -### 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: +On Fedora: ```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 +sudo dnf install -y \ + glib2 \ + gstreamer1.0 \ + libevent \ + zlib \ + openssl \ + libzstd \ + xz-libs \ + wget \ + unzip ``` -### Introduction to the debug tools `udpecho` and `measlat` - -Now let's start simple, we will launch our udp echo server and access it locally: +On Ubuntu: ```bash -udpecho -p 8000 & -nc 127.0.0.1 8000 +sudo apt-get install -y \ + libglib2.0-0 \ + libgstreamer1.0 \ + gstreamer1.0-alsa \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-ugly \ + gstreamer1.0-pulseaudio \ + libevent-2.1 \ + zlib1g \ + libssl1.1 \ + zstd \ + liblzma5 \ + wget \ + unzip ``` -If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done! +## 2) Obtain binaries -Now, instead of using `nc`, we will use `measlat` to use this echo server to measure latencies (make sure that `udpecho` is still running): +Download the version you want here: https://cloud.deuxfleurs.fr/d/612993c04e9d40609242/ + +And extract the zip file: ```bash -measlat -h 127.0.0.1 -p 8000 -t udp +unzip donar*.zip +cd release ``` -`measlat` will send one packet to our udpecho server and wait to receive it back, measure the time it took, display it and exit. +## 3) Callee -You can use `measlat` more extensively by defining the number of measures to do, an interval and the size of the packet: +In a first terminal: ```bash -measlat -h 127.0.0.1 -p 8000 -t udp -c 10 -i 100 -s 150 +./tor2 -f torrc_guard_12 ``` -### 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: +In a second terminal: ```bash -donar -s -a naive -e 3000 -r 3001 +./donar -s -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 ``` -In a third terminal, launch your echo service: +In a third terminal: ```bash -udpecho -p 3000 +./dcall 127.13.3.7 ``` -Display the content of the file `onion_services.pub` that has been created in your working directory. +Your "address" is contained inside the `onion_services.pub`, you must transmit it out of band to people that want to call you. -*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: +## 4) Caller + +In a first terminal: ```bash -donar -c -a naive -o machine_a.pub -r 3000 -e 3001 +./tor2 -f torrc_guard_12 ``` -In a third terminal, launch your echo service: +In a second terminal: ```bash -udpecho -p 3001 +./donar -c -o onion_service.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 ``` -*On machine A* -You can access to the echo service from *machine B* by running: +In a third terminal: ```bash -nc 127.13.3.7 3001 -# or -measlat -h 127.13.3.7 -p 3001 -t udp +./dcall 127.13.3.7 ``` -*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: @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 -``` From 36ed93f98c6eba24d4d13bc26cd10c5704a3504f Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 13:51:41 +0100 Subject: [PATCH 14/18] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65b4624..be49f60 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ In a first terminal: In a second terminal: ```bash -./donar -c -o onion_service.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +./donar -c -o onion_services.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 ``` In a third terminal: From eb684c824a852ad52daa18f25017dc7b08454ed1 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 16:07:43 +0100 Subject: [PATCH 15/18] Patch dcall --- README.md | 313 +++++++++++++++++++++++++++++++++++++++++++--------- src/dcall.c | 38 +++++++ 2 files changed, 298 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index be49f60..67c77b1 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,300 @@ -# DONAR +# Donar -## 1) Runtime dependencies +## Quickstart -On Fedora: +### Installation -```bash -sudo dnf install -y \ - glib2 \ - gstreamer1.0 \ - libevent \ - zlib \ - openssl \ - libzstd \ - xz-libs \ - wget \ - unzip +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 ``` -On Ubuntu: +### 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 -sudo apt-get install -y \ - libglib2.0-0 \ - libgstreamer1.0 \ - gstreamer1.0-alsa \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-pulseaudio \ - libevent-2.1 \ - zlib1g \ - libssl1.1 \ - zstd \ - liblzma5 \ - wget \ - unzip +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 ``` -## 2) Obtain binaries +### Introduction to the debug tools `udpecho` and `measlat` -Download the version you want here: https://cloud.deuxfleurs.fr/d/612993c04e9d40609242/ - -And extract the zip file: +Now let's start simple, we will launch our udp echo server and access it locally: ```bash -unzip donar*.zip -cd release +udpecho -p 8000 & +nc 127.0.0.1 8000 ``` -## 3) Callee +If you write some data on your terminal and press enter, you will see that your data has been repeated. Well done! -In a first terminal: +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 -./tor2 -f torrc_guard_12 +measlat -h 127.0.0.1 -p 8000 -t udp ``` -In a second terminal: +`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 -./donar -s -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +measlat -h 127.0.0.1 -p 8000 -t udp -c 10 -i 100 -s 150 ``` -In a third terminal: +### 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 -./dcall 127.13.3.7 +donar -s -a naive -e 3000 -r 3001 ``` -Your "address" is contained inside the `onion_services.pub`, you must transmit it out of band to people that want to call you. - -## 4) Caller - -In a first terminal: +In a third terminal, launch your echo service: ```bash -./tor2 -f torrc_guard_12 +udpecho -p 3000 ``` -In a second terminal: +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 -o onion_services.pub -a lightning -l 12 -p 'fast_count=3!tick_tock=0!window=2000' -e 5000 -r 5000 +donar -c -a naive -o machine_a.pub -r 3000 -e 3001 ``` -In a third terminal: +In a third terminal, launch your echo service: ```bash -./dcall 127.13.3.7 +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: @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 +``` diff --git a/src/dcall.c b/src/dcall.c index 1c4ba5f..83ec2a3 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -81,6 +81,40 @@ int create_tx_chain(struct dcall_elements* de) { 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...\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; +} + gboolean stop_handler(gpointer user_data) { GMainLoop *loop = user_data; g_main_loop_quit(loop); @@ -112,6 +146,10 @@ int main(int argc, char *argv[]) { gst_element_set_state (de.pipeline, GST_STATE_PLAYING); + 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); + g_unix_signal_add (SIGTERM, stop_handler, loop); g_unix_signal_add (SIGINT, stop_handler, loop); From 2f6fe41778c59bc406d74f818c9b8ee8242d4ef1 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 16:55:20 +0100 Subject: [PATCH 16/18] Update dcall --- src/dcall.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index 83ec2a3..f3d8d43 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -9,6 +9,7 @@ struct dcall_elements { 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) { @@ -32,6 +33,7 @@ int create_rx_chain(struct dcall_elements* de) { 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_opusdec), "plc", TRUE, NULL); g_object_set(G_OBJECT (de->rx_opusdec), "use-inband-fec", FALSE, NULL); @@ -115,6 +117,27 @@ static GstPadProbeReturn jitter_buffer_sink_event(GstPad *pad, GstPadProbeInfo * 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_) +} + +static gboolean pipeline_bus_handler (GstBus *bus, GstMessage *message, gpointer data) { + g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message)); + + 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); @@ -144,11 +167,10 @@ int main(int argc, char *argv[]) { if (create_rx_chain (&de) != 0) return -1; if (create_tx_chain (&de) != 0) return -1; - gst_element_set_state (de.pipeline, GST_STATE_PLAYING); + register_pad(&de); + register_bus(&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_element_set_state (de.pipeline, GST_STATE_PLAYING); g_unix_signal_add (SIGTERM, stop_handler, loop); g_unix_signal_add (SIGINT, stop_handler, loop); @@ -171,6 +193,7 @@ int main(int argc, char *argv[]) { 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; From 2c8b1d9f46845535f3a952a981020655e7905f04 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 17:27:33 +0100 Subject: [PATCH 17/18] Try a new way to detect dropped messages --- src/dcall.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/dcall.c b/src/dcall.c index f3d8d43..4c39640 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -34,6 +34,7 @@ int create_rx_chain(struct dcall_elements* de) { 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); @@ -87,7 +88,7 @@ static GstPadProbeReturn jitter_buffer_sink_event(GstPad *pad, GstPadProbeInfo * struct dcall_elements *de = user_data; GstEvent *event = NULL; - g_print("Entering rtpjitterbuffer sink pad handler...\n"); + 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; @@ -117,17 +118,32 @@ static GstPadProbeReturn jitter_buffer_sink_event(GstPad *pad, GstPadProbeInfo * 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)); + + 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_) + //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; } @@ -168,7 +184,7 @@ int main(int argc, char *argv[]) { if (create_tx_chain (&de) != 0) return -1; register_pad(&de); - register_bus(&de); + //register_bus(&de); gst_element_set_state (de.pipeline, GST_STATE_PLAYING); @@ -193,7 +209,7 @@ int main(int argc, char *argv[]) { gst_element_set_state (de.pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (de.pipeline)); - g_source_remove (de.bus_watch_id); + // g_source_remove (de.bus_watch_id); g_main_loop_unref (loop); return 0; From 22c07f1e26d7ad8bd76249bf690e437f27e25529 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 28 Jan 2020 18:02:39 +0100 Subject: [PATCH 18/18] WIP interception --- src/dcall.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dcall.c b/src/dcall.c index 4c39640..bd7d8c7 100644 --- a/src/dcall.c +++ b/src/dcall.c @@ -3,6 +3,7 @@ #include #include #include +#include struct dcall_elements { GstElement *pipeline; @@ -124,7 +125,14 @@ static GstPadProbeReturn jitter_buffer_sink_buffer(GstPad *pad, GstPadProbeInfo 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)); + //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; }