vorbisStreamSource.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. //--------------------------------------
  2. // vorbisStreamSource.cc
  3. // implementation of streaming audio source
  4. //
  5. // Kurtis Seebaldt
  6. //--------------------------------------
  7. #include "audio/vorbisStreamSource.h"
  8. #include "ogg/os_types.h"
  9. #define BUFFERSIZE 32768
  10. #define CHUNKSIZE 4096
  11. #if defined(TORQUE_BIG_ENDIAN)
  12. #define ENDIAN 1
  13. #else
  14. #define ENDIAN 0
  15. #endif
  16. static size_t _ov_read_func( void *ptr, size_t size, size_t nmemb, void *datasource )
  17. {
  18. Stream *stream = reinterpret_cast<Stream*>( datasource );
  19. // Stream::read() returns true if any data was
  20. // read, so we must track the read bytes ourselves.
  21. U32 startByte = stream->getPosition();
  22. stream->read( size * nmemb, ptr );
  23. U32 endByte = stream->getPosition();
  24. // How many did we actually read?
  25. U32 readBytes = ( endByte - startByte );
  26. U32 readItems = readBytes / size;
  27. return readItems;
  28. }
  29. static int _ov_seek_func( void *datasource, ogg_int64_t offset, int whence )
  30. {
  31. Stream *stream = reinterpret_cast<Stream*>( datasource );
  32. U32 newPos = 0;
  33. if ( whence == SEEK_CUR )
  34. newPos = stream->getPosition() + (U32)offset;
  35. else if ( whence == SEEK_END )
  36. newPos = stream->getStreamSize() - (U32)offset;
  37. else
  38. newPos = (U32)offset;
  39. return stream->setPosition( newPos ) ? 0 : -1;
  40. }
  41. static long _ov_tell_func( void *datasource )
  42. {
  43. Stream *stream = reinterpret_cast<Stream*>( datasource );
  44. return stream->getPosition();
  45. }
  46. VorbisStreamSource::VorbisStreamSource(const char *filename)
  47. {
  48. stream = NULL;
  49. bIsValid = false;
  50. bBuffersAllocated = false;
  51. bVorbisFileInitialized = false;
  52. mBufferList[0] = 0;
  53. clear();
  54. mFilename = filename;
  55. mPosition = Point3F(0.f,0.f,0.f);
  56. }
  57. VorbisStreamSource::~VorbisStreamSource()
  58. {
  59. if(bReady && bIsValid)
  60. freeStream();
  61. }
  62. void VorbisStreamSource::clear()
  63. {
  64. if(stream)
  65. freeStream();
  66. mHandle = NULL_AUDIOHANDLE;
  67. mSource = 0;
  68. if(mBufferList[0] != 0)
  69. alDeleteBuffers(NUMBUFFERS, mBufferList);
  70. for(int i = 0; i < NUMBUFFERS; i++)
  71. mBufferList[i] = 0;
  72. dMemset(&mDescription, 0, sizeof(Audio::Description));
  73. mEnvironment = 0;
  74. mPosition.set(0.f,0.f,0.f);
  75. mDirection.set(0.f,1.f,0.f);
  76. mPitch = 1.f;
  77. mScore = 0.f;
  78. mCullTime = 0;
  79. bReady = false;
  80. bFinishedPlaying = false;
  81. bIsValid = false;
  82. bBuffersAllocated = false;
  83. bVorbisFileInitialized = false;
  84. }
  85. bool VorbisStreamSource::initStream()
  86. {
  87. vorbis_info *vi;
  88. ALint error;
  89. bFinished = false;
  90. // CSH 11/1/15 - Page 404's, not sure what bug this was working around??
  91. // JMQ: changed buffer to static and doubled size. workaround for
  92. // https://206.163.64.242/mantis/view_bug_page.php?f_id=0000242
  93. static char data[BUFFERSIZE*2];
  94. alSourceStop(mSource);
  95. alSourcei(mSource, AL_BUFFER, 0);
  96. stream = ResourceManager->openStream(mFilename);
  97. if(stream != NULL)
  98. {
  99. const bool canSeek = stream->hasCapability( Stream::StreamPosition );
  100. ov_callbacks cb;
  101. cb.read_func = _ov_read_func;
  102. cb.seek_func = canSeek ? _ov_seek_func : NULL;
  103. cb.close_func = NULL;
  104. cb.tell_func = canSeek ? _ov_tell_func : NULL;
  105. S32 ret = ov_open_callbacks( stream, &vf, NULL, 0, cb );
  106. if( ret < 0 )
  107. {
  108. const char* detail = "";
  109. if( ret == OV_ENOTVORBIS )
  110. detail = "; not a Vorbis file";
  111. else if( ret == OV_EVERSION )
  112. detail = "; bad version";
  113. else if( ret == OV_EBADHEADER )
  114. detail = "; bad header";
  115. Con::errorf( "Could not open '%s' for streaming%s", mFilename, detail );
  116. return false;
  117. }
  118. bVorbisFileInitialized = true;
  119. //Read Vorbis File Info
  120. vi = ov_info(&vf,-1);
  121. freq = vi->rate;
  122. long samples = (long)ov_pcm_total(&vf,-1);
  123. if(vi->channels == 1)
  124. {
  125. format = AL_FORMAT_MONO16;
  126. DataSize = 2 * samples;
  127. }
  128. else
  129. {
  130. format = AL_FORMAT_STEREO16;
  131. DataSize = 4 * samples;
  132. }
  133. DataLeft = DataSize;
  134. // Clear Error Code
  135. alGetError();
  136. alGenBuffers(NUMBUFFERS, mBufferList);
  137. if ((error = alGetError()) != AL_NO_ERROR)
  138. return false;
  139. bBuffersAllocated = true;
  140. int numBuffers = 0;
  141. for(int loop = 0; loop < NUMBUFFERS; loop++)
  142. {
  143. ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
  144. if (DataToRead == DataLeft)
  145. bFinished = AL_TRUE;
  146. long ret = oggRead(data, BUFFERSIZE, ENDIAN, &current_section);
  147. if(ret <= 0)
  148. {
  149. bFinished = AL_TRUE;
  150. break;
  151. }
  152. DataLeft -= ret;
  153. alBufferData(mBufferList[loop], format, data, ret, freq);
  154. ++numBuffers;
  155. if ((error = alGetError()) != AL_NO_ERROR)
  156. return false;
  157. if(bFinished)
  158. break;
  159. }
  160. // Queue the buffers on the source
  161. alSourceQueueBuffers(mSource, NUMBUFFERS, mBufferList);
  162. if ((error = alGetError()) != AL_NO_ERROR)
  163. return false;
  164. alSourcei(mSource, AL_LOOPING, AL_FALSE);
  165. bReady = true;
  166. }
  167. else
  168. {
  169. return false;
  170. }
  171. bIsValid = true;
  172. return true;
  173. }
  174. bool VorbisStreamSource::updateBuffers()
  175. {
  176. ALint processed;
  177. ALuint BufferID;
  178. ALint error;
  179. // CSH 11/1/15 - Page 404's, not sure what bug this was working around??
  180. // JMQ: changed buffer to static and doubled size. workaround for
  181. // https://206.163.64.242/mantis/view_bug_page.php?f_id=0000242
  182. static char data[BUFFERSIZE*2];
  183. // don't do anything if stream not loaded properly
  184. if(!bIsValid)
  185. return false;
  186. if(bFinished && mDescription.mIsLooping)
  187. resetStream();
  188. // reset AL error code
  189. alGetError();
  190. #if 1 //def TORQUE_OS_LINUX
  191. // JMQ: this doesn't really help on linux. it may make things worse.
  192. // if it doesn't help on mac/win either, could disable it.
  193. ALint state;
  194. alGetSourcei(mSource, AL_SOURCE_STATE, &state);
  195. if (state == AL_STOPPED)
  196. {
  197. // um, yeah. you should be playing
  198. // restart
  199. alSourcePlay(mSource);
  200. //#ifdef TORQUE_DEBUG
  201. //Con::errorf(">><<>><< THE MUSIC STOPPED >><<>><<");
  202. //#endif
  203. return true;
  204. }
  205. #endif
  206. #ifdef TORQUE_OS_LINUX
  207. checkPosition();
  208. #endif
  209. // Get status
  210. alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
  211. // If some buffers have been played, unqueue them and load new audio into them, then add them to the queue
  212. if (processed > 0)
  213. {
  214. while (processed)
  215. {
  216. alSourceUnqueueBuffers(mSource, 1, &BufferID);
  217. if ((error = alGetError()) != AL_NO_ERROR)
  218. return false;
  219. if (!bFinished)
  220. {
  221. ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
  222. if (DataToRead == DataLeft)
  223. bFinished = AL_TRUE;
  224. long ret = oggRead(data, BUFFERSIZE, ENDIAN, &current_section);
  225. if(ret > 0)
  226. {
  227. DataLeft -= ret;
  228. alBufferData(BufferID, format, data, ret, freq);
  229. if ((error = alGetError()) != AL_NO_ERROR)
  230. return false;
  231. // Queue buffer
  232. alSourceQueueBuffers(mSource, 1, &BufferID);
  233. if ((error = alGetError()) != AL_NO_ERROR)
  234. return false;
  235. }
  236. processed--;
  237. if(bFinished && mDescription.mIsLooping)
  238. {
  239. resetStream();
  240. }
  241. }
  242. else
  243. {
  244. buffersinqueue--;
  245. processed--;
  246. if (buffersinqueue == 0)
  247. {
  248. bFinishedPlaying = AL_TRUE;
  249. return AL_FALSE;
  250. }
  251. }
  252. }
  253. }
  254. return true;
  255. }
  256. void VorbisStreamSource::freeStream()
  257. {
  258. bReady = false;
  259. if(stream != NULL)
  260. ResourceManager->closeStream(stream);
  261. stream = NULL;
  262. if(bBuffersAllocated)
  263. {
  264. if(mBufferList[0] != 0)
  265. alDeleteBuffers(NUMBUFFERS, mBufferList);
  266. for(int i = 0; i < NUMBUFFERS; i++)
  267. mBufferList[i] = 0;
  268. bBuffersAllocated = false;
  269. }
  270. if(bVorbisFileInitialized)
  271. {
  272. ov_clear(&vf);
  273. bVorbisFileInitialized = false;
  274. }
  275. }
  276. void VorbisStreamSource::resetStream()
  277. {
  278. ov_pcm_seek(&vf,0);
  279. DataLeft = DataSize;
  280. bFinished = AL_FALSE;
  281. }
  282. void VorbisStreamSource::setNewFile(const char * file)
  283. {
  284. //---------------------
  285. // close down old file...
  286. //---------------------
  287. if(stream != NULL)
  288. {
  289. ResourceManager->closeStream(stream);
  290. stream = NULL;
  291. }
  292. if(bVorbisFileInitialized)
  293. {
  294. ov_clear(&vf);
  295. bVorbisFileInitialized = false;
  296. }
  297. //---------------------
  298. // open up new file...
  299. //---------------------
  300. mFilename = file;
  301. stream = ResourceManager->openStream(mFilename);
  302. if(stream != NULL)
  303. {
  304. const bool canSeek = stream->hasCapability( Stream::StreamPosition );
  305. ov_callbacks cb;
  306. cb.read_func = _ov_read_func;
  307. cb.seek_func = canSeek ? _ov_seek_func : NULL;
  308. cb.close_func = NULL;
  309. cb.tell_func = canSeek ? _ov_tell_func : NULL;
  310. S32 ret = ov_open_callbacks( stream, &vf, NULL, 0, cb );
  311. if( ret < 0)
  312. {
  313. bFinished = AL_TRUE;
  314. bVorbisFileInitialized = false;
  315. bIsValid = false;
  316. return;
  317. }
  318. //Read Vorbis File Info
  319. vorbis_info * vi = ov_info(&vf,-1);
  320. freq = vi->rate;
  321. long samples = (long)ov_pcm_total(&vf,-1);
  322. if(vi->channels == 1)
  323. {
  324. format = AL_FORMAT_MONO16;
  325. DataSize = 2 * samples;
  326. }
  327. else
  328. {
  329. format = AL_FORMAT_STEREO16;
  330. DataSize = 4 * samples;
  331. }
  332. DataLeft = DataSize;
  333. // Clear Error Code
  334. alGetError();
  335. bFinished = AL_FALSE;
  336. bVorbisFileInitialized = true;
  337. bIsValid = true;
  338. }
  339. }
  340. // ov_read() only returns a maximum of one page worth of data
  341. // this helper function will repeat the read until buffer is full
  342. long VorbisStreamSource::oggRead(char *buffer,int length,
  343. int bigendianp,int *bitstream)
  344. {
  345. long bytesRead = 0;
  346. long totalBytes = 0;
  347. long offset = 0;
  348. long bytesToRead = 0;
  349. while((offset) < length)
  350. {
  351. if((length - offset) < CHUNKSIZE)
  352. bytesToRead = length - offset;
  353. else
  354. bytesToRead = CHUNKSIZE;
  355. bytesRead = ov_read( &vf, (char*)buffer, bytesToRead, bigendianp, 2, 1, bitstream );
  356. //#ifdef TORQUE_OS_LINUX
  357. #if 1 // Might fix mac audio issue and possibly others...based on references, this looks like correct action
  358. // linux ver will hang on exit after a stream loop if we don't
  359. // do this
  360. if (bytesRead == OV_HOLE)
  361. // retry, see:
  362. // http://www.xiph.org/archives/vorbis-dev/200102/0163.html
  363. // http://www.mit.edu/afs/sipb/user/xiphmont/ogg-sandbox/vorbis/doc/vorbis-errors.txt
  364. continue;
  365. #endif
  366. if(bytesRead <= 0)
  367. break;
  368. offset += bytesRead;
  369. buffer += bytesRead;
  370. }
  371. return offset;
  372. }
  373. #ifdef TORQUE_OS_LINUX
  374. // JMQ: OpenAL sometimes replaces the stream source's position with its own
  375. // nifty value, causing the music to pan around the listener. how nice.
  376. // this function checks to see if the current source position in openal
  377. // is near the initial position, and slams it to the correct value if it
  378. // is wrong.
  379. // This is a bad place to put this, but I don't feel like adding a new
  380. // .cc file. And since this is an incredibly lame hack to
  381. // workaround a stupid OpenAL bug, I see no point in overengineering it.
  382. void AudioStreamSource::checkPosition()
  383. {
  384. ALfloat pos[3];
  385. alGetSourcefv(mSource, AL_POSITION, pos);
  386. // just compute the difference between the openal pos and the
  387. // correct pos. it better be pretty friggin small.
  388. Point3F openalPos(pos[0], pos[1], pos[2]);
  389. F32 slopDist = 0.0001f;
  390. F32 dist = mFabs((openalPos - mPosition).len());
  391. if (dist > slopDist)
  392. // slam!
  393. alSource3f(mSource, AL_POSITION, mPosition.x, mPosition.y, mPosition.z);
  394. }
  395. #endif
  396. F32 VorbisStreamSource::getElapsedTime()
  397. {
  398. return ov_time_tell(&vf);
  399. }
  400. F32 VorbisStreamSource::getTotalTime()
  401. {
  402. return ov_time_total(&vf,-1);
  403. }