diff options
Diffstat (limited to 'linden/indra/llaudio/audioengine.cpp')
-rw-r--r-- | linden/indra/llaudio/audioengine.cpp | 1672 |
1 files changed, 1672 insertions, 0 deletions
diff --git a/linden/indra/llaudio/audioengine.cpp b/linden/indra/llaudio/audioengine.cpp new file mode 100644 index 0000000..46e621a --- /dev/null +++ b/linden/indra/llaudio/audioengine.cpp | |||
@@ -0,0 +1,1672 @@ | |||
1 | /** | ||
2 | * @file audioengine.cpp | ||
3 | * @brief implementation of LLAudioEngine class abstracting the Open | ||
4 | * AL audio support | ||
5 | * | ||
6 | * Copyright (c) 2000-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include "linden_common.h" | ||
30 | |||
31 | #include <stdio.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <math.h> | ||
35 | |||
36 | #if LL_LINUX | ||
37 | #include <time.h> | ||
38 | #endif | ||
39 | |||
40 | //#include "message.h" | ||
41 | |||
42 | #include "audioengine.h" | ||
43 | |||
44 | #include "llerror.h" | ||
45 | #include "llmath.h" | ||
46 | |||
47 | #include "sound_ids.h" // temporary hack for min/max distances | ||
48 | |||
49 | #include "llvfs.h" | ||
50 | #include "lldir.h" | ||
51 | #include "llaudiodecodemgr.h" | ||
52 | #include "llassetstorage.h" | ||
53 | |||
54 | // necessary for grabbing sounds from sim (implemented in viewer) | ||
55 | extern void request_sound(const LLUUID &sound_guid); | ||
56 | |||
57 | LLAudioEngine* gAudiop = NULL; | ||
58 | |||
59 | // Maximum amount of time we wait for a transfer to complete before starting | ||
60 | // off another one. | ||
61 | const F32 MAX_CURRENT_TRANSFER_TIME = 60.f; | ||
62 | |||
63 | // | ||
64 | // LLAudioEngine implementation | ||
65 | // | ||
66 | |||
67 | |||
68 | LLAudioEngine::LLAudioEngine() | ||
69 | { | ||
70 | } | ||
71 | |||
72 | |||
73 | LLAudioEngine::~LLAudioEngine() | ||
74 | { | ||
75 | } | ||
76 | |||
77 | |||
78 | BOOL LLAudioEngine::init(const S32 num_channels, void* userdata) | ||
79 | { | ||
80 | mMuted = FALSE; | ||
81 | mMasterGain = 1.f; | ||
82 | mInternetStreamGain = 0.125f; | ||
83 | mUserData = userdata; | ||
84 | mLastStatus = 0; | ||
85 | |||
86 | mNumChannels = num_channels; | ||
87 | |||
88 | |||
89 | mMaxWindGain = 1.0; | ||
90 | |||
91 | mEnableWind = FALSE; | ||
92 | |||
93 | S32 i; | ||
94 | for (i = 0; i < MAX_BUFFERS; i++) | ||
95 | { | ||
96 | mBuffers[i] = NULL; | ||
97 | } | ||
98 | for (i = 0; i < num_channels; i++) | ||
99 | { | ||
100 | mChannels[i] = NULL; | ||
101 | } | ||
102 | |||
103 | allocateListener(); | ||
104 | |||
105 | // Initialize the decode manager | ||
106 | gAudioDecodeMgrp = new LLAudioDecodeMgr; | ||
107 | |||
108 | return TRUE; | ||
109 | } | ||
110 | |||
111 | |||
112 | void LLAudioEngine::shutdown() | ||
113 | { | ||
114 | // Clean up decode manager | ||
115 | delete gAudioDecodeMgrp; | ||
116 | gAudioDecodeMgrp = NULL; | ||
117 | |||
118 | // Clean up audio sources | ||
119 | source_map::iterator iter_src; | ||
120 | for (iter_src = mAllSources.begin(); iter_src != mAllSources.end(); iter_src++) | ||
121 | { | ||
122 | delete iter_src->second; | ||
123 | } | ||
124 | |||
125 | |||
126 | // Clean up audio data | ||
127 | data_map::iterator iter_data; | ||
128 | for (iter_data = mAllData.begin(); iter_data != mAllData.end(); iter_data++) | ||
129 | { | ||
130 | delete iter_data->second; | ||
131 | } | ||
132 | |||
133 | |||
134 | // Clean up channels | ||
135 | S32 i; | ||
136 | if (mChannels) | ||
137 | { | ||
138 | for (i = 0; i < MAX_CHANNELS; i++) | ||
139 | { | ||
140 | if (mChannels[i]) | ||
141 | { | ||
142 | delete mChannels[i]; | ||
143 | mChannels[i] = NULL; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | // Clean up buffers | ||
149 | if (mBuffers) | ||
150 | { | ||
151 | for (i = 0; i < MAX_BUFFERS; i++) | ||
152 | { | ||
153 | if (mBuffers[i]) | ||
154 | { | ||
155 | delete mBuffers[i]; | ||
156 | mBuffers[i] = NULL; | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | |||
163 | void LLAudioEngine::updateChannels() | ||
164 | { | ||
165 | S32 i; | ||
166 | for (i = 0; i < MAX_CHANNELS; i++) | ||
167 | { | ||
168 | if (mChannels[i]) | ||
169 | { | ||
170 | mChannels[i]->updateBuffer(); | ||
171 | mChannels[i]->update3DPosition(); | ||
172 | mChannels[i]->updateLoop(); | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | static const F32 default_max_decode_time = .002f; // 2 ms | ||
178 | void LLAudioEngine::idle(F32 max_decode_time) | ||
179 | { | ||
180 | if (max_decode_time <= 0.f) | ||
181 | { | ||
182 | max_decode_time = default_max_decode_time; | ||
183 | } | ||
184 | |||
185 | // "Update" all of our audio sources, clean up dead ones. | ||
186 | // Primarily does position updating, cleanup of unused audio sources. | ||
187 | // Also does regeneration of the current priority of each audio source. | ||
188 | |||
189 | if (getMuted()) | ||
190 | { | ||
191 | setInternalGain(0.f); | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | setInternalGain(getMasterGain()); | ||
196 | } | ||
197 | |||
198 | S32 i; | ||
199 | for (i = 0; i < MAX_BUFFERS; i++) | ||
200 | { | ||
201 | if (mBuffers[i]) | ||
202 | { | ||
203 | mBuffers[i]->mInUse = FALSE; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | F32 max_priority = -1.f; | ||
208 | LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel | ||
209 | source_map::iterator iter; | ||
210 | for (iter = mAllSources.begin(); iter != mAllSources.end();) | ||
211 | { | ||
212 | LLAudioSource *sourcep = iter->second; | ||
213 | |||
214 | // Update this source | ||
215 | sourcep->update(); | ||
216 | sourcep->updatePriority(); | ||
217 | |||
218 | if (sourcep->isDone()) | ||
219 | { | ||
220 | // The source is done playing, clean it up. | ||
221 | delete sourcep; | ||
222 | mAllSources.erase(iter++); | ||
223 | continue; | ||
224 | } | ||
225 | |||
226 | if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) | ||
227 | { | ||
228 | // We could potentially play this sound if its priority is high enough. | ||
229 | if (sourcep->getPriority() > max_priority) | ||
230 | { | ||
231 | max_priority = sourcep->getPriority(); | ||
232 | max_sourcep = sourcep; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | // Move on to the next source | ||
237 | iter++; | ||
238 | } | ||
239 | |||
240 | // Now, do priority-based organization of audio sources. | ||
241 | // All channels used, check priorities. | ||
242 | // Find channel with lowest priority | ||
243 | if (max_sourcep) | ||
244 | { | ||
245 | LLAudioChannel *channelp = getFreeChannel(max_priority); | ||
246 | if (channelp) | ||
247 | { | ||
248 | //llinfos << "Replacing source in channel due to priority!" << llendl; | ||
249 | max_sourcep->setChannel(channelp); | ||
250 | channelp->setSource(max_sourcep); | ||
251 | if (max_sourcep->isSyncSlave()) | ||
252 | { | ||
253 | // A sync slave, it doesn't start playing until it's synced up with the master. | ||
254 | // Flag this channel as waiting for sync, and return true. | ||
255 | channelp->setWaiting(TRUE); | ||
256 | } | ||
257 | else | ||
258 | { | ||
259 | channelp->setWaiting(FALSE); | ||
260 | channelp->play(); | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | |||
265 | |||
266 | // Do this BEFORE we update the channels | ||
267 | // Update the channels to sync up with any changes that the source made, | ||
268 | // such as changing what sound was playing. | ||
269 | updateChannels(); | ||
270 | |||
271 | // Update queued sounds (switch to next queued data if the current has finished playing) | ||
272 | for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) | ||
273 | { | ||
274 | // This is lame, instead of this I could actually iterate through all the sources | ||
275 | // attached to each channel, since only those with active channels | ||
276 | // can have anything interesting happen with their queue? (Maybe not true) | ||
277 | LLAudioSource *sourcep = iter->second; | ||
278 | if (!sourcep->mQueuedDatap) | ||
279 | { | ||
280 | // Nothing queued, so we don't care. | ||
281 | continue; | ||
282 | } | ||
283 | |||
284 | LLAudioChannel *channelp = sourcep->getChannel(); | ||
285 | if (!channelp) | ||
286 | { | ||
287 | // This sound isn't playing, so we just process move the queue | ||
288 | sourcep->mCurrentDatap = sourcep->mQueuedDatap; | ||
289 | sourcep->mQueuedDatap = NULL; | ||
290 | |||
291 | // Reset the timer so the source doesn't die. | ||
292 | sourcep->mAgeTimer.reset(); | ||
293 | // Make sure we have the buffer set up if we just decoded the data | ||
294 | if (sourcep->mCurrentDatap) | ||
295 | { | ||
296 | updateBufferForData(sourcep->mCurrentDatap); | ||
297 | } | ||
298 | |||
299 | // Actually play the associated data. | ||
300 | sourcep->setupChannel(); | ||
301 | channelp = sourcep->getChannel(); | ||
302 | if (channelp) | ||
303 | { | ||
304 | channelp->updateBuffer(); | ||
305 | sourcep->getChannel()->play(); | ||
306 | } | ||
307 | continue; | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | // Check to see if the current sound is done playing, or looped. | ||
312 | if (!channelp->isPlaying()) | ||
313 | { | ||
314 | sourcep->mCurrentDatap = sourcep->mQueuedDatap; | ||
315 | sourcep->mQueuedDatap = NULL; | ||
316 | |||
317 | // Reset the timer so the source doesn't die. | ||
318 | sourcep->mAgeTimer.reset(); | ||
319 | |||
320 | // Make sure we have the buffer set up if we just decoded the data | ||
321 | if (sourcep->mCurrentDatap) | ||
322 | { | ||
323 | updateBufferForData(sourcep->mCurrentDatap); | ||
324 | } | ||
325 | |||
326 | // Actually play the associated data. | ||
327 | sourcep->setupChannel(); | ||
328 | channelp->updateBuffer(); | ||
329 | sourcep->getChannel()->play(); | ||
330 | } | ||
331 | else if (sourcep->isLoop()) | ||
332 | { | ||
333 | // It's a loop, we need to check and see if we're done with it. | ||
334 | if (channelp->mLoopedThisFrame) | ||
335 | { | ||
336 | sourcep->mCurrentDatap = sourcep->mQueuedDatap; | ||
337 | sourcep->mQueuedDatap = NULL; | ||
338 | |||
339 | // Actually, should do a time sync so if we're a loop master/slave | ||
340 | // we don't drift away. | ||
341 | sourcep->setupChannel(); | ||
342 | sourcep->getChannel()->play(); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | // Lame, update the channels AGAIN. | ||
349 | // Update the channels to sync up with any changes that the source made, | ||
350 | // such as changing what sound was playing. | ||
351 | updateChannels(); | ||
352 | |||
353 | // Hack! For now, just use a global sync master; | ||
354 | LLAudioSource *sync_masterp = NULL; | ||
355 | LLAudioChannel *master_channelp = NULL; | ||
356 | F32 max_sm_priority = -1.f; | ||
357 | for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) | ||
358 | { | ||
359 | LLAudioSource *sourcep = iter->second; | ||
360 | if (sourcep->isSyncMaster()) | ||
361 | { | ||
362 | if (sourcep->getPriority() > max_sm_priority) | ||
363 | { | ||
364 | sync_masterp = sourcep; | ||
365 | master_channelp = sync_masterp->getChannel(); | ||
366 | max_sm_priority = sourcep->getPriority(); | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | if (master_channelp && master_channelp->mLoopedThisFrame) | ||
372 | { | ||
373 | // Synchronize loop slaves with their masters | ||
374 | // Update queued sounds (switch to next queued data if the current has finished playing) | ||
375 | for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) | ||
376 | { | ||
377 | LLAudioSource *sourcep = iter->second; | ||
378 | |||
379 | if (!sourcep->isSyncSlave()) | ||
380 | { | ||
381 | // Not a loop slave, we don't need to do anything | ||
382 | continue; | ||
383 | } | ||
384 | |||
385 | LLAudioChannel *channelp = sourcep->getChannel(); | ||
386 | if (!channelp) | ||
387 | { | ||
388 | // Not playing, don't need to bother. | ||
389 | continue; | ||
390 | } | ||
391 | |||
392 | if (!channelp->isPlaying()) | ||
393 | { | ||
394 | // Now we need to check if our loop master has just looped, and | ||
395 | // start playback if that's the case. | ||
396 | if (sync_masterp->getChannel()) | ||
397 | { | ||
398 | channelp->playSynced(master_channelp); | ||
399 | channelp->setWaiting(FALSE); | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | |||
405 | // Sync up everything that the audio engine needs done. | ||
406 | commitDeferredChanges(); | ||
407 | |||
408 | // Flush unused buffers that are stale enough | ||
409 | for (i = 0; i < MAX_BUFFERS; i++) | ||
410 | { | ||
411 | if (mBuffers[i]) | ||
412 | { | ||
413 | if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) | ||
414 | { | ||
415 | //llinfos << "Flushing unused buffer!" << llendl; | ||
416 | mBuffers[i]->mAudioDatap->mBufferp = NULL; | ||
417 | delete mBuffers[i]; | ||
418 | mBuffers[i] = NULL; | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | |||
424 | // Clear all of the looped flags for the channels | ||
425 | for (i = 0; i < MAX_CHANNELS; i++) | ||
426 | { | ||
427 | if (mChannels[i]) | ||
428 | { | ||
429 | mChannels[i]->mLoopedThisFrame = FALSE; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | // Decode audio files | ||
434 | gAudioDecodeMgrp->processQueue(max_decode_time); | ||
435 | |||
436 | // Call this every frame, just in case we somehow | ||
437 | // missed picking it up in all the places that can add | ||
438 | // or request new data. | ||
439 | startNextTransfer(); | ||
440 | } | ||
441 | |||
442 | BOOL LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid) | ||
443 | { | ||
444 | if (!adp) | ||
445 | { | ||
446 | return FALSE; | ||
447 | } | ||
448 | |||
449 | // Update the audio buffer first - load a sound if we have it. | ||
450 | // Note that this could potentially cause us to waste time updating buffers | ||
451 | // for sounds that actually aren't playing, although this should be mitigated | ||
452 | // by the fact that we limit the number of buffers, and we flush buffers based | ||
453 | // on priority. | ||
454 | if (!adp->getBuffer()) | ||
455 | { | ||
456 | if (adp->hasDecodedData()) | ||
457 | { | ||
458 | adp->load(); | ||
459 | } | ||
460 | else if (adp->hasLocalData()) | ||
461 | { | ||
462 | if (audio_uuid.notNull()) | ||
463 | { | ||
464 | gAudioDecodeMgrp->addDecodeRequest(audio_uuid); | ||
465 | } | ||
466 | } | ||
467 | else | ||
468 | { | ||
469 | return FALSE; | ||
470 | } | ||
471 | } | ||
472 | return TRUE; | ||
473 | } | ||
474 | |||
475 | |||
476 | void LLAudioEngine::enableWind(BOOL enable) | ||
477 | { | ||
478 | if (enable && (!mEnableWind)) | ||
479 | { | ||
480 | initWind(); | ||
481 | mEnableWind = enable; | ||
482 | } | ||
483 | else if (mEnableWind && (!enable)) | ||
484 | { | ||
485 | mEnableWind = enable; | ||
486 | cleanupWind(); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | |||
491 | LLAudioBuffer *LLAudioEngine::getFreeBuffer() | ||
492 | { | ||
493 | S32 i; | ||
494 | for (i = 0; i < MAX_BUFFERS; i++) | ||
495 | { | ||
496 | if (!mBuffers[i]) | ||
497 | { | ||
498 | mBuffers[i] = createBuffer(); | ||
499 | return mBuffers[i]; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | |||
504 | // Grab the oldest unused buffer | ||
505 | F32 max_age = -1.f; | ||
506 | S32 buffer_id = -1; | ||
507 | for (i = 0; i < MAX_BUFFERS; i++) | ||
508 | { | ||
509 | if (mBuffers[i]) | ||
510 | { | ||
511 | if (!mBuffers[i]->mInUse) | ||
512 | { | ||
513 | if (mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > max_age) | ||
514 | { | ||
515 | max_age = mBuffers[i]->mLastUseTimer.getElapsedTimeF32(); | ||
516 | buffer_id = i; | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | |||
522 | if (buffer_id >= 0) | ||
523 | { | ||
524 | llinfos << "Taking over unused buffer " << buffer_id << llendl; | ||
525 | //llinfos << "Flushing unused buffer!" << llendl; | ||
526 | mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL; | ||
527 | delete mBuffers[buffer_id]; | ||
528 | mBuffers[buffer_id] = createBuffer(); | ||
529 | return mBuffers[buffer_id]; | ||
530 | } | ||
531 | return NULL; | ||
532 | } | ||
533 | |||
534 | |||
535 | LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority) | ||
536 | { | ||
537 | S32 i; | ||
538 | for (i = 0; i < mNumChannels; i++) | ||
539 | { | ||
540 | if (!mChannels[i]) | ||
541 | { | ||
542 | // No channel allocated here, use it. | ||
543 | mChannels[i] = createChannel(); | ||
544 | return mChannels[i]; | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | // Channel is allocated but not playing right now, use it. | ||
549 | if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting()) | ||
550 | { | ||
551 | mChannels[i]->cleanup(); | ||
552 | if (mChannels[i]->getSource()) | ||
553 | { | ||
554 | mChannels[i]->getSource()->setChannel(NULL); | ||
555 | } | ||
556 | return mChannels[i]; | ||
557 | } | ||
558 | } | ||
559 | } | ||
560 | |||
561 | // All channels used, check priorities. | ||
562 | // Find channel with lowest priority and see if we want to replace it. | ||
563 | F32 min_priority = 10000.f; | ||
564 | LLAudioChannel *min_channelp = NULL; | ||
565 | |||
566 | for (i = 0; i < mNumChannels; i++) | ||
567 | { | ||
568 | LLAudioChannel *channelp = mChannels[i]; | ||
569 | LLAudioSource *sourcep = channelp->getSource(); | ||
570 | if (sourcep->getPriority() < min_priority) | ||
571 | { | ||
572 | min_channelp = channelp; | ||
573 | min_priority = sourcep->getPriority(); | ||
574 | } | ||
575 | } | ||
576 | |||
577 | if (min_priority > priority) | ||
578 | { | ||
579 | // All playing channels have higher priority, return. | ||
580 | return NULL; | ||
581 | } | ||
582 | |||
583 | // Flush the minimum priority channel, and return it. | ||
584 | min_channelp->cleanup(); | ||
585 | min_channelp->getSource()->setChannel(NULL); | ||
586 | return min_channelp; | ||
587 | } | ||
588 | |||
589 | |||
590 | void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp) | ||
591 | { | ||
592 | S32 i; | ||
593 | for (i = 0; i < MAX_BUFFERS; i++) | ||
594 | { | ||
595 | if (mBuffers[i] == bufferp) | ||
596 | { | ||
597 | delete mBuffers[i]; | ||
598 | mBuffers[i] = NULL; | ||
599 | } | ||
600 | } | ||
601 | } | ||
602 | |||
603 | |||
604 | BOOL LLAudioEngine::preloadSound(const LLUUID &uuid) | ||
605 | { | ||
606 | gAudiop->getAudioData(uuid); // We don't care about the return value, this is just to make sure | ||
607 | // that we have an entry, which will mean that the audio engine knows about this | ||
608 | |||
609 | if (gAudioDecodeMgrp->addDecodeRequest(uuid)) | ||
610 | { | ||
611 | // This means that we do have a local copy, and we're working on decoding it. | ||
612 | return TRUE; | ||
613 | } | ||
614 | |||
615 | // At some point we need to have the audio/asset system check the static VFS | ||
616 | // before it goes off and fetches stuff from the server. | ||
617 | //llwarns << "Used internal preload for non-local sound" << llendl; | ||
618 | return FALSE; | ||
619 | } | ||
620 | |||
621 | |||
622 | BOOL LLAudioEngine::isWindEnabled() | ||
623 | { | ||
624 | return mEnableWind; | ||
625 | } | ||
626 | |||
627 | |||
628 | void LLAudioEngine::setMuted(BOOL muted) | ||
629 | { | ||
630 | mMuted = muted; | ||
631 | enableWind(!mMuted); | ||
632 | } | ||
633 | |||
634 | |||
635 | void LLAudioEngine::setMasterGain(const F32 gain) | ||
636 | { | ||
637 | mMasterGain = gain; | ||
638 | setInternalGain(gain); | ||
639 | } | ||
640 | |||
641 | F32 LLAudioEngine::getMasterGain() | ||
642 | { | ||
643 | return mMasterGain; | ||
644 | } | ||
645 | |||
646 | F32 LLAudioEngine::getInternetStreamGain() | ||
647 | { | ||
648 | return mInternetStreamGain; | ||
649 | } | ||
650 | |||
651 | void LLAudioEngine::setMaxWindGain(F32 gain) | ||
652 | { | ||
653 | mMaxWindGain = gain; | ||
654 | } | ||
655 | |||
656 | |||
657 | F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec) | ||
658 | { | ||
659 | F64 gain = 0.0; | ||
660 | |||
661 | gain = wind_vec.magVec(); | ||
662 | |||
663 | if (gain) | ||
664 | { | ||
665 | if (gain > 20) | ||
666 | { | ||
667 | gain = 20; | ||
668 | } | ||
669 | gain = gain/20.0; | ||
670 | } | ||
671 | |||
672 | return (gain); | ||
673 | } | ||
674 | |||
675 | |||
676 | F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec) | ||
677 | { | ||
678 | LLVector3 listen_right; | ||
679 | F64 theta; | ||
680 | |||
681 | // Wind frame is in listener-relative coordinates | ||
682 | LLVector3 norm_wind = wind_vec; | ||
683 | norm_wind.normVec(); | ||
684 | listen_right.setVec(1.0,0.0,0.0); | ||
685 | |||
686 | // measure angle between wind vec and listener right axis (on 0,PI) | ||
687 | theta = acos(norm_wind * listen_right); | ||
688 | |||
689 | // put it on 0, 1 | ||
690 | theta /= F_PI; | ||
691 | |||
692 | // put it on [0, 0.5, 0] | ||
693 | if (theta > 0.5) theta = 1.0-theta; | ||
694 | if (theta < 0) theta = 0; | ||
695 | |||
696 | return (theta); | ||
697 | } | ||
698 | |||
699 | |||
700 | F64 LLAudioEngine::mapWindVecToPan(LLVector3 wind_vec) | ||
701 | { | ||
702 | LLVector3 listen_right; | ||
703 | F64 theta; | ||
704 | |||
705 | // Wind frame is in listener-relative coordinates | ||
706 | listen_right.setVec(1.0,0.0,0.0); | ||
707 | |||
708 | LLVector3 norm_wind = wind_vec; | ||
709 | norm_wind.normVec(); | ||
710 | |||
711 | // measure angle between wind vec and listener right axis (on 0,PI) | ||
712 | theta = acos(norm_wind * listen_right); | ||
713 | |||
714 | // put it on 0, 1 | ||
715 | theta /= F_PI; | ||
716 | |||
717 | return (theta); | ||
718 | } | ||
719 | |||
720 | |||
721 | void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const LLVector3d &pos_global) | ||
722 | { | ||
723 | // Create a new source (since this can't be associated with an existing source. | ||
724 | //llinfos << "Localized: " << audio_uuid << llendl; | ||
725 | |||
726 | if (mMuted) | ||
727 | { | ||
728 | return; | ||
729 | } | ||
730 | |||
731 | LLUUID source_id; | ||
732 | source_id.generate(); | ||
733 | |||
734 | LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain); | ||
735 | gAudiop->addAudioSource(asp); | ||
736 | if (pos_global.isExactlyZero()) | ||
737 | { | ||
738 | asp->setAmbient(TRUE); | ||
739 | } | ||
740 | else | ||
741 | { | ||
742 | asp->setPositionGlobal(pos_global); | ||
743 | } | ||
744 | asp->updatePriority(); | ||
745 | asp->play(audio_uuid); | ||
746 | } | ||
747 | |||
748 | |||
749 | void LLAudioEngine::setListenerPos(LLVector3 aVec) | ||
750 | { | ||
751 | mListenerp->setPosition(aVec); | ||
752 | } | ||
753 | |||
754 | |||
755 | LLVector3 LLAudioEngine::getListenerPos() | ||
756 | { | ||
757 | if (mListenerp) | ||
758 | { | ||
759 | return(mListenerp->getPosition()); | ||
760 | } | ||
761 | else | ||
762 | { | ||
763 | return(LLVector3::zero); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | |||
768 | void LLAudioEngine::setListenerVelocity(LLVector3 aVec) | ||
769 | { | ||
770 | mListenerp->setVelocity(aVec); | ||
771 | } | ||
772 | |||
773 | |||
774 | void LLAudioEngine::translateListener(LLVector3 aVec) | ||
775 | { | ||
776 | mListenerp->translate(aVec); | ||
777 | } | ||
778 | |||
779 | |||
780 | void LLAudioEngine::orientListener(LLVector3 up, LLVector3 at) | ||
781 | { | ||
782 | mListenerp->orient(up, at); | ||
783 | } | ||
784 | |||
785 | |||
786 | void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) | ||
787 | { | ||
788 | mListenerp->set(pos,vel,up,at); | ||
789 | } | ||
790 | |||
791 | |||
792 | void LLAudioEngine::setDopplerFactor(F32 factor) | ||
793 | { | ||
794 | if (mListenerp) | ||
795 | { | ||
796 | mListenerp->setDopplerFactor(factor); | ||
797 | } | ||
798 | } | ||
799 | |||
800 | |||
801 | F32 LLAudioEngine::getDopplerFactor() | ||
802 | { | ||
803 | if (mListenerp) | ||
804 | { | ||
805 | return mListenerp->getDopplerFactor(); | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | return 0.f; | ||
810 | } | ||
811 | } | ||
812 | |||
813 | |||
814 | void LLAudioEngine::setDistanceFactor(F32 factor) | ||
815 | { | ||
816 | if (mListenerp) | ||
817 | { | ||
818 | mListenerp->setDistanceFactor(factor); | ||
819 | } | ||
820 | } | ||
821 | |||
822 | |||
823 | F32 LLAudioEngine::getDistanceFactor() | ||
824 | { | ||
825 | if (mListenerp) | ||
826 | { | ||
827 | return mListenerp->getDistanceFactor(); | ||
828 | } | ||
829 | else | ||
830 | { | ||
831 | return 0.f; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | |||
836 | void LLAudioEngine::setRolloffFactor(F32 factor) | ||
837 | { | ||
838 | if (mListenerp) | ||
839 | { | ||
840 | mListenerp->setRolloffFactor(factor); | ||
841 | } | ||
842 | } | ||
843 | |||
844 | |||
845 | F32 LLAudioEngine::getRolloffFactor() | ||
846 | { | ||
847 | if (mListenerp) | ||
848 | { | ||
849 | return mListenerp->getRolloffFactor(); | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | return 0.f; | ||
854 | } | ||
855 | } | ||
856 | |||
857 | |||
858 | void LLAudioEngine::commitDeferredChanges() | ||
859 | { | ||
860 | mListenerp->commitDeferredChanges(); | ||
861 | } | ||
862 | |||
863 | |||
864 | LLAudioSource *LLAudioEngine::findAudioSource(const LLUUID &source_id) | ||
865 | { | ||
866 | source_map::iterator iter; | ||
867 | iter = mAllSources.find(source_id); | ||
868 | |||
869 | if (iter == mAllSources.end()) | ||
870 | { | ||
871 | return NULL; | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | return iter->second; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | |||
880 | LLAudioData *LLAudioEngine::getAudioData(const LLUUID &audio_uuid) | ||
881 | { | ||
882 | data_map::iterator iter; | ||
883 | iter = mAllData.find(audio_uuid); | ||
884 | if (iter == mAllData.end()) | ||
885 | { | ||
886 | // Create the new audio data | ||
887 | LLAudioData *adp = new LLAudioData(audio_uuid); | ||
888 | mAllData[audio_uuid] = adp; | ||
889 | return adp; | ||
890 | } | ||
891 | else | ||
892 | { | ||
893 | return iter->second; | ||
894 | } | ||
895 | } | ||
896 | |||
897 | void LLAudioEngine::addAudioSource(LLAudioSource *asp) | ||
898 | { | ||
899 | mAllSources[asp->getID()] = asp; | ||
900 | } | ||
901 | |||
902 | |||
903 | void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp) | ||
904 | { | ||
905 | source_map::iterator iter; | ||
906 | iter = mAllSources.find(asp->getID()); | ||
907 | if (iter == mAllSources.end()) | ||
908 | { | ||
909 | llwarns << "Cleaning up unknown audio source!" << llendl; | ||
910 | return; | ||
911 | } | ||
912 | delete asp; | ||
913 | mAllSources.erase(iter); | ||
914 | } | ||
915 | |||
916 | |||
917 | BOOL LLAudioEngine::hasDecodedFile(const LLUUID &uuid) | ||
918 | { | ||
919 | char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ | ||
920 | uuid.toString(uuid_str); | ||
921 | |||
922 | std::string wav_path; | ||
923 | wav_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str); | ||
924 | wav_path += ".dsf"; | ||
925 | |||
926 | if (gDirUtilp->fileExists(wav_path)) | ||
927 | { | ||
928 | return TRUE; | ||
929 | } | ||
930 | else | ||
931 | { | ||
932 | return FALSE; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | |||
937 | BOOL LLAudioEngine::hasLocalFile(const LLUUID &uuid) | ||
938 | { | ||
939 | // See if it's in the VFS. | ||
940 | return gVFS->getExists(uuid, LLAssetType::AT_SOUND); | ||
941 | } | ||
942 | |||
943 | |||
944 | void LLAudioEngine::startNextTransfer() | ||
945 | { | ||
946 | //llinfos << "LLAudioEngine::startNextTransfer()" << llendl; | ||
947 | if (mCurrentTransfer.notNull() || getMuted()) | ||
948 | { | ||
949 | //llinfos << "Transfer in progress, aborting" << llendl; | ||
950 | return; | ||
951 | } | ||
952 | |||
953 | // Get the ID for the next asset that we want to transfer. | ||
954 | // Pick one in the following order: | ||
955 | LLUUID asset_id; | ||
956 | S32 i; | ||
957 | LLAudioSource *asp = NULL; | ||
958 | LLAudioData *adp = NULL; | ||
959 | data_map::iterator data_iter; | ||
960 | |||
961 | // Check all channels for currently playing sounds. | ||
962 | F32 max_pri = -1.f; | ||
963 | for (i = 0; i < MAX_CHANNELS; i++) | ||
964 | { | ||
965 | if (!mChannels[i]) | ||
966 | { | ||
967 | continue; | ||
968 | } | ||
969 | |||
970 | asp = mChannels[i]->getSource(); | ||
971 | if (!asp) | ||
972 | { | ||
973 | continue; | ||
974 | } | ||
975 | if (asp->getPriority() <= max_pri) | ||
976 | { | ||
977 | continue; | ||
978 | } | ||
979 | |||
980 | if (asp->getPriority() <= max_pri) | ||
981 | { | ||
982 | continue; | ||
983 | } | ||
984 | |||
985 | adp = asp->getCurrentData(); | ||
986 | if (!adp) | ||
987 | { | ||
988 | continue; | ||
989 | } | ||
990 | |||
991 | if (!adp->hasLocalData() && adp->hasValidData()) | ||
992 | { | ||
993 | asset_id = adp->getID(); | ||
994 | max_pri = asp->getPriority(); | ||
995 | } | ||
996 | } | ||
997 | |||
998 | // Check all channels for currently queued sounds. | ||
999 | if (asset_id.isNull()) | ||
1000 | { | ||
1001 | max_pri = -1.f; | ||
1002 | for (i = 0; i < MAX_CHANNELS; i++) | ||
1003 | { | ||
1004 | if (!mChannels[i]) | ||
1005 | { | ||
1006 | continue; | ||
1007 | } | ||
1008 | |||
1009 | LLAudioSource *asp; | ||
1010 | asp = mChannels[i]->getSource(); | ||
1011 | if (!asp) | ||
1012 | { | ||
1013 | continue; | ||
1014 | } | ||
1015 | |||
1016 | if (asp->getPriority() <= max_pri) | ||
1017 | { | ||
1018 | continue; | ||
1019 | } | ||
1020 | |||
1021 | adp = asp->getQueuedData(); | ||
1022 | if (!adp) | ||
1023 | { | ||
1024 | continue; | ||
1025 | } | ||
1026 | |||
1027 | if (!adp->hasLocalData() && adp->hasValidData()) | ||
1028 | { | ||
1029 | asset_id = adp->getID(); | ||
1030 | max_pri = asp->getPriority(); | ||
1031 | } | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | // Check all live channels for other sounds (preloads). | ||
1036 | if (asset_id.isNull()) | ||
1037 | { | ||
1038 | max_pri = -1.f; | ||
1039 | for (i = 0; i < MAX_CHANNELS; i++) | ||
1040 | { | ||
1041 | if (!mChannels[i]) | ||
1042 | { | ||
1043 | continue; | ||
1044 | } | ||
1045 | |||
1046 | LLAudioSource *asp; | ||
1047 | asp = mChannels[i]->getSource(); | ||
1048 | if (!asp) | ||
1049 | { | ||
1050 | continue; | ||
1051 | } | ||
1052 | |||
1053 | if (asp->getPriority() <= max_pri) | ||
1054 | { | ||
1055 | continue; | ||
1056 | } | ||
1057 | |||
1058 | |||
1059 | for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) | ||
1060 | { | ||
1061 | LLAudioData *adp = data_iter->second; | ||
1062 | if (!adp) | ||
1063 | { | ||
1064 | continue; | ||
1065 | } | ||
1066 | |||
1067 | if (!adp->hasLocalData() && adp->hasValidData()) | ||
1068 | { | ||
1069 | asset_id = adp->getID(); | ||
1070 | max_pri = asp->getPriority(); | ||
1071 | } | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | // Check all sources | ||
1077 | if (asset_id.isNull()) | ||
1078 | { | ||
1079 | max_pri = -1.f; | ||
1080 | source_map::iterator source_iter; | ||
1081 | for (source_iter = mAllSources.begin(); source_iter != mAllSources.end(); source_iter++) | ||
1082 | { | ||
1083 | asp = source_iter->second; | ||
1084 | if (!asp) | ||
1085 | { | ||
1086 | continue; | ||
1087 | } | ||
1088 | |||
1089 | if (asp->getPriority() <= max_pri) | ||
1090 | { | ||
1091 | continue; | ||
1092 | } | ||
1093 | |||
1094 | adp = asp->getCurrentData(); | ||
1095 | if (adp && !adp->hasLocalData() && adp->hasValidData()) | ||
1096 | { | ||
1097 | asset_id = adp->getID(); | ||
1098 | max_pri = asp->getPriority(); | ||
1099 | continue; | ||
1100 | } | ||
1101 | |||
1102 | adp = asp->getQueuedData(); | ||
1103 | if (adp && !adp->hasLocalData() && adp->hasValidData()) | ||
1104 | { | ||
1105 | asset_id = adp->getID(); | ||
1106 | max_pri = asp->getPriority(); | ||
1107 | continue; | ||
1108 | } | ||
1109 | |||
1110 | for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) | ||
1111 | { | ||
1112 | LLAudioData *adp = data_iter->second; | ||
1113 | if (!adp) | ||
1114 | { | ||
1115 | continue; | ||
1116 | } | ||
1117 | |||
1118 | if (!adp->hasLocalData() && adp->hasValidData()) | ||
1119 | { | ||
1120 | asset_id = adp->getID(); | ||
1121 | max_pri = asp->getPriority(); | ||
1122 | break; | ||
1123 | } | ||
1124 | } | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | if (asset_id.notNull()) | ||
1129 | { | ||
1130 | llinfos << "Getting asset data for: " << asset_id << llendl; | ||
1131 | gAudiop->mCurrentTransfer = asset_id; | ||
1132 | gAudiop->mCurrentTransferTimer.reset(); | ||
1133 | gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, | ||
1134 | assetCallback, NULL); | ||
1135 | } | ||
1136 | else | ||
1137 | { | ||
1138 | //llinfos << "No pending transfers?" << llendl; | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | // static | ||
1144 | void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code) | ||
1145 | { | ||
1146 | if (result_code) | ||
1147 | { | ||
1148 | llinfos << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl; | ||
1149 | // Need to mark data as bad to avoid constant rerequests. | ||
1150 | LLAudioData *adp = gAudiop->getAudioData(uuid); | ||
1151 | if (adp) | ||
1152 | { | ||
1153 | adp->setHasValidData(FALSE); | ||
1154 | adp->setHasLocalData(FALSE); | ||
1155 | adp->setHasDecodedData(FALSE); | ||
1156 | } | ||
1157 | } | ||
1158 | else | ||
1159 | { | ||
1160 | LLAudioData *adp = gAudiop->getAudioData(uuid); | ||
1161 | if (!adp) | ||
1162 | { | ||
1163 | // Should never happen | ||
1164 | llwarns << "Got asset callback without audio data for " << uuid << llendl; | ||
1165 | } | ||
1166 | else | ||
1167 | { | ||
1168 | adp->setHasValidData(TRUE); | ||
1169 | adp->setHasLocalData(TRUE); | ||
1170 | gAudioDecodeMgrp->addDecodeRequest(uuid); | ||
1171 | } | ||
1172 | } | ||
1173 | gAudiop->mCurrentTransfer = LLUUID::null; | ||
1174 | gAudiop->startNextTransfer(); | ||
1175 | } | ||
1176 | |||
1177 | |||
1178 | // | ||
1179 | // LLAudioSource implementation | ||
1180 | // | ||
1181 | |||
1182 | |||
1183 | LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32 gain) | ||
1184 | : mID(id), | ||
1185 | mOwnerID(owner_id), | ||
1186 | mPriority(0.f), | ||
1187 | mGain(gain), | ||
1188 | mAmbient(FALSE), | ||
1189 | mLoop(FALSE), | ||
1190 | mSyncMaster(FALSE), | ||
1191 | mSyncSlave(FALSE), | ||
1192 | mQueueSounds(FALSE), | ||
1193 | mPlayedOnce(FALSE), | ||
1194 | mChannelp(NULL), | ||
1195 | mCurrentDatap(NULL), | ||
1196 | mQueuedDatap(NULL) | ||
1197 | { | ||
1198 | } | ||
1199 | |||
1200 | |||
1201 | LLAudioSource::~LLAudioSource() | ||
1202 | { | ||
1203 | if (mChannelp) | ||
1204 | { | ||
1205 | // Stop playback of this sound | ||
1206 | mChannelp->setSource(NULL); | ||
1207 | mChannelp = NULL; | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | |||
1212 | void LLAudioSource::setChannel(LLAudioChannel *channelp) | ||
1213 | { | ||
1214 | if (channelp == mChannelp) | ||
1215 | { | ||
1216 | return; | ||
1217 | } | ||
1218 | |||
1219 | mChannelp = channelp; | ||
1220 | } | ||
1221 | |||
1222 | |||
1223 | void LLAudioSource::update() | ||
1224 | { | ||
1225 | if (!getCurrentBuffer()) | ||
1226 | { | ||
1227 | if (getCurrentData()) | ||
1228 | { | ||
1229 | // Hack - try and load the sound. Will do this as a callback | ||
1230 | // on decode later. | ||
1231 | if (getCurrentData()->load()) | ||
1232 | { | ||
1233 | play(getCurrentData()->getID()); | ||
1234 | } | ||
1235 | } | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | void LLAudioSource::updatePriority() | ||
1240 | { | ||
1241 | if (isAmbient()) | ||
1242 | { | ||
1243 | mPriority = 1.f; | ||
1244 | } | ||
1245 | else | ||
1246 | { | ||
1247 | // Priority is based on distance | ||
1248 | LLVector3 dist_vec; | ||
1249 | dist_vec.setVec(getPositionGlobal()); | ||
1250 | dist_vec -= gAudiop->getListenerPos(); | ||
1251 | F32 dist_squared = llmax(1.f, dist_vec.magVecSquared()); | ||
1252 | |||
1253 | mPriority = mGain / dist_squared; | ||
1254 | } | ||
1255 | } | ||
1256 | |||
1257 | BOOL LLAudioSource::setupChannel() | ||
1258 | { | ||
1259 | LLAudioData *adp = getCurrentData(); | ||
1260 | |||
1261 | if (!adp->getBuffer()) | ||
1262 | { | ||
1263 | // We're not ready to play back the sound yet, so don't try and allocate a channel for it. | ||
1264 | //llwarns << "Aborting, no buffer" << llendl; | ||
1265 | return FALSE; | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | if (!mChannelp) | ||
1270 | { | ||
1271 | // Update the priority, in case we need to push out another channel. | ||
1272 | updatePriority(); | ||
1273 | |||
1274 | setChannel(gAudiop->getFreeChannel(getPriority())); | ||
1275 | } | ||
1276 | |||
1277 | if (!mChannelp) | ||
1278 | { | ||
1279 | // Ugh, we don't have any free channels. | ||
1280 | // Now we have to reprioritize. | ||
1281 | // For now, just don't play the sound. | ||
1282 | //llwarns << "Aborting, no free channels" << llendl; | ||
1283 | return FALSE; | ||
1284 | } | ||
1285 | |||
1286 | mChannelp->setSource(this); | ||
1287 | return TRUE; | ||
1288 | } | ||
1289 | |||
1290 | |||
1291 | BOOL LLAudioSource::play(const LLUUID &audio_uuid) | ||
1292 | { | ||
1293 | if (audio_uuid.isNull()) | ||
1294 | { | ||
1295 | if (getChannel()) | ||
1296 | { | ||
1297 | getChannel()->setSource(NULL); | ||
1298 | setChannel(NULL); | ||
1299 | addAudioData(NULL, TRUE); | ||
1300 | } | ||
1301 | } | ||
1302 | // Reset our age timeout if someone attempts to play the source. | ||
1303 | mAgeTimer.reset(); | ||
1304 | |||
1305 | LLAudioData *adp = gAudiop->getAudioData(audio_uuid); | ||
1306 | |||
1307 | BOOL has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); | ||
1308 | |||
1309 | |||
1310 | addAudioData(adp); | ||
1311 | |||
1312 | if (!has_buffer) | ||
1313 | { | ||
1314 | // Don't bother trying to set up a channel or anything, we don't have an audio buffer. | ||
1315 | return FALSE; | ||
1316 | } | ||
1317 | |||
1318 | if (!setupChannel()) | ||
1319 | { | ||
1320 | return FALSE; | ||
1321 | } | ||
1322 | |||
1323 | if (isSyncSlave()) | ||
1324 | { | ||
1325 | // A sync slave, it doesn't start playing until it's synced up with the master. | ||
1326 | // Flag this channel as waiting for sync, and return true. | ||
1327 | getChannel()->setWaiting(TRUE); | ||
1328 | return TRUE; | ||
1329 | } | ||
1330 | |||
1331 | getChannel()->play(); | ||
1332 | return TRUE; | ||
1333 | } | ||
1334 | |||
1335 | |||
1336 | BOOL LLAudioSource::isDone() | ||
1337 | { | ||
1338 | const F32 MAX_AGE = 60.f; | ||
1339 | const F32 MAX_UNPLAYED_AGE = 15.f; | ||
1340 | if (isLoop()) | ||
1341 | { | ||
1342 | // Looped sources never die on their own. | ||
1343 | return FALSE; | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | if (hasPendingPreloads()) | ||
1348 | { | ||
1349 | return FALSE; | ||
1350 | } | ||
1351 | |||
1352 | if (mQueuedDatap) | ||
1353 | { | ||
1354 | // Don't kill this sound if we've got something queued up to play. | ||
1355 | return FALSE; | ||
1356 | } | ||
1357 | |||
1358 | F32 elapsed = mAgeTimer.getElapsedTimeF32(); | ||
1359 | |||
1360 | // This is a single-play source | ||
1361 | if (!mChannelp) | ||
1362 | { | ||
1363 | if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) | ||
1364 | { | ||
1365 | // We don't have a channel assigned, and it's been | ||
1366 | // over 5 seconds since we tried to play it. Don't bother. | ||
1367 | //llinfos << "No channel assigned, source is done" << llendl; | ||
1368 | return TRUE; | ||
1369 | } | ||
1370 | else | ||
1371 | { | ||
1372 | return FALSE; | ||
1373 | } | ||
1374 | } | ||
1375 | |||
1376 | if (mChannelp->isPlaying()) | ||
1377 | { | ||
1378 | if (elapsed > MAX_AGE) | ||
1379 | { | ||
1380 | // Arbitarily cut off non-looped sounds when they're 20 seconds old. | ||
1381 | return TRUE; | ||
1382 | } | ||
1383 | else | ||
1384 | { | ||
1385 | // Sound is still playing and we haven't timed out, don't kill it. | ||
1386 | return FALSE; | ||
1387 | } | ||
1388 | } | ||
1389 | |||
1390 | if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) | ||
1391 | { | ||
1392 | // The sound isn't playing back after 5 seconds or we're already done playing it, kill it. | ||
1393 | return TRUE; | ||
1394 | } | ||
1395 | |||
1396 | return FALSE; | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | void LLAudioSource::addAudioData(LLAudioData *adp, const BOOL set_current) | ||
1401 | { | ||
1402 | // Only handle a single piece of audio data associated with a source right now, | ||
1403 | // until I implement prefetch. | ||
1404 | if (set_current) | ||
1405 | { | ||
1406 | if (!mCurrentDatap) | ||
1407 | { | ||
1408 | mCurrentDatap = adp; | ||
1409 | if (mChannelp) | ||
1410 | { | ||
1411 | mChannelp->updateBuffer(); | ||
1412 | mChannelp->play(); | ||
1413 | } | ||
1414 | |||
1415 | // Make sure the audio engine knows that we want to request this sound. | ||
1416 | gAudiop->startNextTransfer(); | ||
1417 | return; | ||
1418 | } | ||
1419 | else if (mQueueSounds) | ||
1420 | { | ||
1421 | // If we have current data, and we're queuing, put | ||
1422 | // the object onto the queue. | ||
1423 | if (mQueuedDatap) | ||
1424 | { | ||
1425 | // We only queue one sound at a time, and it's a FIFO. | ||
1426 | // Don't put it onto the queue. | ||
1427 | return; | ||
1428 | } | ||
1429 | |||
1430 | if (adp == mCurrentDatap && isLoop()) | ||
1431 | { | ||
1432 | // No point in queueing the same sound if | ||
1433 | // we're looping. | ||
1434 | return; | ||
1435 | } | ||
1436 | mQueuedDatap = adp; | ||
1437 | |||
1438 | // Make sure the audio engine knows that we want to request this sound. | ||
1439 | gAudiop->startNextTransfer(); | ||
1440 | } | ||
1441 | else | ||
1442 | { | ||
1443 | if (mCurrentDatap != adp) | ||
1444 | { | ||
1445 | // Right now, if we're currently playing this sound in a channel, we | ||
1446 | // update the buffer that the channel's associated with | ||
1447 | // and play it. This may not be the correct behavior. | ||
1448 | mCurrentDatap = adp; | ||
1449 | if (mChannelp) | ||
1450 | { | ||
1451 | mChannelp->updateBuffer(); | ||
1452 | mChannelp->play(); | ||
1453 | } | ||
1454 | // Make sure the audio engine knows that we want to request this sound. | ||
1455 | gAudiop->startNextTransfer(); | ||
1456 | } | ||
1457 | } | ||
1458 | } | ||
1459 | else | ||
1460 | { | ||
1461 | // Add it to the preload list. | ||
1462 | mPreloadMap[adp->getID()] = adp; | ||
1463 | gAudiop->startNextTransfer(); | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | |||
1468 | BOOL LLAudioSource::hasPendingPreloads() const | ||
1469 | { | ||
1470 | // Check to see if we've got any preloads on deck for this source | ||
1471 | data_map::const_iterator iter; | ||
1472 | for (iter = mPreloadMap.begin(); iter != mPreloadMap.end(); iter++) | ||
1473 | { | ||
1474 | LLAudioData *adp = iter->second; | ||
1475 | if (!adp->hasDecodedData()) | ||
1476 | { | ||
1477 | // This source is still waiting for a preload | ||
1478 | return TRUE; | ||
1479 | } | ||
1480 | } | ||
1481 | |||
1482 | return FALSE; | ||
1483 | } | ||
1484 | |||
1485 | |||
1486 | LLAudioData *LLAudioSource::getCurrentData() | ||
1487 | { | ||
1488 | return mCurrentDatap; | ||
1489 | } | ||
1490 | |||
1491 | LLAudioData *LLAudioSource::getQueuedData() | ||
1492 | { | ||
1493 | return mQueuedDatap; | ||
1494 | } | ||
1495 | |||
1496 | LLAudioBuffer *LLAudioSource::getCurrentBuffer() | ||
1497 | { | ||
1498 | if (!mCurrentDatap) | ||
1499 | { | ||
1500 | return NULL; | ||
1501 | } | ||
1502 | |||
1503 | return mCurrentDatap->getBuffer(); | ||
1504 | } | ||
1505 | |||
1506 | |||
1507 | |||
1508 | |||
1509 | // | ||
1510 | // LLAudioChannel implementation | ||
1511 | // | ||
1512 | |||
1513 | |||
1514 | LLAudioChannel::LLAudioChannel() : | ||
1515 | mCurrentSourcep(NULL), | ||
1516 | mCurrentBufferp(NULL), | ||
1517 | mLoopedThisFrame(FALSE), | ||
1518 | mWaiting(FALSE) | ||
1519 | { | ||
1520 | } | ||
1521 | |||
1522 | |||
1523 | LLAudioChannel::~LLAudioChannel() | ||
1524 | { | ||
1525 | // Need to disconnect any sources which are using this channel. | ||
1526 | //llinfos << "Cleaning up audio channel" << llendl; | ||
1527 | if (mCurrentSourcep) | ||
1528 | { | ||
1529 | mCurrentSourcep->setChannel(NULL); | ||
1530 | } | ||
1531 | mCurrentBufferp = NULL; | ||
1532 | } | ||
1533 | |||
1534 | |||
1535 | void LLAudioChannel::setSource(LLAudioSource *sourcep) | ||
1536 | { | ||
1537 | //llinfos << this << ": setSource(" << sourcep << ")" << llendl; | ||
1538 | |||
1539 | if (!sourcep) | ||
1540 | { | ||
1541 | // Clearing the source for this channel, don't need to do anything. | ||
1542 | //llinfos << "Clearing source for channel" << llendl; | ||
1543 | cleanup(); | ||
1544 | mCurrentSourcep = NULL; | ||
1545 | mWaiting = FALSE; | ||
1546 | return; | ||
1547 | } | ||
1548 | |||
1549 | if (sourcep == mCurrentSourcep) | ||
1550 | { | ||
1551 | // Don't reallocate the channel, this will make FMOD goofy. | ||
1552 | //llinfos << "Calling setSource with same source!" << llendl; | ||
1553 | } | ||
1554 | |||
1555 | mCurrentSourcep = sourcep; | ||
1556 | updateBuffer(); | ||
1557 | update3DPosition(); | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | BOOL LLAudioChannel::updateBuffer() | ||
1562 | { | ||
1563 | if (!mCurrentSourcep) | ||
1564 | { | ||
1565 | // This channel isn't associated with any source, nothing | ||
1566 | // to be updated | ||
1567 | return FALSE; | ||
1568 | } | ||
1569 | |||
1570 | LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer(); | ||
1571 | if (bufferp == mCurrentBufferp) | ||
1572 | { | ||
1573 | if (bufferp) | ||
1574 | { | ||
1575 | // The source hasn't changed what buffer it's playing | ||
1576 | bufferp->mLastUseTimer.reset(); | ||
1577 | bufferp->mInUse = TRUE; | ||
1578 | } | ||
1579 | return FALSE; | ||
1580 | } | ||
1581 | |||
1582 | // | ||
1583 | // The source changed what buffer it's playing. Whe need to clean up the | ||
1584 | // existing fmod channel | ||
1585 | // | ||
1586 | cleanup(); | ||
1587 | |||
1588 | mCurrentBufferp = bufferp; | ||
1589 | if (bufferp) | ||
1590 | { | ||
1591 | bufferp->mLastUseTimer.reset(); | ||
1592 | bufferp->mInUse = TRUE; | ||
1593 | } | ||
1594 | |||
1595 | if (!mCurrentBufferp) | ||
1596 | { | ||
1597 | // There's no new buffer to be played, so we just abort. | ||
1598 | return FALSE; | ||
1599 | } | ||
1600 | |||
1601 | return TRUE; | ||
1602 | } | ||
1603 | |||
1604 | |||
1605 | |||
1606 | |||
1607 | // | ||
1608 | // LLAudioData implementation | ||
1609 | // | ||
1610 | |||
1611 | |||
1612 | LLAudioData::LLAudioData(const LLUUID &uuid) : | ||
1613 | mID(uuid), | ||
1614 | mBufferp(NULL), | ||
1615 | mHasLocalData(FALSE), | ||
1616 | mHasDecodedData(FALSE), | ||
1617 | mHasValidData(TRUE) | ||
1618 | { | ||
1619 | if (uuid.isNull()) | ||
1620 | { | ||
1621 | // This is a null sound. | ||
1622 | return; | ||
1623 | } | ||
1624 | |||
1625 | if (gAudiop->hasDecodedFile(uuid)) | ||
1626 | { | ||
1627 | // Already have a decoded version, don't need to decode it. | ||
1628 | mHasLocalData = TRUE; | ||
1629 | mHasDecodedData = TRUE; | ||
1630 | } | ||
1631 | else if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) | ||
1632 | { | ||
1633 | mHasLocalData = TRUE; | ||
1634 | } | ||
1635 | } | ||
1636 | |||
1637 | |||
1638 | BOOL LLAudioData::load() | ||
1639 | { | ||
1640 | // For now, just assume we're going to use one buffer per audiodata. | ||
1641 | if (mBufferp) | ||
1642 | { | ||
1643 | // We already have this sound in a buffer, don't do anything. | ||
1644 | llinfos << "Already have a buffer for this sound, don't bother loading!" << llendl; | ||
1645 | return TRUE; | ||
1646 | } | ||
1647 | |||
1648 | mBufferp = gAudiop->getFreeBuffer(); | ||
1649 | if (!mBufferp) | ||
1650 | { | ||
1651 | // No free buffers, abort. | ||
1652 | llinfos << "Not able to allocate a new audio buffer, aborting." << llendl; | ||
1653 | return FALSE; | ||
1654 | } | ||
1655 | |||
1656 | char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ | ||
1657 | char wav_path[MAX_PATH]; /*Flawfinder: ignore*/ | ||
1658 | mID.toString(uuid_str); | ||
1659 | snprintf(wav_path, MAX_PATH, "%s.dsf",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str()); /*Flawfinder: ignore*/ | ||
1660 | |||
1661 | if (!mBufferp->loadWAV(wav_path)) | ||
1662 | { | ||
1663 | // Hrm. Right now, let's unset the buffer, since it's empty. | ||
1664 | gAudiop->cleanupBuffer(mBufferp); | ||
1665 | mBufferp = NULL; | ||
1666 | |||
1667 | return FALSE; | ||
1668 | } | ||
1669 | mBufferp->mAudioDatap = this; | ||
1670 | return TRUE; | ||
1671 | } | ||
1672 | |||