Rolling my own 100hz timer

Starting with the simplest possible thing - just sleep for 10000
microseconds.  Can make it adaptive if need be.
This commit is contained in:
David Kelly 2016-10-10 17:57:04 -07:00
parent b4c064a538
commit b58c36cb12
2 changed files with 54 additions and 15 deletions

View file

@ -15,6 +15,7 @@
#include <QtNetwork/QNetworkDiskCache>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QThread>
#include <AssetClient.h>
#include <AvatarHashMap.h>
@ -48,6 +49,18 @@
static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
// this should send a signal every 10ms, with pretty good precision
void AvatarAudioTimer::start() {
qDebug() << "AvatarAudioTimer::start called";
const int TARGET_INTERVAL_USEC = 10000; // 10ms
while (!_quit) {
// simplest possible timer
usleep(TARGET_INTERVAL_USEC);
emit avatarTick();
}
qDebug() << "AvatarAudioTimer is finished";
}
Agent::Agent(ReceivedMessage& message) :
ThreadedAssignment(message),
_entityEditSender(),
@ -121,7 +134,6 @@ void Agent::handleAudioPacket(QSharedPointer<ReceivedMessage> message) {
_receivedAudioStream.parseData(*message);
_lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();
_receivedAudioStream.clearBuffer();
}
@ -372,11 +384,15 @@ void Agent::executeScript() {
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
_avatarAudioTimer = new QTimer(this);
_avatarAudioTimer->setTimerType(Qt::PreciseTimer);
connect(_avatarAudioTimer, SIGNAL(timeout()), this, SLOT(processAgentAvatarAndAudio()));
_avatarAudioTimer->start(10);
qDebug() << "Connecting avatarAudioTimer and starting...";
AvatarAudioTimer* audioTimerWorker = new AvatarAudioTimer();
audioTimerWorker->moveToThread(&_avatarAudioTimerThread);
connect(audioTimerWorker, &AvatarAudioTimer::avatarTick, this, &Agent::processAgentAvatarAndAudio);
connect(this, &Agent::startAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::start);
connect(this, &Agent::stopAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::stop);
connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater);
_avatarAudioTimerThread.start();
// wire up our additional agent related processing to the update signal
//QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatarAndAudio);
@ -406,6 +422,10 @@ void Agent::setIsAvatar(bool isAvatar) {
// start the timers
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
// tell the audiotimer worker to start working
emit startAvatarAudioTimer();
}
if (!_isAvatar) {
@ -428,7 +448,7 @@ void Agent::sendAvatarIdentityPacket() {
void Agent::processAgentAvatarAndAudio() {
if (!_scriptEngine->isFinished() && _isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / 100;//SCRIPT_FPS + 0.5;
const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / 100 + 0.5;
const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);
QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
@ -513,16 +533,15 @@ void Agent::processAgentAvatarAndAudio() {
audioPacket->writePrimitive(headOrientation);
// encode it
QByteArray decodedBuffer(reinterpret_cast<const char*>(nextSoundOutput), numAvailableSamples*sizeof(int16_t));
QByteArray encodedBuffer;
if (_encoder) {
if(_encoder) {
QByteArray decodedBuffer(reinterpret_cast<const char*>(nextSoundOutput), numAvailableSamples*sizeof(int16_t));
QByteArray encodedBuffer;
_encoder->encode(decodedBuffer, encodedBuffer);
audioPacket->write(encodedBuffer.data(), encodedBuffer.size());
} else {
audioPacket->write(decodedBuffer.data(), decodedBuffer.size());
audioPacket->write(reinterpret_cast<const char*>(nextSoundOutput), numAvailableSamples*sizeof(int16_t));
}
// write the raw audio data
audioPacket->write(encodedBuffer.data(), encodedBuffer.size());
}
// write audio packet to AudioMixer nodes
@ -558,6 +577,9 @@ void Agent::aboutToFinish() {
// cleanup the AudioInjectorManager (and any still running injectors)
DependencyManager::destroy<AudioInjectorManager>();
emit stopAvatarAudioTimer();
_avatarAudioTimerThread.quit();
// cleanup codec & encoder
if (_codec && _encoder) {
_codec->releaseEncoder(_encoder);

View file

@ -32,6 +32,20 @@
#include "MixedAudioStream.h"
class AvatarAudioTimer : public QObject {
Q_OBJECT
signals:
void avatarTick();
public slots:
void start();
void stop() { _quit = true; }
private:
bool _quit { false };
};
class Agent : public ThreadedAssignment {
Q_OBJECT
@ -60,6 +74,7 @@ public:
public slots:
void run() override;
void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); }
void processAgentAvatarAndAudio();
private slots:
void requestScript();
@ -71,9 +86,11 @@ private slots:
void handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleSelectedAudioFormat(QSharedPointer<ReceivedMessage> message);
void processAgentAvatarAndAudio();
void nodeActivated(SharedNodePointer activatedNode);
signals:
void startAvatarAudioTimer();
void stopAvatarAudioTimer();
private:
void negotiateAudioFormat();
void selectAudioFormat(const QString& selectedCodecName);
@ -102,7 +119,7 @@ private:
CodecPluginPointer _codec;
QString _selectedCodecName;
Encoder* _encoder { nullptr };
QTimer* _avatarAudioTimer;
QThread _avatarAudioTimerThread;
};
#endif // hifi_Agent_h