SFML community forums

Help => Audio => Topic started by: Agnfolie on January 26, 2012, 10:12:54 am

Title: Streaming Sound over UDP
Post by: Agnfolie on January 26, 2012, 10:12:54 am
Hello!

I am currently developing a voip like application for my car-puter(minipc in my car). On roadtrips it is nice to be able to speak with the other families we travel with using the car's internal stereo system. I am currently in a state where I can see the info recieved but not hear the sound. I hear some clicking thou! Any ideas to what could be wrong?

Good to know:
I have a UDPSocket(named "Socket") as a global variable to simulate sending between computers.

My Recorder:
Code: [Select]

class NetworkRecorder : public sf::SoundBufferRecorder
{
public:
void setPort(unsigned short outport)
{
port = outport;
}
private:
virtual bool OnProcessSamples(const sf::Int16* samples, std::size_t sampleCount)
{
        //std::cout << "NumSamples: " << sampleCount << " time: " << clock.GetElapsedTime() << std::endl;
packet.Clear();
packet.Append(samples,sampleCount * sizeof(sf::Int16));
sf::Sleep(20);
Socket.Send(packet,"127.0.0.1",port);
return true;
}

//Vars
unsigned short port;
sf::Clock clock;
sf::Packet packet;
};



My Reciever:
Code: [Select]

 class NetworkStreamer : public sf::SoundStream
 {
 public :

     bool Open(unsigned short prt)
     {
         port = prt;
while(Socket.Bind(prt))
{
};
// Initialize the stream -- important!
         Initialize(1, SAMPLECOUNT);
return true;
     }

 private :

     virtual bool OnGetData(Chunk& data)
     {
         //Recieve UDP data and add to stream
sf::Packet packet;
std::cout << "Got Data \n";
Socket.Receive(packet,adr,recieveport);
data.NbSamples = packet.GetDataSize()/sizeof(sf::Int16*);
data.Samples = reinterpret_cast<const sf::Int16*>(packet.GetData());
for(int i = 0;i < data.NbSamples;i+=5)
{
std::cout << data.Samples[i] << "\n";
}
         // Return true to continue playing
         return true;
     }

     virtual void OnSeek(sf::Uint32 timeOffset)
     {
// Allways play the latest recieved
         // Change the current position in the stream source
     }

//Vars
unsigned short port;
sf::UdpSocket Socket;
sf::IpAddress adr;
unsigned short recieveport;

 };


The main parts:
Code: [Select]

void recieveloop(unsigned short port)
{
sf::Clock clock;
NetworkStreamer stream;
stream.Open(port);
stream.Play();
while(1 || clock.GetElapsedTime() < 2000)
{
}
}




int main()
{
unsigned short outport,inport;

outport = 2000;
inport  = 2000;

if (sf::SoundBufferRecorder::IsAvailable())
 {
NetworkRecorder Recorder;
Recorder.Start(SAMPLECOUNT);
Recorder.setPort(outport);
sf::Thread Thread(&recieveloop,inport);
Thread.Launch();
sf::Clock clock;
while( 1 || clock.GetElapsedTime() < 20000)
{
}
Recorder.Stop();



}

return EXIT_SUCCESS;
}


Also another thought:
Is there a way to send the data to multiple IP's or simply out in the air? Seeing as I don't wan't to hardcode the destinations...
Title: Streaming Sound over UDP
Post by: Laurent on January 26, 2012, 11:24:40 am
Quote
Code: [Select]
data.NbSamples = packet.GetDataSize()/sizeof(sf::Int16*)

Should be sizeof(sf::Int16).

If it doesn't totally solve your problem, you should also try to receive data in the main thread, not in the stream's thread (in OnGetData). See the VOIP example, which does exactly what you're trying to do (except that it uses TCP).

Quote
Is there a way to send the data to multiple IP's or simply out in the air? Seeing as I don't wan't to hardcode the destinations...

You can broadcast it to the entire local network -- see sf::IpAddress::Broadcast. It is available only in the latest revision of SFML 2.
Title: Streaming Sound over UDP
Post by: Agnfolie on January 26, 2012, 02:07:37 pm
Quote from: "Laurent"
Quote
Code: [Select]
data.NbSamples = packet.GetDataSize()/sizeof(sf::Int16*)

Should be sizeof(sf::Int16).

If it doesn't totally solve your problem, you should also try to receive data in the main thread, not in the stream's thread (in OnGetData). See the VOIP example, which does exactly what you're trying to do (except that it uses TCP).

Quote
Is there a way to send the data to multiple IP's or simply out in the air? Seeing as I don't wan't to hardcode the destinations...

You can broadcast it to the entire local network -- see sf::IpAddress::Broadcast. It is available only in the latest revision of SFML 2.


Fixed sizeof(sf::Int16) part. (Remember now that I changed this earlier. Trying to retrace my steps but no luck.)

After recompiling with latest GIT release:
sf::Sleep() requires a sf::Time as argument?

Where can I find the latest documentation?
Is sf::IpAddress::Broadcast bound to 192.168.x.x or can it be used on my home networks more unusual 10.x.x.x?
Title: Streaming Sound over UDP
Post by: Laurent on January 26, 2012, 04:51:31 pm
Quote
Where can I find the latest documentation?

On the website.

Quote
Is sf::IpAddress::Broadcast bound to 192.168.x.x or can it be used on my home networks more unusual 10.x.x.x?

The broadcast address is 255.255.255.255, it works on any local network.
Title: Streaming Sound over UDP
Post by: Agnfolie on January 27, 2012, 03:11:59 pm
Quote from: "Laurent"
Quote
Where can I find the latest documentation?

On the website.

Quote
Is sf::IpAddress::Broadcast bound to 192.168.x.x or can it be used on my home networks more unusual 10.x.x.x?

The broadcast address is 255.255.255.255, it works on any local network.


Wonderfull!

Also. Have moved it all over. only thing is I'm having problem with an error
"R6025
-Pure virtual function call"
On top of the call stack is:
Code: [Select]
> sfml-audio-d-2.dll!sf::SoundStream::FillAndPushBuffer(unsigned int bufferNum)  Line 289 + 0x13 bytes C++


And since I have managed to compile it my function
Code: [Select]
virtual bool OnGetData(sf::SoundStream::Chunk& data)
{
if(mySamplesCount > 0)
{
std::cout << "true";
data.Samples   = mySamples; //From UDP recieve loop
data.SampleCount = sizeof(mySamples)/sizeof(sf::Int16); //From UDP recieve loop
return true;
}
else
{
std::cout << "false";
return false;
}
}

must override the virtual function?
Title: Streaming Sound over UDP
Post by: Laurent on January 27, 2012, 04:00:37 pm
Are you sure that you're using the DLL that you recompiled, and not an old one?
Title: Streaming Sound over UDP
Post by: Agnfolie on January 31, 2012, 12:43:32 pm
***EDIT***
Solved everything by rebuilding the program. Don't know what caused it all but my guess is incompatible DLL's.

***EDIT***


Quote from: "Laurent"
Are you sure that you're using the DLL that you recompiled, and not an old one?


Positive! After extensive testing!
The call stack:
Code: [Select]

> msvcr100d.dll!_NMSG_WRITE(int rterrnum)  Line 217 C
  msvcr100d.dll!_purecall()  Line 54 + 0x7 bytes C
  sfml-audio-d-2.dll!sf::SoundRecorder::ProcessCapturedSamples()  Line 180 + 0x29 bytes C++
  sfml-audio-d-2.dll!sf::SoundRecorder::Record()  Line 155 C++


Clicking
Code: [Select]
> sfml-audio-d-2.dll!sf::SoundRecorder::ProcessCapturedSamples()  Line 180 + 0x29 bytes C++

links me to
Code: [Select]
void SoundRecorder::ProcessCapturedSamples()
{
    // Get the number of samples available
    ALCint samplesAvailable;
    alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable);

    if (samplesAvailable > 0)
    {
        // Get the recorded samples
        mySamples.resize(samplesAvailable);
        alcCaptureSamples(captureDevice, &mySamples[0], samplesAvailable);

        // Forward them to the derived class
  THIS LINE:      if (!OnProcessSamples(&mySamples[0], mySamples.size()))   THIS LINE
        {
            // The user wants to stop the capture
            myIsCapturing = false;
        }
    }
}


It can't seem to find my derived function.
Code: [Select]
class Recorder : public sf::SoundBufferRecorder
{
virtual bool OnStart()
{
std::cout << "\nOnStart";
return true;
}



virtual bool OnProcessSamples(const Int16* samples, std::size_t sampleCount)
{
std::cout << "\nProcess....";
packet.Clear();
packet.Append(samples,sampleCount * sizeof(sf::Int16));
std::cout << " \n Recieved: "<<sampleCount;
socket.Send(packet,"127,0,0,1",2000);
return true;
}
Packet packet;
public:
unsigned short port;
};


***EDIT***
Solved everything by rebuilding the program. Don't know what caused it all but my guess is incompatible DLL's.

***EDIT***