mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 07:57:30 +02:00
Merge remote-tracking branch 'origin'
This commit is contained in:
commit
27cc3a8ee5
16 changed files with 282 additions and 278 deletions
|
@ -32,8 +32,6 @@
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
const int DOMAIN_LISTEN_PORT = 40102;
|
const int DOMAIN_LISTEN_PORT = 40102;
|
||||||
|
|
||||||
const int MAX_PACKET_SIZE = 1500;
|
|
||||||
unsigned char packetData[MAX_PACKET_SIZE];
|
unsigned char packetData[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
const int LOGOFF_CHECK_INTERVAL = 5000;
|
const int LOGOFF_CHECK_INTERVAL = 5000;
|
||||||
|
@ -70,10 +68,10 @@ int main(int argc, const char * argv[])
|
||||||
|
|
||||||
agentList.startSilentAgentRemovalThread();
|
agentList.startSilentAgentRemovalThread();
|
||||||
|
|
||||||
std::map<char, Agent *> newestSoloAgents;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (agentList.getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) {
|
if (agentList.getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) {
|
||||||
|
std::map<char, Agent *> newestSoloAgents;
|
||||||
|
|
||||||
agentType = packetData[0];
|
agentType = packetData[0];
|
||||||
unpackSocket(&packetData[1], (sockaddr *)&agentLocalAddress);
|
unpackSocket(&packetData[1], (sockaddr *)&agentLocalAddress);
|
||||||
|
|
||||||
|
|
|
@ -18,18 +18,12 @@
|
||||||
|
|
||||||
Oscilloscope * scope;
|
Oscilloscope * scope;
|
||||||
|
|
||||||
const short BUFFER_LENGTH_BYTES = 1024;
|
|
||||||
const short BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
|
|
||||||
|
|
||||||
const short PACKET_LENGTH_BYTES = 1024;
|
const short PACKET_LENGTH_BYTES = 1024;
|
||||||
const short PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t);
|
const short PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t);
|
||||||
|
|
||||||
const int PHASE_DELAY_AT_90 = 20;
|
const int PHASE_DELAY_AT_90 = 20;
|
||||||
const float AMPLITUDE_RATIO_AT_90 = 0.5;
|
const float AMPLITUDE_RATIO_AT_90 = 0.5;
|
||||||
|
|
||||||
const short RING_BUFFER_FRAMES = 10;
|
|
||||||
const short RING_BUFFER_SIZE_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
const int SAMPLE_RATE = 22050;
|
const int SAMPLE_RATE = 22050;
|
||||||
const float JITTER_BUFFER_LENGTH_MSECS = 30.0;
|
const float JITTER_BUFFER_LENGTH_MSECS = 30.0;
|
||||||
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * (SAMPLE_RATE / 1000.0);
|
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * (SAMPLE_RATE / 1000.0);
|
||||||
|
@ -90,7 +84,23 @@ int audioCallback (const void *inputBuffer,
|
||||||
audioMixerSocket.sin_family = AF_INET;
|
audioMixerSocket.sin_family = AF_INET;
|
||||||
audioMixerSocket.sin_addr.s_addr = data->mixerAddress;
|
audioMixerSocket.sin_addr.s_addr = data->mixerAddress;
|
||||||
audioMixerSocket.sin_port = data->mixerPort;
|
audioMixerSocket.sin_port = data->mixerPort;
|
||||||
data->audioSocket->send((sockaddr *)&audioMixerSocket, (void *)inputLeft, BUFFER_LENGTH_BYTES);
|
|
||||||
|
int leadingBytes = 1 + (sizeof(float) * 3);
|
||||||
|
|
||||||
|
// we need the amount of bytes in the buffer + 1 for type + 12 for 3 floats for position
|
||||||
|
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
|
||||||
|
|
||||||
|
dataPacket[0] = 'I';
|
||||||
|
|
||||||
|
// memcpy the three float positions
|
||||||
|
for (int p = 0; p < 3; p++) {
|
||||||
|
memcpy(dataPacket + 1 + (p * sizeof(float)), &data->sourcePosition[p], sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the audio data to the last 1024 bytes of the data packet
|
||||||
|
memcpy(dataPacket + leadingBytes, inputLeft, BUFFER_LENGTH_BYTES);
|
||||||
|
|
||||||
|
data->audioSocket->send((sockaddr *)&audioMixerSocket, dataPacket, BUFFER_LENGTH_BYTES + leadingBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -134,27 +144,27 @@ int audioCallback (const void *inputBuffer,
|
||||||
// if we've been reset, and there isn't any new packets yet
|
// if we've been reset, and there isn't any new packets yet
|
||||||
// just play some silence
|
// just play some silence
|
||||||
|
|
||||||
if (ringBuffer->endOfLastWrite != NULL) {
|
if (ringBuffer->getEndOfLastWrite() != NULL) {
|
||||||
|
|
||||||
if (!ringBuffer->started && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
|
if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
|
||||||
printf("Held back\n");
|
printf("Held back\n");
|
||||||
} else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) {
|
} else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) {
|
||||||
ringBuffer->started = false;
|
ringBuffer->setStarted(false);
|
||||||
|
|
||||||
starve_counter++;
|
starve_counter++;
|
||||||
printf("Starved #%d\n", starve_counter);
|
printf("Starved #%d\n", starve_counter);
|
||||||
data->wasStarved = 10; // Frames to render the indication that the system was starved.
|
data->wasStarved = 10; // Frames to render the indication that the system was starved.
|
||||||
} else {
|
} else {
|
||||||
ringBuffer->started = true;
|
ringBuffer->setStarted(true);
|
||||||
// play whatever we have in the audio buffer
|
// play whatever we have in the audio buffer
|
||||||
|
|
||||||
// no sample overlap, either a direct copy of the audio data, or a copy with some appended silence
|
// no sample overlap, either a direct copy of the audio data, or a copy with some appended silence
|
||||||
memcpy(queueBuffer, ringBuffer->nextOutput, BUFFER_LENGTH_BYTES);
|
memcpy(queueBuffer, ringBuffer->getNextOutput(), BUFFER_LENGTH_BYTES);
|
||||||
|
|
||||||
ringBuffer->nextOutput += BUFFER_LENGTH_SAMPLES;
|
ringBuffer->setNextOutput(ringBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES);
|
||||||
|
|
||||||
if (ringBuffer->nextOutput == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) {
|
if (ringBuffer->getNextOutput() == ringBuffer->getBuffer() + RING_BUFFER_SAMPLES) {
|
||||||
ringBuffer->nextOutput = ringBuffer->buffer;
|
ringBuffer->setNextOutput(ringBuffer->getBuffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +214,6 @@ void *receiveAudioViaUDP(void *args) {
|
||||||
|
|
||||||
while (!stopAudioReceiveThread) {
|
while (!stopAudioReceiveThread) {
|
||||||
if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) {
|
if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) {
|
||||||
|
|
||||||
bool firstSample = (currentReceiveTime.tv_sec == 0);
|
bool firstSample = (currentReceiveTime.tv_sec == 0);
|
||||||
|
|
||||||
gettimeofday(¤tReceiveTime, NULL);
|
gettimeofday(¤tReceiveTime, NULL);
|
||||||
|
@ -232,30 +241,7 @@ void *receiveAudioViaUDP(void *args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer;
|
AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer;
|
||||||
|
ringBuffer->parseData(receivedData, PACKET_LENGTH_BYTES);
|
||||||
if (ringBuffer->endOfLastWrite == NULL) {
|
|
||||||
ringBuffer->endOfLastWrite = ringBuffer->buffer;
|
|
||||||
} else if (ringBuffer->diffLastWriteNextOutput() > RING_BUFFER_SIZE_SAMPLES - PACKET_LENGTH_SAMPLES) {
|
|
||||||
std::cout << "NAB: " << ringBuffer->nextOutput - ringBuffer->buffer << "\n";
|
|
||||||
std::cout << "LAW: " << ringBuffer->endOfLastWrite - ringBuffer->buffer << "\n";
|
|
||||||
std::cout << "D: " << ringBuffer->diffLastWriteNextOutput() << "\n";
|
|
||||||
std::cout << "Full\n";
|
|
||||||
|
|
||||||
// reset us to started state
|
|
||||||
ringBuffer->endOfLastWrite = ringBuffer->buffer;
|
|
||||||
ringBuffer->nextOutput = ringBuffer->buffer;
|
|
||||||
ringBuffer->started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t *copyToPointer = ringBuffer->endOfLastWrite;
|
|
||||||
|
|
||||||
// just copy the recieved data to the right spot and then add packet length to previous pointer
|
|
||||||
memcpy(copyToPointer, receivedData, PACKET_LENGTH_BYTES);
|
|
||||||
ringBuffer->endOfLastWrite += PACKET_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
if (ringBuffer->endOfLastWrite == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) {
|
|
||||||
ringBuffer->endOfLastWrite = ringBuffer->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG_SAMPLE_DELAY) {
|
if (LOG_SAMPLE_DELAY) {
|
||||||
gettimeofday(&previousReceiveTime, NULL);
|
gettimeofday(&previousReceiveTime, NULL);
|
||||||
|
@ -266,6 +252,10 @@ void *receiveAudioViaUDP(void *args) {
|
||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::setSourcePosition(glm::vec3 newPosition) {
|
||||||
|
audioData->sourcePosition = newPosition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize portaudio and start an audio stream.
|
* Initialize portaudio and start an audio stream.
|
||||||
* Should be called at the beginning of program exection.
|
* Should be called at the beginning of program exection.
|
||||||
|
@ -284,7 +274,7 @@ Audio::Audio(Oscilloscope * s)
|
||||||
|
|
||||||
// setup a UDPSocket
|
// setup a UDPSocket
|
||||||
audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT);
|
audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT);
|
||||||
audioData->ringBuffer = new AudioRingBuffer(RING_BUFFER_SIZE_SAMPLES);
|
audioData->ringBuffer = new AudioRingBuffer();
|
||||||
|
|
||||||
AudioRecThreadStruct threadArgs;
|
AudioRecThreadStruct threadArgs;
|
||||||
threadArgs.sharedAudioData = audioData;
|
threadArgs.sharedAudioData = audioData;
|
||||||
|
@ -359,7 +349,7 @@ void Audio::render(int screenWidth, int screenHeight)
|
||||||
float timeLeftInCurrentBuffer = 0;
|
float timeLeftInCurrentBuffer = 0;
|
||||||
if (audioData->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&audioData->lastCallback, ¤tTime)/(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth;
|
if (audioData->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&audioData->lastCallback, ¤tTime)/(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth;
|
||||||
|
|
||||||
if (audioData->ringBuffer->endOfLastWrite != NULL)
|
if (audioData->ringBuffer->getEndOfLastWrite() != NULL)
|
||||||
remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / BUFFER_LENGTH_SAMPLES * frameWidth;
|
remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / BUFFER_LENGTH_SAMPLES * frameWidth;
|
||||||
|
|
||||||
if (audioData->wasStarved == 0) glColor3f(0, 1, 0);
|
if (audioData->wasStarved == 0) glColor3f(0, 1, 0);
|
||||||
|
|
|
@ -25,11 +25,12 @@ public:
|
||||||
void getInputLoudness(float * lastLoudness, float * averageLoudness);
|
void getInputLoudness(float * lastLoudness, float * averageLoudness);
|
||||||
void updateMixerParams(in_addr_t mixerAddress, in_port_t mixerPort);
|
void updateMixerParams(in_addr_t mixerAddress, in_port_t mixerPort);
|
||||||
|
|
||||||
|
void setSourcePosition(glm::vec3 position);
|
||||||
|
|
||||||
// terminates audio I/O
|
// terminates audio I/O
|
||||||
bool terminate();
|
bool terminate();
|
||||||
private:
|
private:
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
AudioData *audioData;
|
AudioData *audioData;
|
||||||
|
|
||||||
// protects constructor so that public init method is used
|
// protects constructor so that public init method is used
|
||||||
|
|
|
@ -11,17 +11,22 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
|
|
||||||
class AudioData {
|
class AudioData {
|
||||||
public:
|
public:
|
||||||
|
AudioData(int bufferLength);
|
||||||
|
~AudioData();
|
||||||
AudioRingBuffer *ringBuffer;
|
AudioRingBuffer *ringBuffer;
|
||||||
|
|
||||||
UDPSocket *audioSocket;
|
UDPSocket *audioSocket;
|
||||||
|
|
||||||
int16_t *samplesToQueue;
|
int16_t *samplesToQueue;
|
||||||
|
|
||||||
|
glm::vec3 sourcePosition;
|
||||||
|
|
||||||
// store current mixer address and port
|
// store current mixer address and port
|
||||||
in_addr_t mixerAddress;
|
in_addr_t mixerAddress;
|
||||||
in_port_t mixerPort;
|
in_port_t mixerPort;
|
||||||
|
@ -34,9 +39,6 @@ class AudioData {
|
||||||
|
|
||||||
float lastInputLoudness;
|
float lastInputLoudness;
|
||||||
float averagedInputLoudness;
|
float averagedInputLoudness;
|
||||||
|
|
||||||
AudioData(int bufferLength);
|
|
||||||
~AudioData();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__AudioData__) */
|
#endif /* defined(__interface__AudioData__) */
|
||||||
|
|
|
@ -64,6 +64,10 @@ Head::~Head() {
|
||||||
// all data is primitive, do nothing
|
// all data is primitive, do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Head* Head::clone() const {
|
||||||
|
return new Head(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void Head::reset()
|
void Head::reset()
|
||||||
{
|
{
|
||||||
Pitch = Yaw = Roll = 0;
|
Pitch = Yaw = Roll = 0;
|
||||||
|
|
|
@ -24,6 +24,8 @@ class Head : public AgentData {
|
||||||
public:
|
public:
|
||||||
Head();
|
Head();
|
||||||
~Head();
|
~Head();
|
||||||
|
Head* clone() const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void UpdatePos(float frametime, SerialInterface * serialInterface, int head_mirror, glm::vec3 * gravity);
|
void UpdatePos(float frametime, SerialInterface * serialInterface, int head_mirror, glm::vec3 * gravity);
|
||||||
void setNoise (float mag) { noise = mag; }
|
void setNoise (float mag) { noise = mag; }
|
||||||
|
|
|
@ -53,7 +53,6 @@ int simulate_on = 1;
|
||||||
// Network Socket and network constants
|
// Network Socket and network constants
|
||||||
//
|
//
|
||||||
|
|
||||||
const int MAX_PACKET_SIZE = 1500;
|
|
||||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
||||||
char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string
|
char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string
|
||||||
const int DOMAINSERVER_PORT = 40102;
|
const int DOMAINSERVER_PORT = 40102;
|
||||||
|
@ -513,6 +512,7 @@ void simulateHead(float frametime)
|
||||||
myHead.setRenderYaw(myHead.getRenderYaw() + render_yaw_rate);
|
myHead.setRenderYaw(myHead.getRenderYaw() + render_yaw_rate);
|
||||||
myHead.setRenderPitch(render_pitch);
|
myHead.setRenderPitch(render_pitch);
|
||||||
myHead.setPos(glm::vec3(location[0], location[1], location[2]));
|
myHead.setPos(glm::vec3(location[0], location[1], location[2]));
|
||||||
|
audio.setSourcePosition(glm::vec3(location[0], location[1], location[2]));
|
||||||
|
|
||||||
// Get audio loudness data from audio input device
|
// Get audio loudness data from audio input device
|
||||||
float loudness, averageLoudness;
|
float loudness, averageLoudness;
|
||||||
|
|
|
@ -13,229 +13,125 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
#include "UDPSocket.h"
|
#include <AgentList.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
const int MAX_AGENTS = 1000;
|
|
||||||
const int LOGOFF_CHECK_INTERVAL = 1000;
|
|
||||||
|
|
||||||
const unsigned short MIXER_LISTEN_PORT = 55443;
|
const unsigned short MIXER_LISTEN_PORT = 55443;
|
||||||
|
|
||||||
const int BUFFER_LENGTH_BYTES = 1024;
|
|
||||||
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
|
|
||||||
const float SAMPLE_RATE = 22050.0;
|
const float SAMPLE_RATE = 22050.0;
|
||||||
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES/SAMPLE_RATE) * 1000000;
|
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES/SAMPLE_RATE) * 1000000;
|
||||||
|
|
||||||
const short JITTER_BUFFER_MSECS = 20;
|
const short JITTER_BUFFER_MSECS = 20;
|
||||||
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0);
|
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0);
|
||||||
|
|
||||||
const short RING_BUFFER_FRAMES = 10;
|
|
||||||
const short RING_BUFFER_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
||||||
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
|
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
|
||||||
|
|
||||||
|
const float DISTANCE_RATIO = 3.0/4.2;
|
||||||
|
|
||||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
||||||
char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup
|
char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup
|
||||||
const int DOMAINSERVER_PORT = 40102;
|
const int DOMAINSERVER_PORT = 40102;
|
||||||
|
|
||||||
const int MAX_SOURCE_BUFFERS = 20;
|
AgentList agentList(MIXER_LISTEN_PORT);
|
||||||
|
|
||||||
sockaddr_in agentAddress;
|
|
||||||
|
|
||||||
UDPSocket audioSocket = UDPSocket(MIXER_LISTEN_PORT);
|
|
||||||
|
|
||||||
struct AgentList {
|
|
||||||
char *address;
|
|
||||||
unsigned short port;
|
|
||||||
bool active;
|
|
||||||
timeval time;
|
|
||||||
bool bufferTransmitted;
|
|
||||||
} agents[MAX_AGENTS];
|
|
||||||
|
|
||||||
int numAgents = 0;
|
|
||||||
|
|
||||||
AudioRingBuffer *sourceBuffers[MAX_SOURCE_BUFFERS];
|
|
||||||
|
|
||||||
double diffclock(timeval *clock1, timeval *clock2)
|
|
||||||
{
|
|
||||||
double diffms = (clock2->tv_sec - clock1->tv_sec) * 1000.0;
|
|
||||||
diffms += (clock2->tv_usec - clock1->tv_usec) / 1000.0; // us to ms
|
|
||||||
return diffms;
|
|
||||||
}
|
|
||||||
|
|
||||||
double usecTimestamp(timeval *time, double addedUsecs = 0) {
|
|
||||||
return (time->tv_sec * 1000000.0) + time->tv_usec + addedUsecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *sendBuffer(void *args)
|
void *sendBuffer(void *args)
|
||||||
{
|
{
|
||||||
int sentBytes;
|
int sentBytes;
|
||||||
int currentFrame = 1;
|
int nextFrame = 0;
|
||||||
timeval startTime, sendTime, now;
|
timeval startTime;
|
||||||
|
|
||||||
int16_t *clientMix = new int16_t[BUFFER_LENGTH_SAMPLES];
|
|
||||||
long *masterMix = new long[BUFFER_LENGTH_SAMPLES];
|
|
||||||
|
|
||||||
gettimeofday(&startTime, NULL);
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
sentBytes = 0;
|
sentBytes = 0;
|
||||||
|
|
||||||
for (int wb = 0; wb < BUFFER_LENGTH_SAMPLES; wb++) {
|
for (int i = 0; i < agentList.getAgents().size(); i++) {
|
||||||
masterMix[wb] = 0;
|
AudioRingBuffer *agentBuffer = (AudioRingBuffer *) agentList.getAgents()[i].getLinkedData();
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&sendTime, NULL);
|
|
||||||
|
|
||||||
for (int b = 0; b < MAX_SOURCE_BUFFERS; b++) {
|
|
||||||
if (sourceBuffers[b]->endOfLastWrite != NULL) {
|
|
||||||
if (!sourceBuffers[b]->started
|
|
||||||
&& sourceBuffers[b]->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
|
|
||||||
std::cout << "Held back buffer " << b << ".\n";
|
|
||||||
} else if (sourceBuffers[b]->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES) {
|
|
||||||
std::cout << "Buffer " << b << " starved.\n";
|
|
||||||
sourceBuffers[b]->started = false;
|
|
||||||
} else {
|
|
||||||
sourceBuffers[b]->started = true;
|
|
||||||
agents[b].bufferTransmitted = true;
|
|
||||||
|
|
||||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) {
|
|
||||||
masterMix[s] += sourceBuffers[b]->nextOutput[s];
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceBuffers[b]->nextOutput += BUFFER_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
if (sourceBuffers[b]->nextOutput >= sourceBuffers[b]->buffer + RING_BUFFER_SAMPLES) {
|
|
||||||
sourceBuffers[b]->nextOutput = sourceBuffers[b]->buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int a = 0; a < numAgents; a++) {
|
|
||||||
if (diffclock(&agents[a].time, &sendTime) <= LOGOFF_CHECK_INTERVAL) {
|
|
||||||
|
|
||||||
int16_t *previousOutput = NULL;
|
|
||||||
if (agents[a].bufferTransmitted) {
|
|
||||||
previousOutput = (sourceBuffers[a]->nextOutput == sourceBuffers[a]->buffer)
|
|
||||||
? sourceBuffers[a]->buffer + RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES
|
|
||||||
: sourceBuffers[a]->nextOutput - BUFFER_LENGTH_SAMPLES;
|
|
||||||
agents[a].bufferTransmitted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int as = 0; as < BUFFER_LENGTH_SAMPLES; as++) {
|
|
||||||
long longSample = previousOutput != NULL
|
|
||||||
? masterMix[as] - previousOutput[as]
|
|
||||||
: masterMix[as];
|
|
||||||
|
|
||||||
int16_t shortSample;
|
|
||||||
|
|
||||||
if (longSample < 0) {
|
|
||||||
shortSample = std::max(longSample, MIN_SAMPLE_VALUE);
|
|
||||||
} else {
|
|
||||||
shortSample = std::min(longSample, MAX_SAMPLE_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
clientMix[as] = shortSample;
|
|
||||||
|
|
||||||
// std::cout << as << " - CM: " << clientMix[as] << " MM: " << masterMix[as] << "\n";
|
|
||||||
// std::cout << previousOutput - sourceBuffers[a]->buffer << "\n";
|
|
||||||
|
|
||||||
if (previousOutput != NULL) {
|
|
||||||
// std::cout << "PO: " << previousOutput[as] << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sentBytes = audioSocket.send(agents[a].address, agents[a].port, clientMix, BUFFER_LENGTH_BYTES);
|
|
||||||
|
|
||||||
if (sentBytes < BUFFER_LENGTH_BYTES) {
|
if (agentBuffer != NULL && agentBuffer->getEndOfLastWrite() != NULL) {
|
||||||
std::cout << "Error sending mix packet! " << sentBytes << strerror(errno) << "\n";
|
|
||||||
|
if (!agentBuffer->isStarted() && agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
|
||||||
|
printf("Held back buffer %d.\n", i);
|
||||||
|
} else if (agentBuffer->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES) {
|
||||||
|
printf("Buffer %d starved.\n", i);
|
||||||
|
agentBuffer->setStarted(false);
|
||||||
|
} else {
|
||||||
|
// good buffer, add this to the mix
|
||||||
|
agentBuffer->setStarted(true);
|
||||||
|
agentBuffer->setAddedToMix(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < agentList.getAgents().size(); i++) {
|
||||||
|
Agent *agent = &agentList.getAgents()[i];
|
||||||
|
|
||||||
|
int16_t clientMix[BUFFER_LENGTH_SAMPLES] = {};
|
||||||
|
|
||||||
|
for (int j = 0; j < agentList.getAgents().size(); j++) {
|
||||||
|
if (i != j) {
|
||||||
|
AudioRingBuffer *otherAgentBuffer = (AudioRingBuffer *)agentList.getAgents()[j].getLinkedData();
|
||||||
|
|
||||||
|
float *agentPosition = ((AudioRingBuffer *)agent->getLinkedData())->getPosition();
|
||||||
|
float *otherAgentPosition = otherAgentBuffer->getPosition();
|
||||||
|
|
||||||
|
float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) +
|
||||||
|
powf(agentPosition[1] - otherAgentPosition[1], 2) +
|
||||||
|
powf(agentPosition[2] - otherAgentPosition[2], 2));
|
||||||
|
|
||||||
|
float distanceCoeff = powf((logf(DISTANCE_RATIO * distanceToAgent) / logf(3)), 2);
|
||||||
|
|
||||||
|
for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) {
|
||||||
|
int16_t sample = (otherAgentBuffer->getNextOutput()[s] / distanceCoeff);
|
||||||
|
clientMix[s] += sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
agentList.getAgentSocket().send(agent->getPublicSocket(), clientMix, BUFFER_LENGTH_BYTES);
|
||||||
gettimeofday(&now, NULL);
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < agentList.getAgents().size(); i++) {
|
||||||
|
AudioRingBuffer *agentBuffer = (AudioRingBuffer *)agentList.getAgents()[i].getLinkedData();
|
||||||
|
if (agentBuffer->wasAddedToMix()) {
|
||||||
|
agentBuffer->setNextOutput(agentBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES);
|
||||||
|
|
||||||
|
if (agentBuffer->getNextOutput() >= agentBuffer->getBuffer() + RING_BUFFER_SAMPLES) {
|
||||||
|
agentBuffer->setNextOutput(agentBuffer->getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
agentBuffer->setAddedToMix(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow();
|
||||||
|
|
||||||
double usecToSleep = usecTimestamp(&startTime, (currentFrame * BUFFER_SEND_INTERVAL_USECS)) - usecTimestamp(&now);
|
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "NOT SLEEPING!";
|
std::cout << "Took too much time, not sleeping!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFrame++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int addAgent(sockaddr_in *newAddress, void *audioData) {
|
|
||||||
// Search for agent in list and add if needed
|
|
||||||
int is_new = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < numAgents; i++) {
|
|
||||||
if (strcmp(inet_ntoa(newAddress->sin_addr), agents[i].address) == 0
|
|
||||||
&& ntohs(newAddress->sin_port) == agents[i].port) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((i == numAgents) || (agents[i].active == false)) {
|
|
||||||
is_new = 1;
|
|
||||||
|
|
||||||
agents[i].address = new char();
|
|
||||||
strcpy(agents[i].address, inet_ntoa(newAddress->sin_addr));
|
|
||||||
|
|
||||||
agents[i].bufferTransmitted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
agents[i].port = ntohs(newAddress->sin_port);
|
|
||||||
agents[i].active = true;
|
|
||||||
gettimeofday(&agents[i].time, NULL);
|
|
||||||
|
|
||||||
if (sourceBuffers[i]->endOfLastWrite == NULL) {
|
|
||||||
sourceBuffers[i]->endOfLastWrite = sourceBuffers[i]->buffer;
|
|
||||||
} else if (sourceBuffers[i]->diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES) {
|
|
||||||
// reset us to started state
|
|
||||||
sourceBuffers[i]->endOfLastWrite = sourceBuffers[i]->buffer;
|
|
||||||
sourceBuffers[i]->nextOutput = sourceBuffers[i]->buffer;
|
|
||||||
sourceBuffers[i]->started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(sourceBuffers[i]->endOfLastWrite, audioData, BUFFER_LENGTH_BYTES);
|
|
||||||
|
|
||||||
sourceBuffers[i]->endOfLastWrite += BUFFER_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
if (sourceBuffers[i]->endOfLastWrite >= sourceBuffers[i]->buffer + RING_BUFFER_SAMPLES) {
|
|
||||||
sourceBuffers[i]->endOfLastWrite = sourceBuffers[i]->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == numAgents) {
|
|
||||||
numAgents++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *reportAliveToDS(void *args) {
|
void *reportAliveToDS(void *args) {
|
||||||
|
|
||||||
timeval lastSend, now;
|
timeval lastSend;
|
||||||
unsigned char output[7];
|
unsigned char output[7];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
gettimeofday(&lastSend, NULL);
|
gettimeofday(&lastSend, NULL);
|
||||||
|
|
||||||
*output = 'M';
|
*output = 'M';
|
||||||
packSocket(output + 1, 895283510, htons(MIXER_LISTEN_PORT));
|
// packSocket(output + 1, 895283510, htons(MIXER_LISTEN_PORT));
|
||||||
audioSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7);
|
packSocket(output + 1, 788637888, htons(MIXER_LISTEN_PORT));
|
||||||
|
agentList.getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7);
|
||||||
|
|
||||||
gettimeofday(&now, NULL);
|
double usecToSleep = 1000000 - (usecTimestampNow() - usecTimestamp(&lastSend));
|
||||||
|
|
||||||
double usecToSleep = 1000000 - (usecTimestamp(&now) - usecTimestamp(&lastSend));
|
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
@ -245,11 +141,20 @@ void *reportAliveToDS(void *args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void attachNewBufferToAgent(Agent *newAgent) {
|
||||||
|
if (newAgent->getLinkedData() == NULL) {
|
||||||
|
newAgent->setLinkedData(new AudioRingBuffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char * argv[])
|
int main(int argc, const char * argv[])
|
||||||
{
|
{
|
||||||
timeval lastAgentUpdate;
|
|
||||||
ssize_t receivedBytes = 0;
|
ssize_t receivedBytes = 0;
|
||||||
|
|
||||||
|
agentList.linkedDataCreateCallback = attachNewBufferToAgent;
|
||||||
|
|
||||||
|
agentList.startSilentAgentRemovalThread();
|
||||||
|
|
||||||
// setup the agentSocket to report to domain server
|
// setup the agentSocket to report to domain server
|
||||||
pthread_t reportAliveThread;
|
pthread_t reportAliveThread;
|
||||||
pthread_create(&reportAliveThread, NULL, reportAliveToDS, NULL);
|
pthread_create(&reportAliveThread, NULL, reportAliveToDS, NULL);
|
||||||
|
@ -270,29 +175,24 @@ int main(int argc, const char * argv[])
|
||||||
printf("Using static domainserver IP: %s\n", DOMAIN_IP);
|
printf("Using static domainserver IP: %s\n", DOMAIN_IP);
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&lastAgentUpdate, NULL);
|
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
int16_t packetData[BUFFER_LENGTH_SAMPLES];
|
|
||||||
|
|
||||||
for (int b = 0; b < MAX_SOURCE_BUFFERS; b++) {
|
|
||||||
sourceBuffers[b] = new AudioRingBuffer(10 * BUFFER_LENGTH_SAMPLES);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_t sendBufferThread;
|
pthread_t sendBufferThread;
|
||||||
pthread_create(&sendBufferThread, NULL, sendBuffer, NULL);
|
pthread_create(&sendBufferThread, NULL, sendBuffer, NULL);
|
||||||
|
|
||||||
|
sockaddr *agentAddress = new sockaddr;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if(audioSocket.receive((sockaddr *)&agentAddress, packetData, &receivedBytes)) {
|
if(agentList.getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) {
|
||||||
if (receivedBytes == BUFFER_LENGTH_BYTES) {
|
if (receivedBytes >= BUFFER_LENGTH_BYTES) {
|
||||||
if (addAgent(&agentAddress, packetData)) {
|
// add or update the existing interface agent
|
||||||
std::cout << "Added agent: " <<
|
agentList.addOrUpdateAgent(agentAddress, agentAddress, packetData[0]);
|
||||||
inet_ntoa(agentAddress.sin_addr) << " on " <<
|
agentList.updateAgentWithData(agentAddress, (void *)packetData, receivedBytes);
|
||||||
ntohs(agentAddress.sin_port) << "\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
agentList.stopSilentAgentRemovalThread();
|
||||||
pthread_join(reportAliveThread, NULL);
|
pthread_join(reportAliveThread, NULL);
|
||||||
pthread_join(sendBufferThread, NULL);
|
pthread_join(sendBufferThread, NULL);
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,11 @@ Agent::Agent(const Agent &otherAgent) {
|
||||||
lastRecvTimeUsecs = otherAgent.lastRecvTimeUsecs;
|
lastRecvTimeUsecs = otherAgent.lastRecvTimeUsecs;
|
||||||
type = otherAgent.type;
|
type = otherAgent.type;
|
||||||
|
|
||||||
// linked data is transient, gets re-assigned on next packet receive
|
if (otherAgent.linkedData != NULL) {
|
||||||
linkedData = NULL;
|
linkedData = otherAgent.linkedData->clone();
|
||||||
|
} else {
|
||||||
|
linkedData = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Agent& Agent::operator=(Agent otherAgent) {
|
Agent& Agent::operator=(Agent otherAgent) {
|
||||||
|
@ -116,8 +119,6 @@ void Agent::activatePublicSocket() {
|
||||||
activeSocket = publicSocket;
|
activeSocket = publicSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AgentData* Agent::getLinkedData() {
|
AgentData* Agent::getLinkedData() {
|
||||||
return linkedData;
|
return linkedData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ class AgentData {
|
||||||
public:
|
public:
|
||||||
virtual ~AgentData() = 0;
|
virtual ~AgentData() = 0;
|
||||||
virtual void parseData(void * data, int size) = 0;
|
virtual void parseData(void * data, int size) = 0;
|
||||||
|
virtual AgentData* clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
|
|
||||||
|
const int MAX_PACKET_SIZE = 1500;
|
||||||
const unsigned short AGENT_SOCKET_LISTEN_PORT = 40103;
|
const unsigned short AGENT_SOCKET_LISTEN_PORT = 40103;
|
||||||
const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||||
extern const char *SOLO_AGENT_TYPES_STRING;
|
extern const char *SOLO_AGENT_TYPES_STRING;
|
||||||
|
@ -33,6 +34,7 @@ class AgentList {
|
||||||
int updateList(unsigned char *packetData, size_t dataBytes);
|
int updateList(unsigned char *packetData, size_t dataBytes);
|
||||||
bool addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType);
|
bool addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType);
|
||||||
void processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
|
void processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
|
||||||
|
void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
|
||||||
void broadcastToAgents(char *broadcastData, size_t dataBytes);
|
void broadcastToAgents(char *broadcastData, size_t dataBytes);
|
||||||
void sendToAgent(Agent *destAgent, void *packetData, size_t dataBytes);
|
void sendToAgent(Agent *destAgent, void *packetData, size_t dataBytes);
|
||||||
void pingAgents();
|
void pingAgents();
|
||||||
|
@ -44,7 +46,6 @@ class AgentList {
|
||||||
pthread_t removeSilentAgentsThread;
|
pthread_t removeSilentAgentsThread;
|
||||||
|
|
||||||
int indexOfMatchingAgent(sockaddr *senderAddress);
|
int indexOfMatchingAgent(sockaddr *senderAddress);
|
||||||
void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
|
|
||||||
void handlePingReply(sockaddr *agentAddress);
|
void handlePingReply(sockaddr *agentAddress);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,22 +6,115 @@
|
||||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
|
|
||||||
AudioRingBuffer::AudioRingBuffer(short ringBufferSamples) {
|
AudioRingBuffer::AudioRingBuffer() {
|
||||||
ringBufferLengthSamples = ringBufferSamples;
|
|
||||||
started = false;
|
started = false;
|
||||||
|
addedToMix = false;
|
||||||
|
|
||||||
endOfLastWrite = NULL;
|
endOfLastWrite = NULL;
|
||||||
|
|
||||||
buffer = new int16_t[ringBufferLengthSamples];
|
buffer = new int16_t[RING_BUFFER_SAMPLES];
|
||||||
nextOutput = buffer;
|
nextOutput = buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AudioRingBuffer::AudioRingBuffer(const AudioRingBuffer &otherRingBuffer) {
|
||||||
|
started = otherRingBuffer.started;
|
||||||
|
addedToMix = otherRingBuffer.addedToMix;
|
||||||
|
|
||||||
|
buffer = new int16_t[RING_BUFFER_SAMPLES];
|
||||||
|
memcpy(buffer, otherRingBuffer.buffer, sizeof(int16_t) * RING_BUFFER_SAMPLES);
|
||||||
|
|
||||||
|
nextOutput = buffer + (otherRingBuffer.nextOutput - otherRingBuffer.buffer);
|
||||||
|
endOfLastWrite = buffer + (otherRingBuffer.endOfLastWrite - otherRingBuffer.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
AudioRingBuffer::~AudioRingBuffer() {
|
AudioRingBuffer::~AudioRingBuffer() {
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AudioRingBuffer* AudioRingBuffer::clone() const {
|
||||||
|
return new AudioRingBuffer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t* AudioRingBuffer::getNextOutput() {
|
||||||
|
return nextOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioRingBuffer::setNextOutput(int16_t *newPointer) {
|
||||||
|
nextOutput = newPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t* AudioRingBuffer::getEndOfLastWrite() {
|
||||||
|
return endOfLastWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioRingBuffer::setEndOfLastWrite(int16_t *newPointer) {
|
||||||
|
endOfLastWrite = newPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t* AudioRingBuffer::getBuffer() {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioRingBuffer::isStarted() {
|
||||||
|
return started;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioRingBuffer::setStarted(bool status) {
|
||||||
|
started = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioRingBuffer::wasAddedToMix() {
|
||||||
|
return addedToMix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioRingBuffer::setAddedToMix(bool added) {
|
||||||
|
addedToMix = added;
|
||||||
|
}
|
||||||
|
|
||||||
|
float* AudioRingBuffer::getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioRingBuffer::setPosition(float *newPosition) {
|
||||||
|
position[0] = newPosition[0];
|
||||||
|
position[1] = newPosition[1];
|
||||||
|
position[2] = newPosition[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioRingBuffer::parseData(void *data, int size) {
|
||||||
|
unsigned char *audioDataStart = (unsigned char *) data;
|
||||||
|
|
||||||
|
if (size > BUFFER_LENGTH_BYTES) {
|
||||||
|
|
||||||
|
for (int p = 0; p < 3; p ++) {
|
||||||
|
memcpy(&position[p], audioDataStart + 1 + (sizeof(float) * p), sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
audioDataStart += (1 + (sizeof(float) * 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endOfLastWrite == NULL) {
|
||||||
|
endOfLastWrite = buffer;
|
||||||
|
} else if (diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES) {
|
||||||
|
endOfLastWrite = buffer;
|
||||||
|
nextOutput = buffer;
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(endOfLastWrite, audioDataStart, BUFFER_LENGTH_BYTES);
|
||||||
|
|
||||||
|
endOfLastWrite += BUFFER_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
addedToMix = false;
|
||||||
|
|
||||||
|
if (endOfLastWrite >= buffer + RING_BUFFER_SAMPLES) {
|
||||||
|
endOfLastWrite = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
short AudioRingBuffer::diffLastWriteNextOutput()
|
short AudioRingBuffer::diffLastWriteNextOutput()
|
||||||
{
|
{
|
||||||
if (endOfLastWrite == NULL) {
|
if (endOfLastWrite == NULL) {
|
||||||
|
@ -30,20 +123,9 @@ short AudioRingBuffer::diffLastWriteNextOutput()
|
||||||
short sampleDifference = endOfLastWrite - nextOutput;
|
short sampleDifference = endOfLastWrite - nextOutput;
|
||||||
|
|
||||||
if (sampleDifference < 0) {
|
if (sampleDifference < 0) {
|
||||||
sampleDifference += ringBufferLengthSamples;
|
sampleDifference += RING_BUFFER_SAMPLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sampleDifference;
|
return sampleDifference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
short AudioRingBuffer::bufferOverlap(int16_t *pointer, short addedDistance)
|
|
||||||
{
|
|
||||||
short samplesLeft = (buffer + ringBufferLengthSamples) - pointer;
|
|
||||||
|
|
||||||
if (samplesLeft < addedDistance) {
|
|
||||||
return addedDistance - samplesLeft;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,20 +11,43 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "AgentData.h"
|
||||||
|
|
||||||
class AudioRingBuffer {
|
const int BUFFER_LENGTH_BYTES = 1024;
|
||||||
|
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
|
||||||
|
|
||||||
|
const short RING_BUFFER_FRAMES = 10;
|
||||||
|
const short RING_BUFFER_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
class AudioRingBuffer : public AgentData {
|
||||||
public:
|
public:
|
||||||
|
AudioRingBuffer();
|
||||||
|
~AudioRingBuffer();
|
||||||
|
AudioRingBuffer(const AudioRingBuffer &otherRingBuffer);
|
||||||
|
|
||||||
|
void parseData(void *data, int size);
|
||||||
|
AudioRingBuffer* clone() const;
|
||||||
|
|
||||||
|
int16_t* getNextOutput();
|
||||||
|
void setNextOutput(int16_t *newPointer);
|
||||||
|
int16_t* getEndOfLastWrite();
|
||||||
|
void setEndOfLastWrite(int16_t *newPointer);
|
||||||
|
int16_t* getBuffer();
|
||||||
|
bool isStarted();
|
||||||
|
void setStarted(bool status);
|
||||||
|
bool wasAddedToMix();
|
||||||
|
void setAddedToMix(bool added);
|
||||||
|
float* getPosition();
|
||||||
|
void setPosition(float newPosition[]);
|
||||||
|
|
||||||
|
short diffLastWriteNextOutput();
|
||||||
|
private:
|
||||||
|
float position[3];
|
||||||
int16_t *nextOutput;
|
int16_t *nextOutput;
|
||||||
int16_t *endOfLastWrite;
|
int16_t *endOfLastWrite;
|
||||||
int16_t *buffer;
|
int16_t *buffer;
|
||||||
short ringBufferLengthSamples;
|
|
||||||
bool started;
|
bool started;
|
||||||
|
bool addedToMix;
|
||||||
short diffLastWriteNextOutput();
|
|
||||||
short bufferOverlap(int16_t *pointer, short addedDistance);
|
|
||||||
|
|
||||||
AudioRingBuffer(short ringBufferSamples);
|
|
||||||
~AudioRingBuffer();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__AudioRingBuffer__) */
|
#endif /* defined(__interface__AudioRingBuffer__) */
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
double usecTimestamp(timeval *time) {
|
double usecTimestamp(timeval *time) {
|
||||||
return (time->tv_sec * 1000000.0);
|
return (time->tv_sec * 1000000.0 + time->tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
double usecTimestampNow() {
|
double usecTimestampNow() {
|
||||||
timeval now;
|
timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
return (now.tv_sec * 1000000.0);
|
return (now.tv_sec * 1000000.0 + now.tv_usec);
|
||||||
}
|
}
|
|
@ -113,7 +113,6 @@ bool UDPSocket::receive(sockaddr *recvAddress, void *receivedData, ssize_t *rece
|
||||||
|
|
||||||
int UDPSocket::send(sockaddr *destAddress, const void *data, size_t byteLength) {
|
int UDPSocket::send(sockaddr *destAddress, const void *data, size_t byteLength) {
|
||||||
// send data via UDP
|
// send data via UDP
|
||||||
|
|
||||||
int sent_bytes = sendto(handle, (const char*)data, byteLength,
|
int sent_bytes = sendto(handle, (const char*)data, byteLength,
|
||||||
0, (sockaddr *) destAddress, sizeof(sockaddr_in));
|
0, (sockaddr *) destAddress, sizeof(sockaddr_in));
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
#define MAX_BUFFER_LENGTH_BYTES 1024
|
#define MAX_BUFFER_LENGTH_BYTES 1500
|
||||||
|
|
||||||
class UDPSocket {
|
class UDPSocket {
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue