vorbisStreamSource.cc 12 KB

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