mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-10 13:18:08 +02:00
add audio starvation detection
This commit is contained in:
parent
8fb0ed17b7
commit
1df54cffd6
2 changed files with 30 additions and 2 deletions
|
@ -124,7 +124,7 @@ Audio::Audio(QObject* parent) :
|
||||||
_audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS),
|
_audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS),
|
||||||
_lastSentAudioPacket(0),
|
_lastSentAudioPacket(0),
|
||||||
_packetSentTimeGaps(1, APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS),
|
_packetSentTimeGaps(1, APPROXIMATELY_30_SECONDS_OF_AUDIO_PACKETS),
|
||||||
_audioOutputIODevice(_receivedAudioStream)
|
_audioOutputIODevice(_receivedAudioStream, this)
|
||||||
{
|
{
|
||||||
// clear the array of locally injected samples
|
// clear the array of locally injected samples
|
||||||
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||||
|
@ -1823,6 +1823,16 @@ bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) {
|
||||||
return supportedFormat;
|
return supportedFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::outputNotify() {
|
||||||
|
int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads();
|
||||||
|
if (recentUnfulfilled > 0) {
|
||||||
|
qDebug() << "WARNING --- WE HAD at least:" << recentUnfulfilled << "recently unfulfilled readData() calls";
|
||||||
|
|
||||||
|
// TODO: Ryan Huffman -- add code here to increase the AUDIO_OUTPUT_BUFFER_SIZE_FRAMES... this code only
|
||||||
|
// runs in cases where the audio device requested data samples, and ran dry because we couldn't fulfill the request
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) {
|
bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) {
|
||||||
bool supportedFormat = false;
|
bool supportedFormat = false;
|
||||||
|
|
||||||
|
@ -1856,6 +1866,8 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo)
|
||||||
|
|
||||||
// setup our general output device for audio-mixer audio
|
// setup our general output device for audio-mixer audio
|
||||||
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
|
connect(_audioOutput, &QAudioOutput::notify, this, &Audio::outputNotify);
|
||||||
|
|
||||||
_audioOutput->setBufferSize(AUDIO_OUTPUT_BUFFER_SIZE_FRAMES * _outputFrameSize * sizeof(int16_t));
|
_audioOutput->setBufferSize(AUDIO_OUTPUT_BUFFER_SIZE_FRAMES * _outputFrameSize * sizeof(int16_t));
|
||||||
qDebug() << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / sizeof(int16_t) / (float)_outputFrameSize;
|
qDebug() << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / sizeof(int16_t) / (float)_outputFrameSize;
|
||||||
|
|
||||||
|
@ -1934,6 +1946,7 @@ qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
int samplesRequested = maxSize / sizeof(int16_t);
|
int samplesRequested = maxSize / sizeof(int16_t);
|
||||||
int samplesPopped;
|
int samplesPopped;
|
||||||
int bytesWritten;
|
int bytesWritten;
|
||||||
|
|
||||||
if ((samplesPopped = _receivedAudioStream.popSamples(samplesRequested, false)) > 0) {
|
if ((samplesPopped = _receivedAudioStream.popSamples(samplesRequested, false)) > 0) {
|
||||||
AudioRingBuffer::ConstIterator lastPopOutput = _receivedAudioStream.getLastPopOutput();
|
AudioRingBuffer::ConstIterator lastPopOutput = _receivedAudioStream.getLastPopOutput();
|
||||||
lastPopOutput.readSamples((int16_t*)data, samplesPopped);
|
lastPopOutput.readSamples((int16_t*)data, samplesPopped);
|
||||||
|
@ -1943,5 +1956,10 @@ qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
bytesWritten = maxSize;
|
bytesWritten = maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bytesAudioOutputUnplayed = _audio->_audioOutput->bufferSize() - _audio->_audioOutput->bytesFree();
|
||||||
|
if (bytesAudioOutputUnplayed == 0 && bytesWritten == 0) {
|
||||||
|
_unfulfilledReads++;
|
||||||
|
}
|
||||||
|
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,16 +72,22 @@ public:
|
||||||
|
|
||||||
class AudioOutputIODevice : public QIODevice {
|
class AudioOutputIODevice : public QIODevice {
|
||||||
public:
|
public:
|
||||||
AudioOutputIODevice(MixedProcessedAudioStream& receivedAudioStream) : _receivedAudioStream(receivedAudioStream) {};
|
AudioOutputIODevice(MixedProcessedAudioStream& receivedAudioStream, Audio* audio) :
|
||||||
|
_receivedAudioStream(receivedAudioStream), _audio(audio), _unfulfilledReads(0) {};
|
||||||
|
|
||||||
void start() { open(QIODevice::ReadOnly); }
|
void start() { open(QIODevice::ReadOnly); }
|
||||||
void stop() { close(); }
|
void stop() { close(); }
|
||||||
qint64 readData(char * data, qint64 maxSize);
|
qint64 readData(char * data, qint64 maxSize);
|
||||||
qint64 writeData(const char * data, qint64 maxSize) { return 0; }
|
qint64 writeData(const char * data, qint64 maxSize) { return 0; }
|
||||||
|
|
||||||
|
int getRecentUnfulfilledReads() { int unfulfilledReads = _unfulfilledReads; _unfulfilledReads = 0; return unfulfilledReads; }
|
||||||
private:
|
private:
|
||||||
MixedProcessedAudioStream& _receivedAudioStream;
|
MixedProcessedAudioStream& _receivedAudioStream;
|
||||||
|
Audio* _audio;
|
||||||
|
int _unfulfilledReads;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
friend class AudioOutputIODevice;
|
||||||
|
|
||||||
// setup for audio I/O
|
// setup for audio I/O
|
||||||
Audio(QObject* parent = 0);
|
Audio(QObject* parent = 0);
|
||||||
|
@ -170,11 +176,15 @@ public slots:
|
||||||
const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; }
|
const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; }
|
||||||
const QHash<QUuid, AudioStreamStats>& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; }
|
const QHash<QUuid, AudioStreamStats>& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; }
|
||||||
|
|
||||||
|
void outputNotify();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
bool muteToggled();
|
bool muteToggled();
|
||||||
void preProcessOriginalInboundAudio(unsigned int sampleTime, QByteArray& samples, const QAudioFormat& format);
|
void preProcessOriginalInboundAudio(unsigned int sampleTime, QByteArray& samples, const QAudioFormat& format);
|
||||||
void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
||||||
void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void outputFormatChanged();
|
void outputFormatChanged();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue