Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 4 files). Show all
Unified · Split
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <QtNetwork/QNetworkRequest> |
| 15 | 15 | #include <QtNetwork/QNetworkReply> |
| 16 | 16 | |
| 17 | +#include <AudioRingBuffer.h> | |
| 17 | 18 | #include <AvatarData.h> |
| 18 | 19 | #include <NodeList.h> |
| 19 | 20 | #include <PacketHeaders.h> |
| @@ -52,7 +53,9 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co · 32 unmodified lines | ||
| 52 | 53 | _avatarIdentityTimer(NULL), |
| 53 | 54 | _avatarBillboardTimer(NULL), |
| 54 | 55 | _timerFunctionMap(), |
| 55 | − _avatarAudioBuffer(NULL), | |
| 56 | + _isListeningToAudioStream(false), | |
| 57 | + _avatarSound(NULL), | |
| 58 | + _numAvatarSoundSentBytes(0), | |
| 56 | 59 | _controllerScriptingInterface(controllerScriptingInterface), |
| 57 | 60 | _avatarData(NULL), |
| 58 | 61 | _wantMenuItems(wantMenuItems), |
| @@ -260,27 +263,55 @@ void ScriptEngine::run() { · 201 unmodified lines | ||
| 260 | 263 | } |
| 261 | 264 | |
| 262 | 265 | if (_isAvatar && _avatarData) { |
| 266 | + | |
| 267 | + const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5); | |
| 268 | + const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); | |
| 269 | + | |
| 263 | 270 | QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData); |
| 264 | 271 | avatarPacket.append(_avatarData->toByteArray()); |
| 265 | 272 | |
| 266 | 273 | nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); |
| 267 | 274 | |
| 268 | − if (_avatarAudioBuffer && _numAvatarAudioBufferSamples > 0) { | |
| 269 | − // if have an avatar audio stream then send it out to our audio-mixer | |
| 270 | − | |
| 275 | + if (_isListeningToAudioStream || _avatarSound) { | |
| 276 | + // if we have an avatar audio stream then send it out to our audio-mixer | |
| 271 | 277 | bool silentFrame = true; |
| 272 | 278 | |
| 273 | − // check if the all of the _numAvatarAudioBufferSamples to be sent are silence | |
| 274 | − for (int i = 0; i < _numAvatarAudioBufferSamples; ++i) { | |
| 275 | − if (_avatarAudioBuffer[i] != 0) { | |
| 276 | − silentFrame = false; | |
| 277 | − break; | |
| 279 | + int16_t numAvailableSamples = SCRIPT_AUDIO_BUFFER_SAMPLES; | |
| 280 | + const int16_t* nextSoundOutput = NULL; | |
| 281 | + | |
| 282 | + if (_avatarSound) { | |
| 283 | + | |
| 284 | + const QByteArray& soundByteArray = _avatarSound->getByteArray(); | |
| 285 | + nextSoundOutput = reinterpret_cast<const int16_t*>(soundByteArray.data() | |
| 286 | + + _numAvatarSoundSentBytes); | |
| 287 | + | |
| 288 | + int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > SCRIPT_AUDIO_BUFFER_BYTES | |
| 289 | + ? SCRIPT_AUDIO_BUFFER_BYTES | |
| 290 | + : soundByteArray.size() - _numAvatarSoundSentBytes; | |
| 291 | + numAvailableSamples = numAvailableBytes / sizeof(int16_t); | |
| 292 | + | |
| 293 | + | |
| 294 | + // check if the all of the _numAvatarAudioBufferSamples to be sent are silence | |
| 295 | + for (int i = 0; i < numAvailableSamples; ++i) { | |
| 296 | + if (nextSoundOutput[i] != 0) { | |
| 297 | + silentFrame = false; | |
| 298 | + break; | |
| 299 | + } | |
| 300 | + } | |
| 301 | + | |
| 302 | + _numAvatarSoundSentBytes += numAvailableBytes; | |
| 303 | + if (_numAvatarSoundSentBytes == soundByteArray.size()) { | |
| 304 | + // we're done with this sound object - so set our pointer back to NULL | |
| 305 | + // and our sent bytes back to zero | |
| 306 | + _avatarSound = NULL; | |
| 307 | + _numAvatarSoundSentBytes = 0; | |
| 278 | 308 | } |
| 279 | 309 | } |
| 280 | 310 | |
| 281 | 311 | QByteArray audioPacket = byteArrayWithPopulatedHeader(silentFrame |
| 282 | 312 | ? PacketTypeSilentAudioFrame |
| 283 | 313 | : PacketTypeMicrophoneAudioNoEcho); |
| 314 | + | |
| 284 | 315 | QDataStream packetStream(&audioPacket, QIODevice::Append); |
| 285 | 316 | |
| 286 | 317 | // use the orientation and position of this avatar for the source of this audio |
| @@ -289,13 +320,17 @@ void ScriptEngine::run() { · 2 unmodified lines | ||
| 289 | 320 | packetStream.writeRawData(reinterpret_cast<const char*>(&headOrientation), sizeof(glm::quat)); |
| 290 | 321 | |
| 291 | 322 | if (silentFrame) { |
| 323 | + if (!_isListeningToAudioStream) { | |
| 324 | + // if we have a silent frame and we're not listening then just send nothing and break out of here | |
| 325 | + break; | |
| 326 | + } | |
| 327 | + | |
| 292 | 328 | // write the number of silent samples so the audio-mixer can uphold timing |
| 293 | − int16_t numSilentSamples = _numAvatarAudioBufferSamples; | |
| 294 | − packetStream.writeRawData(reinterpret_cast<const char*>(&numSilentSamples), sizeof(int16_t)); | |
| 295 | − } else { | |
| 329 | + packetStream.writeRawData(reinterpret_cast<const char*>(&SCRIPT_AUDIO_BUFFER_SAMPLES), sizeof(int16_t)); | |
| 330 | + } else if (nextSoundOutput) { | |
| 296 | 331 | // write the raw audio data |
| 297 | − packetStream.writeRawData(reinterpret_cast<const char*>(_avatarAudioBuffer), | |
| 298 | − _numAvatarAudioBufferSamples * sizeof(int16_t)); | |
| 332 | + packetStream.writeRawData(reinterpret_cast<const char*>(nextSoundOutput), | |
| 333 | + numAvailableSamples * sizeof(int16_t)); | |
| 299 | 334 | } |
| 300 | 335 | |
| 301 | 336 | nodeList->broadcastToNodes(audioPacket, NodeSet() << NodeType::AudioMixer); |
| @@ -303,7 +338,7 @@ void ScriptEngine::run() { · 1 unmodified line | ||
| 303 | 338 | } |
| 304 | 339 | |
| 305 | 340 | qint64 now = usecTimestampNow(); |
| 306 | − float deltaTime = (float)(now - lastUpdate)/(float)USECS_PER_SECOND; | |
| 341 | + float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; | |
| 307 | 342 | emit update(deltaTime); |
| 308 | 343 | lastUpdate = now; |
| 309 | 344 | |