What is the correct pattern for a persistent chat app periodic video/voice call capabilities?

I’m currently building a chat app that is able to launch into voice/video when needed.

to do this I establish a session and register “signal: chat-msg” SignalEvents for sending text/image/voice_recoding messages.

The session is long lived and persists for possibly a number of hours.

From time to time the user needs to be able to make either voice or video calls in the chat session for rich real-time communication.

At this point I register listener for “streamCreated” and “streamDestroyed” events and publish the users streams.

When the call is finished, I stop publishing and remove event listeners.

This all works fine… however if the user then tries to make a follow on call in the same chat session, I register the “streamCreated” and “streamDestroyed” event listeners, unfortunately, these listeners do not receive the “streamCreated” events for any existing streams that have already joined the call.

What would be the correct way to implement this use case (persistent chat with periodic joining/leaving/rejoining voice/video call)?

Do I need to persist my “streamCreated” and “streamDestroy” event listeners and decople publish/subscribe from these events, and only publish/subscribe when making a call?

The core concept that you must understand is that OpenVidu Sessions are not persistent.
You create a Session, you create Connections for it, and users at your client-side app use a Connection’s token to connect to the Session. This is explained here in the Basic concepts section: Developing your video app - OpenVidu Docs

Once a Session has a user connected, it will remain alive and active until the last of its users disconnects from it. The moment this happens, the Session is automatically closed.

Of course, you can initialize a new Session with the same customSessionId once the previous one has finished. At all effects it will be perceived as the same Session from the user’s perspective. This way you can handle in a very simple manner the need of long-lived Sessions:

  1. You try to initialize your Session “ABC”.
  2. If the HTTP response tells you that the Session “ABC” did not existed and that it has been created, then you can proceed to create new Connections for it.
  3. If the HTTP response tells you that the Session “ABC” already existed (that is a 409 response according to the documentation), then you can also proceed to create new Connections for it.

When Session “ABC” is automatically terminated because the last user connected to it left the Session, you can start again with point 1. Behind the curtains it will be a new Session entity, but as the customSessionId can be “ABC” again, for your application it will be as if Session ABC never finished.

Does this make sense?

Sure, I have no issue with the Session, the users are connected to the session for the life time of the chat.

The issue is when to register for “streamCreated” events, currently I only do this when the user wants to escalate the chat to a voice/video call, and I unregister at the end of the call. However when re-registering for “streamCreated” events, I’m not notified of existing streams…

my question is, should I be registering the “streamCreated” event listener at the start of the session instead, and maintain a “activeStream” list independent of whether the user is on the call or not?

streamCreated event is only triggered in 2 situations:

  1. When first connected to a Session, once for every Stream that was already being published to the Session. This is immediately after triggering the local connectionCreated event.
  2. With the user alreay being connected to the Session, once for every new Stream published to the Session.

If your user has not configured a listener for the streamCreated event when point 2. takes place, it will miss the event. And registering it later does not mean previous streamCreated events will be triggered: they are lost. So yes, the best way to handle this is registering the streamCreated listener even before connecting to the Session, and store and manage the events as you wish during the call.

Cool, I’ll will give that a go.

I’m assuming that

“So yes, the best way to handle this is registering the streamCreated listener even before connecting to the Session, and store and manage the events as you wish during the call.”

You meant Stream instead of Session as you need a connected session to be able to register a listener…

You don’t really need to be connected to the Session to establish the listeners! In fact, as a general rule listeners should be added before connecting to the Session, as some events are triggered immediately after connection success. You would miss those events if you wait to add the listeners after being connected.

Interesting, I did not know that, I think the sample app registers listeners after session connection.

I will give that a try as well :+1:

I don’t think that the basic tutorials do so. For example, here it is our most basic Hello World app:

  1. streamCreated listener is set here.
  2. After that we connect to the Session using a valid token here.

I assume that most tutorials and sample applications do this in this way.

My apologies, you are absolutely correct, I was starting from the ionic example, it does register listeners before connection, this seems to be an issue I’ve introduced with one of my code refactoring when separating out the chat and video/voice calls into separate sub ionic angular components. I suspect that this has raised some other instabilities I was experiencing.

Many thanks for your help, I think this will resolve a number of issues I’ve created for myself.