diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 6b63075da5..444edd1393 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -94,11 +94,16 @@ int main(int argc, const char* argv[]) { sockaddr* agentAddress = new sockaddr; // make sure our agent socket is non-blocking - agentList->getAgentSocket().setBlocking(false); + agentList->getAgentSocket()->setBlocking(false); int nextFrame = 0; timeval startTime; + unsigned char clientPacket[BUFFER_LENGTH_BYTES + 1]; + clientPacket[0] = PACKET_HEADER_MIXED_AUDIO; + + int16_t clientSamples[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {}; + gettimeofday(&startTime, NULL); while (true) { @@ -109,10 +114,10 @@ int main(int argc, const char* argv[]) { if (agentBuffer->getEndOfLastWrite()) { if (!agentBuffer->isStarted() && agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES_PER_CHANNEL + JITTER_BUFFER_SAMPLES) { - printf("Held back buffer for agent with ID %d.\n", agent->getAgentId()); + printf("Held back buffer for agent with ID %d.\n", agent->getAgentID()); agentBuffer->setShouldBeAddedToMix(false); } else if (agentBuffer->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { - printf("Buffer from agent with ID %d starved.\n", agent->getAgentId()); + printf("Buffer from agent with ID %d starved.\n", agent->getAgentID()); agentBuffer->setStarted(false); agentBuffer->setShouldBeAddedToMix(false); } else { @@ -129,8 +134,9 @@ int main(int argc, const char* argv[]) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData(); - - int16_t clientMix[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {}; + + // zero out the client mix for this agent + memset(clientSamples, 0, sizeof(clientSamples)); for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) { if (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent())) { @@ -143,9 +149,7 @@ int main(int argc, const char* argv[]) { int numSamplesDelay = 0; float weakChannelAmplitudeRatio = 1.f; - if (otherAgent != agent) { - printf("DEBUG: The bearing for this agent is %f\n", agentRingBuffer->getBearing()); - + if (otherAgent != agent) { Position agentPosition = agentRingBuffer->getPosition(); Position otherAgentPosition = otherAgentBuffer->getPosition(); @@ -219,11 +223,11 @@ int main(int argc, const char* argv[]) { } int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f - ? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL - : clientMix; + ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL + : clientSamples; int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f - ? clientMix - : clientMix + 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 @@ -249,7 +253,8 @@ int main(int argc, const char* argv[]) { } } - agentList->getAgentSocket().send(agent->getPublicSocket(), clientMix, BUFFER_LENGTH_BYTES); + memcpy(clientPacket + 1, clientSamples, sizeof(clientSamples)); + agentList->getAgentSocket()->send(agent->getPublicSocket(), clientPacket, BUFFER_LENGTH_BYTES + 1); } // push forward the next output pointers for any audio buffers we used @@ -267,10 +272,13 @@ int main(int argc, const char* argv[]) { } // pull any new audio data from agents off of the network stack - while (agentList->getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) { - if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) { + while (agentList->getAgentSocket()->receive(agentAddress, packetData, &receivedBytes)) { + if (packetData[0] == PACKET_HEADER_INJECT_AUDIO || packetData[0] == PACKET_HEADER_MICROPHONE_AUDIO) { + char agentType = (packetData[0] == PACKET_HEADER_MICROPHONE_AUDIO) + ? AGENT_TYPE_AVATAR + : AGENT_TYPE_AUDIO_INJECTOR; - if (agentList->addOrUpdateAgent(agentAddress, agentAddress, packetData[0], agentList->getLastAgentID())) { + if (agentList->addOrUpdateAgent(agentAddress, agentAddress, agentType, agentList->getLastAgentID())) { agentList->increaseAgentID(); } diff --git a/avatar-mixer/src/main.cpp b/avatar-mixer/src/main.cpp index 2f031a6f0a..d51e48b055 100644 --- a/avatar-mixer/src/main.cpp +++ b/avatar-mixer/src/main.cpp @@ -37,7 +37,7 @@ const int AVATAR_LISTEN_PORT = 55444; unsigned char *addAgentToBroadcastPacket(unsigned char *currentPosition, Agent *agentToAdd) { - currentPosition += packAgentId(currentPosition, agentToAdd->getAgentId()); + currentPosition += packAgentId(currentPosition, agentToAdd->getAgentID()); AvatarData *agentData = (AvatarData *)agentToAdd->getLinkedData(); currentPosition += agentData->getBroadcastData(currentPosition); @@ -72,7 +72,7 @@ int main(int argc, const char* argv[]) { uint16_t agentID = 0; while (true) { - if (agentList->getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) { + if (agentList->getAgentSocket()->receive(agentAddress, packetData, &receivedBytes)) { switch (packetData[0]) { case PACKET_HEADER_HEAD_DATA: // grab the agent ID from the packet @@ -93,7 +93,7 @@ int main(int argc, const char* argv[]) { } } - agentList->getAgentSocket().send(agentAddress, broadcastPacket, currentBufferPosition - broadcastPacket); + agentList->getAgentSocket()->send(agentAddress, broadcastPacket, currentBufferPosition - broadcastPacket); break; case PACKET_HEADER_DOMAIN: diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index be906e194d..959456bd03 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -50,7 +50,7 @@ int lastActiveCount = 0; unsigned char* addAgentToBroadcastPacket(unsigned char* currentPosition, Agent* agentToAdd) { *currentPosition++ = agentToAdd->getType(); - currentPosition += packAgentId(currentPosition, agentToAdd->getAgentId()); + currentPosition += packAgentId(currentPosition, agentToAdd->getAgentID()); currentPosition += packSocket(currentPosition, agentToAdd->getPublicSocket()); currentPosition += packSocket(currentPosition, agentToAdd->getLocalSocket()); @@ -97,7 +97,7 @@ int main(int argc, const char * argv[]) uint16_t packetAgentID = 0; while (true) { - if (agentList->getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) && + if (agentList->getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) && (packetData[0] == PACKET_HEADER_DOMAIN_RFD || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) { std::map newestSoloAgents; @@ -149,7 +149,7 @@ int main(int argc, const char * argv[]) agent->setLastHeardMicrostamp(timeNow); // grab the ID for this agent so we can send it back with the packet - packetAgentID = agent->getAgentId(); + packetAgentID = agent->getAgentID(); if (packetData[0] == PACKET_HEADER_DOMAIN_RFD && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { @@ -169,7 +169,7 @@ int main(int argc, const char * argv[]) currentBufferPos += packAgentId(currentBufferPos, packetAgentID); // send the constructed list back to this agent - agentList->getAgentSocket().send((sockaddr*) &agentPublicAddress, + agentList->getAgentSocket()->send((sockaddr*) &agentPublicAddress, broadcastPacket, (currentBufferPos - startPointer) + 1); } diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 4345da12a2..733bd2b715 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -6,7 +6,9 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include #include +#include #include #include @@ -34,10 +36,6 @@ const float EVE_PELVIS_HEIGHT = 0.565925f; const float AUDIO_INJECT_PROXIMITY = 0.4f; bool stopReceiveAgentDataThread; -bool injectAudioThreadRunning = false; - -int TEMP_AUDIO_LISTEN_PORT = 55439; -UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT); void *receiveAgentData(void *args) { sockaddr senderAddress; @@ -47,7 +45,7 @@ void *receiveAgentData(void *args) { AgentList* agentList = AgentList::getInstance(); while (!::stopReceiveAgentDataThread) { - if (agentList->getAgentSocket().receive(&senderAddress, incomingPacket, &bytesReceived)) { + if (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { switch (incomingPacket[0]) { case PACKET_HEADER_BULK_AVATAR_DATA: // this is the positional data for other agents @@ -67,29 +65,6 @@ void *receiveAgentData(void *args) { return NULL; } -void *injectAudio(void *args) { - ::injectAudioThreadRunning = true; - - AudioInjector* eveAudioInjector = (AudioInjector *)args; - - // look for an audio mixer in our agent list - Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); - - if (audioMixer) { - // until the audio mixer is setup for ping-reply, activate the public socket if it's not active - if (!audioMixer->getActiveSocket()) { - audioMixer->activatePublicSocket(); - } - - // we have an active audio mixer we can send data to - eveAudioInjector->injectAudio(&::audioSocket, audioMixer->getActiveSocket()); - } - - ::injectAudioThreadRunning = false; - pthread_exit(0); - return NULL; -} - void createAvatarDataForAgent(Agent* agent) { if (!agent->getLinkedData()) { agent->setLinkedData(new AvatarData()); @@ -138,6 +113,14 @@ int main(int argc, const char* argv[]) { // lower Eve's volume by setting the attentuation modifier (this is a value out of 255) eveAudioInjector.setAttenuationModifier(190); + // pass the agentList UDPSocket pointer to the audio injector + eveAudioInjector.setInjectorSocket(agentList->getAgentSocket()); + + // set the position of the audio injector + float injectorPosition[3]; + memcpy(injectorPosition, &eve.getPosition(), sizeof(injectorPosition)); + eveAudioInjector.setPosition(injectorPosition); + // register the callback for agent data creation agentList->linkedDataCreateCallback = createAvatarDataForAgent; @@ -146,8 +129,6 @@ int main(int argc, const char* argv[]) { timeval thisSend; double numMicrosecondsSleep = 0; - - pthread_t injectAudioThread; int handStateTimer = 0; @@ -167,10 +148,10 @@ int main(int argc, const char* argv[]) { packetPosition += eve.getBroadcastData(packetPosition); // use the UDPSocket instance attached to our agent list to send avatar data to mixer - agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, packetPosition - broadcastPacket); - } + agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(), broadcastPacket, packetPosition - broadcastPacket); + } - if (!::injectAudioThreadRunning) { + if (!eveAudioInjector.isInjectingAudio()) { // enumerate the other agents to decide if one is close enough that eve should talk for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { AvatarData* avatarData = (AvatarData*) agent->getLinkedData(); @@ -180,7 +161,20 @@ int main(int argc, const char* argv[]) { float squareDistance = glm::dot(tempVector, tempVector); if (squareDistance <= AUDIO_INJECT_PROXIMITY) { - pthread_create(&injectAudioThread, NULL, injectAudio, (void*) &eveAudioInjector); + // look for an audio mixer in our agent list + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + // until the audio mixer is setup for ping-reply, activate the public socket if it's not active + if (!audioMixer->getActiveSocket()) { + audioMixer->activatePublicSocket(); + } + + eveAudioInjector.setDestinationSocket(audioMixer->getActiveSocket()); + + // we have an active audio mixer we can send data to + eveAudioInjector.threadInjectionOfAudio(); + } } } } diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 028de6cb04..dee09de6c8 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -104,6 +104,7 @@ int main(int argc, char* argv[]) { 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 (::sourceAudioFile == NULL) { @@ -111,6 +112,8 @@ int main(int argc, char* argv[]) { exit(-1); } else { AudioInjector injector(sourceAudioFile); + injector.setInjectorSocket(&streamSocket); + injector.setDestinationSocket((sockaddr*) &mixerSocket); injector.setPosition(::floatArguments); injector.setBearing(*(::floatArguments + 3)); @@ -120,7 +123,7 @@ int main(int argc, char* argv[]) { int usecDelay = 0; while (true) { - injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket); + injector.injectAudio(); if (!::loopAudio) { delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); diff --git a/interface/Interface.icns b/interface/Interface.icns deleted file mode 100644 index 0ef217a4e2..0000000000 Binary files a/interface/Interface.icns and /dev/null differ diff --git a/interface/interface.icns b/interface/interface.icns new file mode 100644 index 0000000000..f32590eb21 Binary files /dev/null and b/interface/interface.icns differ diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag index 9f6cc39f1b..37d26ba40a 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.frag +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -1,3 +1,5 @@ +#version 120 + // // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // @@ -30,8 +32,6 @@ // Copyright (c) 2004 Sean O'Neil // -#version 120 - uniform vec3 v3LightPos; uniform float g; uniform float g2; diff --git a/interface/resources/shaders/SkyFromAtmosphere.vert b/interface/resources/shaders/SkyFromAtmosphere.vert index 2587d262a2..90fcbc5281 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.vert +++ b/interface/resources/shaders/SkyFromAtmosphere.vert @@ -1,3 +1,5 @@ +#version 120 + // // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // @@ -30,8 +32,6 @@ // Copyright (c) 2004 Sean O'Neil // -#version 120 - uniform vec3 v3CameraPos; // The camera's current position uniform vec3 v3LightPos; // The direction vector to the light source uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels diff --git a/interface/resources/shaders/SkyFromSpace.frag b/interface/resources/shaders/SkyFromSpace.frag index be872c5dbd..b40dc98bd8 100644 --- a/interface/resources/shaders/SkyFromSpace.frag +++ b/interface/resources/shaders/SkyFromSpace.frag @@ -1,3 +1,5 @@ +#version 120 + // // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // @@ -30,8 +32,6 @@ // Copyright (c) 2004 Sean O'Neil // -#version 120 - uniform vec3 v3LightPos; uniform float g; uniform float g2; diff --git a/interface/resources/shaders/SkyFromSpace.vert b/interface/resources/shaders/SkyFromSpace.vert index d230ee8518..2a9907565f 100644 --- a/interface/resources/shaders/SkyFromSpace.vert +++ b/interface/resources/shaders/SkyFromSpace.vert @@ -1,3 +1,5 @@ +#version 120 + // // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // @@ -30,8 +32,6 @@ // Copyright (c) 2004 Sean O'Neil // -#version 120 - uniform vec3 v3CameraPos; // The camera's current position uniform vec3 v3LightPos; // The direction vector to the light source uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6efa88ad58..aa86310cad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -18,6 +18,7 @@ #include #endif +#include #include #include #include @@ -143,18 +144,16 @@ Application::Application(int& argc, char** argv) : _mouseX(0), _mouseY(0), _mousePressed(false), - _mouseMode(NO_EDIT_MODE), _mouseVoxelScale(1.0f / 1024.0f), _paintOn(false), _dominantColor(0), _perfStatsOn(false), - _destructiveAddVoxel(false), _chatEntryOn(false), _oculusTextureID(0), _oculusProgram(0), _oculusDistortionScale(1.25), #ifndef _WIN32 - _audio(&_audioScope, &_myAvatar), + _audio(&_audioScope), #endif _stopNetworkReceiveThread(false), _packetCount(0), @@ -180,7 +179,7 @@ Application::Application(int& argc, char** argv) : AgentList::createInstance(AGENT_TYPE_AVATAR, listenPort); _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking"); if (!_enableNetworkThread) { - AgentList::getInstance()->getAgentSocket().setBlocking(false); + AgentList::getInstance()->getAgentSocket()->setBlocking(false); } const char* domainIP = getCmdOption(argc, constArgv, "--domain"); @@ -202,10 +201,6 @@ Application::Application(int& argc, char** argv) : // the callback for our instance of AgentList is attachNewHeadToAgent AgentList::getInstance()->linkedDataCreateCallback = &attachNewHeadToAgent; - #ifndef _WIN32 - AgentList::getInstance()->audioMixerSocketUpdate = &audioMixerUpdate; - #endif - #ifdef _WIN32 WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData); @@ -235,8 +230,11 @@ Application::Application(int& argc, char** argv) : void Application::initializeGL() { printLog( "Created Display Window.\n" ); + // initialize glut for shape drawing; Qt apparently initializes it on OS X + #ifndef __APPLE__ int argc = 0; glutInit(&argc, 0); + #endif #ifdef _WIN32 glewInit(); @@ -375,7 +373,8 @@ void Application::paintGL() { glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - GLfloat light_position0[] = { 1.0, 1.0, 0.0, 0.0 }; + glm::vec3 relativeSunLoc = glm::normalize(_environment.getSunLocation() - whichCamera.getPosition()); + GLfloat light_position0[] = { relativeSunLoc.x, relativeSunLoc.y, relativeSunLoc.z, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position0); GLfloat ambient_color[] = { 0.7, 0.7, 0.8 }; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color); @@ -547,30 +546,6 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Percent: sendVoxelServerAddScene(); break; - - case Qt::Key_1: - _mouseMode = (_mouseMode == ADD_VOXEL_MODE) ? NO_EDIT_MODE : ADD_VOXEL_MODE; - break; - - case Qt::Key_2: - _mouseMode = (_mouseMode == DELETE_VOXEL_MODE) ? NO_EDIT_MODE : DELETE_VOXEL_MODE; - break; - - case Qt::Key_3: - _mouseMode = (_mouseMode == COLOR_VOXEL_MODE) ? NO_EDIT_MODE : COLOR_VOXEL_MODE; - break; - - case Qt::Key_4: - addVoxelInFrontOfAvatar(); - break; - - case Qt::Key_5: - _mouseVoxelScale /= 2; - break; - - case Qt::Key_6: - _mouseVoxelScale *= 2; - break; case Qt::Key_L: _displayLevels = !_displayLevels; @@ -694,6 +669,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { void Application::mouseMoveEvent(QMouseEvent* event) { _mouseX = event->x(); _mouseY = event->y(); + + // detect drag + glm::vec3 mouseVoxelPos(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); + if (_colorVoxelMode->isChecked() && event->buttons().testFlag(Qt::LeftButton) && mouseVoxelPos != _lastMouseVoxelPos) { + addVoxelUnderCursor(); + } } void Application::mousePressEvent(QMouseEvent* event) { @@ -702,13 +683,13 @@ void Application::mousePressEvent(QMouseEvent* event) { _mouseY = event->y(); _mousePressed = true; - if (_mouseMode == ADD_VOXEL_MODE || _mouseMode == COLOR_VOXEL_MODE) { + if (_addVoxelMode->isChecked() || _colorVoxelMode->isChecked()) { addVoxelUnderCursor(); - } else if (_mouseMode == DELETE_VOXEL_MODE) { + } else if (_deleteVoxelMode->isChecked()) { deleteVoxelUnderCursor(); } - } else if (event->button() == Qt::RightButton && _mouseMode != NO_EDIT_MODE) { + } else if (event->button() == Qt::RightButton && checkedVoxelModeAction() != 0) { deleteVoxelUnderCursor(); } } @@ -722,14 +703,14 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { } void Application::wheelEvent(QWheelEvent* event) { - if (_mouseMode == NO_EDIT_MODE) { + if (checkedVoxelModeAction() == 0) { event->ignore(); return; } if (event->delta() > 0) { - _mouseVoxelScale *= 2; + increaseVoxelSize(); } else { - _mouseVoxelScale /= 2; + decreaseVoxelSize(); } } @@ -819,48 +800,57 @@ void Application::idle() { // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); - float distance; - BoxFace face; _mouseVoxel.s = 0.0f; - if (_mouseMode != NO_EDIT_MODE && _voxels.findRayIntersection( - mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) { - // find the nearest voxel with the desired scale - if (_mouseVoxelScale > _mouseVoxel.s) { - // choose the larger voxel that encompasses the one selected - _mouseVoxel.x = _mouseVoxelScale * floorf(_mouseVoxel.x / _mouseVoxelScale); - _mouseVoxel.y = _mouseVoxelScale * floorf(_mouseVoxel.y / _mouseVoxelScale); - _mouseVoxel.z = _mouseVoxelScale * floorf(_mouseVoxel.z / _mouseVoxelScale); - _mouseVoxel.s = _mouseVoxelScale; - - } else { - glm::vec3 faceVector = getFaceVector(face); - if (_mouseVoxelScale < _mouseVoxel.s) { - // find the closest contained voxel - glm::vec3 pt = (mouseRayOrigin + mouseRayDirection * distance) / (float)TREE_SCALE - - faceVector * (_mouseVoxelScale * 0.5f); - _mouseVoxel.x = _mouseVoxelScale * floorf(pt.x / _mouseVoxelScale); - _mouseVoxel.y = _mouseVoxelScale * floorf(pt.y / _mouseVoxelScale); - _mouseVoxel.z = _mouseVoxelScale * floorf(pt.z / _mouseVoxelScale); + if (checkedVoxelModeAction() != 0) { + float distance; + BoxFace face; + if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) { + // find the nearest voxel with the desired scale + if (_mouseVoxelScale > _mouseVoxel.s) { + // choose the larger voxel that encompasses the one selected + _mouseVoxel.x = _mouseVoxelScale * floorf(_mouseVoxel.x / _mouseVoxelScale); + _mouseVoxel.y = _mouseVoxelScale * floorf(_mouseVoxel.y / _mouseVoxelScale); + _mouseVoxel.z = _mouseVoxelScale * floorf(_mouseVoxel.z / _mouseVoxelScale); _mouseVoxel.s = _mouseVoxelScale; - } - if (_mouseMode == ADD_VOXEL_MODE) { - // use the face to determine the side on which to create a neighbor - _mouseVoxel.x += faceVector.x * _mouseVoxel.s; - _mouseVoxel.y += faceVector.y * _mouseVoxel.s; - _mouseVoxel.z += faceVector.z * _mouseVoxel.s; - } - } - if (_mouseMode == COLOR_VOXEL_MODE) { + } else { + glm::vec3 faceVector = getFaceVector(face); + if (_mouseVoxelScale < _mouseVoxel.s) { + // find the closest contained voxel + glm::vec3 pt = (mouseRayOrigin + mouseRayDirection * distance) / (float)TREE_SCALE - + faceVector * (_mouseVoxelScale * 0.5f); + _mouseVoxel.x = _mouseVoxelScale * floorf(pt.x / _mouseVoxelScale); + _mouseVoxel.y = _mouseVoxelScale * floorf(pt.y / _mouseVoxelScale); + _mouseVoxel.z = _mouseVoxelScale * floorf(pt.z / _mouseVoxelScale); + _mouseVoxel.s = _mouseVoxelScale; + } + if (_addVoxelMode->isChecked()) { + // use the face to determine the side on which to create a neighbor + _mouseVoxel.x += faceVector.x * _mouseVoxel.s; + _mouseVoxel.y += faceVector.y * _mouseVoxel.s; + _mouseVoxel.z += faceVector.z * _mouseVoxel.s; + } + } + } else if (_addVoxelMode->isChecked()) { + // place the voxel a fixed distance away + float worldMouseVoxelScale = _mouseVoxelScale * TREE_SCALE; + glm::vec3 pt = mouseRayOrigin + mouseRayDirection * (2.0f + worldMouseVoxelScale * 0.5f); + _mouseVoxel.x = _mouseVoxelScale * floorf(pt.x / worldMouseVoxelScale); + _mouseVoxel.y = _mouseVoxelScale * floorf(pt.y / worldMouseVoxelScale); + _mouseVoxel.z = _mouseVoxelScale * floorf(pt.z / worldMouseVoxelScale); + _mouseVoxel.s = _mouseVoxelScale; + } + + if (_deleteVoxelMode->isChecked()) { + // red indicates deletion + _mouseVoxel.red = 255; + _mouseVoxel.green = _mouseVoxel.blue = 0; + + } else { // _addVoxelMode->isChecked() || _colorVoxelMode->isChecked() QColor paintColor = _voxelPaintColor->data().value(); _mouseVoxel.red = paintColor.red(); _mouseVoxel.green = paintColor.green(); _mouseVoxel.blue = paintColor.blue(); - - } else if (_mouseMode == DELETE_VOXEL_MODE) { - // red indicates deletion - _mouseVoxel.red = 255; - _mouseVoxel.green = _mouseVoxel.blue = 0; } } @@ -914,11 +904,7 @@ void Application::terminate() { // Close serial port // close(serial_fd); - _myAvatar.writeAvatarDataToFile(); - - #ifndef _WIN32 - _audio.terminate(); - #endif + _myAvatar.writeAvatarDataToFile(); if (_enableNetworkThread) { _stopNetworkReceiveThread = true; @@ -994,10 +980,6 @@ void Application::cycleFrustumRenderMode() { updateFrustumRenderModeAction(); } -void Application::setDestructivePaint(bool destructive) { - _destructiveAddVoxel = destructive; -} - void Application::setRenderWarnings(bool renderWarnings) { _voxels.setRenderPipelineWarnings(renderWarnings); } @@ -1050,6 +1032,56 @@ void Application::setWantsDelta(bool wantsDelta) { _myAvatar.setWantDelta(wantsDelta); } +void Application::updateVoxelModeActions() { + // only the sender can be checked + foreach (QAction* action, _voxelModeActions->actions()) { + if (action->isChecked() && action != sender()) { + action->setChecked(false); + } + } +} + +static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { + unsigned char* bufferOut; + int sizeOut; + + if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + delete bufferOut; + } +} + +void Application::addVoxelInFrontOfAvatar() { + VoxelDetail detail; + + glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.getCameraDirection()) * (1.0f / TREE_SCALE); + detail.s = _mouseVoxelScale; + + detail.x = detail.s * floor(position.x / detail.s); + detail.y = detail.s * floor(position.y / detail.s); + detail.z = detail.s * floor(position.z / detail.s); + QColor paintColor = _voxelPaintColor->data().value(); + detail.red = paintColor.red(); + detail.green = paintColor.green(); + detail.blue = paintColor.blue(); + + PACKET_HEADER message = (_destructiveAddVoxel->isChecked() ? + PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); + sendVoxelEditMessage(message, detail); + + // create the voxel locally so it appears immediately + _voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, + detail.red, detail.green, detail.blue, _destructiveAddVoxel->isChecked()); +} + +void Application::decreaseVoxelSize() { + _mouseVoxelScale /= 2; +} + +void Application::increaseVoxelSize() { + _mouseVoxelScale *= 2; +} + static QIcon createSwatchIcon(const QColor& color) { QPixmap map(16, 16); map.fill(color); @@ -1102,11 +1134,29 @@ void Application::initMenu() { _renderStatsOn->setShortcut(Qt::Key_Slash); (_logOn = toolsMenu->addAction("Log"))->setCheckable(true); _logOn->setChecked(true); - _voxelPaintColor = toolsMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::Key_7); + + QMenu* voxelMenu = menuBar->addMenu("Voxels"); + _voxelModeActions = new QActionGroup(this); + _voxelModeActions->setExclusive(false); // exclusivity implies one is always checked + (_addVoxelMode = voxelMenu->addAction( + "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_1))->setCheckable(true); + _voxelModeActions->addAction(_addVoxelMode); + (_deleteVoxelMode = voxelMenu->addAction( + "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_2))->setCheckable(true); + _voxelModeActions->addAction(_deleteVoxelMode); + (_colorVoxelMode = voxelMenu->addAction( + "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_3))->setCheckable(true); + _voxelModeActions->addAction(_colorVoxelMode); + + voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::Key_4); + voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::Key_5); + voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::Key_6); + + _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::Key_7); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); - toolsMenu->addAction("Create Voxel is Destructive", this, SLOT(setDestructivePaint(bool)))->setCheckable(true); + (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); @@ -1193,16 +1243,6 @@ void Application::init() { gettimeofday(&_lastTimeIdle, NULL); } -static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { - unsigned char* bufferOut; - int sizeOut; - - if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); - delete bufferOut; - } -} - void Application::updateAvatar(float deltaTime) { // Update my avatar's head position from gyros _myAvatar.updateHeadFromGyros(deltaTime, &_serialPort, &_gravity); @@ -1279,7 +1319,7 @@ void Application::updateAvatar(float deltaTime) { // Get audio loudness data from audio input device #ifndef _WIN32 - _myAvatar.setLoudness(_audio.getInputLoudness()); + _myAvatar.setLoudness(_audio.getLastInputLoudness()); #endif // Update Avatar with latest camera and view frustum data... @@ -1327,7 +1367,8 @@ void Application::updateAvatar(float deltaTime) { _paintingVoxel.y >= 0.0 && _paintingVoxel.y <= 1.0 && _paintingVoxel.z >= 0.0 && _paintingVoxel.z <= 1.0) { - PACKET_HEADER message = (_destructiveAddVoxel ? PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); + PACKET_HEADER message = (_destructiveAddVoxel->isChecked() ? + PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); sendVoxelEditMessage(message, _paintingVoxel); } } @@ -1459,15 +1500,15 @@ void Application::displayOculus(Camera& whichCamera) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); _oculusProgram = new ProgramObject(); - _oculusProgram->attachFromSourceCode(GL_FRAGMENT_SHADER_ARB, DISTORTION_FRAGMENT_SHADER); + _oculusProgram->addShaderFromSourceCode(QGLShader::Fragment, DISTORTION_FRAGMENT_SHADER); _oculusProgram->link(); - _textureLocation = _oculusProgram->getUniformLocation("texture"); - _lensCenterLocation = _oculusProgram->getUniformLocation("lensCenter"); - _screenCenterLocation = _oculusProgram->getUniformLocation("screenCenter"); - _scaleLocation = _oculusProgram->getUniformLocation("scale"); - _scaleInLocation = _oculusProgram->getUniformLocation("scaleIn"); - _hmdWarpParamLocation = _oculusProgram->getUniformLocation("hmdWarpParam"); + _textureLocation = _oculusProgram->uniformLocation("texture"); + _lensCenterLocation = _oculusProgram->uniformLocation("lensCenter"); + _screenCenterLocation = _oculusProgram->uniformLocation("screenCenter"); + _scaleLocation = _oculusProgram->uniformLocation("scale"); + _scaleInLocation = _oculusProgram->uniformLocation("scaleIn"); + _hmdWarpParamLocation = _oculusProgram->uniformLocation("hmdWarpParam"); } else { glBindTexture(GL_TEXTURE_2D, _oculusTextureID); @@ -1488,12 +1529,12 @@ void Application::displayOculus(Camera& whichCamera) { glDisable(GL_BLEND); glEnable(GL_TEXTURE_2D); _oculusProgram->bind(); - _oculusProgram->setUniform(_textureLocation, 0); - _oculusProgram->setUniform(_lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 - _oculusProgram->setUniform(_screenCenterLocation, 0.25, 0.5); - _oculusProgram->setUniform(_scaleLocation, 0.25 * scaleFactor, 0.5 * scaleFactor * aspectRatio); - _oculusProgram->setUniform(_scaleInLocation, 4, 2 / aspectRatio); - _oculusProgram->setUniform(_hmdWarpParamLocation, 1.0, 0.22, 0.24, 0); + _oculusProgram->setUniformValue(_textureLocation, 0); + _oculusProgram->setUniformValue(_lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 + _oculusProgram->setUniformValue(_screenCenterLocation, 0.25, 0.5); + _oculusProgram->setUniformValue(_scaleLocation, 0.25 * scaleFactor, 0.5 * scaleFactor * aspectRatio); + _oculusProgram->setUniformValue(_scaleInLocation, 4, 2 / aspectRatio); + _oculusProgram->setUniformValue(_hmdWarpParamLocation, 1.0, 0.22, 0.24, 0); glColor3f(1, 0, 1); glBegin(GL_QUADS); @@ -1507,8 +1548,8 @@ void Application::displayOculus(Camera& whichCamera) { glVertex2f(0, _glWidget->height()); glEnd(); - _oculusProgram->setUniform(_lensCenterLocation, 0.787994, 0.5); - _oculusProgram->setUniform(_screenCenterLocation, 0.75, 0.5); + _oculusProgram->setUniformValue(_lensCenterLocation, 0.787994, 0.5); + _oculusProgram->setUniformValue(_screenCenterLocation, 0.75, 0.5); glBegin(GL_QUADS); glTexCoord2f(0.5, 0); @@ -1577,8 +1618,9 @@ void Application::displaySide(Camera& whichCamera) { // indicate what we'll be adding/removing in mouse mode, if anything if (_mouseVoxel.s != 0) { + glDisable(GL_LIGHTING); glPushMatrix(); - if (_mouseMode == ADD_VOXEL_MODE) { + if (_addVoxelMode->isChecked()) { // use a contrasting color so that we can see what we're doing glColor3ub(_mouseVoxel.red + 128, _mouseVoxel.green + 128, _mouseVoxel.blue + 128); } else { @@ -1592,6 +1634,7 @@ void Application::displaySide(Camera& whichCamera) { glutWireCube(_mouseVoxel.s); glLineWidth(1.0f); glPopMatrix(); + glEnable(GL_LIGHTING); } if (_renderAvatarsOn->isChecked()) { @@ -1896,35 +1939,18 @@ void Application::shiftPaintingColor() { _paintingVoxel.blue = (_dominantColor == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); } -void Application::addVoxelInFrontOfAvatar() { - VoxelDetail detail; - - glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.getCameraDirection()) * (1.0f / TREE_SCALE); - detail.s = _mouseVoxelScale; - - detail.x = detail.s * floor(position.x / detail.s); - detail.y = detail.s * floor(position.y / detail.s); - detail.z = detail.s * floor(position.z / detail.s); - QColor paintColor = _voxelPaintColor->data().value(); - detail.red = paintColor.red(); - detail.green = paintColor.green(); - detail.blue = paintColor.blue(); - - PACKET_HEADER message = (_destructiveAddVoxel ? PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); - sendVoxelEditMessage(message, detail); - - // create the voxel locally so it appears immediately - _voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, detail.red, detail.green, detail.blue, _destructiveAddVoxel); -} - void Application::addVoxelUnderCursor() { if (_mouseVoxel.s != 0) { - PACKET_HEADER message = (_destructiveAddVoxel ? PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); + PACKET_HEADER message = (_destructiveAddVoxel->isChecked() ? + PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); sendVoxelEditMessage(message, _mouseVoxel); // create the voxel locally so it appears immediately _voxels.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, - _mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue, _destructiveAddVoxel); + _mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue, _destructiveAddVoxel->isChecked()); + + // remember the position for drag detection + _lastMouseVoxelPos = glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); } } @@ -1934,6 +1960,9 @@ void Application::deleteVoxelUnderCursor() { // delete the voxel locally so it disappears immediately _voxels.deleteVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + // remember the position for drag detection + _lastMouseVoxelPos = glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); } } @@ -1967,18 +1996,23 @@ void Application::setMenuShortcutsEnabled(bool enabled) { setShortcutsEnabled(_window->menuBar(), enabled); } +// when QActionGroup is set to non-exclusive, it doesn't return anything as checked; +// hence, we must check ourselves +QAction* Application::checkedVoxelModeAction() const { + foreach (QAction* action, _voxelModeActions->actions()) { + if (action->isChecked()) { + return action; + } + } + return 0; +} + void Application::attachNewHeadToAgent(Agent *newAgent) { if (newAgent->getLinkedData() == NULL) { newAgent->setLinkedData(new Avatar(false)); } } -#ifndef _WIN32 -void Application::audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) { - static_cast(QCoreApplication::instance())->_audio.updateMixerParams(newMixerAddress, newMixerPort); -} -#endif - // Receive packets from other agents/servers and decide what to do with them! void* Application::networkReceive(void* args) { sockaddr senderAddress; @@ -1992,7 +2026,7 @@ void* Application::networkReceive(void* args) { app->_wantToKillLocalVoxels = false; } - if (AgentList::getInstance()->getAgentSocket().receive(&senderAddress, app->_incomingPacket, &bytesReceived)) { + if (AgentList::getInstance()->getAgentSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) { app->_packetCount++; app->_bytesCount += bytesReceived; @@ -2010,6 +2044,9 @@ void* Application::networkReceive(void* args) { printf("The rotation: %f, %f, %f\n", rotationRates[0], rotationRates[1], rotationRates[2]); break; + case PACKET_HEADER_MIXED_AUDIO: + app->_audio.addReceivedAudioToBuffer(app->_incomingPacket, bytesReceived); + break; case PACKET_HEADER_VOXEL_DATA: case PACKET_HEADER_VOXEL_DATA_MONOCHROME: case PACKET_HEADER_Z_COMMAND: diff --git a/interface/src/Application.h b/interface/src/Application.h index 5418d0740e..777aaf61bd 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -30,6 +30,7 @@ #include "ui/ChatEntry.h" class QAction; +class QActionGroup; class QGLWidget; class QKeyEvent; class QMainWindow; @@ -57,6 +58,8 @@ public: void mouseReleaseEvent(QMouseEvent* event); void wheelEvent(QWheelEvent* event); + + Avatar* getAvatar() { return &_myAvatar; } private slots: @@ -76,7 +79,6 @@ private slots: void setFrustumOffset(bool frustumOffset); void cycleFrustumRenderMode(); - void setDestructivePaint(bool destructive); void setRenderWarnings(bool renderWarnings); void doKillLocalVoxels(); void doRandomizeVoxelColors(); @@ -89,6 +91,10 @@ private slots: void setWantsMonochrome(bool wantsMonochrome); void setWantsResIn(bool wantsResIn); void setWantsDelta(bool wantsDelta); + void updateVoxelModeActions(); + void addVoxelInFrontOfAvatar(); + void decreaseVoxelSize(); + void increaseVoxelSize(); void chooseVoxelPaintColor(); private: @@ -110,7 +116,6 @@ private: void setupPaintingVoxel(); void shiftPaintingColor(); - void addVoxelInFrontOfAvatar(); void addVoxelUnderCursor(); void deleteVoxelUnderCursor(); @@ -118,10 +123,9 @@ private: void setMenuShortcutsEnabled(bool enabled); + QAction* checkedVoxelModeAction() const; + static void attachNewHeadToAgent(Agent *newAgent); - #ifndef _WIN32 - static void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort); - #endif static void* networkReceive(void* args); QMainWindow* _window; @@ -135,8 +139,13 @@ private: QAction* _renderAvatarsOn; // Whether to render avatars QAction* _oculusOn; // Whether to configure the display for the Oculus Rift QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats - QAction* _logOn; // Whether to show on-screen log + QAction* _logOn; // Whether to show on-screen log + QActionGroup* _voxelModeActions; // The group of voxel edit mode actions + QAction* _addVoxelMode; // Whether add voxel mode is enabled + QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled + QAction* _colorVoxelMode; // Whether color voxel mode is enabled QAction* _voxelPaintColor; // The color with which to paint voxels + QAction* _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive QAction* _frustumOn; // Whether or not to display the debug view frustum QAction* _viewFrustumFromOffset; // Whether or not to offset the view of the frustum QAction* _cameraFrustum; // which frustum to look at @@ -192,18 +201,15 @@ private: int _mouseY; bool _mousePressed; // true if mouse has been pressed (clear when finished) - // The current mode for mouse interaction - enum MouseMode { NO_EDIT_MODE, ADD_VOXEL_MODE, DELETE_VOXEL_MODE, COLOR_VOXEL_MODE }; - MouseMode _mouseMode; - VoxelDetail _mouseVoxel; // details of the voxel under the mouse cursor - float _mouseVoxelScale; // the scale for adding/removing voxels + VoxelDetail _mouseVoxel; // details of the voxel under the mouse cursor + float _mouseVoxelScale; // the scale for adding/removing voxels + glm::vec3 _lastMouseVoxelPos; // the position of the last mouse voxel edit bool _paintOn; // Whether to paint voxels as you fly around unsigned char _dominantColor; // The dominant color of the voxel we're painting VoxelDetail _paintingVoxel; // The voxel we're painting if we're painting bool _perfStatsOn; // Do we want to display perfStats? - bool _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive ChatEntry _chatEntry; // chat entry field bool _chatEntryOn; // Whether to show the chat entry diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8a455ec419..7308b35963 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -10,19 +10,21 @@ #include #include #include - #include #include + #include #include #include #include +#include +#include + +#include "Application.h" #include "Audio.h" #include "Util.h" #include "Log.h" -Oscilloscope * scope; - const int NUM_AUDIO_CHANNELS = 2; const int PACKET_LENGTH_BYTES = 1024; @@ -55,15 +57,8 @@ const float AUDIO_CALLBACK_MSECS = (float)BUFFER_LENGTH_SAMPLES / (float)SAMPLE_ const int AGENT_LOOPBACK_MODIFIER = 307; -const char LOCALHOST_MIXER[] = "0.0.0.0"; -const char WORKCLUB_MIXER[] = "192.168.1.19"; -const char EC2_WEST_MIXER[] = "54.241.92.53"; - -const int AUDIO_UDP_LISTEN_PORT = 55444; - -int starve_counter = 0; +int numStarves = 0; StDev stdev; -bool stopAudioReceiveThread = false; int samplesLeftForFlange = 0; int lastYawMeasuredMaximum = 0; @@ -71,43 +66,31 @@ float flangeIntensity = 0; float flangeRate = 0; float flangeWeight = 0; -timeval firstPlaybackTimer; -int packetsReceivedThisPlayback = 0; float usecsAtStartup = 0; -/** - * Audio callback used by portaudio. - * Communicates with Audio via a shared pointer to Audio::data. - * Writes input audio channels (if they exist) into Audio::data->buffer, - multiplied by Audio::data->inputGain. - * Then writes Audio::data->buffer into output audio channels, and clears - the portion of Audio::data->buffer that has been read from for reuse. - * - * @param[in] inputBuffer A pointer to an internal portaudio data buffer containing data read by portaudio. - * @param[out] outputBuffer A pointer to an internal portaudio data buffer to be read by the configured output device. - * @param[in] frames Number of frames that portaudio requests to be read/written. - (Valid size of input/output buffers = frames * number of channels (2) * sizeof data type (float)). - * @param[in] timeInfo Portaudio time info. Currently unused. - * @param[in] statusFlags Portaudio status flags. Currently unused. - * @param[in] userData Pointer to supplied user data (in this case, a pointer to Audio::data). - Used to communicate with external code (since portaudio calls this function from another thread). - * @return Should be of type PaStreamCallbackResult. Return paComplete to end the stream, or paContinue to continue (default). - Can be used to end the stream from within the callback. - */ - -int audioCallback (const void *inputBuffer, - void *outputBuffer, +// inputBuffer A pointer to an internal portaudio data buffer containing data read by portaudio. +// outputBuffer A pointer to an internal portaudio data buffer to be read by the configured output device. +// frames Number of frames that portaudio requests to be read/written. +// timeInfo Portaudio time info. Currently unused. +// statusFlags Portaudio status flags. Currently unused. +// userData Pointer to supplied user data (in this case, a pointer to the parent Audio object +int audioCallback (const void* inputBuffer, + void* outputBuffer, unsigned long frames, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, - void *userData) -{ - AudioData *data = (AudioData *) userData; + void* userData) { + + Audio* parentAudio = (Audio*) userData; + AgentList* agentList = AgentList::getInstance(); + + Application* interface = (Application*) QCoreApplication::instance(); + Avatar* interfaceAvatar = interface->getAvatar(); int16_t *inputLeft = ((int16_t **) inputBuffer)[0]; // Add Procedural effects to input samples - data->addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES); + parentAudio->addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES); if (inputLeft != NULL) { @@ -118,35 +101,32 @@ int audioCallback (const void *inputBuffer, } loudness /= BUFFER_LENGTH_SAMPLES; - data->lastInputLoudness = loudness; + parentAudio->_lastInputLoudness = loudness; // add data to the scope - scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES); + parentAudio->_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES); - if (data->mixerAddress != 0) { - sockaddr_in audioMixerSocket; - audioMixerSocket.sin_family = AF_INET; - audioMixerSocket.sin_addr.s_addr = data->mixerAddress; - audioMixerSocket.sin_port = data->mixerPort; - + Agent* audioMixer = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { int leadingBytes = 2 + (sizeof(float) * 4); // we need the amount of bytes in the buffer + 1 for type // + 12 for 3 floats for position + float for bearing + 1 attenuation byte unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; - dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; + dataPacket[0] = PACKET_HEADER_MICROPHONE_AUDIO; unsigned char *currentPacketPtr = dataPacket + 1; // memcpy the three float positions - memcpy(currentPacketPtr, &data->linkedAvatar->getHeadPosition(), sizeof(float) * 3); + memcpy(currentPacketPtr, &interfaceAvatar->getHeadPosition(), sizeof(float) * 3); currentPacketPtr += (sizeof(float) * 3); // tell the mixer not to add additional attenuation to our source *(currentPacketPtr++) = 255; // memcpy the corrected render yaw - float correctedYaw = fmodf(-1 * data->linkedAvatar->getAbsoluteHeadYaw(), 360); + float correctedYaw = fmodf(-1 * interfaceAvatar->getAbsoluteHeadYaw(), 360); if (correctedYaw > 180) { correctedYaw -= 360; @@ -154,29 +134,30 @@ int audioCallback (const void *inputBuffer, correctedYaw += 360; } - if (data->mixerLoopbackFlag) { + if (parentAudio->_mixerLoopbackFlag) { correctedYaw = correctedYaw > 0 - ? correctedYaw + AGENT_LOOPBACK_MODIFIER - : correctedYaw - AGENT_LOOPBACK_MODIFIER; + ? correctedYaw + AGENT_LOOPBACK_MODIFIER + : correctedYaw - AGENT_LOOPBACK_MODIFIER; } memcpy(currentPacketPtr, &correctedYaw, sizeof(float)); - currentPacketPtr += sizeof(float); + currentPacketPtr += sizeof(float); // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES); - data->audioSocket->send((sockaddr *)&audioMixerSocket, dataPacket, BUFFER_LENGTH_BYTES + leadingBytes); + agentList->getAgentSocket()->send(audioMixer->getActiveSocket(), dataPacket, BUFFER_LENGTH_BYTES + leadingBytes); } + } - int16_t *outputLeft = ((int16_t **) outputBuffer)[0]; - int16_t *outputRight = ((int16_t **) outputBuffer)[1]; + int16_t* outputLeft = ((int16_t**) outputBuffer)[0]; + int16_t* outputRight = ((int16_t**) outputBuffer)[1]; memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - - AudioRingBuffer *ringBuffer = data->ringBuffer; + + AudioRingBuffer* ringBuffer = &parentAudio->_ringBuffer; // if we've been reset, and there isn't any new packets yet // just play some silence @@ -184,15 +165,16 @@ int audioCallback (const void *inputBuffer, if (ringBuffer->getEndOfLastWrite() != NULL) { if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { - //printLog("Held back, buffer has %d of %d samples required.\n", ringBuffer->diffLastWriteNextOutput(), PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES); + //printLog("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; - + ::numStarves++; + parentAudio->_packetsReceivedThisPlayback = 0; + // printLog("Starved #%d\n", starve_counter); - data->wasStarved = 10; // Frames to render the indication that the system was starved. + parentAudio->_wasStarved = 10; // Frames to render the indication that the system was starved. } else { if (!ringBuffer->isStarted()) { ringBuffer->setStarted(true); @@ -206,21 +188,22 @@ int audioCallback (const void *inputBuffer, // if we haven't fired off the flange effect, check if we should // TODO: lastMeasuredHeadYaw is now relative to body - check if this still works. - int lastYawMeasured = fabsf(data->linkedAvatar->getLastMeasuredHeadYaw()); + int lastYawMeasured = fabsf(interfaceAvatar->getLastMeasuredHeadYaw()); - if (!samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) { + if (!::samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) { // we should flange for one second - if ((lastYawMeasuredMaximum = std::max(lastYawMeasuredMaximum, lastYawMeasured)) != lastYawMeasured) { - lastYawMeasuredMaximum = std::min(lastYawMeasuredMaximum, MIN_FLANGE_EFFECT_THRESHOLD); + if ((::lastYawMeasuredMaximum = std::max(::lastYawMeasuredMaximum, lastYawMeasured)) != lastYawMeasured) { + ::lastYawMeasuredMaximum = std::min(::lastYawMeasuredMaximum, MIN_FLANGE_EFFECT_THRESHOLD); - samplesLeftForFlange = SAMPLE_RATE; + ::samplesLeftForFlange = SAMPLE_RATE; - flangeIntensity = MIN_FLANGE_INTENSITY + - ((lastYawMeasuredMaximum - MIN_FLANGE_EFFECT_THRESHOLD) / (float)(MAX_FLANGE_EFFECT_THRESHOLD - MIN_FLANGE_EFFECT_THRESHOLD)) * + ::flangeIntensity = MIN_FLANGE_INTENSITY + + ((::lastYawMeasuredMaximum - MIN_FLANGE_EFFECT_THRESHOLD) / + (float)(MAX_FLANGE_EFFECT_THRESHOLD - MIN_FLANGE_EFFECT_THRESHOLD)) * (1 - MIN_FLANGE_INTENSITY); - flangeRate = FLANGE_BASE_RATE * flangeIntensity; - flangeWeight = MAX_FLANGE_SAMPLE_WEIGHT * flangeIntensity; + ::flangeRate = FLANGE_BASE_RATE * ::flangeIntensity; + ::flangeWeight = MAX_FLANGE_SAMPLE_WEIGHT * ::flangeIntensity; } } @@ -229,13 +212,14 @@ int audioCallback (const void *inputBuffer, int leftSample = ringBuffer->getNextOutput()[s]; int rightSample = ringBuffer->getNextOutput()[s + PACKET_LENGTH_SAMPLES_PER_CHANNEL]; - if (samplesLeftForFlange > 0) { - float exponent = (SAMPLE_RATE - samplesLeftForFlange - (SAMPLE_RATE / flangeRate)) / (SAMPLE_RATE / flangeRate); - int sampleFlangeDelay = (SAMPLE_RATE / (1000 * flangeIntensity)) * powf(2, exponent); + if (::samplesLeftForFlange > 0) { + float exponent = (SAMPLE_RATE - ::samplesLeftForFlange - (SAMPLE_RATE / ::flangeRate)) / + (SAMPLE_RATE / ::flangeRate); + int sampleFlangeDelay = (SAMPLE_RATE / (1000 * ::flangeIntensity)) * powf(2, exponent); - if (samplesLeftForFlange != SAMPLE_RATE || s >= (SAMPLE_RATE / 2000)) { + if (::samplesLeftForFlange != SAMPLE_RATE || s >= (SAMPLE_RATE / 2000)) { // we have a delayed sample to add to this sample - + int16_t *flangeFrame = ringBuffer->getNextOutput(); int flangeIndex = s - sampleFlangeDelay; @@ -251,13 +235,13 @@ int audioCallback (const void *inputBuffer, int16_t leftFlangeSample = flangeFrame[flangeIndex]; int16_t rightFlangeSample = flangeFrame[flangeIndex + PACKET_LENGTH_SAMPLES_PER_CHANNEL]; - leftSample = (1 - flangeWeight) * leftSample + (flangeWeight * leftFlangeSample); - rightSample = (1 - flangeWeight) * rightSample + (flangeWeight * rightFlangeSample); + leftSample = (1 - ::flangeWeight) * leftSample + (::flangeWeight * leftFlangeSample); + rightSample = (1 - ::flangeWeight) * rightSample + (::flangeWeight * rightFlangeSample); - samplesLeftForFlange--; + ::samplesLeftForFlange--; - if (samplesLeftForFlange == 0) { - lastYawMeasuredMaximum = 0; + if (::samplesLeftForFlange == 0) { + ::lastYawMeasuredMaximum = 0; } } } @@ -267,8 +251,8 @@ int audioCallback (const void *inputBuffer, } // add data to the scope - scope->addSamples(1, outputLeft, PACKET_LENGTH_SAMPLES_PER_CHANNEL); - scope->addSamples(2, outputRight, PACKET_LENGTH_SAMPLES_PER_CHANNEL); + parentAudio->_scope->addSamples(1, outputLeft, PACKET_LENGTH_SAMPLES_PER_CHANNEL); + parentAudio->_scope->addSamples(2, outputRight, PACKET_LENGTH_SAMPLES_PER_CHANNEL); ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -278,140 +262,108 @@ int audioCallback (const void *inputBuffer, } } - gettimeofday(&data->lastCallback, NULL); + gettimeofday(&parentAudio->_lastCallbackTime, NULL); return paContinue; } -void Audio::updateMixerParams(in_addr_t newMixerAddress, in_port_t newMixerPort) { - audioData->mixerAddress = newMixerAddress; - audioData->mixerPort = newMixerPort; -} - -struct AudioRecThreadStruct { - AudioData *sharedAudioData; -}; - -void *receiveAudioViaUDP(void *args) { - AudioRecThreadStruct *threadArgs = (AudioRecThreadStruct *) args; - AudioData *sharedAudioData = threadArgs->sharedAudioData; - - int16_t *receivedData = new int16_t[PACKET_LENGTH_SAMPLES]; - ssize_t receivedBytes; - - // Init Jitter timer values - timeval previousReceiveTime, currentReceiveTime = {}; - gettimeofday(&previousReceiveTime, NULL); - gettimeofday(¤tReceiveTime, NULL); - - int totalPacketsReceived = 0; - - stdev.reset(); - - while (!stopAudioReceiveThread) { - - if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) { - - gettimeofday(¤tReceiveTime, NULL); - totalPacketsReceived++; - - double tDiff = diffclock(&previousReceiveTime, ¤tReceiveTime); - //printLog("tDiff %4.1f\n", tDiff); - // Discard first few received packets for computing jitter (often they pile up on start) - if (totalPacketsReceived > 3) stdev.addValue(tDiff); - if (stdev.getSamples() > 500) { - sharedAudioData->measuredJitter = stdev.getStDev(); - //printLog("Avg: %4.2f, Stdev: %4.2f\n", stdev.getAverage(), sharedAudioData->measuredJitter); - stdev.reset(); - } - - AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer; - - - if (!ringBuffer->isStarted()) { - packetsReceivedThisPlayback++; - } - else { - //printLog("Audio packet received at %6.0f\n", usecTimestampNow()/1000); - } - if (packetsReceivedThisPlayback == 1) gettimeofday(&firstPlaybackTimer, NULL); - - ringBuffer->parseData((unsigned char *)receivedData, PACKET_LENGTH_BYTES); - - previousReceiveTime = currentReceiveTime; - } +void outputPortAudioError(PaError error) { + if (error != paNoError) { + printLog("-- portaudio termination error --\n"); + printLog("PortAudio error (%d): %s\n", error, Pa_GetErrorText(error)); } - - pthread_exit(0); } -void Audio::setMixerLoopbackFlag(bool newMixerLoopbackFlag) { - audioData->mixerLoopbackFlag = newMixerLoopbackFlag; -} - -bool Audio::getMixerLoopbackFlag() { - return audioData->mixerLoopbackFlag; -} - -/** - * Initialize portaudio and start an audio stream. - * Should be called at the beginning of program exection. - * @seealso Audio::terminate - * @return Returns true if successful or false if an error occurred. -Use Audio::getError() to retrieve the error code. - */ -Audio::Audio(Oscilloscope* s, Avatar* linkedAvatar) { - paError = Pa_Initialize(); - if (paError != paNoError) goto error; - - scope = s; - - audioData = new AudioData(); - - audioData->linkedAvatar = linkedAvatar; - - // setup a UDPSocket - audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); - audioData->ringBuffer = new AudioRingBuffer(RING_BUFFER_SAMPLES, PACKET_LENGTH_SAMPLES); - - AudioRecThreadStruct threadArgs; - threadArgs.sharedAudioData = audioData; - - pthread_create(&audioReceiveThread, NULL, receiveAudioViaUDP, (void *) &threadArgs); - - paError = Pa_OpenDefaultStream(&stream, - 2, // input channels - 2, // output channels - (paInt16 | paNonInterleaved), // sample format - SAMPLE_RATE, // sample rate (hz) - BUFFER_LENGTH_SAMPLES, // frames per buffer - audioCallback, // callback function - (void *) audioData); // user data to be passed to callback - if (paError != paNoError) goto error; - - initialized = true; +Audio::Audio(Oscilloscope* scope) : + _stream(NULL), + _ringBuffer(RING_BUFFER_SAMPLES, PACKET_LENGTH_SAMPLES), + _scope(scope), + _averagedLatency(0.0), + _measuredJitter(0), + _wasStarved(0), + _lastInputLoudness(0), + _mixerLoopbackFlag(false), + _lastVelocity(0), + _lastAcceleration(0), + _totalPacketsReceived(0), + _firstPlaybackTime(), + _packetsReceivedThisPlayback(0) +{ + outputPortAudioError(Pa_Initialize()); + outputPortAudioError(Pa_OpenDefaultStream(&_stream, + 2, + 2, + (paInt16 | paNonInterleaved), + SAMPLE_RATE, + BUFFER_LENGTH_SAMPLES, + audioCallback, + (void*) this)); // start the stream now that sources are good to go - Pa_StartStream(stream); - if (paError != paNoError) goto error; - - - return; - -error: - printLog("-- Failed to initialize portaudio --\n"); - printLog("PortAudio error (%d): %s\n", paError, Pa_GetErrorText(paError)); - initialized = false; - delete[] audioData; + outputPortAudioError(Pa_StartStream(_stream)); + + gettimeofday(&_lastReceiveTime, NULL); } - -float Audio::getInputLoudness() const { - return audioData->lastInputLoudness; +Audio::~Audio() { + if (_stream) { + outputPortAudioError(Pa_CloseStream(_stream)); + outputPortAudioError(Pa_Terminate()); + } } -void Audio::render(int screenWidth, int screenHeight) -{ - if (initialized) { +// Take a pointer to the acquired microphone input samples and add procedural sounds +void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { + const float MAX_AUDIBLE_VELOCITY = 6.0; + const float MIN_AUDIBLE_VELOCITY = 0.1; + const int VOLUME_BASELINE = 400; + const float SOUND_PITCH = 8.f; + + float speed = glm::length(_lastVelocity); + float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + + // Add a noise-modulated sinewave with volume that tapers off with speed increasing + if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t)((cosf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + } + } +} + +void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes) { + const int NUM_INITIAL_PACKETS_DISCARD = 3; + + timeval currentReceiveTime; + gettimeofday(¤tReceiveTime, NULL); + _totalPacketsReceived++; + + double timeDiff = diffclock(&_lastReceiveTime, ¤tReceiveTime); + + // Discard first few received packets for computing jitter (often they pile up on start) + if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) { + ::stdev.addValue(timeDiff); + } + + if (::stdev.getSamples() > 500) { + _measuredJitter = ::stdev.getStDev(); + //printLog("Avg: %4.2f, Stdev: %4.2f\n", stdev.getAverage(), sharedAudioData->measuredJitter); + ::stdev.reset(); + } + + if (!_ringBuffer.isStarted()) { + _packetsReceivedThisPlayback++; + } + + if (_packetsReceivedThisPlayback == 1) { + gettimeofday(&_firstPlaybackTime, NULL); + } + + _ringBuffer.parseData((unsigned char *)receivedData, PACKET_LENGTH_BYTES); + + _lastReceiveTime = currentReceiveTime; +} + +void Audio::render(int screenWidth, int screenHeight) { + if (_stream) { glLineWidth(2.0); glBegin(GL_LINES); glColor3f(1,1,1); @@ -438,25 +390,23 @@ void Audio::render(int screenWidth, int screenHeight) } glEnd(); - // Show a bar with the amount of audio remaining in ring buffer beyond current playback float remainingBuffer = 0; timeval currentTime; gettimeofday(¤tTime, NULL); float timeLeftInCurrentBuffer = 0; - if (audioData->lastCallback.tv_usec > 0) { - timeLeftInCurrentBuffer = AUDIO_CALLBACK_MSECS - diffclock(&audioData->lastCallback, ¤tTime); + if (_lastCallbackTime.tv_usec > 0) { + timeLeftInCurrentBuffer = AUDIO_CALLBACK_MSECS - diffclock(&_lastCallbackTime, ¤tTime); } - - // /(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth - if (audioData->ringBuffer->getEndOfLastWrite() != NULL) - remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * AUDIO_CALLBACK_MSECS; + if (_ringBuffer.getEndOfLastWrite() != NULL) + remainingBuffer = _ringBuffer.diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * AUDIO_CALLBACK_MSECS; - if (audioData->wasStarved == 0) glColor3f(0, 1, 0); - else { - glColor3f(0.5 + (float)audioData->wasStarved/20.0, 0, 0); - audioData->wasStarved--; + if (_wasStarved == 0) { + glColor3f(0, 1, 0); + } else { + glColor3f(0.5 + (_wasStarved / 20.0f), 0, 0); + _wasStarved--; } glBegin(GL_QUADS); @@ -466,26 +416,29 @@ void Audio::render(int screenWidth, int screenHeight) glVertex2f(startX, bottomY - 2); glEnd(); - if (audioData->averagedLatency == 0.0) audioData->averagedLatency = remainingBuffer + timeLeftInCurrentBuffer; - else audioData->averagedLatency = 0.99*audioData->averagedLatency + 0.01*((float)remainingBuffer + (float)timeLeftInCurrentBuffer); + if (_averagedLatency == 0.0) { + _averagedLatency = remainingBuffer + timeLeftInCurrentBuffer; + } else { + _averagedLatency = 0.99f * _averagedLatency + 0.01f * (remainingBuffer + timeLeftInCurrentBuffer); + } // 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/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); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 2, topY - 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 2, topY - 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth + 2, bottomY + 2); + glVertex2f(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 2, bottomY + 2); glEnd(); char out[40]; - sprintf(out, "%3.0f\n", audioData->averagedLatency); - drawtext(startX + audioData->averagedLatency/AUDIO_CALLBACK_MSECS*frameWidth - 10, topY-10, 0.10, 0, 1, 0, out, 1,1,0); + sprintf(out, "%3.0f\n", _averagedLatency); + drawtext(startX + _averagedLatency / AUDIO_CALLBACK_MSECS * frameWidth - 10, topY - 10, 0.10, 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 - int jitterPels = (float) audioData->measuredJitter/ ((1000.0*(float)PACKET_LENGTH_SAMPLES/(float)SAMPLE_RATE)) * (float)frameWidth; + int jitterPels = _measuredJitter / ((1000.0f * PACKET_LENGTH_SAMPLES / SAMPLE_RATE)) * frameWidth; glColor3f(0,1,1); glBegin(GL_QUADS); @@ -495,7 +448,7 @@ void Audio::render(int screenWidth, int screenHeight) glVertex2f(startX + jitterPels - 2, bottomY + 2); glEnd(); - sprintf(out,"%3.1f\n", audioData->measuredJitter); + sprintf(out,"%3.1f\n", _measuredJitter); drawtext(startX + jitterPels - 5, topY-10, 0.10, 0, 1, 0, out, 0,1,1); sprintf(out, "%3.1fms\n", JITTER_BUFFER_LENGTH_MSECS); @@ -503,34 +456,4 @@ void Audio::render(int screenWidth, int screenHeight) } } -/** - * Close the running audio stream, and deinitialize portaudio. - * Should be called at the end of program execution. - * @return Returns true if the initialization was successful, or false if an error occured. - The error code may be retrieved by Audio::getError(). - */ -bool Audio::terminate() { - stopAudioReceiveThread = true; - pthread_join(audioReceiveThread, NULL); - - if (initialized) { - initialized = false; - - paError = Pa_CloseStream(stream); - if (paError != paNoError) goto error; - - paError = Pa_Terminate(); - if (paError != paNoError) goto error; - } - - delete audioData; - - return true; - -error: - printLog("-- portaudio termination error --\n"); - printLog("PortAudio error (%d): %s\n", paError, Pa_GetErrorText(paError)); - return false; -} - #endif diff --git a/interface/src/Audio.h b/interface/src/Audio.h index d2ad9073be..4a2b2ec974 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -10,44 +10,46 @@ #define __interface__Audio__ #include -#include "AudioData.h" + +#include + #include "Oscilloscope.h" #include "Avatar.h" class Audio { public: // initializes audio I/O - Audio(Oscilloscope *s, Avatar *linkedAvatar); - - void render(); + Audio(Oscilloscope* scope); + ~Audio(); + void render(int screenWidth, int screenHeight); - bool getMixerLoopbackFlag(); - void setMixerLoopbackFlag(bool newMixerLoopbackFlag); + void setMixerLoopbackFlag(bool mixerLoopbackFlag) { _mixerLoopbackFlag = mixerLoopbackFlag; } - float getInputLoudness() const; - void updateMixerParams(in_addr_t mixerAddress, in_port_t mixerPort); + float getLastInputLoudness() const { return _lastInputLoudness; }; - void setLastAcceleration(glm::vec3 a) { audioData->setLastAcceleration(a); }; - void setLastVelocity(glm::vec3 v) { audioData->setLastVelocity(v); }; + void setLastAcceleration(glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; }; + void setLastVelocity(glm::vec3 lastVelocity) { _lastVelocity = lastVelocity; }; - // terminates audio I/O - bool terminate(); + void addProceduralSounds(int16_t* inputBuffer, int numSamples); + + void addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes); private: - bool initialized; - AudioData *audioData; - - // protects constructor so that public init method is used - Audio(); - - // hold potential error returned from PortAudio functions - PaError paError; - - // audio stream handle - PaStream *stream; - - // audio receive thread - pthread_t audioReceiveThread; + PaStream* _stream; + AudioRingBuffer _ringBuffer; + Oscilloscope* _scope; + timeval _lastCallbackTime; + timeval _lastReceiveTime; + float _averagedLatency; + float _measuredJitter; + int _wasStarved; + float _lastInputLoudness; + bool _mixerLoopbackFlag; + glm::vec3 _lastVelocity; + glm::vec3 _lastAcceleration; + int _totalPacketsReceived; + timeval _firstPlaybackTime; + int _packetsReceivedThisPlayback; // give access to AudioData class from audioCallback friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); diff --git a/interface/src/AudioData.cpp b/interface/src/AudioData.cpp deleted file mode 100644 index 83b53b0ea3..0000000000 --- a/interface/src/AudioData.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// AudioData.cpp -// interface -// -// Created by Stephen Birarda on 1/29/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// -#ifndef _WIN32 - -#include "AudioData.h" - -AudioData::AudioData() { - mixerAddress = 0; - mixerPort = 0; - - averagedLatency = 0.0; - lastCallback.tv_usec = 0; - wasStarved = 0; - measuredJitter = 0; - jitterBuffer = 0; - - mixerLoopbackFlag = false; - audioSocket = NULL; -} - - -AudioData::~AudioData() { - delete audioSocket; -} - -// Take a pointer to the acquired microphone input samples and add procedural sounds -void AudioData::addProceduralSounds(int16_t* inputBuffer, int numSamples) { - const float MAX_AUDIBLE_VELOCITY = 6.0; - const float MIN_AUDIBLE_VELOCITY = 0.1; - float speed = glm::length(_lastVelocity); - float volume = 400 * (1.f - speed/MAX_AUDIBLE_VELOCITY); - // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { - for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) ((cosf((float)i / 8.f * speed) * randFloat()) * volume * speed) ; - } - } - - return; -} - - -#endif diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h deleted file mode 100644 index 80de3df6dc..0000000000 --- a/interface/src/AudioData.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// AudioData.h -// interface -// -// Created by Stephen Birarda on 1/29/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#ifndef __interface__AudioData__ -#define __interface__AudioData__ - -#include -#include -#include "AudioRingBuffer.h" -#include "UDPSocket.h" -#include "Avatar.h" - -class AudioData { - public: - AudioData(); - ~AudioData(); - AudioRingBuffer *ringBuffer; - - UDPSocket *audioSocket; - - Avatar *linkedAvatar; - - // store current mixer address and port - in_addr_t mixerAddress; - in_port_t mixerPort; - - timeval lastCallback; - float averagedLatency; - float measuredJitter; - float jitterBuffer; - int wasStarved; - - float lastInputLoudness; - - bool mixerLoopbackFlag; - - // Added avatar acceleration and velocity for procedural effects sounds from client - void setLastVelocity(glm::vec3 v) { _lastVelocity = v; }; - void setLastAcceleration(glm::vec3 a) { _lastAcceleration = a; }; - void addProceduralSounds(int16_t* inputBuffer, int numSamples); - - private: - glm::vec3 _lastVelocity; - glm::vec3 _lastAcceleration; - - -}; - -#endif /* defined(__interface__AudioData__) */ diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index a84a90adad..8c16c17479 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -12,7 +12,6 @@ #include "Camera.h" #include "Environment.h" #include "renderer/ProgramObject.h" -#include "renderer/ShaderObject.h" #include "world.h" void Environment::init() { @@ -57,24 +56,24 @@ void Environment::renderAtmosphere(Camera& camera) { program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos); glm::vec3 lightDirection = glm::normalize(getSunLocation()); program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection); - program->setUniform(locations[INV_WAVELENGTH_LOCATION], + program->setUniformValue(locations[INV_WAVELENGTH_LOCATION], 1 / powf(getScatteringWavelengths().r, 4.0f), 1 / powf(getScatteringWavelengths().g, 4.0f), 1 / powf(getScatteringWavelengths().b, 4.0f)); - program->setUniform(locations[CAMERA_HEIGHT2_LOCATION], height * height); - program->setUniform(locations[OUTER_RADIUS_LOCATION], getAtmosphereOuterRadius()); - program->setUniform(locations[OUTER_RADIUS2_LOCATION], getAtmosphereOuterRadius() * getAtmosphereOuterRadius()); - program->setUniform(locations[INNER_RADIUS_LOCATION], getAtmosphereInnerRadius()); - program->setUniform(locations[KR_ESUN_LOCATION], getRayleighScattering() * getSunBrightness()); - program->setUniform(locations[KM_ESUN_LOCATION], getMieScattering() * getSunBrightness()); - program->setUniform(locations[KR_4PI_LOCATION], getRayleighScattering() * 4.0f * PIf); - program->setUniform(locations[KM_4PI_LOCATION], getMieScattering() * 4.0f * PIf); - program->setUniform(locations[SCALE_LOCATION], 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())); - program->setUniform(locations[SCALE_DEPTH_LOCATION], 0.25f); - program->setUniform(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], + program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height); + program->setUniformValue(locations[OUTER_RADIUS_LOCATION], getAtmosphereOuterRadius()); + program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], getAtmosphereOuterRadius() * getAtmosphereOuterRadius()); + program->setUniformValue(locations[INNER_RADIUS_LOCATION], getAtmosphereInnerRadius()); + program->setUniformValue(locations[KR_ESUN_LOCATION], getRayleighScattering() * getSunBrightness()); + program->setUniformValue(locations[KM_ESUN_LOCATION], getMieScattering() * getSunBrightness()); + program->setUniformValue(locations[KR_4PI_LOCATION], getRayleighScattering() * 4.0f * PIf); + program->setUniformValue(locations[KM_4PI_LOCATION], getMieScattering() * 4.0f * PIf); + program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())); + program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f); + program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], (1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())) / 0.25f); - program->setUniform(locations[G_LOCATION], -0.990f); - program->setUniform(locations[G2_LOCATION], -0.990f * -0.990f); + program->setUniformValue(locations[G_LOCATION], -0.990f); + program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); @@ -92,26 +91,26 @@ void Environment::renderAtmosphere(Camera& camera) { ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { ProgramObject* program = new ProgramObject(); QByteArray prefix = QByteArray("resources/shaders/SkyFrom") + from; - program->attachFromSourceFile(GL_VERTEX_SHADER_ARB, prefix + ".vert"); - program->attachFromSourceFile(GL_FRAGMENT_SHADER_ARB, prefix + ".frag"); + program->addShaderFromSourceFile(QGLShader::Vertex, prefix + ".vert"); + program->addShaderFromSourceFile(QGLShader::Fragment, prefix + ".frag"); program->link(); - locations[CAMERA_POS_LOCATION] = program->getUniformLocation("v3CameraPos"); - locations[LIGHT_POS_LOCATION] = program->getUniformLocation("v3LightPos"); - locations[INV_WAVELENGTH_LOCATION] = program->getUniformLocation("v3InvWavelength"); - locations[CAMERA_HEIGHT2_LOCATION] = program->getUniformLocation("fCameraHeight2"); - locations[OUTER_RADIUS_LOCATION] = program->getUniformLocation("fOuterRadius"); - locations[OUTER_RADIUS2_LOCATION] = program->getUniformLocation("fOuterRadius2"); - locations[INNER_RADIUS_LOCATION] = program->getUniformLocation("fInnerRadius"); - locations[KR_ESUN_LOCATION] = program->getUniformLocation("fKrESun"); - locations[KM_ESUN_LOCATION] = program->getUniformLocation("fKmESun"); - locations[KR_4PI_LOCATION] = program->getUniformLocation("fKr4PI"); - locations[KM_4PI_LOCATION] = program->getUniformLocation("fKm4PI"); - locations[SCALE_LOCATION] = program->getUniformLocation("fScale"); - locations[SCALE_DEPTH_LOCATION] = program->getUniformLocation("fScaleDepth"); - locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->getUniformLocation("fScaleOverScaleDepth"); - locations[G_LOCATION] = program->getUniformLocation("g"); - locations[G2_LOCATION] = program->getUniformLocation("g2"); + locations[CAMERA_POS_LOCATION] = program->uniformLocation("v3CameraPos"); + locations[LIGHT_POS_LOCATION] = program->uniformLocation("v3LightPos"); + locations[INV_WAVELENGTH_LOCATION] = program->uniformLocation("v3InvWavelength"); + locations[CAMERA_HEIGHT2_LOCATION] = program->uniformLocation("fCameraHeight2"); + locations[OUTER_RADIUS_LOCATION] = program->uniformLocation("fOuterRadius"); + locations[OUTER_RADIUS2_LOCATION] = program->uniformLocation("fOuterRadius2"); + locations[INNER_RADIUS_LOCATION] = program->uniformLocation("fInnerRadius"); + locations[KR_ESUN_LOCATION] = program->uniformLocation("fKrESun"); + locations[KM_ESUN_LOCATION] = program->uniformLocation("fKmESun"); + locations[KR_4PI_LOCATION] = program->uniformLocation("fKr4PI"); + locations[KM_4PI_LOCATION] = program->uniformLocation("fKm4PI"); + locations[SCALE_LOCATION] = program->uniformLocation("fScale"); + locations[SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleDepth"); + locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleOverScaleDepth"); + locations[G_LOCATION] = program->uniformLocation("g"); + locations[G2_LOCATION] = program->uniformLocation("g2"); return program; } diff --git a/interface/src/PairingHandler.cpp b/interface/src/PairingHandler.cpp index 3023290708..06028b4427 100644 --- a/interface/src/PairingHandler.cpp +++ b/interface/src/PairingHandler.cpp @@ -19,7 +19,7 @@ const int PAIRING_SERVER_PORT = 7247; void PairingHandler::sendPairRequest() { // grab the agent socket from the AgentList singleton - UDPSocket *agentSocket = &AgentList::getInstance()->getAgentSocket(); + UDPSocket *agentSocket = AgentList::getInstance()->getAgentSocket(); // prepare the pairing request packet diff --git a/interface/src/renderer/ProgramObject.cpp b/interface/src/renderer/ProgramObject.cpp index d2346bf3b3..5108c15068 100644 --- a/interface/src/renderer/ProgramObject.cpp +++ b/interface/src/renderer/ProgramObject.cpp @@ -6,114 +6,15 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include "ProgramObject.h" -#include "ShaderObject.h" -ProgramObject::ProgramObject() : _handle(glCreateProgramObjectARB()) { -} - -ProgramObject::~ProgramObject() { - glDeleteObjectARB(_handle); -} - -void ProgramObject::attach(ShaderObject* shader) { - glAttachObjectARB(_handle, shader->getHandle()); -} - -bool ProgramObject::attachFromSourceCode(int type, const char* source) { - ShaderObject* shader = new ShaderObject(type); - if (shader->compileSourceCode(source)) { - attach(shader); - return true; - - } else { - delete shader; - return false; - } -} - -bool ProgramObject::attachFromSourceFile(int type, const char* filename) { - ShaderObject* shader = new ShaderObject(type); - if (shader->compileSourceFile(filename)) { - attach(shader); - return true; - - } else { - delete shader; - return false; - } -} - -bool ProgramObject::link() { - glLinkProgramARB(_handle); - int status; - glGetObjectParameterivARB(_handle, GL_OBJECT_LINK_STATUS_ARB, &status); - return status; -} - -QByteArray ProgramObject::getLog() const { - int length; - glGetObjectParameterivARB(_handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - QByteArray log(length, 0); - glGetInfoLogARB(_handle, length, 0, log.data()); - return log; -} - -void ProgramObject::bind() const { - glUseProgramObjectARB(_handle); -} - -void ProgramObject::release() const { - glUseProgramObjectARB(0); -} - -int ProgramObject::getUniformLocation(const char* name) const { - return glGetUniformLocationARB(_handle, name); -} - -void ProgramObject::setUniform(int location, int value) { - glUniform1iARB(location, value); -} - -void ProgramObject::setUniform(const char* name, int value) { - setUniform(getUniformLocation(name), value); -} - -void ProgramObject::setUniform(int location, float value) { - glUniform1fARB(location, value); -} - -void ProgramObject::setUniform(const char* name, float value) { - setUniform(getUniformLocation(name), value); -} - -void ProgramObject::setUniform(int location, float x, float y) { - glUniform2fARB(location, x, y); -} - -void ProgramObject::setUniform(const char* name, float x, float y) { - setUniform(getUniformLocation(name), x, y); +ProgramObject::ProgramObject(QObject* parent) : QGLShaderProgram(parent) { } void ProgramObject::setUniform(int location, const glm::vec3& value) { - glUniform3fARB(location, value.x, value.y, value.z); + setUniformValue(location, value.x, value.y, value.z); } void ProgramObject::setUniform(const char* name, const glm::vec3& value) { - setUniform(getUniformLocation(name), value); + setUniformValue(name, value.x, value.y, value.z); } -void ProgramObject::setUniform(int location, float x, float y, float z) { - glUniform3fARB(location, x, y, z); -} - -void ProgramObject::setUniform(const char* name, float x, float y, float z) { - setUniform(getUniformLocation(name), x, y, z); -} - -void ProgramObject::setUniform(int location, float x, float y, float z, float w) { - glUniform4fARB(location, x, y, z, w); -} - -void ProgramObject::setUniform(const char* name, float x, float y, float z, float w) { - setUniform(getUniformLocation(name), x, y, z, w); -} diff --git a/interface/src/renderer/ProgramObject.h b/interface/src/renderer/ProgramObject.h index e46d40c13f..78f07b7a1b 100644 --- a/interface/src/renderer/ProgramObject.h +++ b/interface/src/renderer/ProgramObject.h @@ -9,58 +9,17 @@ #ifndef __interface__ProgramObject__ #define __interface__ProgramObject__ -#include +#include #include -#include "InterfaceConfig.h" - -class ShaderObject; - -class ProgramObject { +class ProgramObject : public QGLShaderProgram { public: - ProgramObject(); - ~ProgramObject(); - - GLhandleARB getHandle() const { return _handle; } + ProgramObject(QObject* parent = 0); - void attach(ShaderObject* shader); - bool attachFromSourceCode(int type, const char* source); - bool attachFromSourceFile(int type, const char* filename); - - bool link(); - - QByteArray getLog() const; - - void bind() const; - void release() const; - - int getUniformLocation(const char* name) const; - - void setUniform(int location, int value); - void setUniform(const char* name, int value); - - void setUniform(int location, float value); - void setUniform(const char* name, float value); - - void setUniform(int location, float x, float y); - void setUniform(const char* name, float x, float y); - void setUniform(int location, const glm::vec3& value); void setUniform(const char* name, const glm::vec3& value); - - void setUniform(int location, float x, float y, float z); - void setUniform(const char* name, float x, float y, float z); - - void setUniform(int location, float x, float y, float z, float w); - void setUniform(const char* name, float x, float y, float z, float w); - -private: - - Q_DISABLE_COPY(ProgramObject) - - GLhandleARB _handle; }; #endif /* defined(__interface__ProgramObject__) */ diff --git a/interface/src/renderer/ShaderObject.cpp b/interface/src/renderer/ShaderObject.cpp deleted file mode 100644 index d6c1e7ced4..0000000000 --- a/interface/src/renderer/ShaderObject.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// ShaderObject.cpp -// interface -// -// Created by Andrzej Kapolka on 5/7/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. - -#include - -#include "ShaderObject.h" - -ShaderObject::ShaderObject(int type) - : _handle(glCreateShaderObjectARB(type)) { -} - -ShaderObject::~ShaderObject() { - glDeleteObjectARB(_handle); -} - -bool ShaderObject::compileSourceCode(const char* data) { - glShaderSourceARB(_handle, 1, &data, 0); - glCompileShaderARB(_handle); - int status; - glGetObjectParameterivARB(_handle, GL_OBJECT_COMPILE_STATUS_ARB, &status); - return status; -} - -bool ShaderObject::compileSourceFile(const char* filename) { - QFile file(filename); - return file.open(QIODevice::ReadOnly) && compileSourceCode(file.readAll().constData()); -} - -QByteArray ShaderObject::getLog() const { - int length; - glGetObjectParameterivARB(_handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - QByteArray log(length, 0); - glGetInfoLogARB(_handle, length, 0, log.data()); - return log; -} diff --git a/interface/src/renderer/ShaderObject.h b/interface/src/renderer/ShaderObject.h deleted file mode 100644 index 297650a40f..0000000000 --- a/interface/src/renderer/ShaderObject.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// ShaderObject.h -// interface -// -// Created by Andrzej Kapolka on 5/7/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__ShaderObject__ -#define __interface__ShaderObject__ - -#include - -#include "InterfaceConfig.h" - -class ShaderObject { -public: - - ShaderObject(int type); - ~ShaderObject(); - - GLhandleARB getHandle() const { return _handle; } - - bool compileSourceCode(const char* data); - bool compileSourceFile(const char* filename); - - QByteArray getLog() const; - -private: - - Q_DISABLE_COPY(ShaderObject) - - GLhandleARB _handle; -}; - -#endif /* defined(__interface__ShaderObject__) */ diff --git a/interface/src/starfield/Loader.h b/interface/src/starfield/Loader.h index b423d5f1ed..79ae7f7700 100644 --- a/interface/src/starfield/Loader.h +++ b/interface/src/starfield/Loader.h @@ -13,6 +13,8 @@ #error "This is an implementation file - not intended for direct inclusion." #endif +#include + #include "Config.h" #include "starfield/data/InputVertex.h" @@ -99,6 +101,7 @@ namespace starfield { // parse float azi, alt; unsigned c; + setlocale(LC_NUMERIC, "C"); if (sscanf(line, " %f %f #%x", & azi, & alt, & c) == 3) { if (spaceFor( getBrightness(c) )) { diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h index 8a7e4bd6de..97b565c767 100644 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -478,15 +478,15 @@ namespace starfield { " gl_PointSize = s;\n" "}\n"; - _objProgram.attachFromSourceCode(GL_VERTEX_SHADER, VERTEX_SHADER); + _objProgram.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER); GLchar const* const FRAGMENT_SHADER = "#version 120\n" "void main(void) {\n" " gl_FragColor = gl_Color;\n" "}\n"; - _objProgram.attachFromSourceCode(GL_FRAGMENT_SHADER, FRAGMENT_SHADER); + _objProgram.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER); _objProgram.link(); - _alphaLocation = _objProgram.getUniformLocation("alpha"); + _alphaLocation = _objProgram.uniformLocation("alpha"); glGenBuffersARB(1, & _hndVertexArray); } @@ -534,7 +534,7 @@ namespace starfield { // select shader and vertex array _objProgram.bind(); - _objProgram.setUniform(_alphaLocation, alpha); + _objProgram.setUniformValue(_alphaLocation, alpha); glBindBufferARB(GL_ARRAY_BUFFER, _hndVertexArray); glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l); diff --git a/libraries/shared/src/Agent.cpp b/libraries/shared/src/Agent.cpp index a8a47b6134..db4170515a 100644 --- a/libraries/shared/src/Agent.cpp +++ b/libraries/shared/src/Agent.cpp @@ -22,79 +22,70 @@ using shared_lib::printLog; -int unpackAgentId(unsigned char *packedData, uint16_t *agentId) { +int unpackAgentId(unsigned char* packedData, uint16_t* agentId) { memcpy(agentId, packedData, sizeof(uint16_t)); return sizeof(uint16_t); } -int packAgentId(unsigned char *packStore, uint16_t agentId) { +int packAgentId(unsigned char* packStore, uint16_t agentId) { memcpy(packStore, &agentId, sizeof(uint16_t)); return sizeof(uint16_t); } -Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId) : +Agent::Agent(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t agentID) : + _type(type), + _agentID(agentID), + _wakeMicrostamp(usecTimestampNow()), + _lastHeardMicrostamp(usecTimestampNow()), + _activeSocket(NULL), + _bytesReceivedMovingAverage(NULL), + _linkedData(NULL), _isAlive(true) { - if (agentPublicSocket != NULL) { - publicSocket = new sockaddr; - memcpy(publicSocket, agentPublicSocket, sizeof(sockaddr)); + if (publicSocket) { + _publicSocket = new sockaddr(*publicSocket); } else { - publicSocket = NULL; + _publicSocket = NULL; } - if (agentLocalSocket != NULL) { - localSocket = new sockaddr; - memcpy(localSocket, agentLocalSocket, sizeof(sockaddr)); + if (localSocket) { + _localSocket = new sockaddr(*localSocket); } else { - localSocket = NULL; + _localSocket = NULL; } - - type = agentType; - agentId = thisAgentId; - - _wakeMicrostamp = usecTimestampNow(); - _lastHeardMicrostamp = usecTimestampNow(); - - activeSocket = NULL; - linkedData = NULL; - _bytesReceivedMovingAverage = NULL; } -Agent::Agent(const Agent &otherAgent) { - _isAlive = otherAgent._isAlive; - - if (otherAgent.publicSocket != NULL) { - publicSocket = new sockaddr; - memcpy(publicSocket, otherAgent.publicSocket, sizeof(sockaddr)); +Agent::Agent(const Agent &otherAgent) : + _type(otherAgent._type), + _agentID(otherAgent._agentID), + _wakeMicrostamp(otherAgent._wakeMicrostamp), + _lastHeardMicrostamp(otherAgent._lastHeardMicrostamp), + _isAlive(otherAgent._isAlive) +{ + if (otherAgent._publicSocket) { + _publicSocket = new sockaddr(*otherAgent._localSocket); } else { - publicSocket = NULL; + _publicSocket = NULL; } - if (otherAgent.localSocket != NULL) { - localSocket = new sockaddr; - memcpy(localSocket, otherAgent.localSocket, sizeof(sockaddr)); + if (otherAgent._localSocket) { + _localSocket = new sockaddr(*otherAgent._localSocket); } else { - localSocket = NULL; + _localSocket = NULL; } - agentId = otherAgent.agentId; - - if (otherAgent.activeSocket == otherAgent.publicSocket) { - activeSocket = publicSocket; - } else if (otherAgent.activeSocket == otherAgent.localSocket) { - activeSocket = localSocket; + if (otherAgent._activeSocket == otherAgent._publicSocket) { + _activeSocket = _publicSocket; + } else if (otherAgent._activeSocket == otherAgent._localSocket) { + _activeSocket = _localSocket; } else { - activeSocket = NULL; + _activeSocket = NULL; } - _wakeMicrostamp = otherAgent._wakeMicrostamp; - _lastHeardMicrostamp = otherAgent._lastHeardMicrostamp; - type = otherAgent.type; - - if (otherAgent.linkedData != NULL) { - linkedData = otherAgent.linkedData->clone(); + if (otherAgent._linkedData) { + _linkedData = otherAgent._linkedData->clone(); } else { - linkedData = NULL; + _linkedData = NULL; } if (otherAgent._bytesReceivedMovingAverage != NULL) { @@ -114,115 +105,69 @@ void Agent::swap(Agent &first, Agent &second) { using std::swap; swap(first._isAlive, second._isAlive); - swap(first.publicSocket, second.publicSocket); - swap(first.localSocket, second.localSocket); - swap(first.activeSocket, second.activeSocket); - swap(first.type, second.type); - swap(first.linkedData, second.linkedData); - swap(first.agentId, second.agentId); + swap(first._publicSocket, second._publicSocket); + swap(first._localSocket, second._localSocket); + swap(first._activeSocket, second._activeSocket); + swap(first._type, second._type); + swap(first._linkedData, second._linkedData); + swap(first._agentID, second._agentID); swap(first._wakeMicrostamp, second._wakeMicrostamp); swap(first._lastHeardMicrostamp, second._lastHeardMicrostamp); swap(first._bytesReceivedMovingAverage, second._bytesReceivedMovingAverage); } Agent::~Agent() { - delete publicSocket; - delete localSocket; - delete linkedData; + delete _publicSocket; + delete _localSocket; + delete _linkedData; delete _bytesReceivedMovingAverage; } -char Agent::getType() const { - return type; -} - // Names of Agent Types const char* AGENT_TYPE_NAME_DOMAIN = "Domain"; const char* AGENT_TYPE_NAME_VOXEL = "Voxel Server"; const char* AGENT_TYPE_NAME_INTERFACE = "Client Interface"; const char* AGENT_TYPE_NAME_AUDIO_MIXER = "Audio Mixer"; const char* AGENT_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer"; +const char* AGENT_TYPE_NAME_AUDIO_INJECTOR = "Audio Injector"; const char* AGENT_TYPE_NAME_UNKNOWN = "Unknown"; const char* Agent::getTypeName() const { - const char* name = AGENT_TYPE_NAME_UNKNOWN; - switch (this->type) { + switch (this->_type) { case AGENT_TYPE_DOMAIN: - name = AGENT_TYPE_NAME_DOMAIN; - break; + return AGENT_TYPE_NAME_DOMAIN; case AGENT_TYPE_VOXEL: - name = AGENT_TYPE_NAME_VOXEL; - break; + return AGENT_TYPE_NAME_VOXEL; case AGENT_TYPE_AVATAR: - name = AGENT_TYPE_NAME_INTERFACE; - break; + return AGENT_TYPE_NAME_INTERFACE; case AGENT_TYPE_AUDIO_MIXER: - name = AGENT_TYPE_NAME_AUDIO_MIXER; - break; + return AGENT_TYPE_NAME_AUDIO_MIXER; case AGENT_TYPE_AVATAR_MIXER: - name = AGENT_TYPE_NAME_AVATAR_MIXER; - break; + return AGENT_TYPE_NAME_AVATAR_MIXER; + case AGENT_TYPE_AUDIO_INJECTOR: + return AGENT_TYPE_NAME_AUDIO_INJECTOR; + default: + return AGENT_TYPE_NAME_UNKNOWN; } - return name; -} - -void Agent::setType(char newType) { - type = newType; -} - -uint16_t Agent::getAgentId() { - return agentId; -} - -void Agent::setAgentId(uint16_t thisAgentId) { - agentId = thisAgentId; -} - -sockaddr* Agent::getPublicSocket() { - return publicSocket; -} - -void Agent::setPublicSocket(sockaddr *newSocket) { - publicSocket = newSocket; -} - -sockaddr* Agent::getLocalSocket() { - return localSocket; -} - -void Agent::setLocalSocket(sockaddr *newSocket) { - publicSocket = newSocket; -} - -sockaddr* Agent::getActiveSocket() { - return activeSocket; } void Agent::activateLocalSocket() { - activeSocket = localSocket; + _activeSocket = _localSocket; } void Agent::activatePublicSocket() { - activeSocket = publicSocket; -} - -AgentData* Agent::getLinkedData() { - return linkedData; -} - -void Agent::setLinkedData(AgentData *newData) { - linkedData = newData; + _activeSocket = _publicSocket; } bool Agent::operator==(const Agent& otherAgent) { - return matches(otherAgent.publicSocket, otherAgent.localSocket, otherAgent.type); + return matches(otherAgent._publicSocket, otherAgent._localSocket, otherAgent._type); } bool Agent::matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, char otherAgentType) { // checks if two agent objects are the same agent (same type + local + public address) - return type == otherAgentType - && socketMatch(publicSocket, otherPublicSocket) - && socketMatch(localSocket, otherLocalSocket); + return _type == otherAgentType + && socketMatch(_publicSocket, otherPublicSocket) + && socketMatch(_localSocket, otherLocalSocket); } void Agent::recordBytesReceived(int bytesReceived) { @@ -252,15 +197,15 @@ float Agent::getAverageKilobitsPerSecond() { void Agent::printLog(Agent const& agent) { char publicAddressBuffer[16] = {'\0'}; - unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent.publicSocket); + unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent._publicSocket); //char localAddressBuffer[16] = {'\0'}; //unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, agent.localSocket); ::printLog("# %d %s (%c) @ %s:%d\n", - agent.agentId, + agent._agentID, agent.getTypeName(), - agent.type, + agent._type, publicAddressBuffer, publicAddressPort); } \ No newline at end of file diff --git a/libraries/shared/src/Agent.h b/libraries/shared/src/Agent.h index b611770593..55ef67c8e5 100644 --- a/libraries/shared/src/Agent.h +++ b/libraries/shared/src/Agent.h @@ -23,20 +23,20 @@ class Agent { public: - Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId); + Agent(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t agentID); Agent(const Agent &otherAgent); ~Agent(); Agent& operator=(Agent otherAgent); bool operator==(const Agent& otherAgent); - bool matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, char otherAgentType); + bool matches(sockaddr* otherPublicSocket, sockaddr* otherLocalSocket, char otherAgentType); - char getType() const; + char getType() const { return _type; } + void setType(char type) { _type = type; } const char* getTypeName() const; - void setType(char newType); - uint16_t getAgentId(); - void setAgentId(uint16_t thisAgentId); + uint16_t getAgentID() const { return _agentID; } + void setAgentID(uint16_t agentID) { _agentID = agentID;} double getWakeMicrostamp() const { return _wakeMicrostamp; } void setWakeMicrostamp(double wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; } @@ -44,17 +44,18 @@ public: double getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } void setLastHeardMicrostamp(double lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } - sockaddr* getPublicSocket(); - void setPublicSocket(sockaddr *newSocket); - sockaddr* getLocalSocket(); - void setLocalSocket(sockaddr *newSocket); - sockaddr* getActiveSocket(); + sockaddr* getPublicSocket() const { return _publicSocket; } + void setPublicSocket(sockaddr* publicSocket) { _publicSocket = publicSocket; } + sockaddr* getLocalSocket() const { return _localSocket; } + void setLocalSocket(sockaddr* localSocket) { _localSocket = localSocket; } + + sockaddr* getActiveSocket() const { return _activeSocket; } void activatePublicSocket(); void activateLocalSocket(); - AgentData* getLinkedData(); - void setLinkedData(AgentData *newData); + AgentData* getLinkedData() const { return _linkedData; } + void setLinkedData(AgentData* linkedData) { _linkedData = linkedData; } bool isAlive() const { return _isAlive; }; void setAlive(bool isAlive) { _isAlive = isAlive; }; @@ -67,13 +68,15 @@ public: private: void swap(Agent &first, Agent &second); - sockaddr *publicSocket, *localSocket, *activeSocket; - char type; - uint16_t agentId; + char _type; + uint16_t _agentID; double _wakeMicrostamp; double _lastHeardMicrostamp; + sockaddr* _publicSocket; + sockaddr* _localSocket; + sockaddr* _activeSocket; SimpleMovingAverage* _bytesReceivedMovingAverage; - AgentData* linkedData; + AgentData* _linkedData; bool _isAlive; }; diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 44364bfc88..fef0446056 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -78,10 +78,6 @@ AgentList::~AgentList() { pthread_mutex_destroy(&mutex); } -UDPSocket& AgentList::getAgentSocket() { - return agentSocket; -} - unsigned int AgentList::getSocketListenPort() { return socketListenPort; } @@ -184,7 +180,7 @@ Agent* AgentList::agentWithAddress(sockaddr *senderAddress) { Agent* AgentList::agentWithID(uint16_t agentID) { for(AgentList::iterator agent = begin(); agent != end(); agent++) { - if (agent->getAgentId() == agentID) { + if (agent->getAgentID() == agentID) { return &(*agent); } } @@ -243,14 +239,10 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, // set the agent active right away newAgent->activatePublicSocket(); } - - if (newAgent->getType() == AGENT_TYPE_AUDIO_MIXER && audioMixerSocketUpdate != NULL) { - // this is an audio mixer - // for now that means we need to tell the audio class - // to use the local socket information the domain server gave us - sockaddr_in *publicSocketIn = (sockaddr_in *)publicSocket; - audioMixerSocketUpdate(publicSocketIn->sin_addr.s_addr, publicSocketIn->sin_port); - } else if (newAgent->getType() == AGENT_TYPE_VOXEL || newAgent->getType() == AGENT_TYPE_AVATAR_MIXER) { + + if (newAgent->getType() == AGENT_TYPE_VOXEL || + newAgent->getType() == AGENT_TYPE_AVATAR_MIXER || + newAgent->getType() == AGENT_TYPE_AUDIO_MIXER) { // this is currently the cheat we use to talk directly to our test servers on EC2 // to be removed when we have a proper identification strategy newAgent->activatePublicSocket(); @@ -341,8 +333,8 @@ void *pingUnknownAgents(void *args) { && (agent->getPublicSocket() != NULL && agent->getLocalSocket() != NULL)) { // ping both of the sockets for the agent so we can figure out // which socket we can use - agentList->getAgentSocket().send(agent->getPublicSocket(), &PACKET_HEADER_PING, 1); - agentList->getAgentSocket().send(agent->getLocalSocket(), &PACKET_HEADER_PING, 1); + agentList->getAgentSocket()->send(agent->getPublicSocket(), &PACKET_HEADER_PING, 1); + agentList->getAgentSocket()->send(agent->getLocalSocket(), &PACKET_HEADER_PING, 1); } } @@ -437,7 +429,7 @@ void *checkInWithDomainServer(void *args) { packSocket(packet + 2, localAddress, htons(parentAgentList->getSocketListenPort())); - parentAgentList->getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, packet, sizeof(packet)); + parentAgentList->getAgentSocket()->send(DOMAIN_IP, DOMAINSERVER_PORT, packet, sizeof(packet)); packet[0] = PACKET_HEADER_DOMAIN_LIST_REQUEST; diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index db71357114..280927929f 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -46,11 +46,10 @@ public: AgentListIterator end() const; void(*linkedDataCreateCallback)(Agent *); - void(*audioMixerSocketUpdate)(in_addr_t, in_port_t); int size() { return _numAgents; } - UDPSocket& getAgentSocket(); + UDPSocket* getAgentSocket() { return &agentSocket; } void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } diff --git a/libraries/shared/src/AgentTypes.h b/libraries/shared/src/AgentTypes.h index c43af79446..e095cb1035 100644 --- a/libraries/shared/src/AgentTypes.h +++ b/libraries/shared/src/AgentTypes.h @@ -20,8 +20,9 @@ // Agent Type Codes const char AGENT_TYPE_DOMAIN = 'D'; const char AGENT_TYPE_VOXEL = 'V'; -const char AGENT_TYPE_AVATAR = 'I'; // could also be injector??? +const char AGENT_TYPE_AVATAR = 'I'; const char AGENT_TYPE_AUDIO_MIXER = 'M'; const char AGENT_TYPE_AVATAR_MIXER = 'W'; +const char AGENT_TYPE_AUDIO_INJECTOR = 'A'; #endif diff --git a/libraries/shared/src/AudioInjector.cpp b/libraries/shared/src/AudioInjector.cpp index 6e65c168d0..c89385226c 100644 --- a/libraries/shared/src/AudioInjector.cpp +++ b/libraries/shared/src/AudioInjector.cpp @@ -21,33 +21,43 @@ const float SAMPLE_RATE = 22050.0f; const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000; AudioInjector::AudioInjector(const char* filename) : - _numTotalBytesAudio(0), + _position(), _bearing(0), - _attenuationModifier(255) + _attenuationModifier(255), + _indexOfNextSlot(0), + _isInjectingAudio(false) { - _position[0] = 0.0f; - _position[1] = 0.0f; - _position[2] = 0.0f; - std::fstream sourceFile; sourceFile.open(filename, std::ios::in | std::ios::binary); sourceFile.seekg(0, std::ios::end); - _numTotalBytesAudio = sourceFile.tellg(); - if (_numTotalBytesAudio == -1) { + int totalBytes = sourceFile.tellg(); + if (totalBytes == -1) { printf("Error reading audio data from file %s\n", filename); _audioSampleArray = NULL; } else { - printf("Read %d bytes from audio file\n", _numTotalBytesAudio); + printf("Read %d bytes from audio file\n", totalBytes); sourceFile.seekg(0, std::ios::beg); - long sizeOfShortArray = _numTotalBytesAudio / 2; - _audioSampleArray = new int16_t[sizeOfShortArray]; + _numTotalSamples = totalBytes / 2; + _audioSampleArray = new int16_t[_numTotalSamples]; - sourceFile.read((char *)_audioSampleArray, _numTotalBytesAudio); + sourceFile.read((char *)_audioSampleArray, totalBytes); } } +AudioInjector::AudioInjector(int maxNumSamples) : + _numTotalSamples(maxNumSamples), + _position(), + _bearing(0), + _attenuationModifier(255), + _indexOfNextSlot(0), + _isInjectingAudio(false) +{ + _audioSampleArray = new int16_t[maxNumSamples]; + memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t)); +} + AudioInjector::~AudioInjector() { delete[] _audioSampleArray; } @@ -58,8 +68,25 @@ void AudioInjector::setPosition(float* position) { _position[2] = position[2]; } -void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const { - if (_audioSampleArray != NULL) { +void AudioInjector::addSample(const int16_t sample) { + if (_indexOfNextSlot != _numTotalSamples) { + // only add this sample if we actually have space for it + _audioSampleArray[_indexOfNextSlot++] = sample; + } +} + +void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { + if (_audioSampleArray + _indexOfNextSlot + numSamples <= _audioSampleArray + (_numTotalSamples / sizeof(int16_t))) { + // only copy the audio from the sample buffer if there's space + memcpy(_audioSampleArray + _indexOfNextSlot, sampleBuffer, numSamples * sizeof(int16_t)); + _indexOfNextSlot += numSamples; + } +} + +void AudioInjector::injectAudio() { + if (_audioSampleArray) { + _isInjectingAudio = true; + timeval startTime; // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte @@ -80,24 +107,38 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, &_bearing, sizeof(float)); currentPacketPtr += sizeof(float); - for (int i = 0; i < _numTotalBytesAudio; i += BUFFER_LENGTH_BYTES) { + for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { gettimeofday(&startTime, NULL); - int numBytesToCopy = BUFFER_LENGTH_BYTES; + int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; - if (_numTotalBytesAudio - i < BUFFER_LENGTH_BYTES) { - numBytesToCopy = _numTotalBytesAudio - i; - memset(currentPacketPtr + numBytesToCopy, 0, BUFFER_LENGTH_BYTES - numBytesToCopy); + if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { + numSamplesToCopy = _numTotalSamples - i; + memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); } - memcpy(currentPacketPtr, _audioSampleArray + (i / 2), numBytesToCopy); + memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); - injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); + _injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket)); double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); if (usecToSleep > 0) { usleep(usecToSleep); } } + + _isInjectingAudio = false; } } + +void* injectAudioViaThread(void* args) { + AudioInjector* parentInjector = (AudioInjector*) args; + parentInjector->injectAudio(); + + pthread_exit(0); +} + +void AudioInjector::threadInjectionOfAudio() { + pthread_t audioInjectThread; + pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) this); +} diff --git a/libraries/shared/src/AudioInjector.h b/libraries/shared/src/AudioInjector.h index 2515dcfcdc..3e79869034 100644 --- a/libraries/shared/src/AudioInjector.h +++ b/libraries/shared/src/AudioInjector.h @@ -17,19 +17,32 @@ class AudioInjector { public: AudioInjector(const char* filename); + AudioInjector(int maxNumSamples); ~AudioInjector(); + bool isInjectingAudio() const { return _isInjectingAudio; } + void setPosition(float* position); void setBearing(float bearing) { _bearing = bearing; } void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; } + void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket; } + void setDestinationSocket(sockaddr* destinationSocket) { _destinationSocket = *destinationSocket; } - void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const; + void addSample(const int16_t sample); + void addSamples(int16_t* sampleBuffer, int numSamples); + + void injectAudio(); + void threadInjectionOfAudio(); private: int16_t* _audioSampleArray; - int _numTotalBytesAudio; + int _numTotalSamples; float _position[3]; float _bearing; unsigned char _attenuationModifier; + int _indexOfNextSlot; + UDPSocket* _injectorSocket; + sockaddr _destinationSocket; + bool _isInjectingAudio; }; #endif /* defined(__hifi__AudioInjector__) */ diff --git a/libraries/shared/src/AudioRingBuffer.cpp b/libraries/shared/src/AudioRingBuffer.cpp index b49b65945c..746ff523f8 100644 --- a/libraries/shared/src/AudioRingBuffer.cpp +++ b/libraries/shared/src/AudioRingBuffer.cpp @@ -7,6 +7,9 @@ // #include + +#include "PacketHeaders.h" + #include "AudioRingBuffer.h" AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : @@ -46,18 +49,22 @@ AudioRingBuffer* AudioRingBuffer::clone() const { const int AGENT_LOOPBACK_MODIFIER = 307; int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { - if (numBytes > (_bufferLengthSamples * sizeof(int16_t))) { + + unsigned char* dataBuffer = sourceBuffer + 1; + + if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO || + sourceBuffer[0] == PACKET_HEADER_MICROPHONE_AUDIO) { + // if this came from an injector or interface client + // there's data required for spatialization to pull out - unsigned char *dataPtr = sourceBuffer + 1; + memcpy(&_position, dataBuffer, sizeof(_position)); + dataBuffer += (sizeof(_position)); - memcpy(&_position, dataPtr, sizeof(_position)); - dataPtr += (sizeof(_position)); - - unsigned int attenuationByte = *(dataPtr++); + unsigned int attenuationByte = *(dataBuffer++); _attenuationRatio = attenuationByte / 255.0f; - memcpy(&_bearing, dataPtr, sizeof(float)); - dataPtr += sizeof(_bearing); + memcpy(&_bearing, dataBuffer, sizeof(float)); + dataBuffer += sizeof(_bearing); if (_bearing > 180 || _bearing < -180) { // we were passed an invalid bearing because this agent wants loopback (pressed the H key) @@ -70,8 +77,6 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { } else { _shouldLoopbackForAgent = false; } - - sourceBuffer = dataPtr; } if (!_endOfLastWrite) { @@ -82,7 +87,7 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { _started = false; } - memcpy(_endOfLastWrite, sourceBuffer, _bufferLengthSamples * sizeof(int16_t)); + memcpy(_endOfLastWrite, dataBuffer, _bufferLengthSamples * sizeof(int16_t)); _endOfLastWrite += _bufferLengthSamples; diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 1b385a68f7..8d9c4ae880 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -20,6 +20,8 @@ const PACKET_HEADER PACKET_HEADER_PING_REPLY = 'R'; const PACKET_HEADER PACKET_HEADER_HEAD_DATA = 'H'; const PACKET_HEADER PACKET_HEADER_Z_COMMAND = 'Z'; const PACKET_HEADER PACKET_HEADER_INJECT_AUDIO = 'I'; +const PACKET_HEADER PACKET_HEADER_MIXED_AUDIO = 'A'; +const PACKET_HEADER PACKET_HEADER_MICROPHONE_AUDIO = 'M'; const PACKET_HEADER PACKET_HEADER_SET_VOXEL = 'S'; const PACKET_HEADER PACKET_HEADER_SET_VOXEL_DESTRUCTIVE = 'O'; const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E'; diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 31040946e0..88930d4af4 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -27,7 +27,7 @@ using shared_lib::printLog; sockaddr_in destSockaddr, senderAddress; -bool socketMatch(sockaddr *first, sockaddr *second) { +bool socketMatch(sockaddr* first, sockaddr* second) { if (first != NULL && second != NULL) { // utility function that indicates if two sockets are equivalent @@ -51,7 +51,7 @@ bool socketMatch(sockaddr *first, sockaddr *second) { } } -int packSocket(unsigned char *packStore, in_addr_t inAddress, in_port_t networkOrderPort) { +int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort) { packStore[0] = inAddress >> 24; packStore[1] = inAddress >> 16; packStore[2] = inAddress >> 8; @@ -63,12 +63,12 @@ int packSocket(unsigned char *packStore, in_addr_t inAddress, in_port_t networkO return 6; // could be dynamically more if we need IPv6 } -int packSocket(unsigned char *packStore, sockaddr *socketToPack) { - return packSocket(packStore, ((sockaddr_in *) socketToPack)->sin_addr.s_addr, ((sockaddr_in *) socketToPack)->sin_port); +int packSocket(unsigned char* packStore, sockaddr* socketToPack) { + return packSocket(packStore, ((sockaddr_in*) socketToPack)->sin_addr.s_addr, ((sockaddr_in*) socketToPack)->sin_port); } -int unpackSocket(unsigned char *packedData, sockaddr *unpackDestSocket) { - sockaddr_in *destinationSocket = (sockaddr_in *) unpackDestSocket; +int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket) { + sockaddr_in* destinationSocket = (sockaddr_in*) unpackDestSocket; destinationSocket->sin_addr.s_addr = (packedData[0] << 24) + (packedData[1] << 16) + (packedData[2] << 8) + packedData[3]; destinationSocket->sin_port = (packedData[4] << 8) + packedData[5]; return 6; // this could be more if we ever need IPv6 @@ -76,8 +76,8 @@ int unpackSocket(unsigned char *packedData, sockaddr *unpackDestSocket) { int getLocalAddress() { // get this agent's local address so we can pass that to DS - struct ifaddrs * ifAddrStruct = NULL; - struct ifaddrs * ifa = NULL; + struct ifaddrs* ifAddrStruct = NULL; + struct ifaddrs* ifa = NULL; int family; int localAddress = 0; @@ -107,9 +107,9 @@ int getLocalAddress() { return localAddress; } -unsigned short loadBufferWithSocketInfo(char *addressBuffer, sockaddr *socket) { +unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) { if (socket != NULL) { - char *copyBuffer = inet_ntoa(((sockaddr_in*) socket)->sin_addr); + char* copyBuffer = inet_ntoa(((sockaddr_in*) socket)->sin_addr); memcpy(addressBuffer, copyBuffer, strlen(copyBuffer)); return htons(((sockaddr_in*) socket)->sin_port); } else { @@ -204,13 +204,12 @@ void UDPSocket::setBlocking(bool blocking) { } // Receive data on this socket with retrieving address of sender -bool UDPSocket::receive(void *receivedData, ssize_t *receivedBytes) { - - return receive((sockaddr *)&senderAddress, receivedData, receivedBytes); +bool UDPSocket::receive(void* receivedData, ssize_t* receivedBytes) const { + return receive((sockaddr*) &senderAddress, receivedData, receivedBytes); } // Receive data on this socket with the address of the sender -bool UDPSocket::receive(sockaddr *recvAddress, void *receivedData, ssize_t *receivedBytes) { +bool UDPSocket::receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const { #ifdef _WIN32 int addressSize = sizeof(*recvAddress); @@ -223,7 +222,7 @@ bool UDPSocket::receive(sockaddr *recvAddress, void *receivedData, ssize_t *rece return (*receivedBytes > 0); } -int UDPSocket::send(sockaddr *destAddress, const void *data, size_t byteLength) { +int UDPSocket::send(sockaddr* destAddress, const void* data, size_t byteLength) const { // send data via UDP int sent_bytes = sendto(handle, (const char*)data, byteLength, 0, (sockaddr *) destAddress, sizeof(sockaddr_in)); @@ -236,7 +235,7 @@ int UDPSocket::send(sockaddr *destAddress, const void *data, size_t byteLength) return sent_bytes; } -int UDPSocket::send(char * destAddress, int destPort, const void *data, size_t byteLength) { +int UDPSocket::send(char* destAddress, int destPort, const void* data, size_t byteLength) const { // change address and port on reusable global to passed variables destSockaddr.sin_addr.s_addr = inet_addr(destAddress); diff --git a/libraries/shared/src/UDPSocket.h b/libraries/shared/src/UDPSocket.h index 80c093d6f4..d246d9e512 100644 --- a/libraries/shared/src/UDPSocket.h +++ b/libraries/shared/src/UDPSocket.h @@ -19,26 +19,26 @@ #define MAX_BUFFER_LENGTH_BYTES 1500 class UDPSocket { - public: - UDPSocket(int listening_port); - ~UDPSocket(); - bool init(); - void setBlocking(bool blocking); - bool isBlocking() { return blocking; } - int send(sockaddr *destAddress, const void *data, size_t byteLength); - int send(char *destAddress, int destPort, const void *data, size_t byteLength); - bool receive(void *receivedData, ssize_t *receivedBytes); - bool receive(sockaddr *recvAddress, void *receivedData, ssize_t *receivedBytes); - private: - int handle; - bool blocking; +public: + UDPSocket(int listening_port); + ~UDPSocket(); + bool init(); + void setBlocking(bool blocking); + bool isBlocking() { return blocking; } + int send(sockaddr* destAddress, const void* data, size_t byteLength) const; + int send(char* destAddress, int destPort, const void* data, size_t byteLength) const; + bool receive(void* receivedData, ssize_t* receivedBytes) const; + bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const; +private: + int handle; + bool blocking; }; -bool socketMatch(sockaddr *first, sockaddr *second); -int packSocket(unsigned char *packStore, in_addr_t inAddress, in_port_t networkOrderPort); -int packSocket(unsigned char *packStore, sockaddr *socketToPack); -int unpackSocket(unsigned char *packedData, sockaddr *unpackDestSocket); +bool socketMatch(sockaddr* first, sockaddr* second); +int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort); +int packSocket(unsigned char* packStore, sockaddr* socketToPack); +int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket); int getLocalAddress(); -unsigned short loadBufferWithSocketInfo(char *addressBuffer, sockaddr *socket); +unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket); #endif /* defined(__interface__UDPSocket__) */ diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 6530bc1d6f..25e86f1f8a 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -168,7 +168,7 @@ void resInVoxelDistributor(AgentList* agentList, if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { - agentList->getAgentSocket().send(agent->getActiveSocket(), + agentList->getAgentSocket()->send(agent->getActiveSocket(), agentData->getPacket(), agentData->getPacketLength()); trueBytesSent += agentData->getPacketLength(); truePacketsSent++; @@ -178,8 +178,8 @@ void resInVoxelDistributor(AgentList* agentList, } } else { if (agentData->isPacketWaiting()) { - agentList->getAgentSocket().send(agent->getActiveSocket(), - agentData->getPacket(), agentData->getPacketLength()); + agentList->getAgentSocket()->send(agent->getActiveSocket(), + agentData->getPacket(), agentData->getPacketLength()); trueBytesSent += agentData->getPacketLength(); truePacketsSent++; agentData->resetVoxelPacket(); @@ -190,7 +190,7 @@ void resInVoxelDistributor(AgentList* agentList, } // send the environment packet int envPacketLength = environmentData.getBroadcastData(tempOutputBuffer); - agentList->getAgentSocket().send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); + agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); trueBytesSent += envPacketLength; truePacketsSent++; @@ -288,7 +288,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { - agentList->getAgentSocket().send(agent->getActiveSocket(), + agentList->getAgentSocket()->send(agent->getActiveSocket(), agentData->getPacket(), agentData->getPacketLength()); trueBytesSent += agentData->getPacketLength(); truePacketsSent++; @@ -298,7 +298,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, } } else { if (agentData->isPacketWaiting()) { - agentList->getAgentSocket().send(agent->getActiveSocket(), + agentList->getAgentSocket()->send(agent->getActiveSocket(), agentData->getPacket(), agentData->getPacketLength()); trueBytesSent += agentData->getPacketLength(); truePacketsSent++; @@ -310,7 +310,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, } // send the environment packet int envPacketLength = environmentData.getBroadcastData(tempOutputBuffer); - agentList->getAgentSocket().send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); + agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); trueBytesSent += envPacketLength; truePacketsSent++; @@ -501,7 +501,7 @@ int main(int argc, const char * argv[]) // check to see if we need to persist our voxel state persistVoxelsWhenDirty(); - if (agentList->getAgentSocket().receive(&agentPublicAddress, packetData, &receivedBytes)) { + if (agentList->getAgentSocket()->receive(&agentPublicAddress, packetData, &receivedBytes)) { // XXXBHG: Hacked in support for 'S' SET command if (packetData[0] == PACKET_HEADER_SET_VOXEL || packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) { bool destructive = (packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE);