AUD_Streamer.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*****************************************************************************
  19. ** **
  20. ** Westwood Studios Pacific. **
  21. ** **
  22. ** Confidential Information **
  23. ** Copyright (C) 2000 - All Rights Reserved **
  24. ** **
  25. ******************************************************************************
  26. ** **
  27. ** Project: Dune Emperor **
  28. ** **
  29. ** Module: <module> (<prefix>_) **
  30. ** **
  31. ** Version: $ID$ **
  32. ** **
  33. ** File name: audplay.cpp **
  34. ** **
  35. ** Created by: 04/??/00 TR **
  36. ** **
  37. ** Description: <description> **
  38. ** **
  39. *****************************************************************************/
  40. /*****************************************************************************
  41. ** Includes **
  42. *****************************************************************************/
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <wpaudio/altypes.h>
  46. #include <wpaudio/Streamer.h>
  47. #include <wpaudio/StreamBuffering.h>
  48. #include <wpaudio/source.h>
  49. #include <wsys/file.h>
  50. #include <wpaudio/device.h>
  51. #include <wpaudio/channel.h>
  52. #include <wpaudio/thread.h>
  53. // 'assignment within condition expression'.
  54. #pragma warning(disable : 4706)
  55. DBG_DECLARE_TYPE ( AudioStreamer );
  56. /*****************************************************************************
  57. ** Externals **
  58. *****************************************************************************/
  59. /*****************************************************************************
  60. ** Defines **
  61. *****************************************************************************/
  62. #define AS_PLAYING 0x00000001
  63. #define AS_PAUSED 0x00000002
  64. #define AS_FILL 0x00000004 // service thread should fill this stream
  65. #define AS_NO_FILE_CLOSE 0x00000080 // file was not opened by us
  66. #define AS_OPEN 0x00000010 // we have a file to play
  67. #define AS_LOOPING 0x00000020 // seamlessly loop stream
  68. #define MIN_FRAME_SIZE (4*1024)
  69. /*****************************************************************************
  70. ** Private Types **
  71. *****************************************************************************/
  72. typedef struct AudioStreamerTag
  73. {
  74. ListNode nd;
  75. volatile int flags;
  76. AudioDevice *device;
  77. AudioChannel *channel;
  78. TimeStamp buffering;
  79. TimeStamp end_time_stamp;
  80. TimeStamp start_time_stamp;
  81. STM_STREAM *stream;
  82. STM_ACCESS *in;
  83. STM_ACCESS *out;
  84. AudioSample sample;
  85. AudioFormat format;
  86. File *file;
  87. Lock pause;
  88. Lock lock;
  89. int pending_bytes; // number of bytes submitted to audio playback
  90. int total_bytes;
  91. int data_start;
  92. int bytes_left;
  93. int frame_size;
  94. int stream_pos;
  95. int max_volume;
  96. char stream_name[80];
  97. #ifndef IG_FINAL_RELEASE
  98. char name[200];
  99. #endif
  100. DBG_TYPE()
  101. } AudioStreamer;
  102. /*****************************************************************************
  103. ** Private Data **
  104. *****************************************************************************/
  105. static AUD_Thread *thread = NULL;
  106. static ListHead streams;
  107. static int initialized = FALSE;
  108. /*****************************************************************************
  109. ** Public Data **
  110. *****************************************************************************/
  111. /*****************************************************************************
  112. ** Private Prototypes **
  113. *****************************************************************************/
  114. static int streamNextFrame ( AudioChannel *channel );
  115. static int streamSampleDone ( AudioChannel *channel );
  116. static int streamStop ( AudioChannel *channel );
  117. static void service_stream ( AudioStreamer *as );
  118. static AUD_ThreadCB service_streams;
  119. static int recalcBuffering ( AudioStreamer *as, TimeStamp buffering, AudioFormat *format );
  120. /*****************************************************************************
  121. ** Private Functions **
  122. *****************************************************************************/
  123. /******************************************************************/
  124. /* */
  125. /* */
  126. /******************************************************************/
  127. static int streamNextFrame ( AudioChannel *channel )
  128. {
  129. AudioStreamer *as = (AudioStreamer*) channel->Data;
  130. DBG_ASSERT_TYPE ( as, AudioStreamer );
  131. STM_AccessAdvance ( as->out, as->pending_bytes ); // mark these bytes as having been used
  132. as->stream_pos += as->pending_bytes;
  133. if ( as->stream_pos > as->total_bytes )
  134. {
  135. as->stream_pos %= as->total_bytes;
  136. }
  137. STM_AccessGetBlock ( as->out );
  138. if ( as->frame_size > as->out->Block.Bytes )
  139. {
  140. as->pending_bytes = as->out->Block.Bytes;
  141. }
  142. else
  143. {
  144. as->pending_bytes = as->frame_size;
  145. }
  146. channel->bytesInFrame = as->pending_bytes;
  147. channel->bytesRemaining = channel->bytesInFrame;
  148. channel->frameData = (char *) as->out->Block.Data;
  149. return vNO_ERROR;
  150. }
  151. /******************************************************************/
  152. /* */
  153. /* */
  154. /******************************************************************/
  155. static int streamSampleDone ( AudioChannel *channel )
  156. {
  157. return streamStop ( channel );
  158. }
  159. /******************************************************************/
  160. /* */
  161. /* */
  162. /******************************************************************/
  163. static int streamStop ( AudioChannel *channel )
  164. {
  165. AudioStreamer *as = (AudioStreamer*) channel->Data;
  166. DBG_ASSERT_TYPE ( as, AudioStreamer );
  167. if ( as->flags & (AS_PLAYING|AS_PAUSED))
  168. {
  169. as->end_time_stamp = AudioGetTime();
  170. }
  171. FLAGS_CLEAR ( as->flags, AS_PLAYING | AS_PAUSED | AS_FILL );
  172. LockInit ( &as->pause );
  173. return vNO_ERROR;
  174. }
  175. /******************************************************************/
  176. /* */
  177. /* */
  178. /******************************************************************/
  179. static int streamFill ( AudioStreamer *as, TimeStamp amount )
  180. {
  181. int bytes_to_fill;
  182. int transfered = 0; // initialize to prevent compiler warning
  183. int bytes;
  184. int result;
  185. int looping;
  186. DBG_ASSERT_TYPE ( as, AudioStreamer );
  187. AUD_ThreadBeginCriticalSection ( thread );
  188. looping = ( as->flags & AS_LOOPING ) ;
  189. if ( amount )
  190. {
  191. bytes_to_fill = AudioFormatBytes ( &as->format, amount );
  192. }
  193. else
  194. {
  195. bytes_to_fill = (int) STM_AccessTotalBytes ( as->in );
  196. }
  197. while ( bytes_to_fill )
  198. {
  199. if ( (bytes = bytes_to_fill) > as->bytes_left )
  200. {
  201. bytes = as->bytes_left;
  202. }
  203. result = STM_AccessFileTransfer ( as->in, as->file, bytes, &transfered );
  204. as->bytes_left -= transfered;
  205. bytes_to_fill -= transfered;
  206. if ( as->bytes_left <= 0 || result == STM_EOF || result == STM_FAIL )
  207. {
  208. if ( looping )
  209. {
  210. // seek to start of stream and continue filling
  211. as->file->seek ( as->data_start, File::START );
  212. as->bytes_left = as->total_bytes;
  213. }
  214. else
  215. {
  216. FLAGS_CLEAR ( as->flags, AS_FILL );
  217. as->bytes_left = 0;
  218. bytes_to_fill = 0;
  219. }
  220. }
  221. }
  222. AUD_ThreadEndCriticalSection ( thread );
  223. return transfered;
  224. }
  225. /******************************************************************/
  226. /* */
  227. /* */
  228. /******************************************************************/
  229. static void service_stream ( AudioStreamer *as )
  230. {
  231. DBG_ASSERT_TYPE ( as, AudioStreamer );
  232. if ( ! (as->flags & AS_FILL ) )
  233. {
  234. return;
  235. }
  236. streamFill ( as, 0 );
  237. }
  238. /******************************************************************/
  239. /* */
  240. /* */
  241. /******************************************************************/
  242. static int service_streams ( AUD_Thread *thread, void *data )
  243. {
  244. AudioStreamer *as;
  245. ListHead *list = (ListHead *) data;
  246. if ( list )
  247. {
  248. as = (AudioStreamer*) ListFirstItem ( list );
  249. while ( as )
  250. {
  251. service_stream ( as );
  252. as = (AudioStreamer*) ListNextItem ( &as->nd );
  253. }
  254. }
  255. return TRUE;
  256. }
  257. /******************************************************************/
  258. /* */
  259. /* */
  260. /******************************************************************/
  261. static int recalcBuffering ( AudioStreamer *as, TimeStamp buffering, AudioFormat *format )
  262. {
  263. uint size;
  264. STM_STREAM *stm;
  265. DBG_ASSERT_TYPE ( as, AudioStreamer );
  266. stm = as->stream;
  267. DBG_ASSERT ( stm );
  268. DBG_ASSERT ( format );
  269. size = (uint) AudioFormatBytes ( format, buffering );
  270. as->frame_size = AudioFormatBytes ( format, AudioChannelFrameTime ( as->channel )*2 );
  271. if ( as->frame_size < MIN_FRAME_SIZE )
  272. {
  273. as->frame_size = MIN_FRAME_SIZE;
  274. }
  275. if ( STM_StreamTotalBytes ( stm ) != size )
  276. {
  277. STM_SBUFFER *buffer;
  278. STM_StreamDestroyBuffers ( stm );
  279. buffer = STM_SBufferCreate ( size, 0 );
  280. if ( buffer )
  281. {
  282. STM_StreamAddSBuffer ( stm, buffer );
  283. }
  284. }
  285. return STM_StreamTotalBytes ( stm ) == size;
  286. }
  287. /*****************************************************************************
  288. ** Public Functions **
  289. *****************************************************************************/
  290. /******************************************************************/
  291. /* */
  292. /* */
  293. /******************************************************************/
  294. int AudioStreamerInit ( void )
  295. {
  296. ListInit ( &streams );
  297. thread = AUD_ThreadCreate ( "Streamer Thread", AUD_THREAD_PRI_HIGH, service_streams );
  298. if ( thread )
  299. {
  300. AUD_ThreadSetInterval ( thread, SECONDS(1) );
  301. AUD_ThreadSetData ( thread, &streams );
  302. }
  303. initialized = TRUE;
  304. return TRUE;
  305. }
  306. /******************************************************************/
  307. /* */
  308. /* */
  309. /******************************************************************/
  310. void AudioStreamerDeinit ( void )
  311. {
  312. AudioStreamer *as;
  313. if ( !initialized )
  314. {
  315. return ;
  316. }
  317. msg_assert ( ListIsEmpty ( &streams), ("Not all streams were destroyed"));
  318. while ( as = (AudioStreamer*) ListFirstItem ( &streams ))
  319. {
  320. AudioStreamerStop ( as );
  321. AudioStreamerDestroy ( as );
  322. }
  323. if ( thread )
  324. {
  325. AUD_ThreadDestroy ( thread );
  326. thread = NULL;
  327. }
  328. initialized = FALSE;
  329. }
  330. /******************************************************************/
  331. /* */
  332. /* */
  333. /******************************************************************/
  334. AudioStreamer* AudioStreamerCreate ( AudioDevice *dev, TimeStamp buffering )
  335. {
  336. AudioStreamer *as;
  337. if ( !dev || !initialized )
  338. {
  339. return NULL;
  340. }
  341. if ( buffering <=0 || buffering < SECONDS(7))
  342. {
  343. buffering = SECONDS(7);
  344. }
  345. ALLOC_STRUCT ( as, AudioStreamer );
  346. DBG_SET_TYPE ( as, AudioStreamer );
  347. ListNodeInit ( &as->nd );
  348. as->device = dev;
  349. as->channel = AudioDeviceReserveChannel ( dev, AUDIO_CHANNEL_TYPE_USER );
  350. as->buffering = buffering;
  351. AudioSampleInit ( &as->sample );
  352. AudioFormatInit ( &as->format );
  353. LockInit ( &as->pause );
  354. LockInit ( &as->lock );
  355. strcpy ( as->stream_name, "Audio Stream" );
  356. if ( !as->channel )
  357. {
  358. msg_assert ( FALSE, ("Unable to reserve channel for streamer"));
  359. goto error;
  360. }
  361. as->max_volume = AUDIO_VOLUME_MAX;
  362. as->channel->GroupAttribs = NULL;
  363. as->channel->SfxAttribs = NULL;
  364. as->channel->CompAttribs = NULL;
  365. as->channel->FadeAttribs = NULL;
  366. as->channel->Data = (void *) as;
  367. as->channel->CB_NextFrame = streamNextFrame;
  368. as->channel->CB_SampleDone = streamSampleDone;
  369. as->channel->CB_Stop = streamStop;
  370. as->stream = STM_StreamCreate ( );
  371. if ( !as->stream )
  372. {
  373. goto error;
  374. }
  375. AUD_ThreadBeginCriticalSection ( thread );
  376. ListNodeAppend ( &streams, &as->nd );
  377. AUD_ThreadEndCriticalSection ( thread );
  378. return as;
  379. error:
  380. AudioStreamerDestroy ( as );
  381. return NULL;
  382. }
  383. /******************************************************************/
  384. /* */
  385. /* */
  386. /******************************************************************/
  387. void AudioStreamerDestroy ( AudioStreamer *as )
  388. {
  389. DBG_ASSERT_TYPE ( as, AudioStreamer );
  390. msg_assert ( !(as->flags & AS_PLAYING), ("Trying to destroy as stream while is is still playing"));
  391. if ( ListNodeInList ( &as->nd ))
  392. {
  393. AUD_ThreadBeginCriticalSection ( thread );
  394. ListNodeRemove ( &as->nd );
  395. AUD_ThreadEndCriticalSection ( thread );
  396. }
  397. AudioStreamerClose ( as );
  398. if ( as->in )
  399. {
  400. STM_AccessRelease ( as->in );
  401. as->in = NULL;
  402. }
  403. if ( as->out )
  404. {
  405. STM_AccessRelease ( as->out );
  406. as->out = NULL;
  407. }
  408. if ( as->stream )
  409. {
  410. STM_StreamDestroy ( as->stream );
  411. }
  412. if ( as->channel )
  413. {
  414. AudioChannelRelease ( as->channel );
  415. }
  416. if ( as->file )
  417. {
  418. if ( ! (as->flags & AS_NO_FILE_CLOSE ))
  419. {
  420. as->file->close() ;
  421. }
  422. as->file = NULL;
  423. }
  424. DBG_INVALIDATE_TYPE ( as );
  425. MEM_Free ( as );
  426. }
  427. /******************************************************************/
  428. /* */
  429. /* */
  430. /******************************************************************/
  431. void AudioStreamerSetAttribs ( AudioStreamer *as, AudioAttribs *attribs )
  432. {
  433. DBG_ASSERT_TYPE ( as, AudioStreamer );
  434. as->channel->GroupAttribs = attribs;
  435. }
  436. /******************************************************************/
  437. /* */
  438. /* */
  439. /******************************************************************/
  440. void AudioStreamerSetFadeAttribs ( AudioStreamer *as, AudioAttribs *attribs )
  441. {
  442. DBG_ASSERT_TYPE ( as, AudioStreamer );
  443. as->channel->FadeAttribs = attribs;
  444. }
  445. /******************************************************************/
  446. /* */
  447. /* */
  448. /******************************************************************/
  449. int AudioStreamerOpen ( AudioStreamer *as, File *file)
  450. {
  451. DBG_ASSERT_TYPE ( as, AudioStreamer );
  452. if ( Locked ( &as->lock ) || !file )
  453. {
  454. return FALSE;
  455. }
  456. AUD_ThreadBeginCriticalSection ( thread );
  457. AudioStreamerClose ( as );
  458. FLAGS_SET ( as->flags, AS_NO_FILE_CLOSE ); // we did not open this file so do not close it
  459. as->file = file;
  460. if ( !AudioFormatReadWaveFile ( as->file, &as->format, &as->total_bytes ))
  461. {
  462. goto error;
  463. }
  464. strncpy ( as->name, file->getName(), ArrayLen ( as->name ) );
  465. ArrayEnd ( as->name );
  466. AudioSampleSetName ( &as->sample, as->name );
  467. as->data_start = as->file->position();
  468. as->stream_pos = 0;
  469. FLAGS_SET ( as->flags, AS_OPEN );
  470. AUD_ThreadEndCriticalSection ( thread );
  471. return TRUE;
  472. error:
  473. if ( as->file )
  474. {
  475. as->file = NULL;
  476. }
  477. FLAGS_CLEAR ( as->flags, AS_OPEN );
  478. AUD_ThreadEndCriticalSection ( thread );
  479. return FALSE;
  480. }
  481. /******************************************************************/
  482. /* */
  483. /* */
  484. /******************************************************************/
  485. int AudioStreamerOpen ( AudioStreamer *as, const char *filename )
  486. {
  487. File *file;
  488. int opened;
  489. file = TheFileSystem->open ( (char *)filename, File::READ|File::BINARY );
  490. if ( !file )
  491. {
  492. return FALSE;
  493. }
  494. opened = AudioStreamerOpen ( as, file );
  495. if ( !opened )
  496. {
  497. file->close();
  498. return FALSE;
  499. }
  500. // we did open this file so automatically close when stream is closed
  501. FLAGS_CLEAR ( as->flags, AS_NO_FILE_CLOSE );
  502. return TRUE;
  503. }
  504. /******************************************************************/
  505. /* */
  506. /* */
  507. /******************************************************************/
  508. int AudioStreamerStart ( AudioStreamer *as )
  509. {
  510. TimeStamp time;
  511. DBG_ASSERT_TYPE ( as, AudioStreamer );
  512. if ( Locked ( &as->lock ) || !(as->flags & AS_OPEN ))
  513. {
  514. return FALSE;
  515. }
  516. AUD_ThreadBeginCriticalSection ( thread );
  517. as->stream_pos = AudioFormatSeekToPos ( as->file, &as->format, as->stream_pos, as->data_start );
  518. as->bytes_left = as->total_bytes - as->stream_pos;
  519. if ( as->in )
  520. {
  521. STM_AccessRelease ( as->in );
  522. as->in = NULL;
  523. }
  524. if ( as->out )
  525. {
  526. STM_AccessRelease ( as->out );
  527. as->out = NULL;
  528. }
  529. if ( !recalcBuffering ( as, as->buffering, &as->format ) )
  530. {
  531. goto error;
  532. }
  533. STM_StreamReset ( as->stream);
  534. as->in = STM_StreamAcquireAccess ( as->stream, vSTM_ACCESS_ID_IN );
  535. as->out = STM_StreamAcquireAccess ( as->stream, vSTM_ACCESS_ID_OUT );
  536. if ( !as->in || !as->out )
  537. {
  538. goto error;
  539. }
  540. time = max ( AudioChannelBufferTime ( as->channel )*2, AUD_ThreadGetInterval(thread)*4);
  541. time = max ( time, (TimeStamp)SECONDS(4));
  542. if ( !streamFill ( as, time ))
  543. {
  544. goto error;
  545. }
  546. STM_AccessGetBlock ( as->out );
  547. as->sample.Data = (char *) as->out->Block.Data;
  548. as->sample.Bytes = AudioFormatBytes ( &as->format, AudioChannelFrameTime ( as->channel ));
  549. if ( as->sample.Bytes > as->out->Block.Bytes )
  550. {
  551. as->sample.Bytes = as->out->Block.Bytes ;
  552. }
  553. as->sample.Format = &as->format;
  554. as->pending_bytes = as->sample.Bytes;
  555. //AudioAttribsSetVolume ( &as->channel->ChannelAttribs, AUDIO_VOLUME_MAX );
  556. AudioChannelSetSample ( as->channel, &as->sample );
  557. FLAGS_SET ( as->flags, AS_PLAYING );
  558. if ( AudioChannelStart ( as->channel ) != vNO_ERROR )
  559. {
  560. FLAGS_CLEAR ( as->flags, AS_PLAYING );
  561. STM_AccessRelease ( as->in );
  562. as->in = NULL;
  563. STM_AccessRelease ( as->out );
  564. as->out = NULL;
  565. goto error;
  566. }
  567. as->start_time_stamp = AudioGetTime();
  568. as->end_time_stamp = as->start_time_stamp;
  569. FLAGS_SET ( as->flags, AS_FILL );
  570. AUD_ThreadEndCriticalSection ( thread );
  571. return TRUE;
  572. error:
  573. AUD_ThreadEndCriticalSection ( thread );
  574. return FALSE;
  575. }
  576. /******************************************************************/
  577. /* */
  578. /* */
  579. /******************************************************************/
  580. void AudioStreamerStop ( AudioStreamer *as )
  581. {
  582. DBG_ASSERT_TYPE ( as, AudioStreamer );
  583. if ( NotLocked ( &as->lock ) )
  584. {
  585. if ( as->channel )
  586. {
  587. AUD_ThreadBeginCriticalSection ( thread );
  588. AudioChannelStop ( as->channel );
  589. AUD_ThreadEndCriticalSection ( thread );
  590. }
  591. }
  592. }
  593. /******************************************************************/
  594. /* */
  595. /* */
  596. /******************************************************************/
  597. void AudioStreamerClose ( AudioStreamer *as )
  598. {
  599. DBG_ASSERT_TYPE ( as, AudioStreamer );
  600. if ( NotLocked ( &as->lock ) )
  601. {
  602. AUD_ThreadBeginCriticalSection ( thread );
  603. AudioStreamerStop ( as );
  604. if ( as->file )
  605. {
  606. if ( ! (as->flags & AS_NO_FILE_CLOSE ))
  607. {
  608. as->file->close();
  609. }
  610. as->file = NULL;
  611. }
  612. FLAGS_CLEAR ( as->flags, AS_OPEN | AS_NO_FILE_CLOSE | AS_LOOPING ) ;
  613. AUD_ThreadEndCriticalSection ( thread );
  614. }
  615. }
  616. /******************************************************************/
  617. /* */
  618. /* */
  619. /******************************************************************/
  620. void AudioStreamerLock ( AudioStreamer *as )
  621. {
  622. DBG_ASSERT_TYPE ( as, AudioStreamer );
  623. LockAcquire ( &as->lock );
  624. }
  625. /******************************************************************/
  626. /* */
  627. /* */
  628. /******************************************************************/
  629. void AudioStreamerUnlock ( AudioStreamer *as )
  630. {
  631. DBG_ASSERT_TYPE ( as, AudioStreamer );
  632. LockRelease ( &as->lock );
  633. }
  634. /******************************************************************/
  635. /* */
  636. /* */
  637. /******************************************************************/
  638. void AudioStreamerPause ( AudioStreamer *as )
  639. {
  640. DBG_ASSERT_TYPE ( as, AudioStreamer );
  641. if ( NotLocked ( &as->pause ))
  642. {
  643. if ( as->channel )
  644. {
  645. AUD_ThreadBeginCriticalSection ( thread );
  646. AudioChannelPause ( as->channel );
  647. if ( as->flags & AS_PLAYING )
  648. {
  649. FLAGS_SET ( as->flags, AS_PAUSED );
  650. FLAGS_CLEAR ( as->flags, AS_PLAYING );
  651. }
  652. AUD_ThreadEndCriticalSection ( thread );
  653. }
  654. }
  655. LockAcquire ( &as->pause );
  656. }
  657. /******************************************************************/
  658. /* */
  659. /* */
  660. /******************************************************************/
  661. void AudioStreamerResume ( AudioStreamer *as )
  662. {
  663. DBG_ASSERT_TYPE ( as, AudioStreamer );
  664. if ( Locked ( &as->pause ) )
  665. {
  666. LockRelease ( &as->pause );
  667. if ( NotLocked ( &as->pause ))
  668. {
  669. if ( as->channel )
  670. {
  671. AUD_ThreadBeginCriticalSection ( thread );
  672. if ( as->flags & AS_PAUSED )
  673. {
  674. FLAGS_CLEAR ( as->flags, AS_PAUSED );
  675. FLAGS_SET ( as->flags, AS_PLAYING );
  676. }
  677. AudioChannelResume ( as->channel );
  678. AUD_ThreadEndCriticalSection ( thread );
  679. }
  680. }
  681. }
  682. }
  683. /******************************************************************/
  684. /* */
  685. /* */
  686. /******************************************************************/
  687. int AudioStreamerIsPlaying ( AudioStreamer *as )
  688. {
  689. DBG_ASSERT_TYPE ( as , AudioStreamer );
  690. return as->flags & AS_PLAYING ;
  691. }
  692. /******************************************************************/
  693. /* */
  694. /* */
  695. /******************************************************************/
  696. int AudioStreamerActive ( AudioStreamer *as )
  697. {
  698. DBG_ASSERT_TYPE ( as , AudioStreamer );
  699. return as->flags & (AS_PLAYING|AS_PAUSED) ;
  700. }
  701. /******************************************************************/
  702. /* */
  703. /* */
  704. /******************************************************************/
  705. void AudioStreamerSetName ( AudioStreamer *as, const char *name )
  706. {
  707. DBG_ASSERT_TYPE ( as , AudioStreamer );
  708. strncpy ( as->stream_name, name, sizeof(as->stream_name));
  709. as->stream_name[ sizeof(as->stream_name) -1 ] = 0;
  710. }
  711. /******************************************************************/
  712. /* */
  713. /* */
  714. /******************************************************************/
  715. const char *AudioStreamerName ( AudioStreamer *as )
  716. {
  717. DBG_ASSERT_TYPE ( as , AudioStreamer );
  718. return as->stream_name;
  719. }
  720. /******************************************************************/
  721. /* */
  722. /* */
  723. /******************************************************************/
  724. void AudioStreamerFadeIn ( AudioStreamer *as )
  725. {
  726. DBG_ASSERT_TYPE ( as, AudioStreamer );
  727. AudioAttribsAdjustVolume ( &as->channel->ChannelAttribs, as->max_volume );
  728. }
  729. /******************************************************************/
  730. /* */
  731. /* */
  732. /******************************************************************/
  733. void AudioStreamerFadeOut ( AudioStreamer *as )
  734. {
  735. DBG_ASSERT_TYPE ( as, AudioStreamer );
  736. AudioAttribsAdjustVolume ( &as->channel->ChannelAttribs, AUDIO_VOLUME_MIN );
  737. }
  738. /******************************************************************/
  739. /* */
  740. /* */
  741. /******************************************************************/
  742. int AudioStreamerIsFading ( AudioStreamer *as )
  743. {
  744. DBG_ASSERT_TYPE ( as, AudioStreamer );
  745. return AudioStreamerIsPlaying ( as ) && !AudioAttribsVolumeAdjusted ( &as->channel->ChannelAttribs );
  746. }
  747. /******************************************************************/
  748. /* */
  749. /* */
  750. /******************************************************************/
  751. void AudioStreamerWaitForFade ( AudioStreamer *as )
  752. {
  753. DBG_ASSERT_TYPE ( as, AudioStreamer );
  754. TimeStamp time_out = AudioGetTime() + as->channel->ChannelAttribs.VolumeLevel.duration;
  755. while ( AudioStreamerIsFading ( as ) && (AudioGetTime() < time_out) )
  756. {
  757. //ServiceAllAudio (); TODO: trolfs
  758. break;
  759. }
  760. }
  761. /******************************************************************/
  762. /* */
  763. /* */
  764. /******************************************************************/
  765. TimeStamp AudioStreamerEndTimeStamp ( AudioStreamer *as )
  766. {
  767. DBG_ASSERT_TYPE ( as, AudioStreamer );
  768. return as->end_time_stamp;
  769. }
  770. /******************************************************************/
  771. /* */
  772. /* */
  773. /******************************************************************/
  774. void AudioStreamerStarve ( void )
  775. {
  776. AudioStreamer *as;
  777. if ( !initialized )
  778. {
  779. return;
  780. }
  781. as = (AudioStreamer*) ListFirstItem ( &streams );
  782. AUD_ThreadBeginCriticalSection ( thread );
  783. while ( as )
  784. {
  785. FLAGS_CLEAR ( as->flags, AS_FILL );
  786. as = (AudioStreamer*) ListNextItem ( &as->nd );
  787. }
  788. AUD_ThreadEndCriticalSection ( thread );
  789. }
  790. /******************************************************************/
  791. /* */
  792. /* */
  793. /******************************************************************/
  794. void AudioStreamerStopAllStreams ( void )
  795. {
  796. AudioStreamer *as;
  797. if ( !initialized )
  798. {
  799. return;
  800. }
  801. AUD_ThreadBeginCriticalSection ( thread );
  802. as = (AudioStreamer*) ListFirstItem ( &streams );
  803. while ( as )
  804. {
  805. AudioStreamerStop ( as );
  806. as = (AudioStreamer*) ListNextItem ( &as->nd );
  807. }
  808. AUD_ThreadEndCriticalSection ( thread );
  809. }
  810. /******************************************************************/
  811. /* */
  812. /* */
  813. /******************************************************************/
  814. void AudioStreamerCloseAllStreams ( void )
  815. {
  816. AudioStreamer *as;
  817. if ( !initialized )
  818. {
  819. return;
  820. }
  821. as = (AudioStreamer*) ListFirstItem ( &streams );
  822. while ( as )
  823. {
  824. AudioStreamerClose ( as );
  825. as = (AudioStreamer*) ListNextItem ( &as->nd );
  826. }
  827. }
  828. /******************************************************************/
  829. /* */
  830. /* */
  831. /******************************************************************/
  832. void AudioStreamerCloseAllStreamsUsingFile ( File *file )
  833. {
  834. AudioStreamer *as;
  835. if ( !initialized )
  836. {
  837. return;
  838. }
  839. as = (AudioStreamer*) ListFirstItem ( &streams );
  840. while ( as )
  841. {
  842. if ( as->file == file )
  843. {
  844. AudioStreamerClose ( as );
  845. }
  846. as = (AudioStreamer*) ListNextItem ( &as->nd );
  847. }
  848. }
  849. /******************************************************************/
  850. /* */
  851. /* */
  852. /******************************************************************/
  853. void AudioStreamerLockAllStreams ( void )
  854. {
  855. AudioStreamer *as;
  856. if ( !initialized )
  857. {
  858. return;
  859. }
  860. as = (AudioStreamer*) ListFirstItem ( &streams );
  861. while ( as )
  862. {
  863. AudioStreamerLock ( as );
  864. as = (AudioStreamer*) ListNextItem ( &as->nd );
  865. }
  866. }
  867. /******************************************************************/
  868. /* */
  869. /* */
  870. /******************************************************************/
  871. void AudioStreamerUnlockAllStreams ( void )
  872. {
  873. AudioStreamer *as;
  874. if ( !initialized )
  875. {
  876. return;
  877. }
  878. as = (AudioStreamer*) ListFirstItem ( &streams );
  879. while ( as )
  880. {
  881. AudioStreamerUnlock ( as );
  882. as = (AudioStreamer*) ListNextItem ( &as->nd );
  883. }
  884. }
  885. /******************************************************************/
  886. /* */
  887. /* */
  888. /******************************************************************/
  889. void AudioStreamerPauseAllStreams ( void )
  890. {
  891. AudioStreamer *as;
  892. if ( !initialized )
  893. {
  894. return;
  895. }
  896. as = (AudioStreamer*) ListFirstItem ( &streams );
  897. while ( as )
  898. {
  899. AudioStreamerPause ( as );
  900. as = (AudioStreamer*) ListNextItem ( &as->nd );
  901. }
  902. }
  903. /******************************************************************/
  904. /* */
  905. /* */
  906. /******************************************************************/
  907. void AudioStreamerResumeAllStreams ( void )
  908. {
  909. AudioStreamer *as;
  910. if ( !initialized )
  911. {
  912. return;
  913. }
  914. as = (AudioStreamer*) ListFirstItem ( &streams );
  915. while ( as )
  916. {
  917. AudioStreamerResume ( as );
  918. as = (AudioStreamer*) ListNextItem ( &as->nd );
  919. }
  920. }
  921. /******************************************************************/
  922. /* */
  923. /* */
  924. /******************************************************************/
  925. void AudioStreamerFadeOutAllStreams ( void )
  926. {
  927. AudioStreamer *as;
  928. if ( !initialized )
  929. {
  930. return;
  931. }
  932. as = (AudioStreamer*) ListFirstItem ( &streams );
  933. while ( as )
  934. {
  935. AudioStreamerFadeOut ( as );
  936. as = (AudioStreamer*) ListNextItem ( &as->nd );
  937. }
  938. }
  939. /******************************************************************/
  940. /* */
  941. /* */
  942. /******************************************************************/
  943. void AudioStreamerFadeInAllStreams ( void )
  944. {
  945. AudioStreamer *as;
  946. if ( !initialized )
  947. {
  948. return;
  949. }
  950. as = (AudioStreamer*) ListFirstItem ( &streams );
  951. while ( as )
  952. {
  953. AudioStreamerFadeIn ( as );
  954. as = (AudioStreamer*) ListNextItem ( &as->nd );
  955. }
  956. }
  957. /******************************************************************/
  958. /* */
  959. /* */
  960. /******************************************************************/
  961. int AudioStreamerAllFaded ( void )
  962. {
  963. AudioStreamer *as;
  964. if ( !initialized )
  965. {
  966. return true;
  967. }
  968. as = (AudioStreamer*) ListFirstItem ( &streams );
  969. while ( as )
  970. {
  971. if ( AudioStreamerIsFading ( as ) )
  972. {
  973. return FALSE;
  974. }
  975. as = (AudioStreamer*) ListNextItem ( &as->nd );
  976. }
  977. return TRUE;
  978. }
  979. /******************************************************************/
  980. /* */
  981. /* */
  982. /******************************************************************/
  983. int AudioStreamerGetPosition ( AudioStreamer *as )
  984. {
  985. DBG_ASSERT_TYPE ( as, AudioStreamer );
  986. return as->stream_pos;
  987. }
  988. /******************************************************************/
  989. /* */
  990. /* */
  991. /******************************************************************/
  992. void AudioStreamerSetPosition ( AudioStreamer *as, int pos )
  993. {
  994. DBG_ASSERT_TYPE ( as, AudioStreamer );
  995. int playing = AudioStreamerIsPlaying ( as );
  996. AudioStreamerStop ( as );
  997. as->stream_pos = pos;
  998. if ( playing )
  999. {
  1000. AudioStreamerStart ( as );
  1001. }
  1002. }
  1003. /******************************************************************/
  1004. /* */
  1005. /* */
  1006. /******************************************************************/
  1007. TimeStamp AudioStreamerGetTimePosition ( AudioStreamer *as )
  1008. {
  1009. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1010. if ( as->flags & AS_OPEN )
  1011. {
  1012. return AudioFormatTime ( &as->format, as->stream_pos );
  1013. }
  1014. return 0;
  1015. }
  1016. /******************************************************************/
  1017. /* */
  1018. /* */
  1019. /******************************************************************/
  1020. void AudioStreamerSetTimePosition ( AudioStreamer *as, TimeStamp time )
  1021. {
  1022. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1023. if ( as->flags & AS_OPEN )
  1024. {
  1025. AudioStreamerSetPosition ( as, AudioFormatBytes ( &as->format, time ));
  1026. }
  1027. else
  1028. {
  1029. AudioStreamerSetPosition ( as, 0 );
  1030. }
  1031. }
  1032. /******************************************************************/
  1033. /* */
  1034. /* */
  1035. /******************************************************************/
  1036. void AudioStreamerSetVolume ( AudioStreamer *as, int volume )
  1037. {
  1038. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1039. AudioChannelSetVolume ( as->channel, volume );
  1040. }
  1041. /******************************************************************/
  1042. /* */
  1043. /* */
  1044. /******************************************************************/
  1045. int AudioStreamerGetVolume ( AudioStreamer *as )
  1046. {
  1047. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1048. return AudioChannelGetVolume ( as->channel );
  1049. }
  1050. /******************************************************************/
  1051. /* */
  1052. /* */
  1053. /******************************************************************/
  1054. void AudioStreamerSetMaxVolume ( AudioStreamer *as, int volume )
  1055. {
  1056. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1057. if ( volume > AUDIO_VOLUME_MAX )
  1058. {
  1059. volume = AUDIO_VOLUME_MAX;
  1060. }
  1061. else if ( volume < AUDIO_VOLUME_MIN )
  1062. {
  1063. volume = AUDIO_VOLUME_MIN;
  1064. }
  1065. as->max_volume = volume;
  1066. }
  1067. /******************************************************************/
  1068. /* */
  1069. /* */
  1070. /******************************************************************/
  1071. int AudioStreamerGetMaxVolume ( AudioStreamer *as )
  1072. {
  1073. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1074. return as->max_volume;
  1075. }
  1076. /******************************************************************/
  1077. /* */
  1078. /* */
  1079. /******************************************************************/
  1080. void AudioStreamerSetLooping ( AudioStreamer *as, int loop )
  1081. {
  1082. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1083. AUD_ThreadBeginCriticalSection ( thread );
  1084. if ( loop )
  1085. {
  1086. FLAGS_SET ( as->flags, AS_LOOPING );
  1087. }
  1088. else
  1089. {
  1090. FLAGS_CLEAR ( as->flags, AS_LOOPING );
  1091. }
  1092. AUD_ThreadEndCriticalSection ( thread );
  1093. }
  1094. /******************************************************************/
  1095. /* */
  1096. /* */
  1097. /******************************************************************/
  1098. int AudioStreamerIsLooping ( AudioStreamer *as )
  1099. {
  1100. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1101. return as->flags & AS_LOOPING;
  1102. }
  1103. /******************************************************************/
  1104. /* */
  1105. /* */
  1106. /******************************************************************/
  1107. int AudioStreamerIsAudible ( AudioStreamer *as )
  1108. {
  1109. DBG_ASSERT_TYPE ( as, AudioStreamer );
  1110. return AudioChannelIsAudible ( as->channel );
  1111. }
  1112. /******************************************************************/
  1113. /* */
  1114. /* */
  1115. /******************************************************************/
  1116. void AudioStreamerSetPriority ( AudioStreamer *as, Int priority )
  1117. {
  1118. }
  1119. #define vRANGE 15
  1120. /******************************************************************/
  1121. /* */
  1122. /* */
  1123. /******************************************************************/
  1124. static void streamDump ( AudioStreamer *as, int index, void (*print) ( char *text) )
  1125. {
  1126. int range = vRANGE;
  1127. int in;
  1128. int total;
  1129. int percent;
  1130. char buffer[200];
  1131. uint out_pos;
  1132. uint in_pos;
  1133. if ( !as->stream )
  1134. {
  1135. sprintf ( buffer, "%02d: Invalid Stream\n", index);
  1136. print ( buffer );
  1137. return;
  1138. }
  1139. total = STM_StreamTotalBytes ( as->stream );
  1140. in = 0;
  1141. out_pos = 0;
  1142. in_pos = 0;
  1143. percent = 0;
  1144. if ( total )
  1145. {
  1146. in = (STM_StreamTotalBytesIn ( as->stream )*range)/total;
  1147. if ( as->out )
  1148. {
  1149. out_pos = (STM_AccessPosition ( as->out ) * range)/total;
  1150. }
  1151. if ( as->in )
  1152. {
  1153. in_pos = (STM_AccessPosition ( as->in ) * range)/total;
  1154. }
  1155. percent = (STM_StreamTotalBytesIn ( as->stream )*100)/total;
  1156. }
  1157. if ( out_pos == in_pos )
  1158. {
  1159. if ( in == 0)
  1160. {
  1161. if ( out_pos < vRANGE-1 )
  1162. {
  1163. in_pos = (out_pos + 1);
  1164. }
  1165. else
  1166. {
  1167. in_pos = 0;
  1168. }
  1169. }
  1170. else
  1171. {
  1172. if ( out_pos > 0 )
  1173. {
  1174. in_pos = (out_pos - 1);
  1175. }
  1176. else
  1177. {
  1178. in_pos = vRANGE-1 ;
  1179. }
  1180. }
  1181. }
  1182. char gauge[vRANGE+1];
  1183. uint i;
  1184. for ( i =0; i < vRANGE; i++)
  1185. {
  1186. gauge[i] = ' ';
  1187. }
  1188. gauge[vRANGE] = 0;
  1189. if ( out_pos > in_pos )
  1190. {
  1191. for ( i =out_pos+1; i < vRANGE; i++)
  1192. gauge[i] = '*';
  1193. for ( i =0; i < in_pos; i++)
  1194. gauge[i] = '*';
  1195. }
  1196. else
  1197. {
  1198. for ( i =out_pos+1; i < in_pos; i++)
  1199. gauge[i] = '*';
  1200. }
  1201. gauge[in_pos] = '>';
  1202. gauge[out_pos] = '<';
  1203. char name[sizeof(as->name)+1];
  1204. char *ptr ;
  1205. int seconds, minutes;
  1206. strcpy ( name, as->name );
  1207. ptr = strrchr ( name, '.' );
  1208. if ( ptr )
  1209. {
  1210. *ptr = 0;
  1211. }
  1212. ptr = strrchr ( name, '\\' );
  1213. if ( ptr )
  1214. {
  1215. strcpy ( name, ptr );
  1216. }
  1217. TimeStamp time = AudioFormatTime ( &as->format, as->total_bytes - as->stream_pos );
  1218. minutes = (int) IN_MINUTES(time);
  1219. time -= MINUTES(minutes);
  1220. seconds = (int) IN_SECONDS(time);
  1221. time -= SECONDS(seconds);
  1222. time = (int) IN_MSECONDS(time);
  1223. sprintf ( buffer, "%.12s %4d Kb %.31s \n", AudioStreamerName( as ), total/1024, name);
  1224. print ( buffer );
  1225. sprintf ( buffer, " Status: %s %s %s %d:%02d:%03d \n",
  1226. as->flags & AS_PLAYING ? "Play " : (as->flags & AS_PAUSED ? "Paused" : "Stop ") ,
  1227. as->flags & AS_FILL ? "Fill" : " ",
  1228. Locked( &as->lock ) ? "Locked" : " ",
  1229. minutes, seconds, time );
  1230. print ( buffer );
  1231. sprintf ( buffer, " Buffer: |%s| %3d %%\n", gauge, percent );
  1232. print ( buffer );
  1233. }
  1234. /******************************************************************/
  1235. /* */
  1236. /* */
  1237. /******************************************************************/
  1238. void AudioStreamerDump ( void (*print) ( char *text ))
  1239. {
  1240. AudioStreamer *as;
  1241. char buffer[200];
  1242. char temp[100];
  1243. int index = 0;
  1244. if ( !initialized )
  1245. {
  1246. print ("\nAudio Streamer not initialized\n" );
  1247. return ;
  1248. }
  1249. print ("\nAudio Streamer\n" );
  1250. AudioServiceInfoDump ( AUD_ThreadServiceInfo (thread), temp );
  1251. sprintf ( buffer, "service:%s\n", temp );
  1252. print (buffer );
  1253. as = (AudioStreamer*) ListFirstItem ( &streams );
  1254. if ( as )
  1255. {
  1256. while ( as )
  1257. {
  1258. streamDump ( as , index++, print);
  1259. as = (AudioStreamer*) ListNextItem ( &as->nd );
  1260. }
  1261. }
  1262. else
  1263. {
  1264. print ("No streams created\n" );
  1265. }
  1266. }