Merge pull request #1657 from birarda/master

more NL repairs for concurrency issues, fix audio starve display
This commit is contained in:
Philip Rosedale 2014-01-23 11:41:34 -08:00
commit d34bb53d53
5 changed files with 55 additions and 56 deletions

View file

@ -109,7 +109,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_window(new QMainWindow(desktop())),
_glWidget(new GLCanvas()),
_nodeThread(new QThread(this)),
_datagramProcessor(new DatagramProcessor()),
_datagramProcessor(),
_frameCount(0),
_fps(120.0f),
_justStarted(true),
@ -174,20 +174,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
listenPort = atoi(portStr);
}
// put the NodeList and datagram processing on the node thread
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort);
nodeList->moveToThread(_nodeThread);
_datagramProcessor->moveToThread(_nodeThread);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), _datagramProcessor, SLOT(processDatagrams()));
// start the nodeThread so its event loop is running
_nodeThread->start();
// make sure the node thread is given highest priority
_nodeThread->setPriority(QThread::TimeCriticalPriority);
// start the nodeThread so its event loop is running
_nodeThread->start();
// put the NodeList and datagram processing on the node thread
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort);
nodeList->moveToThread(_nodeThread);
_datagramProcessor.moveToThread(_nodeThread);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams()));
// put the audio processing on a separate thread
QThread* audioThread = new QThread(this);
@ -236,7 +236,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
// move the silentNodeTimer to the _nodeThread
QTimer* silentNodeTimer = new QTimer(this);
QTimer* silentNodeTimer = new QTimer();
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
silentNodeTimer->moveToThread(_nodeThread);
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
@ -282,17 +282,35 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
Application::~Application() {
qInstallMessageHandler(NULL);
// make sure we don't call the idle timer any more
delete idleTimer;
Menu::getInstance()->saveSettings();
_rearMirrorTools->saveSettings(_settings);
_settings->sync();
// let the avatar mixer know we're out
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
// ask the datagram processing thread to quit and wait until it is done
_nodeThread->thread()->quit();
_nodeThread->thread()->wait();
_nodeThread->quit();
_nodeThread->wait();
// ask the audio thread to quit and wait until it is done
_audio.thread()->quit();
_audio.thread()->wait();
_voxelProcessor.terminate();
_voxelHideShowThread.terminate();
_voxelEditSender.terminate();
_particleEditSender.terminate();
if (_persistThread) {
_persistThread->terminate();
_persistThread->deleteLater();
_persistThread = NULL;
}
storeSizeAndPosition();
saveScripts();
@ -377,9 +395,6 @@ void Application::initializeGL() {
qDebug("Voxel parsing thread created.");
}
// call terminate before exiting
connect(this, SIGNAL(aboutToQuit()), SLOT(terminate()));
// call our timer function every second
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(timer()));
@ -1329,11 +1344,11 @@ void Application::timer() {
_fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_packetsPerSecond = (float) _datagramProcessor->getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_bytesPerSecond = (float) _datagramProcessor->getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_frameCount = 0;
_datagramProcessor->resetCounters();
_datagramProcessor.resetCounters();
gettimeofday(&_timerStart, NULL);
@ -1412,28 +1427,6 @@ void Application::idle() {
}
}
void Application::terminate() {
// Close serial port
// close(serial_fd);
Menu::getInstance()->saveSettings();
_rearMirrorTools->saveSettings(_settings);
_settings->sync();
// let the avatar mixer know we're out
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
_voxelProcessor.terminate();
_voxelHideShowThread.terminate();
_voxelEditSender.terminate();
_particleEditSender.terminate();
if (_persistThread) {
_persistThread->terminate();
_persistThread->deleteLater();
_persistThread = NULL;
}
}
void Application::checkBandwidthMeterClick() {
// ... to be called upon button release

View file

@ -230,7 +230,6 @@ private slots:
void timer();
void idle();
void terminate();
void setFullscreen(bool fullscreen);
void setEnable3DTVMode(bool enable3DTVMode);
@ -333,7 +332,7 @@ private:
BandwidthMeter _bandwidthMeter;
QThread* _nodeThread;
DatagramProcessor* _datagramProcessor;
DatagramProcessor _datagramProcessor;
QNetworkAccessManager* _networkAccessManager;
QSettings* _settings;

View file

@ -443,6 +443,15 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
QByteArray outputBuffer;
outputBuffer.resize(numRequiredOutputSamples * sizeof(int16_t));
if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) {
// we don't have any audio data left in the output buffer
// we just starved
qDebug() << "Audio output just starved.";
_ringBuffer.setIsStarved(true);
_numFramesDisplayStarve = 10;
}
// if there is anything in the ring buffer, decide what to do
if (_ringBuffer.samplesAvailable() > 0) {
if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
@ -515,12 +524,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
}
}
} else if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) {
// we don't have any audio data left in the output buffer, and the ring buffer from
// the network has nothing in it either - we just starved
qDebug() << "Audio output just starved.";
_ringBuffer.setIsStarved(true);
_numFramesDisplayStarve = 10;
}
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size());

View file

@ -236,7 +236,11 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr,
node->setLastHeardMicrostamp(usecTimestampNow());
if (!senderSockAddr.isNull()) {
activateSocketFromNodeCommunication(senderSockAddr);
if (senderSockAddr == node->getPublicSocket()) {
node->activatePublicSocket();
} else if (senderSockAddr == node->getLocalSocket()) {
node->activateLocalSocket();
}
}
if (node->getActiveSocket() || senderSockAddr.isNull()) {
@ -754,7 +758,7 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt
}
void NodeList::pingInactiveNodes() {
foreach (const SharedNodePointer& node, _nodeHash) {
foreach (const SharedNodePointer& node, getNodeHash()) {
if (!node->getActiveSocket()) {
// we don't have an active link to this node, ping it to set that up
pingPublicAndLocalSocketsForInactiveNode(node.data());
@ -791,7 +795,7 @@ void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddre
SharedNodePointer NodeList::soloNodeOfType(char nodeType) {
if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
foreach (const SharedNodePointer& node, _nodeHash) {
foreach (const SharedNodePointer& node, getNodeHash()) {
if (node->getType() == nodeType) {
return node;
}

View file

@ -87,7 +87,6 @@ public:
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
void clear();
void reset();
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
@ -163,6 +162,7 @@ private:
void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData);
void resetDomainData(char domainField[], const char* domainData);
void domainLookup();
void clear();
};
#endif /* defined(__hifi__NodeList__) */