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.cpp635
1 files changed, 635 insertions, 0 deletions
diff --git a/linden/indra/llaudio/llaudiodecodemgr.cpp b/linden/indra/llaudio/llaudiodecodemgr.cpp
new file mode 100644
index 0000000..d98ff5d
--- /dev/null
+++ b/linden/indra/llaudio/llaudiodecodemgr.cpp
@@ -0,0 +1,635 @@
1/**
2 * @file llaudiodecodemgr.cpp
3 *
4 * Copyright (c) 2003-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include <vector>
30#include <iterator>
31#include <algorithm>
32#include <stdio.h>
33
34#include "llaudiodecodemgr.h"
35
36#include "vorbisdecode.h"
37#include "audioengine.h"
38#include "lllfsthread.h"
39#include "llvfile.h"
40#include "llstring.h"
41#include "lldir.h"
42#include "llendianswizzle.h"
43#include "audioengine.h"
44#include "llassetstorage.h"
45
46#include "vorbis/codec.h"
47#include "vorbis/vorbisfile.h"
48
49extern LLAudioEngine *gAudiop;
50
51LLAudioDecodeMgr *gAudioDecodeMgrp = NULL;
52
53static const S32 WAV_HEADER_SIZE = 44;
54
55class LLVorbisDecodeState
56{
57public:
58 LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename);
59 virtual ~LLVorbisDecodeState();
60
61 BOOL initDecode();
62 BOOL decodeSection(); // Return TRUE if done.
63 BOOL finishDecode();
64
65 void flushBadFile();
66
67 BOOL isValid() const { return mValid; }
68 BOOL isDone() const { return mDone; }
69 const LLUUID &getUUID() const { return mUUID; }
70protected:
71 BOOL mValid;
72 BOOL mDone;
73 LLUUID mUUID;
74
75 std::vector<U8> mWAVBuffer;
76#if !defined(USE_WAV_VFILE)
77 LLString mOutFilename;
78 LLLFSThread::handle_t mFileHandle;
79#endif
80
81 LLVFile *mInFilep;
82 OggVorbis_File mVF;
83 S32 mCurrentSection;
84};
85
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)
253{
254 LLVFile *file = (LLVFile *)datasource;
255
256 if (file->read((U8*)ptr, (S32)(size * nmemb))) /*Flawfinder: ignore*/
257 {
258 S32 read = file->getLastBytesRead();
259 return read / size; /*Flawfinder: ignore*/
260 }
261 else
262 {
263 return 0;
264 }
265}
266
267int vfs_seek(void *datasource, ogg_int64_t offset, int whence)
268{
269 LLVFile *file = (LLVFile *)datasource;
270
271 // vfs has 31-bit files
272 if (offset > S32_MAX)
273 {
274 return -1;
275 }
276
277 S32 origin;
278 switch (whence) {
279 case SEEK_SET:
280 origin = 0;
281 break;
282 case SEEK_END:
283 origin = file->getSize();
284 break;
285 case SEEK_CUR:
286 origin = -1;
287 break;
288 default:
289 llerrs << "Invalid whence argument to vfs_seek" << llendl;
290 return -1;
291 }
292
293 if (file->seek((S32)offset, origin))
294 {
295 return 0;
296 }
297 else
298 {
299 return -1;
300 }
301}
302
303int vfs_close (void *datasource)
304{
305 LLVFile *file = (LLVFile *)datasource;
306
307 delete file;
308
309 return 0;
310}
311
312long vfs_tell (void *datasource)
313{
314 LLVFile *file = (LLVFile *)datasource;
315
316 return file->tell();
317}
318
319
320
321
322LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename)
323{
324 mDone = FALSE;
325 mValid = FALSE;
326 mUUID = uuid;
327 mInFilep = NULL;
328 mCurrentSection = 0;
329#if !defined(USE_WAV_VFILE)
330 mOutFilename = out_filename;
331 mFileHandle = LLLFSThread::nullHandle();
332#endif
333 // No default value for mVF, it's an ogg structure?
334}
335
336LLVorbisDecodeState::~LLVorbisDecodeState()
337{
338 if (!mDone)
339 {
340 delete mInFilep;
341 mInFilep = NULL;
342 }
343}
344
345
346BOOL LLVorbisDecodeState::initDecode()
347{
348 ov_callbacks vfs_callbacks;
349 vfs_callbacks.read_func = vfs_read;
350 vfs_callbacks.seek_func = vfs_seek;
351 vfs_callbacks.close_func = vfs_close;
352 vfs_callbacks.tell_func = vfs_tell;
353
354 //llinfos << "Initing decode from vfile: " << mUUID << llendl;
355
356 mInFilep = new LLVFile(gVFS, mUUID, LLAssetType::AT_SOUND);
357 if (!mInFilep || !mInFilep->getSize())
358 {
359 llwarns << "unable to open vorbis source vfile for reading" << llendl;
360 delete mInFilep;
361 mInFilep = NULL;
362 return FALSE;
363 }
364
365 int r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks);
366 if(r < 0)
367 {
368 llwarns << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << llendl;
369 return(FALSE);
370 }
371
372 size_t size_guess = (size_t)ov_pcm_total(&mVF, -1);
373 vorbis_info* vi = ov_info(&mVF, -1);
374 size_guess *= vi->channels;
375 size_guess *= 2;
376 size_guess += 2048;
377 mWAVBuffer.reserve(size_guess);
378 mWAVBuffer.resize(WAV_HEADER_SIZE);
379
380 {
381 // write the .wav format header
382 //"RIFF"
383 mWAVBuffer[0] = 0x52;
384 mWAVBuffer[1] = 0x49;
385 mWAVBuffer[2] = 0x46;
386 mWAVBuffer[3] = 0x46;
387
388 // length = datalen + 36 (to be filled in later)
389 mWAVBuffer[4] = 0x00;
390 mWAVBuffer[5] = 0x00;
391 mWAVBuffer[6] = 0x00;
392 mWAVBuffer[7] = 0x00;
393
394 //"WAVE"
395 mWAVBuffer[8] = 0x57;
396 mWAVBuffer[9] = 0x41;
397 mWAVBuffer[10] = 0x56;
398 mWAVBuffer[11] = 0x45;
399
400 // "fmt "
401 mWAVBuffer[12] = 0x66;
402 mWAVBuffer[13] = 0x6D;
403 mWAVBuffer[14] = 0x74;
404 mWAVBuffer[15] = 0x20;
405
406 // chunk size = 16
407 mWAVBuffer[16] = 0x10;
408 mWAVBuffer[17] = 0x00;
409 mWAVBuffer[18] = 0x00;
410 mWAVBuffer[19] = 0x00;
411
412 // format (1 = PCM)
413 mWAVBuffer[20] = 0x01;
414 mWAVBuffer[21] = 0x00;
415
416 // number of channels
417 mWAVBuffer[22] = 0x01;
418 mWAVBuffer[23] = 0x00;
419
420 // samples per second
421 mWAVBuffer[24] = 0x44;
422 mWAVBuffer[25] = 0xAC;
423 mWAVBuffer[26] = 0x00;
424 mWAVBuffer[27] = 0x00;
425
426 // average bytes per second
427 mWAVBuffer[28] = 0x88;
428 mWAVBuffer[29] = 0x58;
429 mWAVBuffer[30] = 0x01;
430 mWAVBuffer[31] = 0x00;
431
432 // bytes to output at a single time
433 mWAVBuffer[32] = 0x02;
434 mWAVBuffer[33] = 0x00;
435
436 // 16 bits per sample
437 mWAVBuffer[34] = 0x10;
438 mWAVBuffer[35] = 0x00;
439
440 // "data"
441 mWAVBuffer[36] = 0x64;
442 mWAVBuffer[37] = 0x61;
443 mWAVBuffer[38] = 0x74;
444 mWAVBuffer[39] = 0x61;
445
446 // these are the length of the data chunk, to be filled in later
447 mWAVBuffer[40] = 0x00;
448 mWAVBuffer[41] = 0x00;
449 mWAVBuffer[42] = 0x00;
450 mWAVBuffer[43] = 0x00;
451 }
452
453 //{
454 //char **ptr=ov_comment(&mVF,-1)->user_comments;
455// vorbis_info *vi=ov_info(&vf,-1);
456 //while(*ptr){
457 // fprintf(stderr,"%s\n",*ptr);
458 // ++ptr;
459 //}
460// fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate);
461// fprintf(stderr,"\nDecoded length: %ld samples\n", (long)ov_pcm_total(&vf,-1));
462// fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor);
463 //}
464 return TRUE;
465}
466
467BOOL LLVorbisDecodeState::decodeSection()
468{
469 if (!mInFilep)
470 {
471 llwarns << "No VFS file to decode in vorbis!" << llendl;
472 return TRUE;
473 }
474 if (mDone)
475 {
476// llwarns << "Already done with decode, aborting!" << llendl;
477 return TRUE;
478 }
479 char pcmout[4096]; /*Flawfinder: ignore*/
480
481 BOOL eof = FALSE;
482 long ret=ov_read(&mVF, pcmout, sizeof(pcmout), 0, 2, 1, &mCurrentSection);
483 if (ret == 0)
484 {
485 /* EOF */
486 eof = TRUE;
487 mDone = TRUE;
488 mValid = TRUE;
489// llinfos << "Vorbis EOF" << llendl;
490 }
491 else if (ret < 0)
492 {
493 /* error in the stream. Not a problem, just reporting it in
494 case we (the app) cares. In this case, we don't. */
495
496 llwarns << "BAD vorbis decode in decodeSection." << llendl;
497
498 mValid = FALSE;
499 mDone = TRUE;
500 // We're done, return TRUE.
501 return TRUE;
502 }
503 else
504 {
505// llinfos << "Vorbis read " << ret << "bytes" << llendl;
506 /* we don't bother dealing with sample rate changes, etc, but.
507 you'll have to*/
508 std::copy(pcmout, pcmout+ret, std::back_inserter(mWAVBuffer));
509 }
510 return eof;
511}
512
513BOOL LLVorbisDecodeState::finishDecode()
514{
515 if (!isValid())
516 {
517 llwarns << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << llendl;
518 return TRUE; // We've finished
519 }
520
521#if !defined(USE_WAV_VFILE)
522 if (mFileHandle == LLLFSThread::nullHandle())
523#endif
524 {
525 ov_clear(&mVF);
526
527 // write "data" chunk length, in little-endian format
528 S32 data_length = mWAVBuffer.size() - WAV_HEADER_SIZE;
529 mWAVBuffer[40] = (data_length) & 0x000000FF;
530 mWAVBuffer[41] = (data_length >> 8) & 0x000000FF;
531 mWAVBuffer[42] = (data_length >> 16) & 0x000000FF;
532 mWAVBuffer[43] = (data_length >> 24) & 0x000000FF;
533 // write overall "RIFF" length, in little-endian format
534 data_length += 36;
535 mWAVBuffer[4] = (data_length) & 0x000000FF;
536 mWAVBuffer[5] = (data_length >> 8) & 0x000000FF;
537 mWAVBuffer[6] = (data_length >> 16) & 0x000000FF;
538 mWAVBuffer[7] = (data_length >> 24) & 0x000000FF;
539
540 //
541 // FUCK!!! Vorbis encode/decode messes up loop point transitions (pop)
542 // do a cheap-and-cheesy crossfade
543 //
544 {
545 S16 *samplep;
546 S32 i;
547 S32 fade_length;
548 char pcmout[4096]; /*Flawfinder: ignore*/
549
550 fade_length = llmin((S32)128,(S32)(data_length-36)/8);
551 if((S32)mWAVBuffer.size() >= (WAV_HEADER_SIZE + 2* fade_length))
552 {
553 memcpy(pcmout, &mWAVBuffer[WAV_HEADER_SIZE], (2 * fade_length)); /*Flawfinder: ignore*/
554 }
555 llendianswizzle(&pcmout, 2, fade_length);
556
557 samplep = (S16 *)pcmout;
558 for (i = 0 ;i < fade_length; i++)
559 {
560 *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length));
561 samplep++;
562 }
563
564 llendianswizzle(&pcmout, 2, fade_length);
565 if((WAV_HEADER_SIZE+(2 * fade_length)) < (S32)mWAVBuffer.size())
566 {
567 memcpy(&mWAVBuffer[WAV_HEADER_SIZE], pcmout, (2 * fade_length)); /*Flawfinder: ignore*/
568 }
569 S32 near_end = mWAVBuffer.size() - (2 * fade_length);
570 if ((S32)mWAVBuffer.size() >= ( near_end + 2* fade_length))
571 {
572 memcpy(pcmout, &mWAVBuffer[near_end], (2 * fade_length)); /*Flawfinder: ignore*/
573 }
574 llendianswizzle(&pcmout, 2, fade_length);
575
576 samplep = (S16 *)pcmout;
577 for (i = fade_length-1 ; i >= 0; i--)
578 {
579 *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length));
580 samplep++;
581 }
582
583 llendianswizzle(&pcmout, 2, fade_length);
584 if (near_end + (2 * fade_length) < (S32)mWAVBuffer.size())
585 {
586 memcpy(&mWAVBuffer[near_end], pcmout, (2 * fade_length));/*Flawfinder: ignore*/
587 }
588 }
589
590 if (36 == data_length)
591 {
592 llwarns << "BAD Vorbis decode in finishDecode!" << llendl;
593 mValid = FALSE;
594 return TRUE; // we've finished
595 }
596#if !defined(USE_WAV_VFILE)
597 mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, data_length);
598#endif
599 }
600
601 if (mFileHandle != LLLFSThread::nullHandle())
602 {
603 LLLFSThread::status_t s = LLLFSThread::sLocal->getRequestStatus(mFileHandle);
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 {
614 LLLFSThread::Request* req = (LLLFSThread::Request*)LLLFSThread::sLocal->getRequest(mFileHandle);
615 if (req->getBytesRead() == 0) //!= req->getBytes() // should be safe, but needs testing
616 {
617 llwarns << "Unable to write file in LLVorbisDecodeState::finishDecode" << llendl;
618 mValid = FALSE;
619 return TRUE; // we've finished
620 }
621 }
622 LLLFSThread::sLocal->completeRequest(mFileHandle);
623 }
624
625 mDone = TRUE;
626
627#if defined(USE_WAV_VFILE)
628 // write the data.
629 LLVFile output(gVFS, mUUID, LLAssetType::AT_SOUND_WAV);
630 output.write(&mWAVBuffer[0], mWAVBuffer.size());
631#endif
632 //llinfos << "Finished decode for " << getUUID() << llendl;
633
634 return TRUE;
635}