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

Author Topic: Basic VoIP Problems  (Read 8257 times)

0 Members and 1 Guest are viewing this topic.

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« on: February 02, 2010, 02:35:10 am »
I don't exactly know what's wrong with this, but it doesn't play any sound. I'm fairly certain it should play something, since it outputs stuff that doesn't seem totally constant. Can anybody point me in the right direction? Using latest SFML snapshot in Visual Studio 2008. Static linking.

This is my third attempt, all ended up like this.

Server
Code: [Select]
int main(int argc, char* argv[])
{
CanNet::TCPSocket server;
CanNet::TCPSocket* client = NULL;
CanNet::Buffer buff;
sf::SoundBuffer sndBuffer;
sf::Sound sndPlay(sndBuffer);
short buffer[8000];
bool connected = false;

CanNet::Startup();

server.Listen("1337");

FILE* fOut = fopen("received.dat", "w");

while (1)
{
if (!connected)
{
// Wait for connections
client = server.Accept();

if (client != NULL)
{
std::cout << "Client Connected!" << std::endl;
connected = true;
}
} else {
int size = client->Receive(buff);

if (size > 0)
{
sndPlay.Stop();
buff.Read(&buffer, size);
fwrite(&buffer, size, 1, fOut);
sndBuffer.LoadFromSamples(&buffer[0], size / 2, 1, 8000);
sndPlay.Play();
}
}

Sleep(1);
}

fclose(fOut);

server.Close();

CanNet::Shutdown();
return 0;
}

Client
Code: [Select]
int main(int argc, char* argv[])
{
CanNet::TCPSocket sock;
CanNet::Buffer buff;
sf::SoundBufferRecorder sndRec;
sf::SoundBuffer sndBuffer = sndRec.GetBuffer();

CanNet::Startup();

if (!sock.Connect("127.0.0.1", "1337"))
{
sock.Close();
std::cout << "Unable to connect." << std::endl;
CanNet::Shutdown();
return 0;
}

sndRec.Start(8000);

while (1)
{
if (!sock.IsConnected())
{
std::cout << "Lost connection." << std::endl;
break;
}

// Do shit.

Sleep(16); // ~60fps.

sndRec.Stop();

sndBuffer = sndRec.GetBuffer();

buff.Clear();
buff.Write((void*)sndBuffer.GetSamples(), sndBuffer.GetSamplesCount() * 2); // 1 sample = 2 bytes
sock.Send(buff);

sndRec.Start(8000);
}

sndRec.Stop();
sock.Close();

CanNet::Shutdown();

return 0;
}


Custom made networking system. I also have
Code: [Select]
An internal OpenAL call failed in soundbuffer.cpp (308) : AL_INVALID_VALUE, a numeric argument is out of range in the server.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Basic VoIP Problems
« Reply #1 on: February 02, 2010, 07:56:54 am »
There are two problems in your code, one major and one minor.

First, your server program has an endless loop that stops/fills/starts the sound at a high frequency -- you will hardly hear anything. Here you are streaming a sound, thus you should use the sf::SoundStream class (read the tutorial to know how to use it). This was the major issue.

Secondly, in your client code start/stop/copy/send recording at 60 FPS -- not a good idea. You should rather implement a custom sf::SoundRecorder that sends its data continuously when its available. Same here, read the tutorial ;)

And you're lucky: there's a VoIP sample that does exactly what you want (and what I describe) in the SFML SDK.
Laurent Gomila - SFML developer

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #2 on: February 02, 2010, 08:33:56 pm »
Thanks Laurent. :D

Works nicely, but I didn't understand it entirely. How would you go about not keeping all the sound data in memory?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Basic VoIP Problems
« Reply #3 on: February 02, 2010, 10:50:52 pm »
The sound data is never stored, it is passed directly from the source to the destination in real time.
Quote
microphone --> your custom recorder --> ... network ... --> your custom soundstream --> sound card
Laurent Gomila - SFML developer

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #4 on: February 03, 2010, 01:44:21 am »
*cough* I was going from the VoIP example, too, I couldn't figure out how to not store all sound in the std::vector.

Just threaded the server, so it can play and do other things, too.

Edit: I think I know how to do it...trying.

Edit 2: Got it. :) Thanks.

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #5 on: September 06, 2010, 12:19:35 am »
*sigh*

Okay, I lost my previous source and can't remember how to do this. How would I go about removing the storage of all audio, I don't want all the samples to be stored in the std::vector to be replayed.

I'm using the VoIP example. SFML 1.6, 2.0 doesn't work, crashes.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Basic VoIP Problems
« Reply #6 on: September 06, 2010, 08:30:09 am »
Quote
How would I go about removing the storage of all audio, I don't want all the samples to be stored in the std::vector to be replayed.

You can remove the samples from the array as soon as they've been sent to the sound stream.

Quote
SFML 1.6, 2.0 doesn't work, crashes.

Really? Where? When?
Laurent Gomila - SFML developer

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #7 on: September 06, 2010, 08:58:09 am »
Quote from: "Laurent"
Quote
How would I go about removing the storage of all audio, I don't want all the samples to be stored in the std::vector to be replayed.

You can remove the samples from the array as soon as they've been sent to the sound stream.

Ehh, in OnGetData?

Quote from: "Laurent"
Quote
SFML 1.6, 2.0 doesn't work, crashes.

Really? Where? When?

I just tried it again, it crashed when I stopped streaming audio from the client, the server crashes. Asset failed in OnGetData, the std::copy, not sure it it was me but it happened before I made any changed, too.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Basic VoIP Problems
« Reply #8 on: September 06, 2010, 09:31:05 am »
Quote
Ehh, in OnGetData?

Yes, for example.

Quote
I just tried it again, it crashed when I stopped streaming audio from the client, the server crashes. Asset failed in OnGetData, the std::copy, not sure it it was me but it happened before I made any changed, too.

Ok, I'll check that.
Laurent Gomila - SFML developer

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #9 on: September 06, 2010, 08:16:25 pm »
I just tried clearing mySamples in OnGetData, and it crashed. I expected that. I have no idea how to do this, the closest I got would skip around a lot (I'm not even sure it cleared).

I can see that when a new packet is received that contains audio data, the data is appended to mySamples. In OnGetData, data past the previous read offset is copied into myTempBuffer for playing. I just don't understand where/how I should do it properly.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Basic VoIP Problems
« Reply #10 on: September 06, 2010, 10:20:27 pm »
You can't clear the data that you return in OnGetData (because it's going to be used by the caller), but you can clear everything else. I mean, all the previous data that have already been streamed.

Maybe you can also find another solution, inspired from double-buffering: you accumulate data in one buffer while the other is consumed by the OnGetData calls; when the latter is empty you swap them (the empty one starts to be filled and the full one starts to be consumed) and so on and so on...

Just a few ideas, I didn't really think about this before. If you understand what happens with the sample buffers, you should be able to find a working solution ;)
Laurent Gomila - SFML developer

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #11 on: September 06, 2010, 10:55:39 pm »
Ohh, okay. Yeah, I cleared the mySamples vector before copying the samples from the packet to it. In OnGetData, I removed the use of the offset. That worked. :D

Thanks again!

TheMagicNumber

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Basic VoIP Problems
« Reply #12 on: September 07, 2010, 07:33:32 pm »
Me again, I need to wrap how SFML handles this into something much different. I need all of this to be accessed from code without changing OnGetData and OnProcessSamples. I tried making a few classes but that failed horribly.

I'm trying to implement VoIP in GML (Game Maker, using this in a DLL). Right now, I have a set of functions that I'll list at the end of this post. They didn't work well at all and made clicking noises, used lots of memory (even after I tell it to clear), and repeated what played. It sometimes crashes too... My fault.

Code: [Select]
bool can_record()

SampleBuffer:
samplebuffer create()
void destroy(samplebuffer)
void clear(samplebuffer)
void read(samplebuffer, buffer)
void write(samplebuffer, buffer)

Recorder:
void create()
void destroy()
void start()
void stop()
bool has_samples()
samplebuffer get_samples()

Player:
player create()
void destroy(player)
void play(player)
void stop(player)
void add_samples(player, samplebuffer)


I need a design based on something like that without changing much of the internals.

Using my functions, I tried: a recorder and a player, I added samples from the recorder into the player when there were samples, then cleared.

Can I get some suggestions? Nobody I spoke with on MSN even tried to help me out.

Again, I can't change the code in OnGetData and OnProcessSamples at all. I need it to work all inside a DLL to accomplish the same thing. If it's impossible for me to do it like this, let me know, I'll try thinking of another way.