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

Author Topic: sf::SoundStream::OnGetData called only a few times  (Read 2744 times)

0 Members and 1 Guest are viewing this topic.

Gigotdarnaud

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
sf::SoundStream::OnGetData called only a few times
« on: July 24, 2012, 11:58:08 am »
Hello,

I'm using sf::SoundRecorder / sf::SoundStream to make a VOIP client. The recording and the networking (using Qt for the later) are working just fine (except that the SoundRecorder crash on exit, go figure), but I'm running into a weird behavior when I'm subclassing sf::SoundStream.

Beforehand, my code:
Sound.h
#ifndef DEF_SOUND
#define DEF_SOUND
/* Some includes */

class Sound : public QObject, public sf::SoundStream
{
    Q_OBJECT
    public:
        Sound(size_t sampleRate);

    protected:

        virtual bool OnGetData(Chunk& Data);

    public slots:

        void queue(const IntVector & samples);

    private:

        sf::Mutex m_bmux;
        QQueue<IntVector > m_buff;

        size_t m_sampleRate;

};

#endif
 

Sound.cpp
#include "Sound.h"

#include <QDebug>
#define D() qDebug() << __FILE__ << ";" << __LINE__


Sound::Sound(size_t sampleRate):sf::SoundStream()
{
    m_sampleRate=sampleRate;
    Initialize(1, m_sampleRate);
    Play();
}


bool Sound::OnGetData(Chunk& Data)
{
    m_bmux.Lock();
    if(m_buff.size()<1)
    {
        m_bmux.Unlock();
        return true;
    }

    IntVector bu = m_buff.dequeue();

    m_bmux.Unlock();


    size_t bfs=bu.size();
    sf::Int16* bf=new sf::Int16[bfs]; //Possible memory leak? SFML documentation is unclear about that...

    for(size_t i=0;i<bfs;++i)
        bf[i]=bu[i];


    Data.Samples   = bf;
    Data.NbSamples = bfs;

    D() << "B";

    return true;
}

void Sound::queue(const IntVector & samples)
{
    m_bmux.Lock();
    if(m_buff.size() < 150)
        m_buff.enqueue(samples);
    else
        D() << "Buffer full!";
    m_bmux.Unlock();

    Play();
    D() << "A";

}
 

IntVector is a QVector<sf::Int16> typedef.
All the Qt containers behave like STL's here. A queue's a queue, and a "vector" is a wrapper over a C-array.
I call queue() every once in a while (each time I receive a frame). For debug purpose it's at the moment directly connected to a sf::SoundRecorder.

The minor part of the problem:
in OnGetData(), do I loose the ownership of the data array I put into the chunk? Both the documentation and the tutorial are very vague about it.

The MAJOR part of the problem:
I expected the console output to be ABABAB..., give or take.
What I get, however, is "ABBBAAAAAAAAAA...". OnGetData() just stop being called, yet the GetState() function still return Playing.
I tried delaying the Play() call, calling it only when there are at least 3 frames in the buffer. This time I got "AAABBBAABBAABBAABBAAAAAAAAAAAAAAAAAA...", so it's kind of better, but it's still broken.
I tried calling Initialize(), Stop(), etc. pretty much everywhere in the code, obviously it just doesn't work this way.

I'm compiling with Mingw32, on a 64bits Windows 7. I used to work with OpenAL directly, but it was a pain to debug and to maintain, this is why I switched to SFML 1.6 for the VOIP.

Anyone got a suggestion on what's wrong with what I've done here?

Thanks,

Gig


PS: I apologize for my English, it is not my mothertongue.
« Last Edit: July 24, 2012, 12:06:15 pm by Gigotdarnaud »

Gigotdarnaud

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::SoundStream::OnGetData called only a few times
« Reply #1 on: July 25, 2012, 12:00:52 pm »
Okay, so I got a few updates.
I made a new code from scratch in a new project, still with SFML 1.6, and I still got this strange behavior.
I migrated to SFML 2.0, changed a few things in the code because of the new name conventions, and this is the code I got in the end:

Main.cpp
#include <QCoreApplication>

#include "Player.h"

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    Player play(44100);
    play.play();

    return app.exec();
}
 

Player.h
#ifndef PLAYER_H
#define PLAYER_H

#include <QObject>
#include <SFML2/Audio.hpp>

#include <QDebug>
#define D() qDebug() << __FILE__ << ";" << __LINE__

class Player : public QObject, public sf::SoundStream
{
    public:
        Player(size_t sampleRate);

    protected:
        virtual bool onGetData(Chunk& Data);
        virtual void onSeek(sf::Time) {}

};

#endif // PLAYER_H
 

Player.cpp
#include "Player.h"

Player::Player(size_t sampleRate)
{
    initialize(1, sampleRate);
}

bool Player::onGetData(Chunk& Data)
{
     D() << "B";
    return true;
}
 

Aaaand it still don't work. I got three "B", and then nothing, onGetData() isn't called anymore. Is it because I don't give any data the first three times? It just doesn't make any sense.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: sf::SoundStream::OnGetData called only a few times
« Reply #2 on: July 25, 2012, 11:05:04 pm »
Hum yes, you have to provide audio data. If you want to output silence, you must create the corresponding data, which I guess is a sequence of zeros.

The stream stops when it has no more data to play.
Laurent Gomila - SFML developer

Gigotdarnaud

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: sf::SoundStream::OnGetData called only a few times
« Reply #3 on: July 25, 2012, 11:24:45 pm »
Hum, so if I don't receive anything from the network, I have to create a few zero-ed frames? Why not, it should be an easy fix. I'll try it ASAP and get back with what I've found.
However, what I don't get is that I couldn't restart the SoundStream once it went down because of an empty frame with "Play".
Anyway, this behavior should be explained in the documentation or the tutorial (something like "Warning: the Chunk must NOT be empty, or else!").

Thank you again Laurent.

EDIT: It seems to be working just fine now:

bool Player::onGetData(Chunk& Data)
{
    sf::Int16* buff=new sf::Int16[800];
    Data.samples=buff;
    Data.sampleCount=800;

     D() << "B";
    return true;
}
 

Now I got a segfault on exit though (Ctrl-C from the terminal is quite violent thought, I hope a 'softer' exit will fix it)
« Last Edit: July 25, 2012, 11:42:04 pm by Gigotdarnaud »