aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llaudio/llaudiodecodemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llaudio/llaudiodecodemgr.cpp')
-rw-r--r--linden/indra/llaudio/llaudiodecodemgr.cpp378
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
53static const S32 WAV_HEADER_SIZE = 44; 53static const S32 WAV_HEADER_SIZE = 44;
54 54
55class LLVorbisDecodeState 55
56//////////////////////////////////////////////////////////////////////////////
57
58
59class LLVorbisDecodeState : public LLRefCount
56{ 60{
57public: 61public:
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; }
70protected: 87protected:
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
86void 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
96LLAudioDecodeMgr::LLAudioDecodeMgr()
97{
98 mCurrentDecodep = NULL;
99}
100
101LLAudioDecodeMgr::~LLAudioDecodeMgr()
102{
103 delete mCurrentDecodep;
104 mCurrentDecodep = NULL;
105}
106
107
108void 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
211BOOL 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
230S32 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
252size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) 104size_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)
303int vfs_close (void *datasource) 155int 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
312long vfs_tell (void *datasource) 162long 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
322LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename) 168LLVorbisDecodeState::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
479void 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
490class LLAudioDecodeMgr::Impl
491{
492 friend class LLAudioDecodeMgr;
493public:
494 Impl() {};
495 ~Impl() {};
496
497 void processQueue(const F32 num_secs = 0.005);
498
499protected:
500 LLLinkedQueue<LLUUID> mDecodeQueue;
501 LLPointer<LLVorbisDecodeState> mCurrentDecodep;
502};
503
504
505void 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
606LLAudioDecodeMgr::LLAudioDecodeMgr()
607{
608 mImpl = new Impl;
609}
610
611LLAudioDecodeMgr::~LLAudioDecodeMgr()
612{
613 delete mImpl;
614}
615
616void LLAudioDecodeMgr::processQueue(const F32 num_secs)
617{
618 mImpl->processQueue(num_secs);
619}
620
621BOOL 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