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