diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index a26b1a4674..32a6393525 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -33,6 +33,7 @@ bool includeBillboard = true; bool includeBorderTracer = true; bool includeMovingBug = true; bool includeBlinkingVoxel = false; +bool includeDanceFloor = true; const int ANIMATION_LISTEN_PORT = 40107; @@ -392,6 +393,131 @@ static void sendBlinkingStringOfLights() { } } +bool danceFloorInitialized = false; +const float DANCE_FLOOR_LIGHT_SIZE = 1.0f / TREE_SCALE; // approximately 1 meter +const int DANCE_FLOOR_LENGTH = 10; +const int DANCE_FLOOR_WIDTH = 10; +glm::vec3 danceFloorPosition(100.0f / TREE_SCALE, 30.0f / TREE_SCALE, 10.0f / TREE_SCALE); +glm::vec3 danceFloorLights[DANCE_FLOOR_LENGTH][DANCE_FLOOR_WIDTH]; +unsigned char danceFloorOffColor[3] = { 240, 240, 240 }; +const int DANCE_FLOOR_COLORS = 6; + +unsigned char danceFloorOnColorA[DANCE_FLOOR_COLORS][3] = { + { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, + { 0, 191, 255 }, { 0, 250, 154 }, { 255, 69, 0 }, +}; +unsigned char danceFloorOnColorB[DANCE_FLOOR_COLORS][3] = { + { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } , + { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } +}; +float danceFloorGradient = 0.5f; +const float BEATS_PER_MINUTE = 118.0f; +const float SECONDS_PER_MINUTE = 60.0f; +const float FRAMES_PER_BEAT = (SECONDS_PER_MINUTE * ACTUAL_FPS) / BEATS_PER_MINUTE; +float danceFloorGradientIncrement = 1.0f / FRAMES_PER_BEAT; +const float DANCE_FLOOR_MAX_GRADIENT = 1.0f; +const float DANCE_FLOOR_MIN_GRADIENT = 0.0f; +const int DANCE_FLOOR_VOXELS_PER_PACKET = 100; +const int PACKETS_PER_DANCE_FLOOR = DANCE_FLOOR_VOXELS_PER_PACKET / (DANCE_FLOOR_WIDTH * DANCE_FLOOR_LENGTH); +int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH]; + +void sendDanceFloor() { + PACKET_HEADER message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; // we're a bully! + float lightScale = DANCE_FLOOR_LIGHT_SIZE; + static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; + unsigned char* bufferOut; + int sizeOut; + + // first initialized the billboard of lights if needed... + if (!::danceFloorInitialized) { + for (int i = 0; i < DANCE_FLOOR_WIDTH; i++) { + for (int j = 0; j < DANCE_FLOOR_LENGTH; j++) { + + int randomColorIndex = randIntInRange( -(DANCE_FLOOR_COLORS), (DANCE_FLOOR_COLORS + 1)); + ::danceFloorColors[i][j] = randomColorIndex; + ::danceFloorLights[i][j] = ::danceFloorPosition + + glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); + } + } + ::danceFloorInitialized = true; + } + + ::danceFloorGradient += ::danceFloorGradientIncrement; + + if (::danceFloorGradient >= DANCE_FLOOR_MAX_GRADIENT) { + ::danceFloorGradient = DANCE_FLOOR_MAX_GRADIENT; + ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; + } + if (::danceFloorGradient <= DANCE_FLOOR_MIN_GRADIENT) { + ::danceFloorGradient = DANCE_FLOOR_MIN_GRADIENT; + ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; + } + + for (int i = 0; i < DANCE_FLOOR_LENGTH; i++) { + for (int j = 0; j < DANCE_FLOOR_WIDTH; j++) { + + int nthVoxel = ((i * DANCE_FLOOR_WIDTH) + j); + int item = nthVoxel % DANCE_FLOOR_VOXELS_PER_PACKET; + + ::danceFloorLights[i][j] = ::danceFloorPosition + + glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); + + details[item].s = lightScale; + details[item].x = ::danceFloorLights[i][j].x; + details[item].y = ::danceFloorLights[i][j].y; + details[item].z = ::danceFloorLights[i][j].z; + + if (danceFloorColors[i][j] > 0) { + int color = danceFloorColors[i][j] - 1; + details[item].red = (::danceFloorOnColorA[color][0] + + ((::danceFloorOnColorB[color][0] - ::danceFloorOnColorA[color][0]) + * ::danceFloorGradient)); + details[item].green = (::danceFloorOnColorA[color][1] + + ((::danceFloorOnColorB[color][1] - ::danceFloorOnColorA[color][1]) + * ::danceFloorGradient)); + details[item].blue = (::danceFloorOnColorA[color][2] + + ((::danceFloorOnColorB[color][2] - ::danceFloorOnColorA[color][2]) + * ::danceFloorGradient)); + } else if (::danceFloorColors[i][j] < 0) { + int color = -(::danceFloorColors[i][j] + 1); + details[item].red = (::danceFloorOnColorB[color][0] + + ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) + * ::danceFloorGradient)); + details[item].green = (::danceFloorOnColorB[color][1] + + ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) + * ::danceFloorGradient)); + details[item].blue = (::danceFloorOnColorB[color][2] + + ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) + * ::danceFloorGradient)); + } else { + int color = 0; + details[item].red = (::danceFloorOnColorB[color][0] + + ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) + * ::danceFloorGradient)); + details[item].green = (::danceFloorOnColorB[color][1] + + ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) + * ::danceFloorGradient)); + details[item].blue = (::danceFloorOnColorB[color][2] + + ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) + * ::danceFloorGradient)); + } + + if (item == DANCE_FLOOR_VOXELS_PER_PACKET - 1) { + if (createVoxelEditMessage(message, 0, DANCE_FLOOR_VOXELS_PER_PACKET, + (VoxelDetail*)&details, bufferOut, sizeOut)){ + ::packetsSent++; + ::bytesSent += sizeOut; + if (::shouldShowPacketsPerSecond) { + printf("sending packet of size=%d\n", sizeOut); + } + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + delete[] bufferOut; + } + } + } + } +} + bool billboardInitialized = false; const int BILLBOARD_HEIGHT = 9; const int BILLBOARD_WIDTH = 45; @@ -405,7 +531,7 @@ float billboardGradientIncrement = 0.01f; const float BILLBOARD_MAX_GRADIENT = 1.0f; const float BILLBOARD_MIN_GRADIENT = 0.0f; const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light -const int VOXELS_PER_PACKET = 135; +const int VOXELS_PER_PACKET = 100; const int PACKETS_PER_BILLBOARD = VOXELS_PER_PACKET / (BILLBOARD_HEIGHT * BILLBOARD_WIDTH); @@ -514,6 +640,9 @@ void* animateVoxels(void* args) { if (::includeBlinkingVoxel) { sendVoxelBlinkMessage(); } + if (::includeDanceFloor) { + sendDanceFloor(); + } double end = usecTimestampNow(); double elapsedSeconds = (end - ::start) / 1000000.0; @@ -555,6 +684,9 @@ int main(int argc, const char * argv[]) const char* INCLUDE_BLINKING_VOXEL = "--includeBlinkingVoxel"; ::includeBlinkingVoxel = cmdOptionExists(argc, argv, INCLUDE_BLINKING_VOXEL); + const char* NO_DANCE_FLOOR = "--NoDanceFloor"; + ::includeDanceFloor = !cmdOptionExists(argc, argv, NO_DANCE_FLOOR); + // Handle Local Domain testing with the --local command line const char* showPPS = "--showPPS"; ::shouldShowPacketsPerSecond = cmdOptionExists(argc, argv, showPPS); diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index e4a4f83b07..982ebc526c 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -55,7 +55,7 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); -const float DISTANCE_RATIO = 3.0f / 0.3f; +const float DISTANCE_SCALE = 2.5f; const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; const int PHASE_DELAY_AT_90 = 20; @@ -166,8 +166,8 @@ int main(int argc, const char* argv[]) { powf(agentPosition.z - otherAgentPosition.z, 2)); float minCoefficient = std::min(1.0f, - powf(0.5, - (logf(DISTANCE_RATIO * distanceToAgent) / logf(2.5)) + powf(0.3, + (logf(DISTANCE_SCALE * distanceToAgent) / logf(2.5)) - 1)); distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; } @@ -214,8 +214,8 @@ int main(int argc, const char* argv[]) { (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] - * otherAgentBuffer->getAttenuationRatio() - * offAxisCoefficient; + * otherAgentBuffer->getAttenuationRatio() + * offAxisCoefficient; bearingRelativeAngleToSource *= (M_PI / 180); @@ -225,15 +225,15 @@ int main(int argc, const char* argv[]) { } int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f - ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL - : clientSamples; + ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL + : clientSamples; int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f - ? clientSamples - : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + ? clientSamples + : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer() - ? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay - : otherAgentBuffer->getNextOutput() - numSamplesDelay; + ? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay + : otherAgentBuffer->getNextOutput() - numSamplesDelay; for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { @@ -246,7 +246,7 @@ int main(int argc, const char* argv[]) { int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient); plateauAdditionOfSamples(goodChannel[s], currentSample); - if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { + if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay], currentSample * weakChannelAmplitudeRatio); } @@ -287,6 +287,11 @@ int main(int argc, const char* argv[]) { } agentList->updateAgentWithData(agentAddress, packetData, receivedBytes); + + if (std::isnan(((AudioRingBuffer *)avatarAgent->getLinkedData())->getBearing())) { + // kill off this agent - temporary solution to mixer crash on mac sleep + avatarAgent->setAlive(false); + } } else if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) { Agent* matchingInjector = NULL; diff --git a/avatar-mixer/src/main.cpp b/avatar-mixer/src/main.cpp index eca698e673..89861ddcc8 100644 --- a/avatar-mixer/src/main.cpp +++ b/avatar-mixer/src/main.cpp @@ -84,7 +84,7 @@ int main(int argc, const char* argv[]) { // parse positional data from an agent agentList->updateAgentWithData(avatarAgent, packetData, receivedBytes); - + case PACKET_HEADER_INJECT_AUDIO: currentBufferPosition = broadcastPacket + 1; // send back a packet with other active agent data to this agent diff --git a/eve/src/main.cpp b/eve/src/main.cpp index bf32474b33..c670be050e 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -204,6 +204,4 @@ int main(int argc, const char* argv[]) { agentList->stopDomainServerCheckInThread(); agentList->stopPingUnknownAgentsThread(); agentList->stopSilentAgentRemovalThread(); -} - - +} \ No newline at end of file diff --git a/injector/CMakeLists.txt b/injector/CMakeLists.txt index ba3393956a..2c022b0e92 100644 --- a/injector/CMakeLists.txt +++ b/injector/CMakeLists.txt @@ -18,4 +18,5 @@ 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}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/injector/src/main.cpp b/injector/src/main.cpp index df751f50a1..32a8442d8f 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -14,14 +14,16 @@ #include #include +#include +#include +#include #include #include #include #include #include -char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53"; -const int AUDIO_UDP_LISTEN_PORT = 55443; +const int AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15; const int DEFAULT_INJECTOR_VOLUME = 0xFF; @@ -30,12 +32,12 @@ bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":rb::t::c::a::f:"; +const char *allowedParameters = ":rb::t::c::a::f::d:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; +float triggerDistance = 0; -void usage(void) -{ +void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; std::cout << " -r Random sleep mode. If not specified will default to constant loop." << std::endl; std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl; @@ -43,10 +45,10 @@ void usage(void) std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; + std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; } -bool processParameters(int parameterCount, char* parameterData[]) -{ +bool processParameters(int parameterCount, char* parameterData[]) { int p; while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { switch (p) { @@ -86,6 +88,10 @@ bool processParameters(int parameterCount, char* parameterData[]) ::volume = atoi(optarg); std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; break; + case 'd': + ::triggerDistance = atof(optarg); + std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; + break; default: usage(); return false; @@ -94,45 +100,149 @@ bool processParameters(int parameterCount, char* parameterData[]) return true; }; -int main(int argc, char* argv[]) { +bool stopReceiveAgentDataThread; +void *receiveAgentData(void *args) { + sockaddr senderAddress; + ssize_t bytesReceived; + unsigned char incomingPacket[MAX_PACKET_SIZE]; + + AgentList* agentList = AgentList::getInstance(); + + while (!::stopReceiveAgentDataThread) { + if (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { + switch (incomingPacket[0]) { + case PACKET_HEADER_BULK_AVATAR_DATA: + // this is the positional data for other agents + // pass that off to the agentList processBulkAgentData method + agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived); + break; + default: + // have the agentList handle list of agents from DS, replies from other agents, etc. + agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived); + break; + } + } + } + + pthread_exit(0); + return NULL; +} + +void createAvatarDataForAgent(Agent* agent) { + if (!agent->getLinkedData()) { + agent->setLinkedData(new AvatarData(agent)); + } +} + +int main(int argc, char* argv[]) { + // new seed for random audio sleep times srand(time(0)); + int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1)); - UDPSocket streamSocket(AUDIO_UDP_SEND_PORT); - - sockaddr_in mixerSocket; - mixerSocket.sin_family = AF_INET; - mixerSocket.sin_addr.s_addr = inet_addr(EC2_WEST_AUDIO_SERVER); - mixerSocket.sin_port = htons((uint16_t)AUDIO_UDP_LISTEN_PORT); - - - if (processParameters(argc, argv)) { + if (processParameters(argc, argv)) { if (::sourceAudioFile == NULL) { std::cout << "[FATAL] Source audio file not specified" << std::endl; exit(-1); } else { AudioInjector injector(sourceAudioFile); + // create an AgentList instance to handle communication with other agents + AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT); + + pthread_t receiveAgentDataThread; + pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL); + + // start telling the domain server that we are alive + agentList->startDomainServerCheckInThread(); + + // start the agent list thread that will kill off agents when they stop talking + agentList->startSilentAgentRemovalThread(); + injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); injector.setBearing(*(::floatArguments + 3)); injector.setVolume(::volume); - - float delay = 0; - int usecDelay = 0; + + // register the callback for agent data creation + agentList->linkedDataCreateCallback = createAvatarDataForAgent; + + unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO; + + timeval thisSend; + double numMicrosecondsSleep = 0; while (true) { - injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket); - - if (!::loopAudio) { - delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); - usecDelay = delay * 1000 * 1000; - usleep(usecDelay); + if (::triggerDistance) { + + // update the thisSend timeval to the current time + gettimeofday(&thisSend, NULL); + + // find the current avatar mixer + Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); + + // make sure we actually have an avatar mixer with an active socket + if (avatarMixer && avatarMixer->getActiveSocket() != NULL) { + // use the UDPSocket instance attached to our agent list to ask avatar mixer for a list of avatars + agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(), + &broadcastPacket, + sizeof(broadcastPacket)); + } + + if (!injector.isInjectingAudio()) { + // enumerate the other agents to decide if one is close enough that we should inject + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + AvatarData* avatarData = (AvatarData*) agent->getLinkedData(); + + if (avatarData) { + glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition(); + float squareDistance = glm::dot(tempVector, tempVector); + + if (squareDistance <= ::triggerDistance) { + // look for an audio mixer in our agent list + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + // we have an active audio mixer we can send data to + AudioInjectionManager::threadInjector(&injector); + } + } + } + } + } + + // sleep for the correct amount of time to have data send be consistently timed + if ((numMicrosecondsSleep = (AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS * 1000) - + (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { + usleep(numMicrosecondsSleep); + } + } else { + // look for an audio mixer in our agent list + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + injector.injectAudio(agentList->getAgentSocket(), audioMixer->getActiveSocket()); + } + + float delay = 0; + int usecDelay = 0; + + if (!::loopAudio) { + delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); + usecDelay = delay * 1000 * 1000; + usleep(usecDelay); + } } } - } + + // stop the receive agent data thread + stopReceiveAgentDataThread = true; + pthread_join(receiveAgentDataThread, NULL); + + // stop the agent list's threads + agentList->stopDomainServerCheckInThread(); + agentList->stopSilentAgentRemovalThread(); + } } - return 0; } - diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80d095329d..dedfe315b1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -954,11 +954,7 @@ void Application::pair() { PairingHandler::sendPairRequest(); } -void Application::setHead(bool head) { - #ifndef _WIN32 - _audio.setMixerLoopbackFlag(head); - #endif - +void Application::setHead(bool head) { if (head) { _myCamera.setMode(CAMERA_MODE_MIRROR); _myCamera.setModeShiftRate(100.0f); @@ -1115,13 +1111,15 @@ void Application::initMenu() { _window->setMenuBar(menuBar); QMenu* fileMenu = menuBar->addMenu("File"); - fileMenu->addAction("Quit", this, SLOT(quit()), Qt::Key_Q); + fileMenu->addAction("Quit", this, SLOT(quit()), (Qt::Key_Q || Qt::Key_Control)); QMenu* pairMenu = menuBar->addMenu("Pair"); pairMenu->addAction("Pair", this, SLOT(pair())); QMenu* optionsMenu = menuBar->addMenu("Options"); (_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setHead(bool)), Qt::Key_H))->setCheckable(true); + (_echoAudioMode = optionsMenu->addAction("Echo Audio"))->setCheckable(true); + optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N)->setCheckable(true); (_gyroLook = optionsMenu->addAction("Gyro Look"))->setCheckable(true); _gyroLook->setChecked(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index 35d49d275a..f611a803b9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -13,6 +13,7 @@ #include #include +#include #include @@ -64,6 +65,7 @@ public: Avatar* getAvatar() { return &_myAvatar; } VoxelSystem* getVoxels() { return &_voxels; } Environment* getEnvironment() { return &_environment; } + bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } private slots: @@ -137,7 +139,8 @@ private: QMainWindow* _window; QGLWidget* _glWidget; - QAction* _lookingInMirror; // Are we currently rendering one's own head as if in mirror? + QAction* _lookingInMirror; // Are we currently rendering one's own head as if in mirror? + QAction* _echoAudioMode; // Are we asking the mixer to echo back our audio? QAction* _gyroLook; // Whether to allow the gyro data from head to move your view QAction* _mouseLook; // Whether the have the mouse near edge of screen move your view QAction* _showHeadMouse; // Whether the have the mouse near edge of screen move your view diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8acb70ebcc..97929a99ca 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -158,10 +158,10 @@ int audioCallback (const void* inputBuffer, correctedYaw += 360; } - if (parentAudio->_mixerLoopbackFlag) { + if (Application::getInstance()->shouldEchoAudio()) { correctedYaw = correctedYaw > 0 - ? correctedYaw + AGENT_LOOPBACK_MODIFIER - : correctedYaw - AGENT_LOOPBACK_MODIFIER; + ? correctedYaw + AGENT_LOOPBACK_MODIFIER + : correctedYaw - AGENT_LOOPBACK_MODIFIER; } memcpy(currentPacketPtr, &correctedYaw, sizeof(float)); @@ -310,7 +310,6 @@ Audio::Audio(Oscilloscope* scope) : NUM_AUDIO_CHANNELS * (SAMPLE_RATE / 1000.0)), _wasStarved(0), _lastInputLoudness(0), - _mixerLoopbackFlag(false), _lastVelocity(0), _lastAcceleration(0), _totalPacketsReceived(0), diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 34a342a1d4..197daf0194 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -24,8 +24,6 @@ public: void render(int screenWidth, int screenHeight); - void setMixerLoopbackFlag(bool mixerLoopbackFlag) { _mixerLoopbackFlag = mixerLoopbackFlag; } - float getLastInputLoudness() const { return _lastInputLoudness; }; void setLastAcceleration(glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; }; @@ -52,7 +50,6 @@ private: short _jitterBufferSamples; int _wasStarved; float _lastInputLoudness; - bool _mixerLoopbackFlag; glm::vec3 _lastVelocity; glm::vec3 _lastAcceleration; int _totalPacketsReceived; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 766109255f..27e9df1679 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -476,7 +476,14 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { glm::quat orientation = getOrientation(); // reset hand and arm positions according to hand movement - glm::vec3 transformedHandMovement = orientation * (_movedHandOffset * glm::vec3(-2.0f, -1.0f, -1.0f)); + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; + + glm::vec3 transformedHandMovement + = right * _movedHandOffset.x * 2.0f + + up * -_movedHandOffset.y * 2.0f + + front * -_movedHandOffset.y * 2.0f; _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement; @@ -1139,8 +1146,12 @@ void Avatar::renderBody(bool lookingInMirror) { float alpha = lookingInMirror ? 1.0f : glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); + if (lookingInMirror || _owningAgent) { + alpha = 1.0f; + } + // Always render other people, and render myself when beyond threshold distance - if (b == AVATAR_JOINT_HEAD_BASE) { // the head is rendered as a special case + if (b == AVATAR_JOINT_HEAD_BASE) { // the head is rendered as a special if (lookingInMirror || _owningAgent || distanceToCamera > RENDER_OPAQUE_BEYOND * 0.5) { _head.render(lookingInMirror, _cameraPosition, alpha); } diff --git a/interface/src/AvatarTouch.cpp b/interface/src/AvatarTouch.cpp index 9ca1e33b57..58da2c3241 100644 --- a/interface/src/AvatarTouch.cpp +++ b/interface/src/AvatarTouch.cpp @@ -13,7 +13,7 @@ const float THREAD_RADIUS = 0.007; const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.2; -const float AVATAR_FACING_THRESHOLD = 0.1f; // (-1 to 1) (larger value indicates narrower angle of influence +const float AVATAR_FACING_THRESHOLD = -0.5f; // (-1 to 1) (larger value indicates narrower angle of influence AvatarTouch::AvatarTouch() { @@ -55,8 +55,7 @@ void AvatarTouch::simulate (float deltaTime) { facingEachOther = true; } - if ((distanceBetweenBodies < _reachableRadius) - && (facingEachOther)) { + if (distanceBetweenBodies < _reachableRadius) { _canReachToOtherAvatar = true; _vectorBetweenHands = _yourHandPosition - _myHandPosition; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 547d732f3b..c04ddfb9ed 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -42,8 +42,8 @@ vector irisTexture; Head::Head(Avatar* owningAvatar) : HeadData((AvatarData*)owningAvatar), - _renderAlpha(0.0), yawRate(0.0f), + _renderAlpha(0.0), _returnHeadToCenter(false), _skinColor(0.0f, 0.0f, 0.0f), _position(0.0f, 0.0f, 0.0f), @@ -364,7 +364,9 @@ void Head::renderMouth() { glm::vec3 rightBottom = _mouthPosition + r * 0.4f - u * 1.0f + f * 0.7f; // constrain all mouth vertices to a sphere slightly larger than the head... - float constrainedRadius = _scale + 0.001f; + const float MOUTH_OFFSET_OFF_FACE = 0.003f; + + float constrainedRadius = _scale + MOUTH_OFFSET_OFF_FACE; middle = _position + glm::normalize(middle - _position) * constrainedRadius; leftCorner = _position + glm::normalize(leftCorner - _position) * constrainedRadius; rightCorner = _position + glm::normalize(rightCorner - _position) * constrainedRadius; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index ea8787a902..5e1b72e5c4 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -887,11 +887,14 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { bool VoxelSystem::isViewChanging() { bool result = false; // assume the best + +/** TEMPORARY HACK ****** // If our viewFrustum has changed since our _lastKnowViewFrustum if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) { result = true; _lastKnowViewFrustum = *_viewFrustum; // save last known } +**/ return result; } diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index 275161730e..f8fc9f742f 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -58,7 +58,11 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) { // if we don't have an explicit destination socket then pull active socket for current audio mixer from agent list if (!_isDestinationSocketExplicit) { - _destinationSocket = *AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER)->getActiveSocket(); + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + _destinationSocket = *audioMixer->getActiveSocket(); + } } injector->injectAudio(_injectorSocket, &_destinationSocket); diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 299ffcc2cb..006dd825bf 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -7,6 +7,7 @@ // #include +#include #include "PacketHeaders.h" @@ -56,7 +57,12 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { memcpy(&_bearing, dataBuffer, sizeof(float)); dataBuffer += sizeof(_bearing); - if (_bearing > 180 || _bearing < -180) { + // if this agent sent us a NaN bearing then don't consider this good audio and bail + if (std::isnan(_bearing)) { + _endOfLastWrite = _nextOutput = _buffer; + _started = false; + return 0; + } else if (_bearing > 180 || _bearing < -180) { // we were passed an invalid bearing because this agent wants loopback (pressed the H key) _shouldLoopbackForAgent = true; @@ -66,7 +72,7 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { : _bearing + AGENT_LOOPBACK_MODIFIER; } else { _shouldLoopbackForAgent = false; - } + } } // make sure we have enough bytes left for this to be the right amount of audio diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 170b86147b..2b28ac620d 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -250,7 +250,8 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket if (agent->getType() == AGENT_TYPE_AUDIO_MIXER || agent->getType() == AGENT_TYPE_VOXEL || - agent->getType() == AGENT_TYPE_ANIMATION_SERVER) { + agent->getType() == AGENT_TYPE_ANIMATION_SERVER || + agent->getType() == AGENT_TYPE_AUDIO_INJECTOR) { // until the Audio class also uses our agentList, we need to update // the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously agent->setLastHeardMicrostamp(usecTimestampNow());