transmitter full movement, and audio jitter buffer tweaks/debugging data

This commit is contained in:
Philip Rosedale 2013-03-11 16:19:55 -07:00
parent 79f39483d0
commit 674bd8d798
6 changed files with 88 additions and 31 deletions

View file

@ -14,10 +14,13 @@
#include <cstring>
#include "Audio.h"
#include "Util.h"
#include <SharedUtil.h>
#include "UDPSocket.h"
Oscilloscope * scope;
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);
@ -33,8 +36,11 @@ const int PHASE_DELAY_AT_90 = 20;
const float AMPLITUDE_RATIO_AT_90 = 0.5;
const int SAMPLE_RATE = 22050;
const float JITTER_BUFFER_LENGTH_MSECS = 30.0;
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * (SAMPLE_RATE / 1000.0);
const float JITTER_BUFFER_LENGTH_MSECS = 4;
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS *
NUM_AUDIO_CHANNELS * (SAMPLE_RATE / 1000.0);
const float AUDIO_CALLBACK_MSECS = (float)BUFFER_LENGTH_SAMPLES / (float)SAMPLE_RATE * 1000.0;
const int FLANGE_EFFECT_THRESHOLD = 200;
const float FLANGE_RATE = 4;
@ -49,7 +55,10 @@ StDev stdev;
bool stopAudioReceiveThread = false;
int samplesLeftForFlange = 0;
#define LOG_SAMPLE_DELAY 1
timeval firstPlaybackTimer;
int packetsReceivedThisPlayback = 0;
#define LOG_SAMPLE_DELAY 0
std::ofstream logFile;
@ -85,6 +94,8 @@ int audioCallback (const void *inputBuffer,
int16_t *inputLeft = ((int16_t **) inputBuffer)[0];
// int16_t *inputRight = ((int16_t **) inputBuffer)[1];
//printf("Audio callback at %6.0f\n", usecTimestampNow()/1000);
if (inputLeft != NULL) {
if (data->mixerAddress != 0) {
@ -163,16 +174,23 @@ int audioCallback (const void *inputBuffer,
if (ringBuffer->getEndOfLastWrite() != NULL) {
if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
printf("Held back\n");
if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
printf("Held back, buffer has %d of %d samples required.\n", ringBuffer->diffLastWriteNextOutput(), PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES);
} else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) {
ringBuffer->setStarted(false);
starve_counter++;
packetsReceivedThisPlayback = 0;
printf("Starved #%d\n", starve_counter);
data->wasStarved = 10; // Frames to render the indication that the system was starved.
} else {
ringBuffer->setStarted(true);
if (!ringBuffer->isStarted()) {
ringBuffer->setStarted(true);
printf("starting playback %3.1f msecs delayed, \n", (usecTimestampNow() - usecTimestamp(&firstPlaybackTimer))/1000.0);
} else {
//printf("pushing buffer\n");
}
// play whatever we have in the audio buffer
// if we haven't fired off the flange effect, check if we should
@ -265,7 +283,7 @@ void *receiveAudioViaUDP(void *args) {
delete[] directory;
delete[] filename;
}
while (!stopAudioReceiveThread) {
if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) {
bool firstSample = (currentReceiveTime.tv_sec == 0);
@ -295,6 +313,17 @@ void *receiveAudioViaUDP(void *args) {
}
AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer;
if (!ringBuffer->isStarted()) {
printf("Audio packet %d received at %6.0f\n", ++packetsReceivedThisPlayback, usecTimestampNow()/1000);
}
else {
//printf("Audio packet received at %6.0f\n", usecTimestampNow()/1000);
}
if (packetsReceivedThisPlayback == 1) gettimeofday(&firstPlaybackTimer, NULL);
ringBuffer->parseData(receivedData, PACKET_LENGTH_BYTES);
if (LOG_SAMPLE_DELAY) {
@ -407,10 +436,14 @@ void Audio::render(int screenWidth, int screenHeight)
timeval currentTime;
gettimeofday(&currentTime, NULL);
float timeLeftInCurrentBuffer = 0;
if (audioData->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&audioData->lastCallback, &currentTime)/(1000.0*(float)PACKET_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth;
if (audioData->lastCallback.tv_usec > 0) {
timeLeftInCurrentBuffer = AUDIO_CALLBACK_MSECS - diffclock(&audioData->lastCallback, &currentTime);
}
// /(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth
if (audioData->ringBuffer->getEndOfLastWrite() != NULL)
remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * frameWidth;
remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * AUDIO_CALLBACK_MSECS;
if (audioData->wasStarved == 0) glColor3f(0, 1, 0);
else {
@ -420,8 +453,8 @@ void Audio::render(int screenWidth, int screenHeight)
glBegin(GL_QUADS);
glVertex2f(startX, topY + 5);
glVertex2f(startX + remainingBuffer + timeLeftInCurrentBuffer, topY + 5);
glVertex2f(startX + remainingBuffer + timeLeftInCurrentBuffer, bottomY - 5);
glVertex2f(startX + (remainingBuffer + timeLeftInCurrentBuffer)/AUDIO_CALLBACK_MSECS*frameWidth, topY + 5);
glVertex2f(startX + (remainingBuffer + timeLeftInCurrentBuffer)/AUDIO_CALLBACK_MSECS*frameWidth, bottomY - 5);
glVertex2f(startX, bottomY - 5);
glEnd();
@ -431,15 +464,16 @@ void Audio::render(int screenWidth, int screenHeight)
// Show a yellow bar with the averaged msecs latency you are hearing (from time of packet receipt)
glColor3f(1,1,0);
glBegin(GL_QUADS);
glVertex2f(startX + audioData->averagedLatency - 2, topY - 2);
glVertex2f(startX + audioData->averagedLatency + 2, topY - 2);
glVertex2f(startX + audioData->averagedLatency + 2, bottomY + 2);
glVertex2f(startX + audioData->averagedLatency - 2, bottomY + 2);
glVertex2f(startX + audioData->averagedLatency/AUDIO_CALLBACK_MSECS*frameWidth - 2, topY - 2);
glVertex2f(startX + audioData->averagedLatency/AUDIO_CALLBACK_MSECS*frameWidth + 2, topY - 2);
glVertex2f(startX + audioData->averagedLatency/AUDIO_CALLBACK_MSECS*frameWidth + 2, bottomY + 2);
glVertex2f(startX + audioData->averagedLatency/AUDIO_CALLBACK_MSECS*frameWidth - 2, bottomY + 2);
glEnd();
char out[20];
sprintf(out, "%3.0f\n", audioData->averagedLatency/(float)frameWidth*(1000.0*(float)PACKET_LENGTH_SAMPLES/(float)SAMPLE_RATE));
drawtext(startX + audioData->averagedLatency - 10, topY-10, 0.08, 0, 1, 0, out, 1,1,0);
char out[40];
sprintf(out, "%3.0f\n", audioData->averagedLatency);
drawtext(startX + audioData->averagedLatency/AUDIO_CALLBACK_MSECS*frameWidth - 10, topY-10, 0.08, 0, 1, 0, out, 1,1,0);
//drawtext(startX + 0, topY-10, 0.08, 0, 1, 0, out, 1,1,0);
// Show a Cyan bar with the most recently measured jitter stdev

View file

@ -40,7 +40,7 @@ void Hand::reset()
transmitterHz = DEFAULT_TRANSMITTER_HZ;
}
void Hand::render()
void Hand::render(int isMine)
{
const float POINTER_LENGTH = 20.0;
glPushMatrix();
@ -122,13 +122,13 @@ void Hand::processTransmitterData(char *packetData, int numBytes) {
const float ANG_VEL_THRESHOLD = 0.0;
float angVelScale = ANG_VEL_SENSITIVITY*(1.0/getTransmitterHz());
//addAngularVelocity(gyrX*angVelScale,gyrZ*angVelScale,-gyrY*angVelScale);
addAngularVelocity(0,
addAngularVelocity(fabs(gyrX*angVelScale)>ANG_VEL_THRESHOLD?gyrX*angVelScale:0,
fabs(gyrZ*angVelScale)>ANG_VEL_THRESHOLD?gyrZ*angVelScale:0,
0);
fabs(-gyrY*angVelScale)>ANG_VEL_THRESHOLD?-gyrY*angVelScale:0);
// Add linear forces to the hand
//const float LINEAR_VEL_SENSITIVITY = 50.0;
const float LINEAR_VEL_SENSITIVITY = 0.0;
const float LINEAR_VEL_SENSITIVITY = 5.0;
float linVelScale = LINEAR_VEL_SENSITIVITY*(1.0/getTransmitterHz());
glm::vec3 linVel(linX*linVelScale, linZ*linVelScale, -linY*linVelScale);
addVelocity(linVel);
@ -184,14 +184,37 @@ void Hand::simulate(float deltaTime)
-rollRate*ANGULAR_DAMPING_COEFFICIENT*deltaTime);
}
// The absolute threshold method
// The absolute limits method (no springs)
if (1) {
// Limit rotation
const float YAW_LIMIT = 20;
const float PITCH_LIMIT = 20;
if (yaw > YAW_LIMIT) { yaw = YAW_LIMIT; yawRate = 0.0; }
if (yaw < -YAW_LIMIT) { yaw = -YAW_LIMIT; yawRate = 0.0; }
if (pitch > PITCH_LIMIT) { pitch = PITCH_LIMIT; pitchRate = 0.0; }
if (pitch < -PITCH_LIMIT) { pitch = -PITCH_LIMIT; pitchRate = 0.0; }
// Damp Rotation Rates
yawRate *= 0.99;
pitchRate *= 0.99;
rollRate *= 0.99;
// Limit position
const float X_LIMIT = 1.0;
const float Y_LIMIT = 1.0;
const float Z_LIMIT = 1.0;
if (position.x > DEFAULT_X + X_LIMIT) { position.x = DEFAULT_X + X_LIMIT; velocity.x = 0; }
if (position.x < DEFAULT_X - X_LIMIT) { position.x = DEFAULT_X - X_LIMIT; velocity.x = 0; }
if (position.y > DEFAULT_Y + Y_LIMIT) { position.y = DEFAULT_Y + Y_LIMIT; velocity.y = 0; }
if (position.y < DEFAULT_Y - Y_LIMIT) { position.y = DEFAULT_Y - Y_LIMIT; velocity.y = 0; }
if (position.z > DEFAULT_Z + Z_LIMIT) { position.z = DEFAULT_Z + Z_LIMIT; velocity.z = 0; }
if (position.z < DEFAULT_Z - Z_LIMIT) { position.z = DEFAULT_Z - Z_LIMIT; velocity.z = 0; }
// Damp Velocity
velocity *= 0.99;
// Damp Yaw Rate
yawRate *= 0.99;
}
}

View file

@ -20,7 +20,7 @@ class Hand {
public:
Hand(glm::vec3 color);
void simulate (float deltaTime);
void render ();
void render (int isMine);
void reset ();
void setNoise (float mag) { noise = mag; };
void addVelocity (glm::vec3 v) { velocity += v; };

View file

@ -239,7 +239,7 @@ void Head::simulate(float deltaTime)
}
void Head::render(int faceToFace, float * myLocation)
void Head::render(int faceToFace, int isMine, float * myLocation)
{
int side = 0;
@ -255,7 +255,7 @@ void Head::render(int faceToFace, float * myLocation)
glRotatef(Yaw, 0, 1, 0);
hand->render();
hand->render(1);
// Don't render a head if it is really close to your location, because that is your own head!
if ((distanceToCamera > 1.0) || faceToFace) {

View file

@ -47,7 +47,7 @@ class Head : public AgentData {
float getRoll() {return Roll;}
float getYaw() {return Yaw;}
void render(int faceToFace, float * myLocation);
void render(int faceToFace, int isMine, float * myLocation);
void simulate(float);
// Send and receive network data

View file

@ -588,7 +588,7 @@ void display(void)
glPushMatrix();
glm::vec3 pos = agentHead->getPos();
glTranslatef(-pos.x, -pos.y, -pos.z);
agentHead->render(0, &location[0]);
agentHead->render(0, 0, &location[0]);
glPopMatrix();
}
}
@ -602,7 +602,7 @@ void display(void)
glPushMatrix();
glLoadIdentity();
glTranslatef(0.f, 0.f, -7.f);
myHead.render(display_head, &location[0]);
myHead.render(display_head, 1, &location[0]);
glPopMatrix();
//glm::vec3 test(0.5, 0.5, 0.5);