Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: VoIp System where server passes clients speech to every other client.  (Read 13034 times)

0 Members and 2 Guests are viewing this topic.

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
Hello everybody. I am working with a Virtual Construction and we are trying to create a VoIP system to our Unreal Engine Project. We added the Audio libraries and managed to record and play the Microphone sound. However, we are unsuccessful to make Voice chat working as described in Topic. What we are are trying to achieve is that when one client speaks, it will pass the voice data to Dedicated Server than then multicast it to every other client. Basically basic voice chat use see in almost every multiplayer game.

There is VoIP example and it uses own Network Sound class, but it seems, that is only connects to one IP and when connected, no other clients can connect it, so it might not be suitable in this scenario. Any help from you guys? Thank you very much.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
So with what are you exactly stuck?

In order to send data to multiple clients you of course have to open a connection to each client.
Have you implemented this already?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
So with what are you exactly stuck?

In order to send data to multiple clients you of course have to open a connection to each client.
Have you implemented this already?

For what I undestand, when you open connection, it can only take one connection and then closes to ther connections. So what if there is a ten people playing? So do I need to create ten listeners and connect every client to each listener? Project is also drop in and drop out system, so would I require open listening connection for player when joining game and then make all clients to connect the joined person? Thanks.

edit: Also, it would not be good if clients need to open the listening port, because we might not be sure, if the player has the port blocked or already used. So in this case the server needs to listen evereybody and then forward the data to clients. So clients would need some other system that plays the sound as the server passes the data. So I need help with that.
« Last Edit: June 22, 2018, 03:06:29 pm by Deliciouscookie »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Quote
For what I undestand, when you open connection, it can only take one connection and then closes to ther connections.
That's wrong, of course. A listener can accept more than one connection, and once accepted, a connection can live as long as you need it. Nothing forces you to have a single connection active at a time.
Laurent Gomila - SFML developer

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
Quote
For what I undestand, when you open connection, it can only take one connection and then closes to ther connections.
That's wrong, of course. A listener can accept more than one connection, and once accepted, a connection can live as long as you need it. Nothing forces you to have a single connection active at a time.
Hmm. Interesting. So that would solve one problem. So in Dedicated server, I would open listener. And then all clients connect to that one listener. And when server gets the data, instead of playing it, it would just send it to all clients.

So would I pass the data.samples from this function to clients (code taken from Server.cpp in examples)?

Quote
    virtual bool onGetData(sf::SoundStream::Chunk& data)
    {
        // We have reached the end of the buffer and all audio data have been played: we can stop playback
        if ((m_offset >= m_samples.size()) && m_hasFinished)
            return false;

        // No new data has arrived since last update: wait until we get some
        while ((m_offset >= m_samples.size()) && !m_hasFinished)
            sf::sleep(sf::milliseconds(10));

        // Copy samples into a local buffer to avoid synchronization problems
        // (don't forget that we run in two separate threads)
        {
            sf::Lock lock(m_mutex);
            m_tempBuffer.assign(m_samples.begin() + m_offset, m_samples.end());
        }

        // Fill audio data to pass to the stream
        data.samples     = &m_tempBuffer[0];
        data.sampleCount = m_tempBuffer.size();

        // Update the playing offset
        m_offset += m_tempBuffer.size();

        return true;
    }

I assume there is a simple function that can be run all the time from clients that takes the data when passed to them? This is getting interesting.

edit: Unless... Does every client hear the others when connected to same listener automatically? That would solve lot of things and save me from passing things from the server side manually. Sorry for questions,  I would love to test this myself, but for now, I only have single computer and cannot try anything networked until far next week :).
« Last Edit: June 22, 2018, 03:53:35 pm by Deliciouscookie »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Quote
Does every client hear the others when connected to same listener automatically?
No, a connection is between two peers. Otherwise you have to use UDP broadcast.
Laurent Gomila - SFML developer

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
Quote
For what I undestand, when you open connection, it can only take one connection and then closes to ther connections.
That's wrong, of course. A listener can accept more than one connection, and once accepted, a connection can live as long as you need it. Nothing forces you to have a single connection active at a time.

Thanks for reply. However, I cannnot get two clients to connect to a listening server. When ever I connect one client, everything works. When I connect second client, the server won't take the connection. I tried to look up the code and make different kind of modifications, but result is same. Two client are unable to connect to server. If I open two connections with two different ports then everything of course works, but that isn't ideal at all :/..

Any help guys?
Here is the example code I used: https://github.com/SFML/SFML/tree/master/examples/voip

edit: I have tried this only in local network. Atleast then, Server only says "Client Connected" for the first clients and no others. Not sure If I create a connection over internet.
« Last Edit: June 24, 2018, 12:44:03 pm by Deliciouscookie »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
This example doesn't manage multiple clients, it stops listening after the first connection, on purpose. So you can't just use it as it is and hope that it will work for your use case, you'll have to design a multi-client server by yourself (it's not that hard... just have listener.accept in a loop).
Laurent Gomila - SFML developer

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
This example doesn't manage multiple clients, it stops listening after the first connection, on purpose. So you can't just use it as it is and hope that it will work for your use case, you'll have to design a multi-client server by yourself (it's not that hard... just have listener.accept in a loop).

Thanks for the comment Laurent. After lot of studying, I managed to get this further. Now my server will listen and accept multiple client. My Server code is:

(click to show/hide)

Client is the same as before:
(click to show/hide)

My Problem is that sound sounds really weird! It's kinda cuts of sometimes and almost all the time, I can hear my self twice. I even set up a local network where other computer was a server and then I connected to it through another computer. So it was not just a circular sound problem that was happening.

So I am having a hard time with the twice playing sound AND I am not really sure how to go on, if I want to send the sound to all clients that are connected to server  :-\? Any help with these two again, thank you.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Quote
My Problem is that sound sounds really weird!
Was it already like this with the unmodified code (with a single client)? Or did it stop working fine after your modifications?
Laurent Gomila - SFML developer

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
Re: VoIp System where server passes clients speech to every other client.
« Reply #10 on: June 25, 2018, 02:44:26 pm »
Quote
My Problem is that sound sounds really weird!
Was it already like this with the unmodified code (with a single client)? Or did it stop working fine after your modifications?
It was same before. Modified code just allowed additional clients to join, but didn't improve the quality itself.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: VoIp System where server passes clients speech to every other client.
« Reply #11 on: June 25, 2018, 03:09:43 pm »
The example should work fine, but if it doesn't, then you should clearly not base your code on it. It will probably be harder and take more time, but maybe you should start from scratch; you would learn more about all this network stuff and in the end, understand better what's going on in your program.
Laurent Gomila - SFML developer

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
Re: VoIp System where server passes clients speech to every other client.
« Reply #12 on: June 25, 2018, 03:30:41 pm »
The example should work fine, but if it doesn't, then you should clearly not base your code on it. It will probably be harder and take more time, but maybe you should start from scratch; you would learn more about all this network stuff and in the end, understand better what's going on in your program.

I guess you are right. Maybe there is something wrong with implementing the code into Unreal Engine. I will look upon that. Perhaps Unreal own multi-threading is messing something up. I need to look upon these. Thanks for your help. But hey! About the last question that was on my mind. Any suggestions how to start with server sending the voip to all client when one speaks?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: VoIp System where server passes clients speech to every other client.
« Reply #13 on: June 25, 2018, 04:02:55 pm »
Quote
About the last question that was on my mind. Any suggestions how to start with server sending the voip to all client when one speaks?
Once you have a server that accepts multiple clients, what's the problem with sending the data to all of them? Where are you stuck?
Laurent Gomila - SFML developer

Deliciouscookie

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • Email
Re: VoIp System where server passes clients speech to every other client.
« Reply #14 on: June 25, 2018, 06:26:05 pm »
Quote
About the last question that was on my mind. Any suggestions how to start with server sending the voip to all client when one speaks?
Once you have a server that accepts multiple clients, what's the problem with sending the data to all of them? Where are you stuck?


Good news! I found a bug in my code and now voice is working perfectly with multiple clients! I'm sorry if I sound stupid. My Speciality is with Unreal Engine and I am still somewhat unfamiliar with networking this SFML provides. So where I am stuck is, I'm not really sure what I am supposed to do all together. I could maybe use Unreal Engines networking properties to multicast the Received Packet to clients and then put it in buffer and try to play it, but I am pretty sure, that it would be much better to do here in SFML and leave Unreal out of it as much as possible. I really trying to learn at the same time, so bare with me here  ::)

Here is the working code that is little cleaned up and the faulty break;s have been removed.


(click to show/hide)

edit: I think sending the packet here to other clients is the key. I was wondering to use something like this after Server is sure it received the voice package:

Quote
for (std::list<sf::TcpSocket*>::iterator it = clients.begin(); it != clients.end(); ++it)
{
   sf::TcpSocket& client2 = **it;
        // Don't send same voice to speaker.
   if (client2.getLocalPort() != client.getLocalPort())
   {
      UE_LOG(LogTemp, Warning, TEXT("Sending audio to one of the clients"));
      client2.send(packet);
   }
}

But if I use that, i'm not still sure how the clients can receive the packet. Am I in the right tracks here? Any help about receiving the packet on the client side? Thanks.

Above code would go inside this IF-sentence
Quote
if (id == audioData)
       {
 // Extract audio samples from the packet, and append it to our samples buffer
          const sf::Int16* samples = reinterpret_cast<const sf::Int16*>(static_cast<const char*>(packet.getData()) + 1);
« Last Edit: June 25, 2018, 08:34:37 pm by Deliciouscookie »