diff options
Diffstat (limited to 'linden/indra/llaudio/llaudiodecodemgr.cpp')
-rw-r--r-- | linden/indra/llaudio/llaudiodecodemgr.cpp | 378 |
1 files changed, 191 insertions, 187 deletions
diff --git a/linden/indra/llaudio/llaudiodecodemgr.cpp b/linden/indra/llaudio/llaudiodecodemgr.cpp index d98ff5d..832c314 100644 --- a/linden/indra/llaudio/llaudiodecodemgr.cpp +++ b/linden/indra/llaudio/llaudiodecodemgr.cpp | |||
@@ -52,9 +52,25 @@ LLAudioDecodeMgr *gAudioDecodeMgrp = NULL; | |||
52 | 52 | ||
53 | static const S32 WAV_HEADER_SIZE = 44; | 53 | static const S32 WAV_HEADER_SIZE = 44; |
54 | 54 | ||
55 | class LLVorbisDecodeState | 55 | |
56 | ////////////////////////////////////////////////////////////////////////////// | ||
57 | |||
58 | |||
59 | class LLVorbisDecodeState : public LLRefCount | ||
56 | { | 60 | { |
57 | public: | 61 | public: |
62 | class WriteResponder : public LLLFSThread::Responder | ||
63 | { | ||
64 | public: | ||
65 | WriteResponder(LLVorbisDecodeState* decoder) : mDecoder(decoder) {} | ||
66 | ~WriteResponder() {} | ||
67 | void completed(S32 bytes) | ||
68 | { | ||
69 | mDecoder->ioComplete(bytes); | ||
70 | } | ||
71 | LLPointer<LLVorbisDecodeState> mDecoder; | ||
72 | }; | ||
73 | |||
58 | LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename); | 74 | LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename); |
59 | virtual ~LLVorbisDecodeState(); | 75 | virtual ~LLVorbisDecodeState(); |
60 | 76 | ||
@@ -64,12 +80,14 @@ public: | |||
64 | 80 | ||
65 | void flushBadFile(); | 81 | void flushBadFile(); |
66 | 82 | ||
83 | void ioComplete(S32 bytes) { mBytesRead = bytes; } | ||
67 | BOOL isValid() const { return mValid; } | 84 | BOOL isValid() const { return mValid; } |
68 | BOOL isDone() const { return mDone; } | 85 | BOOL isDone() const { return mDone; } |
69 | const LLUUID &getUUID() const { return mUUID; } | 86 | const LLUUID &getUUID() const { return mUUID; } |
70 | protected: | 87 | protected: |
71 | BOOL mValid; | 88 | BOOL mValid; |
72 | BOOL mDone; | 89 | BOOL mDone; |
90 | LLAtomicS32 mBytesRead; | ||
73 | LLUUID mUUID; | 91 | LLUUID mUUID; |
74 | 92 | ||
75 | std::vector<U8> mWAVBuffer; | 93 | std::vector<U8> mWAVBuffer; |
@@ -83,172 +101,6 @@ protected: | |||
83 | S32 mCurrentSection; | 101 | S32 mCurrentSection; |
84 | }; | 102 | }; |
85 | 103 | ||
86 | void LLVorbisDecodeState::flushBadFile() | ||
87 | { | ||
88 | if (mInFilep) | ||
89 | { | ||
90 | llwarns << "Flushing bad vorbis file from VFS for " << mUUID << llendl; | ||
91 | mInFilep->remove(); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | LLAudioDecodeMgr::LLAudioDecodeMgr() | ||
97 | { | ||
98 | mCurrentDecodep = NULL; | ||
99 | } | ||
100 | |||
101 | LLAudioDecodeMgr::~LLAudioDecodeMgr() | ||
102 | { | ||
103 | delete mCurrentDecodep; | ||
104 | mCurrentDecodep = NULL; | ||
105 | } | ||
106 | |||
107 | |||
108 | void LLAudioDecodeMgr::processQueue(const F32 num_secs) | ||
109 | { | ||
110 | LLUUID uuid; | ||
111 | |||
112 | LLTimer decode_timer; | ||
113 | |||
114 | BOOL done = FALSE; | ||
115 | while (!done) | ||
116 | { | ||
117 | if (mCurrentDecodep) | ||
118 | { | ||
119 | BOOL res; | ||
120 | |||
121 | // Decode in a loop until we're done or have run out of time. | ||
122 | while(!(res = mCurrentDecodep->decodeSection()) && (decode_timer.getElapsedTimeF32() < num_secs)) | ||
123 | { | ||
124 | // decodeSection does all of the work above | ||
125 | } | ||
126 | |||
127 | if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid()) | ||
128 | { | ||
129 | // We had an error when decoding, abort. | ||
130 | llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; | ||
131 | mCurrentDecodep->flushBadFile(); | ||
132 | LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); | ||
133 | adp->setHasValidData(FALSE); | ||
134 | delete mCurrentDecodep; | ||
135 | mCurrentDecodep = NULL; | ||
136 | done = TRUE; | ||
137 | } | ||
138 | |||
139 | if (!res) | ||
140 | { | ||
141 | // We've used up out time slice, bail... | ||
142 | done = TRUE; | ||
143 | } | ||
144 | else if (mCurrentDecodep) | ||
145 | { | ||
146 | if (mCurrentDecodep->finishDecode()) | ||
147 | { | ||
148 | // We finished! | ||
149 | if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) | ||
150 | { | ||
151 | LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); | ||
152 | adp->setHasDecodedData(TRUE); | ||
153 | adp->setHasValidData(TRUE); | ||
154 | |||
155 | // At this point, we could see if anyone needs this sound immediately, but | ||
156 | // I'm not sure that there's a reason to - we need to poll all of the playing | ||
157 | // sounds anyway. | ||
158 | //llinfos << "Finished the vorbis decode, now what?" << llendl; | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | llinfos << "Vorbis decode failed!!!" << llendl; | ||
163 | } | ||
164 | delete mCurrentDecodep; | ||
165 | mCurrentDecodep = NULL; | ||
166 | } | ||
167 | done = TRUE; // done for now | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if (!done) | ||
172 | { | ||
173 | if (!mDecodeQueue.getLength()) | ||
174 | { | ||
175 | // Nothing else on the queue. | ||
176 | done = TRUE; | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | LLUUID uuid; | ||
181 | mDecodeQueue.pop(uuid); | ||
182 | if (gAudiop->hasDecodedFile(uuid)) | ||
183 | { | ||
184 | // This file has already been decoded, don't decode it again. | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | lldebugs << "Decoding " << uuid << " from audio queue!" << llendl; | ||
189 | |||
190 | char uuid_str[64]; /*Flawfinder: ignore*/ | ||
191 | char d_path[LL_MAX_PATH]; /*Flawfinder: ignore*/ | ||
192 | |||
193 | LLTimer timer; | ||
194 | timer.reset(); | ||
195 | |||
196 | uuid.toString(uuid_str); | ||
197 | snprintf(d_path, LL_MAX_PATH, "%s.dsf", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str()); /*Flawfinder: ignore*/ | ||
198 | |||
199 | mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path); | ||
200 | if (!mCurrentDecodep->initDecode()) | ||
201 | { | ||
202 | delete mCurrentDecodep; | ||
203 | mCurrentDecodep = NULL; | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | |||
210 | |||
211 | BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) | ||
212 | { | ||
213 | if (gAudiop->hasDecodedFile(uuid)) | ||
214 | { | ||
215 | // Already have a decoded version, don't need to decode it. | ||
216 | return TRUE; | ||
217 | } | ||
218 | |||
219 | if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) | ||
220 | { | ||
221 | // Just put it on the decode queue. | ||
222 | gAudioDecodeMgrp->mDecodeQueue.push(uuid); | ||
223 | return TRUE; | ||
224 | } | ||
225 | |||
226 | return FALSE; | ||
227 | } | ||
228 | |||
229 | |||
230 | S32 LLAudioDecodeMgr::getRequestCount() | ||
231 | { | ||
232 | /* | ||
233 | S32 count = 0; | ||
234 | if (mCurrentTransfer.notNull()) | ||
235 | { | ||
236 | count++; | ||
237 | } | ||
238 | |||
239 | count += mRequestQueue.getLength(); | ||
240 | return count; | ||
241 | */ | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | |||
246 | |||
247 | |||
248 | |||
249 | |||
250 | |||
251 | |||
252 | size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) | 104 | size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) |
253 | { | 105 | { |
254 | LLVFile *file = (LLVFile *)datasource; | 106 | LLVFile *file = (LLVFile *)datasource; |
@@ -303,26 +155,21 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence) | |||
303 | int vfs_close (void *datasource) | 155 | int vfs_close (void *datasource) |
304 | { | 156 | { |
305 | LLVFile *file = (LLVFile *)datasource; | 157 | LLVFile *file = (LLVFile *)datasource; |
306 | |||
307 | delete file; | 158 | delete file; |
308 | |||
309 | return 0; | 159 | return 0; |
310 | } | 160 | } |
311 | 161 | ||
312 | long vfs_tell (void *datasource) | 162 | long vfs_tell (void *datasource) |
313 | { | 163 | { |
314 | LLVFile *file = (LLVFile *)datasource; | 164 | LLVFile *file = (LLVFile *)datasource; |
315 | |||
316 | return file->tell(); | 165 | return file->tell(); |
317 | } | 166 | } |
318 | 167 | ||
319 | |||
320 | |||
321 | |||
322 | LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename) | 168 | LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename) |
323 | { | 169 | { |
324 | mDone = FALSE; | 170 | mDone = FALSE; |
325 | mValid = FALSE; | 171 | mValid = FALSE; |
172 | mBytesRead = -1; | ||
326 | mUUID = uuid; | 173 | mUUID = uuid; |
327 | mInFilep = NULL; | 174 | mInFilep = NULL; |
328 | mCurrentSection = 0; | 175 | mCurrentSection = 0; |
@@ -594,32 +441,27 @@ BOOL LLVorbisDecodeState::finishDecode() | |||
594 | return TRUE; // we've finished | 441 | return TRUE; // we've finished |
595 | } | 442 | } |
596 | #if !defined(USE_WAV_VFILE) | 443 | #if !defined(USE_WAV_VFILE) |
597 | mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, data_length); | 444 | mBytesRead = -1; |
445 | mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, data_length, | ||
446 | new WriteResponder(this)); | ||
598 | #endif | 447 | #endif |
599 | } | 448 | } |
600 | 449 | ||
601 | if (mFileHandle != LLLFSThread::nullHandle()) | 450 | if (mFileHandle != LLLFSThread::nullHandle()) |
602 | { | 451 | { |
603 | LLLFSThread::status_t s = LLLFSThread::sLocal->getRequestStatus(mFileHandle); | 452 | if (mBytesRead >= 0) |
604 | if (s != LLLFSThread::STATUS_COMPLETE) | ||
605 | { | ||
606 | if (s != LLLFSThread::STATUS_QUEUED && s != LLLFSThread::STATUS_INPROGRESS) | ||
607 | { | ||
608 | llerrs << "Bad file status in LLVorbisDecodeState::finishDecode: " << s << llendl; | ||
609 | } | ||
610 | return FALSE; // not finished | ||
611 | } | ||
612 | else | ||
613 | { | 453 | { |
614 | LLLFSThread::Request* req = (LLLFSThread::Request*)LLLFSThread::sLocal->getRequest(mFileHandle); | 454 | if (mBytesRead == 0) |
615 | if (req->getBytesRead() == 0) //!= req->getBytes() // should be safe, but needs testing | ||
616 | { | 455 | { |
617 | llwarns << "Unable to write file in LLVorbisDecodeState::finishDecode" << llendl; | 456 | llwarns << "Unable to write file in LLVorbisDecodeState::finishDecode" << llendl; |
618 | mValid = FALSE; | 457 | mValid = FALSE; |
619 | return TRUE; // we've finished | 458 | return TRUE; // we've finished |
620 | } | 459 | } |
621 | } | 460 | } |
622 | LLLFSThread::sLocal->completeRequest(mFileHandle); | 461 | else |
462 | { | ||
463 | return FALSE; // not done | ||
464 | } | ||
623 | } | 465 | } |
624 | 466 | ||
625 | mDone = TRUE; | 467 | mDone = TRUE; |
@@ -633,3 +475,165 @@ BOOL LLVorbisDecodeState::finishDecode() | |||
633 | 475 | ||
634 | return TRUE; | 476 | return TRUE; |
635 | } | 477 | } |
478 | |||
479 | void LLVorbisDecodeState::flushBadFile() | ||
480 | { | ||
481 | if (mInFilep) | ||
482 | { | ||
483 | llwarns << "Flushing bad vorbis file from VFS for " << mUUID << llendl; | ||
484 | mInFilep->remove(); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | ////////////////////////////////////////////////////////////////////////////// | ||
489 | |||
490 | class LLAudioDecodeMgr::Impl | ||
491 | { | ||
492 | friend class LLAudioDecodeMgr; | ||
493 | public: | ||
494 | Impl() {}; | ||
495 | ~Impl() {}; | ||
496 | |||
497 | void processQueue(const F32 num_secs = 0.005); | ||
498 | |||
499 | protected: | ||
500 | LLLinkedQueue<LLUUID> mDecodeQueue; | ||
501 | LLPointer<LLVorbisDecodeState> mCurrentDecodep; | ||
502 | }; | ||
503 | |||
504 | |||
505 | void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) | ||
506 | { | ||
507 | LLUUID uuid; | ||
508 | |||
509 | LLTimer decode_timer; | ||
510 | |||
511 | BOOL done = FALSE; | ||
512 | while (!done) | ||
513 | { | ||
514 | if (mCurrentDecodep) | ||
515 | { | ||
516 | BOOL res; | ||
517 | |||
518 | // Decode in a loop until we're done or have run out of time. | ||
519 | while(!(res = mCurrentDecodep->decodeSection()) && (decode_timer.getElapsedTimeF32() < num_secs)) | ||
520 | { | ||
521 | // decodeSection does all of the work above | ||
522 | } | ||
523 | |||
524 | if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid()) | ||
525 | { | ||
526 | // We had an error when decoding, abort. | ||
527 | llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; | ||
528 | mCurrentDecodep->flushBadFile(); | ||
529 | LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); | ||
530 | adp->setHasValidData(FALSE); | ||
531 | mCurrentDecodep = NULL; | ||
532 | done = TRUE; | ||
533 | } | ||
534 | |||
535 | if (!res) | ||
536 | { | ||
537 | // We've used up out time slice, bail... | ||
538 | done = TRUE; | ||
539 | } | ||
540 | else if (mCurrentDecodep) | ||
541 | { | ||
542 | if (mCurrentDecodep->finishDecode()) | ||
543 | { | ||
544 | // We finished! | ||
545 | if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) | ||
546 | { | ||
547 | LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); | ||
548 | adp->setHasDecodedData(TRUE); | ||
549 | adp->setHasValidData(TRUE); | ||
550 | |||
551 | // At this point, we could see if anyone needs this sound immediately, but | ||
552 | // I'm not sure that there's a reason to - we need to poll all of the playing | ||
553 | // sounds anyway. | ||
554 | //llinfos << "Finished the vorbis decode, now what?" << llendl; | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | llinfos << "Vorbis decode failed!!!" << llendl; | ||
559 | } | ||
560 | mCurrentDecodep = NULL; | ||
561 | } | ||
562 | done = TRUE; // done for now | ||
563 | } | ||
564 | } | ||
565 | |||
566 | if (!done) | ||
567 | { | ||
568 | if (!mDecodeQueue.getLength()) | ||
569 | { | ||
570 | // Nothing else on the queue. | ||
571 | done = TRUE; | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | LLUUID uuid; | ||
576 | mDecodeQueue.pop(uuid); | ||
577 | if (gAudiop->hasDecodedFile(uuid)) | ||
578 | { | ||
579 | // This file has already been decoded, don't decode it again. | ||
580 | continue; | ||
581 | } | ||
582 | |||
583 | lldebugs << "Decoding " << uuid << " from audio queue!" << llendl; | ||
584 | |||
585 | char uuid_str[64]; /*Flawfinder: ignore*/ | ||
586 | char d_path[LL_MAX_PATH]; /*Flawfinder: ignore*/ | ||
587 | |||
588 | LLTimer timer; | ||
589 | timer.reset(); | ||
590 | |||
591 | uuid.toString(uuid_str); | ||
592 | snprintf(d_path, LL_MAX_PATH, "%s.dsf", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str()); /*Flawfinder: ignore*/ | ||
593 | |||
594 | mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path); | ||
595 | if (!mCurrentDecodep->initDecode()) | ||
596 | { | ||
597 | mCurrentDecodep = NULL; | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | |||
604 | ////////////////////////////////////////////////////////////////////////////// | ||
605 | |||
606 | LLAudioDecodeMgr::LLAudioDecodeMgr() | ||
607 | { | ||
608 | mImpl = new Impl; | ||
609 | } | ||
610 | |||
611 | LLAudioDecodeMgr::~LLAudioDecodeMgr() | ||
612 | { | ||
613 | delete mImpl; | ||
614 | } | ||
615 | |||
616 | void LLAudioDecodeMgr::processQueue(const F32 num_secs) | ||
617 | { | ||
618 | mImpl->processQueue(num_secs); | ||
619 | } | ||
620 | |||
621 | BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) | ||
622 | { | ||
623 | if (gAudiop->hasDecodedFile(uuid)) | ||
624 | { | ||
625 | // Already have a decoded version, don't need to decode it. | ||
626 | return TRUE; | ||
627 | } | ||
628 | |||
629 | if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) | ||
630 | { | ||
631 | // Just put it on the decode queue. | ||
632 | mImpl->mDecodeQueue.push(uuid); | ||
633 | return TRUE; | ||
634 | } | ||
635 | |||
636 | return FALSE; | ||
637 | } | ||
638 | |||
639 | |||