set jitter buffer on application start to 1/2 of a packet

This commit is contained in:
Philip Rosedale 2013-06-20 09:08:37 -07:00
parent 3304f0eb2e
commit 2c8c34f9bd
4 changed files with 67 additions and 30 deletions

View file

@ -72,6 +72,10 @@ const glm::vec3 START_LOCATION(4.f, 0.f, 5.f); // Where one's own agent begin
const int IDLE_SIMULATE_MSECS = 16; // How often should call simulate and other stuff
// in the idle loop? (60 FPS is default)
const int STARTUP_JITTER_SAMPLES = PACKET_LENGTH_SAMPLES_PER_CHANNEL / 2;
// Startup optimistically with small jitter buffer that
// will start playback on the second received audio packet.
// customized canvas that simply forwards requests/events to the singleton application
class GLCanvas : public QGLWidget {
protected:
@ -155,7 +159,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_oculusProgram(0),
_oculusDistortionScale(1.25),
#ifndef _WIN32
_audio(&_audioScope, 0),
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
#endif
_stopNetworkReceiveThread(false),
_packetCount(0),

View file

@ -28,12 +28,6 @@
// Uncomment the following definition to test audio device latency by copying output to input
//#define TEST_AUDIO_LOOPBACK
const int NUM_AUDIO_CHANNELS = 2;
const int PACKET_LENGTH_BYTES = 1024;
const int PACKET_LENGTH_BYTES_PER_CHANNEL = PACKET_LENGTH_BYTES / 2;
const int PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t);
const int PACKET_LENGTH_SAMPLES_PER_CHANNEL = PACKET_LENGTH_SAMPLES / 2;
const int PHASE_DELAY_AT_90 = 20;
const float AMPLITUDE_RATIO_AT_90 = 0.5;
@ -172,31 +166,39 @@ int audioCallback (const void* inputBuffer,
// just play some silence
if (ringBuffer->getEndOfLastWrite()) {
if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() < (PACKET_LENGTH_SAMPLES + parentAudio->_jitterBufferSamples)) {
// printLog("Held back, buffer has %d of %d samples required.\n",
// ringBuffer->diffLastWriteNextOutput(),
// PACKET_LENGTH_SAMPLES + parentAudio->_jitterBufferSamples);
//
// If not enough audio has arrived to start playback, keep waiting
//
//printLog("Held back, buffer has %d of %d samples required.\n",
// ringBuffer->diffLastWriteNextOutput(),
// PACKET_LENGTH_SAMPLES + parentAudio->_jitterBufferSamples);
} else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) {
//
// If we have run out of audio to send to the audio device, we have starved,
// so reset the ring buffer and packet counters.
//
ringBuffer->setStarted(false);
::numStarves++;
parentAudio->_packetsReceivedThisPlayback = 0;
printLog("Starved, remaining buffer msecs = %.0f\n",
ringBuffer->diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * AUDIO_CALLBACK_MSECS);
//printLog("Starved, remaining buffer msecs = %.0f\n",
// ringBuffer->diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * AUDIO_CALLBACK_MSECS);
parentAudio->_wasStarved = 10; // Frames to render the indication that the system was starved.
parentAudio->_wasStarved = 10; // display frame countdown to show red 'starved' bar.
} else {
//
// We are either already playing back, or we have enough audio to start playing back.
//
if (!ringBuffer->isStarted()) {
ringBuffer->setStarted(true);
printLog("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n",
(usecTimestampNow() - usecTimestamp(&parentAudio->_firstPacketReceivedTime))/1000.0,
parentAudio->_jitterBufferSamples,
parentAudio->_packetsReceivedThisPlayback);
} else {
// printLog("pushing buffer\n");
//printLog("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n",
// (usecTimestampNow() - usecTimestamp(&parentAudio->_firstPacketReceivedTime))/1000.0,
// parentAudio->_jitterBufferSamples,
// parentAudio->_packetsReceivedThisPlayback);
}
//
// play whatever we have in the audio buffer
//
// if we haven't fired off the flange effect, check if we should
// TODO: lastMeasuredHeadYaw is now relative to body - check if this still works.
@ -322,14 +324,34 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
//
unsigned long FRAMES_PER_BUFFER = BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
#define PA_SAMPLE_TYPE paInt16
PaStreamParameters inputParameters, outputParameters;
inputParameters.device = Pa_GetDefaultInputDevice();
inputParameters.channelCount = 2; // Stereo input
inputParameters.sampleFormat = (paInt16 | paNonInterleaved);
//inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.suggestedLatency = 0.0116;
inputParameters.hostApiSpecificStreamInfo = NULL;
outputParameters.device = Pa_GetDefaultOutputDevice();
outputParameters.channelCount = 2; // Stereo output
outputParameters.sampleFormat = (paInt16 | paNonInterleaved);
//outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.suggestedLatency = 0.0116;
outputParameters.hostApiSpecificStreamInfo = NULL;
outputPortAudioError(Pa_OpenStream(&_stream,
&inputParameters,
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paNoFlag,
audioCallback,
(void*) this));
/*
const PaStreamParameters* inputParameters;
const PaStreamParameters* outputParameters;
inputParameters->channelCount =
outputPortAudioError(Pa_OpenStream(&_stream, <#const PaStreamParameters *inputParameters#>, <#const PaStreamParameters *outputParameters#>, SAMPLE_RATE, FRAMES_PER_BUFFER, <#PaStreamFlags streamFlags#>, audioCallback, (void*) this));
*/
outputPortAudioError(Pa_OpenDefaultStream(&_stream,
2,
2,
@ -338,9 +360,13 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
FRAMES_PER_BUFFER,
audioCallback,
(void*) this));
*/
// start the stream now that sources are good to go
outputPortAudioError(Pa_StartStream(_stream));
printLog("Default low input, output latency (secs): %0.4f, %0.4f\n",
Pa_GetDeviceInfo(Pa_GetDefaultInputDevice())->defaultLowInputLatency,
Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice())->defaultLowOutputLatency);
const PaStreamInfo* streamInfo = Pa_GetStreamInfo(_stream);
printLog("Audio started, msecs latency In: %.0f, Out: %.0f\n", streamInfo->inputLatency * 1000.f,
@ -494,7 +520,7 @@ void Audio::render(int screenWidth, int screenHeight) {
glVertex2f(currentX, topY);
glVertex2f(currentX, bottomY);
for (int i = 0; i < RING_BUFFER_LENGTH_FRAMES; i++) {
for (int i = 0; i < RING_BUFFER_LENGTH_FRAMES / 2; i++) {
glVertex2f(currentX, halfY);
glVertex2f(currentX + frameWidth, halfY);
currentX += frameWidth;

View file

@ -16,6 +16,13 @@
#include "Oscilloscope.h"
#include "Avatar.h"
const int NUM_AUDIO_CHANNELS = 2;
const int PACKET_LENGTH_BYTES = 1024;
const int PACKET_LENGTH_BYTES_PER_CHANNEL = PACKET_LENGTH_BYTES / 2;
const int PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t);
const int PACKET_LENGTH_SAMPLES_PER_CHANNEL = PACKET_LENGTH_SAMPLES / 2;
class Audio {
public:
// initializes audio I/O

View file

@ -22,7 +22,7 @@ const int BUFFER_LENGTH_BYTES_STEREO = 1024;
const int BUFFER_LENGTH_BYTES_PER_CHANNEL = 512;
const int BUFFER_LENGTH_SAMPLES_PER_CHANNEL = BUFFER_LENGTH_BYTES_PER_CHANNEL / sizeof(int16_t);
const short RING_BUFFER_LENGTH_FRAMES = 10;
const short RING_BUFFER_LENGTH_FRAMES = 20;
const short RING_BUFFER_LENGTH_SAMPLES = RING_BUFFER_LENGTH_FRAMES * BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
class AudioRingBuffer : public AgentData {