Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

misc: rx thread activate #2828

Merged
merged 20 commits into from
Jan 11, 2024
Merged

misc: rx thread activate #2828

merged 20 commits into from
Jan 11, 2024

Conversation

cspiel1
Copy link
Collaborator

@cspiel1 cspiel1 commented Dec 12, 2023

The last part for the audio RX "real-time" thread.

Enables RX thread via config, uses worker for passing work to the main thread and adds tests to ensure thread safety.

  • stream,rtprecv: activate RX thread via config
  • test: run call tests with RX_MODE_THREAD
  • test: main - init async workers
  • rtprecv: detach from RTP/RTCP sockets before re_cancel
  • stream,rtprecv: detach from RTP/RTCP also in RECEIVE_MODE_MAIN
  • test: call - add AUDIO_MODE_THREAD for test_call_aufilt
  • test: call - reset to RECEIVE_MODE_MAIN
  • rtprecv: use enable flag to prevent data race on stream termination
  • test: call - do not test unsupported combination
  • test: call - failure debug for test_media_base()
  • rtprecv: detach sockets before attach
  • rtprecv: warnings for UDP thread attach
  • aur: add mutex locks
  • aur: add aubuf_mtx

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 12, 2023

When everything is green the commit ee740e3 will be reverted.

@cspiel1 cspiel1 added the RX thread RX real-time thread label Dec 12, 2023
@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 13, 2023

This can be tested by enabling the RX thread with this line in your ~/.baresip/config:

rtp_rxmode		thread

@juha-h Please could you test this with the Android App?

@larsimmisch Please could you test this with the vad filter?

You will notice the line

rtp_receiver: RTP RX thread started

in stdout of the baresip process.

@larsimmisch
Copy link
Contributor

larsimmisch commented Dec 13, 2023

I saw a problem on main yesterday with fvad and my application. I play a file using audio_set_source("aufile", filename) and then start a recording with audio_set_player("aufile", "record.wav"). Starting the recording returns 0, but the file is empty. Looking into it a bit, I saw that in aurecv_start_player, aurecv_codec(ar); returns NULL, so it exits early.

On v.3.7.0, the recording is created successfully. I don't understand why I didn't see that earlier.

Any hints what to look for? Creating a minimal test application would obviously be good, but I wouldn't get to it before the weekend.

@larsimmisch
Copy link
Contributor

Ah, it can be reproduced through the debug interface.

Something like:

/insmod menu
/uanew <sip:test@immisch-macbook-pro.local>

Then place an incoming call, accept it and:

/auplay aufile,record.wav

My config has:

audio_path		/usr/local/share/baresip
audio_player		aufile,/dev/null
audio_source		aufile,/usr/local/share/baresip/ringback_s16.wav
module			fvad.so

@juha-h
Copy link
Collaborator

juha-h commented Dec 14, 2023

@cspiel1 I tried the PR in my Android app and receiving audio worked OK. I saw these in the log:

12-14 09:43:05.870 25379 25426 D Baresip Lib: rtp_receiver: RTP RX thread started
...
12-14 09:43:06.388 25379 25426 D Baresip Lib: audio_recv: create audio buffer [20 - 300 ms] [640 - 9600 bytes]

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 14, 2023

Thanks @juha-h for the test. The log is exactly what I would expect.

@larsimmisch I understood that this problem is in main branch HEAD. So not directly related to this PR. I will try to analyse+solve this immediately. Thanks!

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 14, 2023

@larsimmisch The issue you found has nothing to do with fvad. Here is the fix: #2830

@larsimmisch
Copy link
Contributor

Thanks for the speedy fix on main!

I've now tested this branch (with the fix cherry-picked) with the config rtp_rxmode thread and I did see rtp_receiver: RTP RX thread started.

The test was fine.

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 14, 2023

Thanks for the test!

src/aureceiver.c Outdated
@@ -722,16 +746,19 @@ int aurecv_debug(struct re_printf *pf, const struct audio_recv *ar)
err |= mbuf_printf(mb, " time = (not started)\n");
}

err |= re_hprintf(pf, " player: %s,%s %s\n",
err |= mbuf_printf(mb, " player: %s,%s %s\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like a separate bugfix ? perhaps a separate PR for this ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/config.c Outdated
cfg->avt.rxmode = RECEIVE_MODE_THREAD;
warning("rtp_rxmode thread is currently "
"experimental\n");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please compare all values, and print a warning if it matches none

src/config.c Outdated
@@ -633,6 +644,8 @@ int config_print(struct re_printf *pf, const struct config *cfg)
cfg->avt.rtp_stats ? "yes" : "no",
cfg->avt.rtp_timeout,
cfg->avt.bundle ? "yes" : "no",
cfg->avt.rxmode == RECEIVE_MODE_THREAD ? "thread" :
"main",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if someone adds a new mode called e.g. "foo" ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added rtp_receive_mode_str().

test/call.c Outdated
@@ -853,11 +853,12 @@ static void event_handler(struct ua *ua, enum ua_event ev,
}


int test_call_answer(void)
static int test_call_answer_base(enum rtp_receive_mode rxmode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding the explicit rxmode is a good solution.

please note that it should also be possible to add new arguments to the selftest binary,
that can set the rxmode. This will make it possible to run the test with these options:

$ ./selftest -r main
$ ./selftest -r thread

@juha-h
Copy link
Collaborator

juha-h commented Dec 28, 2023

I have not seen a rational for rx thread. What are its advantages/disadvantages? In which situations it should he activated? Why is it not the default mode?

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 28, 2023

I have not seen a rational for rx thread. What are its advantages/disadvantages? In which situations it should he activated? Why is it not the default mode?

We had this discussion earlyer in this year. To sum it up: Audio processing should be done in an independent thread. The main thread handles everything from SIP signaling, parts of video processing and also processing of arbitrary baresip modules.

In the meanwhile we already have test results that show that the RX thread reduces the maximum deviation from the packet time that is caused by long blocking calls at the beginning of a call. For our products we already switched to rtp_rxmode thread.

For now rtp_rxmode main will be the default mode which will not change the behavior. In the future we could make rtp_rxmode thread to the default or maybe the only supported mode.

edit:
Processing of incoming RTP audio in a separate thread is also proposed by this book: https://csperkins.org/standards/rtp-book.html

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 28, 2023

Resolved the conflicts right now.

still TODO:

$ ./selftest -r main
$ ./selftest -r thread

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 28, 2023

TODO:

  • check if new selftest command arguments work
  • check if github actions run both RX modes
  • no sanitizer warnings

@juha-h
Copy link
Collaborator

juha-h commented Dec 29, 2023

@cspiel1 Thanks for the explanation.

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 29, 2023

Now test_call_rtcp produces a sanitizer warning (not in single test mode).

In re/src/rtp/sess.c when the sender report is created in mk_sr() which runs in the main thread.

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 29, 2023

It is a mystery to me why this didn't appear earlier. The output of sanitizer is:

./test/selftest -r thread
...
Write of size 8 at 0x7b4c00034428 by thread T59 (mutexes: write M0):
    #0 handle_incoming_sr /home/cspiel/src/baresip/re/src/rtp/sess.c:181
    ...
Previous read of size 8 at 0x7b4c00034428 by main thread (mutexes: write M1):
    #0 sender_apply_handler /home/cspiel/src/baresip/re/src/rtp/sess.c:400

@sreimers solutions that I can think of

  • (A) Run the RTCP sender report timer in the RX thread.
  • (B) Add a mutex to struct rtp_source.

(A) most likely would produce new concurrency problems that would have to be solved.
While with (B) we have to be careful to hold lock time short and don't forget any r/w cases.


edit: Just realized that this should not occur, because the write to the struct rtp_source fields should be done also in main thread. So the correct solution is to ensure that both read and write is done in main thread.


edit 2: Last edit was not correct. The RTCP call back handler in baresip passes RTCP work to the main thread. But in re there are write operations to struct rtp_source done by rtcp_recv_handler() and rtcp_sess_rx_rtp() which run in the RX thread. Thus we need to handle this somehow. Solution (B)?

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Dec 29, 2023

Most of the RTCP work in re is done from RX thread if activated.
These functions are called from main thread:

  • rtcp_debug()
  • rtcp_stats()
  • send_rtcp_report(), but this could be changed with solution (A)

@alfredh alfredh removed this from the v3.9.0 milestone Jan 1, 2024
@cspiel1
Copy link
Collaborator Author

cspiel1 commented Jan 2, 2024

Last commit implements solution (A).

TODO:

  • lock rtcp_debug()
  • lock rtcp_stats()

Edit: Done with this PR in re: baresip/re#1037

@cspiel1
Copy link
Collaborator Author

cspiel1 commented Jan 3, 2024

Rebased and dropped the reverted changes in tests.

The following commit will add delayed calls to audio_debug(). There are further concurrency problems with RTCP.

@cspiel1 cspiel1 force-pushed the rx_thread_activate branch 2 times, most recently from 26136d6 to a5f8af4 Compare January 9, 2024 14:11
@cspiel1
Copy link
Collaborator Author

cspiel1 commented Jan 9, 2024

When waiting on multiple different events with valgrind it showed that 2ms
timers lead to a faster test finish than 1ms timers.
@alfredh
Copy link
Collaborator

alfredh commented Jan 11, 2024

it should be ok to merge this now..

@sreimers sreimers changed the title rx thread activate misc: rx thread activate Jan 11, 2024
@sreimers sreimers merged commit 66ee75e into baresip:main Jan 11, 2024
16 checks passed
@cspiel1 cspiel1 deleted the rx_thread_activate branch January 11, 2024 08:48
@cspiel1
Copy link
Collaborator Author

cspiel1 commented Jan 11, 2024

Thank you for your support, reviews and interest on this work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RX thread RX real-time thread
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants