mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Fixing race condition on seek, correcting some issues with frame timing
This commit is contained in:
parent
900f425f35
commit
48b0465e56
3 changed files with 59 additions and 23 deletions
|
@ -47,19 +47,19 @@ RecordingScriptingInterface::RecordingScriptingInterface() {
|
||||||
connect(audioClient.data(), &AudioClient::inputReceived, this, &RecordingScriptingInterface::processAudioInput);
|
connect(audioClient.data(), &AudioClient::inputReceived, this, &RecordingScriptingInterface::processAudioInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecordingScriptingInterface::isPlaying() {
|
bool RecordingScriptingInterface::isPlaying() const {
|
||||||
return _player->isPlaying();
|
return _player->isPlaying();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecordingScriptingInterface::isPaused() {
|
bool RecordingScriptingInterface::isPaused() const {
|
||||||
return _player->isPaused();
|
return _player->isPaused();
|
||||||
}
|
}
|
||||||
|
|
||||||
float RecordingScriptingInterface::playerElapsed() {
|
float RecordingScriptingInterface::playerElapsed() const {
|
||||||
return _player->position();
|
return _player->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
float RecordingScriptingInterface::playerLength() {
|
float RecordingScriptingInterface::playerLength() const {
|
||||||
return _player->length();
|
return _player->length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,10 @@ void RecordingScriptingInterface::setPlayerAudioOffset(float audioOffset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordingScriptingInterface::setPlayerTime(float time) {
|
void RecordingScriptingInterface::setPlayerTime(float time) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setPlayerTime", Qt::BlockingQueuedConnection, Q_ARG(float, time));
|
||||||
|
return;
|
||||||
|
}
|
||||||
_player->seek(time);
|
_player->seek(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,23 +134,27 @@ void RecordingScriptingInterface::setPlayerUseSkeletonModel(bool useSkeletonMode
|
||||||
_useSkeletonModel = useSkeletonModel;
|
_useSkeletonModel = useSkeletonModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordingScriptingInterface::play() {
|
|
||||||
_player->play();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecordingScriptingInterface::pausePlayer() {
|
void RecordingScriptingInterface::pausePlayer() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "pausePlayer", Qt::BlockingQueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
_player->pause();
|
_player->pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordingScriptingInterface::stopPlaying() {
|
void RecordingScriptingInterface::stopPlaying() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "stopPlaying", Qt::BlockingQueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
_player->stop();
|
_player->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecordingScriptingInterface::isRecording() {
|
bool RecordingScriptingInterface::isRecording() const {
|
||||||
return _recorder->isRecording();
|
return _recorder->isRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
float RecordingScriptingInterface::recorderElapsed() {
|
float RecordingScriptingInterface::recorderElapsed() const {
|
||||||
return _recorder->position();
|
return _recorder->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,17 @@ public:
|
||||||
RecordingScriptingInterface();
|
RecordingScriptingInterface();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool isPlaying();
|
|
||||||
bool isPaused();
|
|
||||||
float playerElapsed();
|
|
||||||
float playerLength();
|
|
||||||
void loadRecording(const QString& filename);
|
void loadRecording(const QString& filename);
|
||||||
|
|
||||||
void startPlaying();
|
void startPlaying();
|
||||||
|
void pausePlayer();
|
||||||
|
void stopPlaying();
|
||||||
|
bool isPlaying() const;
|
||||||
|
bool isPaused() const;
|
||||||
|
|
||||||
|
float playerElapsed() const;
|
||||||
|
float playerLength() const;
|
||||||
|
|
||||||
void setPlayerVolume(float volume);
|
void setPlayerVolume(float volume);
|
||||||
void setPlayerAudioOffset(float audioOffset);
|
void setPlayerAudioOffset(float audioOffset);
|
||||||
void setPlayerTime(float time);
|
void setPlayerTime(float time);
|
||||||
|
@ -40,13 +45,13 @@ public slots:
|
||||||
void setPlayerUseAttachments(bool useAttachments);
|
void setPlayerUseAttachments(bool useAttachments);
|
||||||
void setPlayerUseHeadModel(bool useHeadModel);
|
void setPlayerUseHeadModel(bool useHeadModel);
|
||||||
void setPlayerUseSkeletonModel(bool useSkeletonModel);
|
void setPlayerUseSkeletonModel(bool useSkeletonModel);
|
||||||
void play();
|
|
||||||
void pausePlayer();
|
|
||||||
void stopPlaying();
|
|
||||||
bool isRecording();
|
|
||||||
float recorderElapsed();
|
|
||||||
void startRecording();
|
void startRecording();
|
||||||
void stopRecording();
|
void stopRecording();
|
||||||
|
bool isRecording() const;
|
||||||
|
|
||||||
|
float recorderElapsed() const;
|
||||||
|
|
||||||
void saveRecording(const QString& filename);
|
void saveRecording(const QString& filename);
|
||||||
void loadLastRecording();
|
void loadLastRecording();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "Deck.h"
|
#include "Deck.h"
|
||||||
|
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
|
@ -101,9 +103,13 @@ float Deck::position() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Frame::Time MIN_FRAME_WAIT_INTERVAL = Frame::secondsToFrameTime(0.001f);
|
static const Frame::Time MIN_FRAME_WAIT_INTERVAL = Frame::secondsToFrameTime(0.001f);
|
||||||
static const Frame::Time MAX_FRAME_PROCESSING_TIME = Frame::secondsToFrameTime(0.002f);
|
static const Frame::Time MAX_FRAME_PROCESSING_TIME = Frame::secondsToFrameTime(0.004f);
|
||||||
|
|
||||||
void Deck::processFrames() {
|
void Deck::processFrames() {
|
||||||
|
if (qApp->thread() != QThread::currentThread()) {
|
||||||
|
qWarning() << "Processing frames must only happen on the main thread.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
Locker lock(_mutex);
|
Locker lock(_mutex);
|
||||||
if (_pause) {
|
if (_pause) {
|
||||||
return;
|
return;
|
||||||
|
@ -115,10 +121,17 @@ void Deck::processFrames() {
|
||||||
// FIXME add code to start dropping frames if we fall behind.
|
// FIXME add code to start dropping frames if we fall behind.
|
||||||
// Alternatively, add code to cache frames here and then process only the last frame of a given type
|
// Alternatively, add code to cache frames here and then process only the last frame of a given type
|
||||||
// ... the latter will work for Avatar, but not well for audio I suspect.
|
// ... the latter will work for Avatar, but not well for audio I suspect.
|
||||||
|
bool overLimit = false;
|
||||||
for (nextClip = getNextClip(); nextClip; nextClip = getNextClip()) {
|
for (nextClip = getNextClip(); nextClip; nextClip = getNextClip()) {
|
||||||
auto currentPosition = Frame::frameTimeFromEpoch(_startEpoch);
|
auto currentPosition = Frame::frameTimeFromEpoch(_startEpoch);
|
||||||
if ((currentPosition - startingPosition) >= MAX_FRAME_PROCESSING_TIME) {
|
if ((currentPosition - startingPosition) >= MAX_FRAME_PROCESSING_TIME) {
|
||||||
qCWarning(recordingLog) << "Exceeded maximum frame processing time, breaking early";
|
qCWarning(recordingLog) << "Exceeded maximum frame processing time, breaking early";
|
||||||
|
#ifdef WANT_RECORDING_DEBUG
|
||||||
|
qCDebug(recordingLog) << "Starting: " << currentPosition;
|
||||||
|
qCDebug(recordingLog) << "Current: " << startingPosition;
|
||||||
|
qCDebug(recordingLog) << "Trigger: " << triggerPosition;
|
||||||
|
#endif
|
||||||
|
overLimit = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,9 +163,19 @@ void Deck::processFrames() {
|
||||||
|
|
||||||
// If we have more clip frames available, set the timer for the next one
|
// If we have more clip frames available, set the timer for the next one
|
||||||
_position = Frame::frameTimeFromEpoch(_startEpoch);
|
_position = Frame::frameTimeFromEpoch(_startEpoch);
|
||||||
auto nextFrameTime = nextClip->positionFrameTime();
|
int nextInterval = 1;
|
||||||
auto interval = Frame::frameTimeToMilliseconds(nextFrameTime - _position);
|
if (!overLimit) {
|
||||||
_timer.singleShot(interval, [this] {
|
auto nextFrameTime = nextClip->positionFrameTime();
|
||||||
|
nextInterval = (int)Frame::frameTimeToMilliseconds(nextFrameTime - _position);
|
||||||
|
#ifdef WANT_RECORDING_DEBUG
|
||||||
|
qCDebug(recordingLog) << "Now " << _position;
|
||||||
|
qCDebug(recordingLog) << "Next frame time " << nextInterval;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef WANT_RECORDING_DEBUG
|
||||||
|
qCDebug(recordingLog) << "Setting timer for next processing " << nextInterval;
|
||||||
|
#endif
|
||||||
|
_timer.singleShot(nextInterval, [this] {
|
||||||
processFrames();
|
processFrames();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue