This commit is contained in:
Andrzej Kapolka 2013-06-14 10:31:10 -07:00
commit b4d4cfd994
9 changed files with 191 additions and 8 deletions

View file

@ -18,4 +18,10 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
# link the shared hifi library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
# link the stk library
set(STK_ROOT_DIR ${ROOT_DIR}/externals/stk)
find_package(STK REQUIRED)
target_link_libraries(${TARGET_NAME} ${STK_LIBRARIES})
include_directories(${STK_INCLUDE_DIRS})

View file

@ -11,10 +11,18 @@
#include "AvatarAudioRingBuffer.h"
AvatarAudioRingBuffer::AvatarAudioRingBuffer() :
_twoPoles(),
_shouldLoopbackForAgent(false) {
}
AvatarAudioRingBuffer::~AvatarAudioRingBuffer() {
// enumerate the freeVerbs map and delete the FreeVerb objects
for (TwoPoleAgentMap::iterator poleIterator = _twoPoles.begin(); poleIterator != _twoPoles.end(); poleIterator++) {
delete poleIterator->second;
}
}
int AvatarAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
_shouldLoopbackForAgent = (sourceBuffer[0] == PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO);
return PositionalAudioRingBuffer::parseData(sourceBuffer, numBytes);

View file

@ -9,20 +9,29 @@
#ifndef __hifi__AvatarAudioRingBuffer__
#define __hifi__AvatarAudioRingBuffer__
#include <Stk.h>
#include <TwoPole.h>
#include "PositionalAudioRingBuffer.h"
typedef std::map<uint16_t, stk::TwoPole*> TwoPoleAgentMap;
class AvatarAudioRingBuffer : public PositionalAudioRingBuffer {
public:
AvatarAudioRingBuffer();
~AvatarAudioRingBuffer();
int parseData(unsigned char* sourceBuffer, int numBytes);
TwoPoleAgentMap& getTwoPoles() { return _twoPoles; }
bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; }
private:
// disallow copying of AvatarAudioRingBuffer objects
AvatarAudioRingBuffer(const AvatarAudioRingBuffer&);
AvatarAudioRingBuffer& operator= (const AvatarAudioRingBuffer&);
TwoPoleAgentMap _twoPoles;
bool _shouldLoopbackForAgent;
};

View file

@ -24,6 +24,7 @@
#include <AgentTypes.h>
#include <SharedUtil.h>
#include <StdDev.h>
#include <Logstash.h>
#include "InjectedAudioRingBuffer.h"
#include "AvatarAudioRingBuffer.h"
@ -46,7 +47,7 @@ const unsigned short MIXER_LISTEN_PORT = 55443;
const short JITTER_BUFFER_MSECS = 12;
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0);
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000;
const long long BUFFER_SEND_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000);
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
@ -57,7 +58,7 @@ void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) {
long normalizedSample = std::min(MAX_SAMPLE_VALUE, sumSample);
normalizedSample = std::max(MIN_SAMPLE_VALUE, sumSample);
mixSample = normalizedSample;
mixSample = normalizedSample;
}
void attachNewBufferToAgent(Agent *newAgent) {
@ -70,9 +71,20 @@ void attachNewBufferToAgent(Agent *newAgent) {
}
}
bool wantLocalDomain = false;
int main(int argc, const char* argv[]) {
setvbuf(stdout, NULL, _IOLBF, 0);
// Handle Local Domain testing with the --local command line
const char* local = "--local";
::wantLocalDomain = cmdOptionExists(argc, argv,local);
if (::wantLocalDomain) {
printf("Local Domain MODE!\n");
int ip = getLocalAddress();
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
}
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
ssize_t receivedBytes = 0;
@ -100,12 +112,42 @@ int main(int argc, const char* argv[]) {
timeval lastDomainServerCheckIn = {};
timeval beginSendTime, endSendTime;
float sumFrameTimePercentages = 0.0f;
int numStatCollections = 0;
// if we'll be sending stats, call the Logstash::socket() method to make it load the logstash IP outside the loop
if (Logstash::shouldSendStats()) {
Logstash::socket();
}
while (true) {
if (Logstash::shouldSendStats()) {
gettimeofday(&beginSendTime, NULL);
}
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
gettimeofday(&lastDomainServerCheckIn, NULL);
AgentList::getInstance()->sendDomainServerCheckIn();
if (Logstash::shouldSendStats() && numStatCollections > 0) {
// if we should be sending stats to Logstash send the appropriate average now
const char MIXER_LOGSTASH_METRIC_NAME[] = "audio-mixer-frame-time-usage";
// we're sending a floating point percentage with two mandatory numbers after decimal point
// that could be up to 6 bytes
const int MIXER_LOGSTASH_PACKET_BYTES = strlen(MIXER_LOGSTASH_METRIC_NAME) + 7;
char logstashPacket[MIXER_LOGSTASH_PACKET_BYTES];
float averageFrameTimePercentage = sumFrameTimePercentages / numStatCollections;
int packetBytes = sprintf(logstashPacket, "%s %.2f", MIXER_LOGSTASH_METRIC_NAME, averageFrameTimePercentage);
agentList->getAgentSocket()->send(Logstash::socket(), logstashPacket, packetBytes);
sumFrameTimePercentages = 0.0f;
numStatCollections = 0;
}
}
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
@ -136,6 +178,8 @@ int main(int argc, const char* argv[]) {
int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.0f;
stk::TwoPole* otherAgentTwoPole = NULL;
if (otherAgent != agent) {
glm::vec3 listenerPosition = agentRingBuffer->getPosition();
@ -212,6 +256,26 @@ int main(int argc, const char* argv[]) {
float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource)));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
// grab the TwoPole object for this source, add it if it doesn't exist
TwoPoleAgentMap& agentTwoPoles = agentRingBuffer->getTwoPoles();
TwoPoleAgentMap::iterator twoPoleIterator = agentTwoPoles.find(otherAgent->getAgentID());
if (twoPoleIterator == agentTwoPoles.end()) {
// setup the freeVerb effect for this source for this client
otherAgentTwoPole = agentTwoPoles[otherAgent->getAgentID()] = new stk::TwoPole;
} else {
otherAgentTwoPole = twoPoleIterator->second;
}
// calculate the reasonance for this TwoPole based on angle to source
float TWO_POLE_CUT_OFF_FREQUENCY = 800.0f;
float TWO_POLE_MAX_FILTER_STRENGTH = 0.4f;
otherAgentTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
TWO_POLE_MAX_FILTER_STRENGTH
* fabsf(bearingRelativeAngleToSource) / 180.0f,
true);
}
}
@ -237,6 +301,10 @@ int main(int argc, const char* argv[]) {
plateauAdditionOfSamples(delayedChannel[s], earlierSample);
}
if (otherAgentTwoPole) {
otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]);
}
int16_t currentSample = otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient;
plateauAdditionOfSamples(goodChannel[s], currentSample);
@ -318,6 +386,22 @@ int main(int argc, const char* argv[]) {
}
}
if (Logstash::shouldSendStats()) {
// send a packet to our logstash instance
// calculate the percentage value for time elapsed for this send (of the max allowable time)
gettimeofday(&endSendTime, NULL);
float percentageOfMaxElapsed = ((float) (usecTimestamp(&endSendTime) - usecTimestamp(&beginSendTime))
/ BUFFER_SEND_INTERVAL_USECS) * 100.0f;
if (percentageOfMaxElapsed > 0) {
sumFrameTimePercentages += percentageOfMaxElapsed;
}
numStatCollections++;
}
long long usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow();
if (usecToSleep > 0) {

View file

@ -15,8 +15,4 @@ include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
# link the threads library
find_package(Threads REQUIRED)
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})

View file

@ -0,0 +1,45 @@
//
// Logstash.cpp
// hifi
//
// Created by Stephen Birarda on 6/11/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <cstring>
#include <cstdio>
#include <netdb.h>
#include "SharedUtil.h"
#include "Logstash.h"
sockaddr_in Logstash::logstashSocket = {};
sockaddr* Logstash::socket() {
if (logstashSocket.sin_addr.s_addr == 0) {
// we need to construct the socket object
// assume IPv4
logstashSocket.sin_family = AF_INET;
// use the constant port
logstashSocket.sin_port = htons(LOGSTASH_UDP_PORT);
// lookup the IP address for the constant hostname
struct hostent* logstashHostInfo;
if ((logstashHostInfo = gethostbyname(LOGSTASH_HOSTNAME))) {
memcpy(&logstashSocket.sin_addr, logstashHostInfo->h_addr_list[0], logstashHostInfo->h_length);
} else {
printf("Failed to lookup logstash IP - will try again on next log attempt.\n");
}
}
return (sockaddr*) &logstashSocket;
}
bool Logstash::shouldSendStats() {
static bool shouldSendStats = isInEnvironment("production");
return shouldSendStats;
}

View file

@ -0,0 +1,25 @@
//
// Logstash.h
// hifi
//
// Created by Stephen Birarda on 6/11/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__Logstash__
#define __hifi__Logstash__
#include <netinet/in.h>
const int LOGSTASH_UDP_PORT = 9500;
const char LOGSTASH_HOSTNAME[] = "graphite.highfidelity.io";
class Logstash {
public:
static sockaddr* socket();
static bool shouldSendStats();
private:
static sockaddr_in logstashSocket;
};
#endif /* defined(__hifi__Logstash__) */

View file

@ -110,6 +110,15 @@ void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) {
byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11
}
bool isInEnvironment(const char* environment) {
char* environmentString = getenv("HIFI_ENVIRONMENT");
if (environmentString && strcmp(environmentString, environment) == 0) {
return true;
} else {
return false;
}
}
void switchToResourcesParentIfRequired() {
#ifdef __APPLE__

View file

@ -57,6 +57,7 @@ void setAtBit(unsigned char& byte, int bitIndex);
int getSemiNibbleAt(unsigned char& byte, int bitIndex);
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value);
bool isInEnvironment(const char* environment);
void switchToResourcesParentIfRequired();