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.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.QuoteFor 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.
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;
}
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.
QuoteFor 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.
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).
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.QuoteMy 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?
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.
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?
QuoteAbout 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?
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);
}
}
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);
Yes, that looks correct.So if client is connected to Server. Do I need to make some forever running loop in clients also? And If client is connected, does it receive packages automatically if I use something like this:
char data[100];
std::size_t received;
// TCP socket:
if (socket.receive(data, 100, received) != sf::Socket::Done)
{
// error...
}
std::cout << "Received " << received << " bytes" << std::endl;
(click to show/hide)
You're using blocking sockets, so the receive calls will block until they receive data. Which also means that your function gets stuck waiting for data.
Maybe there are more issues that I missed by glancing over it.
if (id == endOfStream)
{
// End of stream reached: we stop receiving audio data
// std::cout << "Audio data has been 100% received!" << std::endl;
stop();
Canrun = false;
UE_LOG(LogTemp, Warning, TEXT("Audio Stream successfully finished"));
}
You're using blocking sockets, so the receive calls will block until they receive data. Which also means that your function gets stuck waiting for data.
Maybe there are more issues that I missed by glancing over it.
I think I found out the culprit. It is because stop() function won't work if the EndStream data won't come over network. I tested this by doing this:Quoteif (id == endOfStream)
{
// End of stream reached: we stop receiving audio data
// std::cout << "Audio data has been 100% received!" << std::endl;
stop();
Canrun = false;
UE_LOG(LogTemp, Warning, TEXT("Audio Stream successfully finished"));
}
If I create server and connect client through other program and then send endOfStream id, program goes pass the stop() and I get the LOG printing. If I create client and connect it through the visual studio code and then send endOfStream id, I never get the LOG printing, so program halts to stop and never goes pass it. Also, If I remove all the code and not run the stop(), the program never ends. The problem was never that I won't getting out of the loop. Problem is that I cannot run the stop() command for some reason.
So, question is, why the stop() won't run for me.
FTimerDelegate TimerCallback;
TimerCallback.BindLambda([&]
{
WaitLittle = false;
});
FTimerHandle Handle;
World->GetTimerManager().SetTimer(Handle, TimerCallback, 0.5f, false);
LambdaServer = FLambdaRunnable::RunLambdaOnBackGroundThread([&]()
{
// Build an audio stream to play sound data as it is received through the network
Disconnecter Disconnect("localhost", 2435);
Disconnect.start();
while (WaitLittle);
});
You're using blocking sockets, so the receive calls will block until they receive data. Which also means that your function gets stuck waiting for data.
Maybe there are more issues that I missed by glancing over it.
I think I found out the culprit. It is because stop() function won't work if the EndStream data won't come over network. I tested this by doing this:Quoteif (id == endOfStream)
{
// End of stream reached: we stop receiving audio data
// std::cout << "Audio data has been 100% received!" << std::endl;
stop();
Canrun = false;
UE_LOG(LogTemp, Warning, TEXT("Audio Stream successfully finished"));
}
If I create server and connect client through other program and then send endOfStream id, program goes pass the stop() and I get the LOG printing. If I create client and connect it through the visual studio code and then send endOfStream id, I never get the LOG printing, so program halts to stop and never goes pass it. Also, If I remove all the code and not run the stop(), the program never ends. The problem was never that I won't getting out of the loop. Problem is that I cannot run the stop() command for some reason.
So, question is, why the stop() won't run for me.
Got it working. Problem was when I spawned the class that sole purpose was to send the endStream message, it was destroyed too soon. So I added a little timer so the buffer get some data and then the endStream message goes through and everything closes nicely. Not best way i'm sure, but atleast now it's working without constant crashesQuoteFTimerDelegate TimerCallback;
TimerCallback.BindLambda([&]
{
WaitLittle = false;
});
FTimerHandle Handle;
World->GetTimerManager().SetTimer(Handle, TimerCallback, 0.5f, false);
LambdaServer = FLambdaRunnable::RunLambdaOnBackGroundThread([&]()
{
// Build an audio stream to play sound data as it is received through the network
Disconnecter Disconnect("localhost", 2435);
Disconnect.start();
while (WaitLittle);
});