Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

959 lines
30 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: XMA Decoding
  4. //
  5. //=====================================================================================//
  6. #include "audio_pch.h"
  7. #include "tier1/mempool.h"
  8. #include "circularbuffer.h"
  9. #include "tier1/utllinkedlist.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //#define DEBUG_XMA
  13. // Failed attempt to allow mixer to request data that is immediately discarded
  14. // to support < 0 delay samples
  15. //#define ALLOW_SKIP_SAMPLES
  16. // XMA is supposed to decode at an ideal max of 512 mono samples every 4msec.
  17. // XMA can only peel a max of 1984 stereo samples per poll request (if available).
  18. // Max is not achievable and degrades based on quality settings, stereo, etc, but using these numbers for for calcs.
  19. // 1984 stereo samples should be decoded by xma in 31 msec.
  20. // 1984 stereo samples at 44.1Khz dictates a request every 45 msec.
  21. // GetOutputData() must be clocked faster than 45 msec or samples will not be available.
  22. // However, the XMA decoder must be serviced much faster. It was designed for 5 msec.
  23. // 15 msec seems to be fast enough for XMA to decode enough to keep the smaller buffer sizes satisfied, and have slop for +/- 5 msec swings.
  24. // Need at least this amount of decoded pcm samples before mixing can commence.
  25. // This needs to be able to cover the initial mix request, while a new decode cycle is in flight.
  26. #define MIN_READYTOMIX ( ( 2 * XMA_POLL_RATE ) * 0.001f )
  27. // number of samples that xma decodes
  28. // must be 128 aligned for mono (1984 is hw max for stereo)
  29. #define XMA_MONO_OUTPUT_BUFFER_SAMPLES 2048
  30. #define XMA_STEREO_OUTPUT_BUFFER_SAMPLES 1920
  31. // for decoder input
  32. // xma blocks are fetched from the datacache into one of these hw buffers for decoding
  33. // must be in quantum units of XMA_BLOCK_SIZE
  34. #define XMA_INPUT_BUFFER_SIZE ( 8 * XMA_BLOCK_SIZE )
  35. // circular staging buffer to drain xma decoder and stage until mixer requests
  36. // must be large enough to hold the slowest expected mixing frame worth of samples
  37. #define PCM_STAGING_BUFFER_TIME 200
  38. // xma physical heap, supplies xma input buffers for hw decoder
  39. // each potential channel must be able to peel 2 buffers for driving xma decoder
  40. #define XMA_PHYSICAL_HEAP_SIZE ( 2 * MAX_CHANNELS * XMA_INPUT_BUFFER_SIZE )
  41. // in millseconds
  42. #define MIX_IO_DATA_TIMEOUT 2000 // async i/o from dvd could be very late
  43. #define MIX_DECODER_TIMEOUT 3000 // decoder might be very busy
  44. #define MIX_DECODER_POLLING_LATENCY 5 // not faster than 5ms, or decoder will sputter
  45. // diagnostic errors
  46. #define ERROR_IO_DATA_TIMEOUT -1 // async i/o taking too long to deliver xma blocks
  47. #define ERROR_IO_TRUNCATED_BLOCK -2 // async i/o failed to deliver complete blocks
  48. #define ERROR_IO_NO_XMA_DATA -3 // async i/o failed to deliver any block
  49. #define ERROR_DECODER_TIMEOUT -4 // decoder taking too long to decode xma blocks
  50. #define ERROR_OUT_OF_MEMORY -5 // not enough physical memory for xma blocks
  51. #define ERROR_XMA_PARSE -6 // decoder barfed on xma blocks
  52. #define ERROR_XMA_CANTLOCK -7 // hw not acting as expected
  53. #define ERROR_XMA_CANTSUBMIT -8 // hw not acting as expected
  54. #define ERROR_XMA_CANTRESUME -9 // hw not acting as expected
  55. #define ERROR_XMA_NO_PCM_DATA -10 // no xma decoded pcm data ready
  56. #define ERROR_NULL_BUFFER -11 // logic flaw, expected buffer is null
  57. const char *g_XMAErrorStrings[] =
  58. {
  59. "Unknown Error Code",
  60. "Async I/O Data Timeout", // ERROR_IO_DATA_TIMEOUT
  61. "Async I/O Truncated Block", // ERROR_IO_TRUNCATED_BLOCK
  62. "Async I/O Data Not Ready", // ERROR_IO_NO_XMA_DATA
  63. "Decoder Timeout", // ERROR_DECODER_TIMEOUT
  64. "Out Of Memory", // ERROR_OUT_OF_MEMORY
  65. "XMA Parse", // ERROR_XMA_PARSE
  66. "XMA Cannot Lock", // ERROR_XMA_CANTLOCK
  67. "XMA Cannot Submit", // ERROR_XMA_CANTSUBMIT
  68. "XMA Cannot Resume", // ERROR_XMA_CANTRESUME
  69. "XMA No PCM Data Ready", // ERROR_XMA_NO_PCM_DATA
  70. "NULL Buffer", // ERROR_NULL_BUFFER
  71. };
  72. class CXMAAllocator
  73. {
  74. public:
  75. static void *Alloc( int bytes )
  76. {
  77. MEM_ALLOC_CREDIT();
  78. return XMemAlloc( bytes,
  79. MAKE_XALLOC_ATTRIBUTES(
  80. 0,
  81. false,
  82. TRUE,
  83. FALSE,
  84. eXALLOCAllocatorId_XAUDIO,
  85. XALLOC_PHYSICAL_ALIGNMENT_4K,
  86. XALLOC_MEMPROTECT_WRITECOMBINE_LARGE_PAGES,
  87. FALSE,
  88. XALLOC_MEMTYPE_PHYSICAL ) );
  89. }
  90. static void Free( void *p )
  91. {
  92. XMemFree( p,
  93. MAKE_XALLOC_ATTRIBUTES(
  94. 0,
  95. false,
  96. TRUE,
  97. FALSE,
  98. eXALLOCAllocatorId_XAUDIO,
  99. XALLOC_PHYSICAL_ALIGNMENT_4K,
  100. XALLOC_MEMPROTECT_WRITECOMBINE_LARGE_PAGES,
  101. FALSE,
  102. XALLOC_MEMTYPE_PHYSICAL ) );
  103. }
  104. };
  105. // for XMA decoding, fixed size allocations aligned to 4K from a single physical heap
  106. CAlignedMemPool< XMA_INPUT_BUFFER_SIZE, 4096, XMA_PHYSICAL_HEAP_SIZE, CXMAAllocator > g_XMAMemoryPool;
  107. ConVar snd_xma_spew_warnings( "snd_xma_spew_warnings", "0" );
  108. ConVar snd_xma_spew_startup( "snd_xma_spew_startup", "0" );
  109. ConVar snd_xma_spew_mixers( "snd_xma_spew_mixers", "0" );
  110. ConVar snd_xma_spew_decode( "snd_xma_spew_decode", "0" );
  111. ConVar snd_xma_spew_drain( "snd_xma_spew_drain", "0" );
  112. #ifdef DEBUG_XMA
  113. ConVar snd_xma_record( "snd_xma_record", "0" );
  114. ConVar snd_xma_spew_errors( "snd_xma_spew_errors", "0" );
  115. #endif
  116. //-----------------------------------------------------------------------------
  117. // Purpose: Mixer for ADPCM encoded audio
  118. //-----------------------------------------------------------------------------
  119. class CAudioMixerWaveXMA : public CAudioMixerWave
  120. {
  121. public:
  122. typedef CAudioMixerWave BaseClass;
  123. CAudioMixerWaveXMA( IWaveData *data, int initialStreamPosition );
  124. ~CAudioMixerWaveXMA( void );
  125. virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress );
  126. virtual int GetOutputData( void **pData, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] );
  127. virtual void SetSampleStart( int newPosition );
  128. virtual int GetPositionForSave();
  129. virtual void SetPositionFromSaved( int savedPosition );
  130. virtual int GetMixSampleSize() { return CalcSampleSize( 16, m_NumChannels ); }
  131. virtual bool IsReadyToMix();
  132. virtual bool ShouldContinueMixing();
  133. private:
  134. int GetXMABlocksAndSubmitToDecoder( bool bDecoderLocked );
  135. int UpdatePositionForLooping( int *pNumRequestedSamples );
  136. int ServiceXMADecoder( bool bForceUpdate );
  137. int GetPCMSamples( int numRequested, char *pData );
  138. XMAPLAYBACK *m_pXMAPlayback;
  139. // input buffers, encoded xma
  140. byte *m_pXMABuffers[2];
  141. int m_XMABufferIndex;
  142. // output buffer, decoded pcm samples, a staging circular buffer, waiting for mixer requests
  143. // due to staging nature, contains decoded samples from multiple input buffers
  144. CCircularBuffer *m_pPCMSamples;
  145. int m_SampleRate;
  146. int m_NumChannels;
  147. // maximum possible decoded samples
  148. int m_SampleCount;
  149. // decoded sample position
  150. int m_SamplePosition;
  151. // current data marker
  152. int m_LastDataOffset;
  153. int m_DataOffset;
  154. // total bytes of data
  155. int m_TotalBytes;
  156. #if defined( ALLOW_SKIP_SAMPLES )
  157. // number of samples to throwaway
  158. int m_SkipSamples;
  159. #endif
  160. // timers
  161. unsigned int m_StartTime;
  162. unsigned int m_LastDrainTime;
  163. unsigned int m_LastPollTime;
  164. int m_hMixerList;
  165. int m_Error;
  166. unsigned int m_bStartedMixing : 1;
  167. unsigned int m_bFinished : 1;
  168. unsigned int m_bLooped : 1;
  169. };
  170. CUtlFixedLinkedList< CAudioMixerWaveXMA * > g_XMAMixerList;
  171. CON_COMMAND( snd_xma_info, "Spew XMA Info" )
  172. {
  173. Msg( "XMA Memory:\n" );
  174. Msg( " Blocks Allocated: %d\n", g_XMAMemoryPool.NumAllocated() );
  175. Msg( " Blocks Free: %d\n", g_XMAMemoryPool.NumFree() );
  176. Msg( " Total Bytes: %d\n", g_XMAMemoryPool.BytesTotal() );
  177. Msg( "Active XMA Mixers: %d\n", g_XMAMixerList.Count() );
  178. for ( int hMixer = g_XMAMixerList.Head(); hMixer != g_XMAMixerList.InvalidIndex(); hMixer = g_XMAMixerList.Next( hMixer ) )
  179. {
  180. CAudioMixerWaveXMA *pXMAMixer = g_XMAMixerList[hMixer];
  181. Msg( " rate:%5d ch:%1d '%s'\n", pXMAMixer->GetSource()->SampleRate(), pXMAMixer->GetSource()->IsStereoWav() ? 2 : 1, pXMAMixer->GetSource()->GetFileName() );
  182. }
  183. }
  184. CAudioMixerWaveXMA::CAudioMixerWaveXMA( IWaveData *data, int initialStreamPosition ) : CAudioMixerWave( data )
  185. {
  186. Assert( dynamic_cast<CAudioSourceWave *>(&m_pData->Source()) != NULL );
  187. m_Error = 0;
  188. m_NumChannels = m_pData->Source().IsStereoWav() ? 2 : 1;
  189. m_SampleRate = m_pData->Source().SampleRate();
  190. m_bLooped = m_pData->Source().IsLooped();
  191. m_SampleCount = m_pData->Source().SampleCount();
  192. m_TotalBytes = m_pData->Source().DataSize();
  193. #if defined( ALLOW_SKIP_SAMPLES )
  194. m_SkipSamples = 0;
  195. #endif
  196. m_LastDataOffset = initialStreamPosition;
  197. m_DataOffset = initialStreamPosition;
  198. m_SamplePosition = 0;
  199. if ( initialStreamPosition )
  200. {
  201. m_SamplePosition = m_pData->Source().StreamToSamplePosition( initialStreamPosition );
  202. CAudioMixerWave::m_sample_loaded_index = m_SamplePosition;
  203. CAudioMixerWave::m_sample_max_loaded = m_SamplePosition + 1;
  204. }
  205. m_bStartedMixing = false;
  206. m_bFinished = false;
  207. m_StartTime = 0;
  208. m_LastPollTime = 0;
  209. m_LastDrainTime = 0;
  210. m_pXMAPlayback = NULL;
  211. m_pPCMSamples = NULL;
  212. m_pXMABuffers[0] = NULL;
  213. m_pXMABuffers[1] = NULL;
  214. m_XMABufferIndex = 0;
  215. m_hMixerList = g_XMAMixerList.AddToTail( this );
  216. #ifdef DEBUG_XMA
  217. if ( snd_xma_record.GetBool() )
  218. {
  219. WaveCreateTmpFile( "debug.wav", m_SampleRate, 16, m_NumChannels );
  220. }
  221. #endif
  222. if ( snd_xma_spew_mixers.GetBool() )
  223. {
  224. Msg( "XMA: 0x%8.8x (%2d), Mixer Alloc, '%s'\n", (unsigned int)this, g_XMAMixerList.Count(), m_pData->Source().GetFileName() );
  225. }
  226. }
  227. CAudioMixerWaveXMA::~CAudioMixerWaveXMA( void )
  228. {
  229. if ( m_pXMAPlayback )
  230. {
  231. XMAPlaybackDestroy( m_pXMAPlayback );
  232. g_XMAMemoryPool.Free( m_pXMABuffers[0] );
  233. if ( m_pXMABuffers[1] )
  234. {
  235. g_XMAMemoryPool.Free( m_pXMABuffers[1] );
  236. }
  237. }
  238. if ( m_pPCMSamples )
  239. {
  240. FreeCircularBuffer( m_pPCMSamples );
  241. }
  242. g_XMAMixerList.Remove( m_hMixerList );
  243. if ( snd_xma_spew_mixers.GetBool() )
  244. {
  245. Msg( "XMA: 0x%8.8x (%2d), Mixer Freed, '%s'\n", (unsigned int)this, g_XMAMixerList.Count(), m_pData->Source().GetFileName() );
  246. }
  247. }
  248. void CAudioMixerWaveXMA::Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress )
  249. {
  250. if ( m_NumChannels == 1 )
  251. {
  252. pDevice->Mix16Mono( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress );
  253. }
  254. else
  255. {
  256. pDevice->Mix16Stereo( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress );
  257. }
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Looping is achieved in two passes to provide a circular view of the linear data.
  261. // Pass1: Clamps a sample request to the end of data.
  262. // Pass2: Snaps to the loop start, and returns the number of samples to discard, could be 0,
  263. // up to the expected loop sample position.
  264. // Returns the number of samples to discard, or 0.
  265. //-----------------------------------------------------------------------------
  266. int CAudioMixerWaveXMA::UpdatePositionForLooping( int *pNumRequestedSamples )
  267. {
  268. if ( !m_bLooped )
  269. {
  270. // not looping, no fixups
  271. return 0;
  272. }
  273. int numLeadingSamples;
  274. int numTrailingSamples;
  275. CAudioSourceWave &source = reinterpret_cast<CAudioSourceWave &>(m_pData->Source());
  276. int loopSampleStart = source.GetLoopingInfo( NULL, &numLeadingSamples, &numTrailingSamples );
  277. int numRemainingSamples = ( m_SampleCount - numTrailingSamples ) - m_SamplePosition;
  278. // possibly straddling the end of data (and thus about to loop)
  279. // want to split the straddle into two regions, due to loops possibly requiring a trailer and leader of discarded samples
  280. if ( numRemainingSamples > 0 )
  281. {
  282. // first region, all the remaining samples, clamped until end of desired data
  283. *pNumRequestedSamples = min( *pNumRequestedSamples, numRemainingSamples );
  284. // nothing to discard
  285. return 0;
  286. }
  287. else if ( numRemainingSamples == 0 )
  288. {
  289. // at exact end of desired data, snap the sample position back
  290. // the position will be correct AFTER discarding decoded trailing and leading samples
  291. m_SamplePosition = loopSampleStart;
  292. // clamp the request
  293. numRemainingSamples = ( m_SampleCount - numTrailingSamples ) - m_SamplePosition;
  294. *pNumRequestedSamples = min( *pNumRequestedSamples, numRemainingSamples );
  295. // flush these samples so the sample position is the real loop sample starting position
  296. return numTrailingSamples + numLeadingSamples;
  297. }
  298. return 0;
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Get and submit XMA block(s). The decoder must stay blocks ahead of mixer
  302. // so the decoded samples are available for peeling.
  303. // An XMA file is thus treated as a series of fixed size large buffers (multiple xma blocks),
  304. // which are streamed in sequentially. The XMA buffers may be delayed from the
  305. // audio data cache due to async i/o latency.
  306. // Returns < 0 if error, 0 if no decode started, 1 if decode submitted.
  307. //-----------------------------------------------------------------------------
  308. int CAudioMixerWaveXMA::GetXMABlocksAndSubmitToDecoder( bool bDecoderIsLocked )
  309. {
  310. int status = 0;
  311. if ( m_DataOffset >= m_TotalBytes )
  312. {
  313. if ( !m_bLooped )
  314. {
  315. // end of file, no more data to decode
  316. // not an error, because decoder finishes long before samples drained
  317. return 0;
  318. }
  319. // start from beginning of loop
  320. CAudioSourceWave &source = reinterpret_cast<CAudioSourceWave &>(m_pData->Source());
  321. source.GetLoopingInfo( &m_DataOffset, NULL, NULL );
  322. m_DataOffset *= XMA_BLOCK_SIZE;
  323. }
  324. HRESULT hr;
  325. bool bLocked = false;
  326. if ( !bDecoderIsLocked )
  327. {
  328. // decoder must be locked before any access
  329. hr = XMAPlaybackRequestModifyLock( m_pXMAPlayback );
  330. if ( FAILED( hr ) )
  331. {
  332. status = ERROR_XMA_CANTLOCK;
  333. goto cleanUp;
  334. }
  335. hr = XMAPlaybackWaitUntilModifyLockObtained( m_pXMAPlayback );
  336. if ( FAILED( hr ) )
  337. {
  338. status = ERROR_XMA_CANTLOCK;
  339. goto cleanUp;
  340. }
  341. bLocked = true;
  342. }
  343. // the input buffer can never be less than a single xma block (buffer size is multiple blocks)
  344. int bufferSize = min( m_TotalBytes - m_DataOffset, XMA_INPUT_BUFFER_SIZE );
  345. if ( !bufferSize )
  346. {
  347. // EOF
  348. goto cleanUp;
  349. }
  350. Assert( !( bufferSize % XMA_BLOCK_SIZE ) );
  351. byte *pXMABuffer = m_pXMABuffers[m_XMABufferIndex & 0x01];
  352. if ( !pXMABuffer )
  353. {
  354. // shouldn't happen, buffer should have been allocated
  355. Assert( 0 );
  356. status = ERROR_NULL_BUFFER;
  357. goto cleanUp;
  358. }
  359. if ( !XMAPlaybackQueryReadyForMoreData( m_pXMAPlayback, 0 ) || XMAPlaybackQueryInputDataPending( m_pXMAPlayback, 0, pXMABuffer ) )
  360. {
  361. // decoder too saturated for more data or
  362. // decoder still decoding from input hw buffer
  363. goto cleanUp;
  364. }
  365. // get xma block(s)
  366. // pump to get all of requested data
  367. char *pData;
  368. int total = 0;
  369. while ( total < bufferSize )
  370. {
  371. int available = m_pData->ReadSourceData( (void **)&pData, m_DataOffset, bufferSize - total, NULL );
  372. if ( !available )
  373. break;
  374. // aggregate into hw buffer
  375. V_memcpy( pXMABuffer + total, pData, available );
  376. m_DataOffset += available;
  377. total += available;
  378. }
  379. if ( total != bufferSize )
  380. {
  381. if ( !total )
  382. {
  383. // failed to get any data, could be async latency or file error
  384. status = ERROR_IO_NO_XMA_DATA;
  385. }
  386. else
  387. {
  388. // failed to get complete xma block(s)
  389. status = ERROR_IO_TRUNCATED_BLOCK;
  390. }
  391. goto cleanUp;
  392. }
  393. // track the currently submitted offset
  394. // this is used as a cheap method for save/restore because an XMA seek table is not available
  395. m_LastDataOffset = m_DataOffset - total;
  396. // start decoding the block(s) in the hw buffer
  397. hr = XMAPlaybackSubmitData( m_pXMAPlayback, 0, pXMABuffer, bufferSize );
  398. if ( FAILED( hr ) )
  399. {
  400. // failed to start decoder
  401. status = ERROR_XMA_CANTSUBMIT;
  402. goto cleanUp;
  403. }
  404. // decode submitted
  405. status = 1;
  406. // advance to next buffer
  407. m_XMABufferIndex++;
  408. if ( snd_xma_spew_decode.GetBool() )
  409. {
  410. Msg( "XMA: 0x%8.8x, XMABuffer: 0x%8.8x, BufferSize: %d, NextDataOffset: %d, %s\n", (unsigned int)this, pXMABuffer, bufferSize, m_DataOffset, m_pData->Source().GetFileName() );
  411. }
  412. cleanUp:
  413. if ( bLocked )
  414. {
  415. // release the lock and let the decoder run
  416. hr = XMAPlaybackResumePlayback( m_pXMAPlayback );
  417. if ( FAILED( hr ) )
  418. {
  419. status = ERROR_XMA_CANTRESUME;
  420. }
  421. }
  422. return status;
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Drain the XMA Decoder into the staging circular buffer of PCM for mixer.
  426. // Fetch new XMA samples for the decoder.
  427. //-----------------------------------------------------------------------------
  428. int CAudioMixerWaveXMA::ServiceXMADecoder( bool bForceUpdate )
  429. {
  430. // allow decoder to work without being polled (lock causes a decoding stall)
  431. // decoder must be allowed minimum operating latency
  432. // the buffers are sized to compensate for the operating latency
  433. if ( !bForceUpdate && ( Plat_MSTime() - m_LastPollTime <= MIX_DECODER_POLLING_LATENCY ) )
  434. {
  435. return 0;
  436. }
  437. m_LastPollTime = Plat_MSTime();
  438. // lock and pause the decoder to gain access
  439. HRESULT hr = XMAPlaybackRequestModifyLock( m_pXMAPlayback );
  440. if ( FAILED( hr ) )
  441. {
  442. m_Error = ERROR_XMA_CANTLOCK;
  443. return -1;
  444. }
  445. hr = XMAPlaybackWaitUntilModifyLockObtained( m_pXMAPlayback );
  446. if ( FAILED( hr ) )
  447. {
  448. m_Error = ERROR_XMA_CANTLOCK;
  449. return -1;
  450. }
  451. DWORD dwParseError = XMAPlaybackGetParseError( m_pXMAPlayback, 0 );
  452. if ( dwParseError )
  453. {
  454. if ( snd_xma_spew_warnings.GetBool() )
  455. {
  456. Warning( "XMA: 0x%8.8x, Decoder Error, Parse: %d, '%s'\n", (unsigned int)this, dwParseError, m_pData->Source().GetFileName() );
  457. }
  458. m_Error = ERROR_XMA_PARSE;
  459. return -1;
  460. }
  461. #ifdef DEBUG_XMA
  462. if ( snd_xma_spew_errors.GetBool() )
  463. {
  464. DWORD dwError = XMAPlaybackGetErrorBits( m_pXMAPlayback, 0 );
  465. if ( dwError )
  466. {
  467. Warning( "XMA: 0x%8.8x, Playback Error: %d, '%s'\n", (unsigned int)this, dwError, m_pData->Source().GetFileName() );
  468. }
  469. }
  470. #endif
  471. int numNewSamples = XMAPlaybackQueryAvailableData( m_pXMAPlayback, 0 );
  472. int numMaxSamples = m_pPCMSamples->GetWriteAvailable()/( m_NumChannels*sizeof( short ) );
  473. int numSamples = min( numNewSamples, numMaxSamples );
  474. while ( numSamples )
  475. {
  476. char *pPCMData = NULL;
  477. int numSamplesDecoded = XMAPlaybackConsumeDecodedData( m_pXMAPlayback, 0, numSamples, (void**)&pPCMData );
  478. // put into staging buffer, ready for mixer to drain
  479. m_pPCMSamples->Write( pPCMData, numSamplesDecoded*m_NumChannels*sizeof( short ) );
  480. numSamples -= numSamplesDecoded;
  481. numNewSamples -= numSamplesDecoded;
  482. }
  483. // queue up more blocks for the decoder
  484. // the decoder will always finish ahead of the mixer, submit nothing, and the mixer will still be draining
  485. int decodeStatus = GetXMABlocksAndSubmitToDecoder( true );
  486. if ( decodeStatus < 0 )
  487. {
  488. m_Error = decodeStatus;
  489. return -1;
  490. }
  491. m_bFinished = ( numNewSamples == 0 ) && ( decodeStatus == 0 ) && XMAPlaybackIsIdle( m_pXMAPlayback, 0 );
  492. // decoder was paused for access, let the decoder run
  493. hr = XMAPlaybackResumePlayback( m_pXMAPlayback );
  494. if ( FAILED( hr ) )
  495. {
  496. m_Error = ERROR_XMA_CANTRESUME;
  497. return -1;
  498. }
  499. return 1;
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Drain the PCM staging buffer.
  503. // Copy samples (numSamplesToCopy && pData). Return actual copied.
  504. // Flush Samples (numSamplesToCopy && !pData). Return actual flushed.
  505. // Query available number of samples (!numSamplesToCopy && !pData). Returns available.
  506. //-----------------------------------------------------------------------------
  507. int CAudioMixerWaveXMA::GetPCMSamples( int numSamplesToCopy, char *pData )
  508. {
  509. int numReadySamples = m_pPCMSamples->GetReadAvailable()/( m_NumChannels*sizeof( short ) );
  510. // peel sequential samples from the stream's staging buffer
  511. int numCopiedSamples = 0;
  512. int numRequestedSamples = min( numSamplesToCopy, numReadySamples );
  513. if ( numRequestedSamples )
  514. {
  515. if ( pData )
  516. {
  517. // copy to caller
  518. m_pPCMSamples->Read( pData, numRequestedSamples*m_NumChannels*sizeof( short ) );
  519. pData += numRequestedSamples*m_NumChannels*sizeof( short );
  520. }
  521. else
  522. {
  523. // flush
  524. m_pPCMSamples->Advance( numRequestedSamples*m_NumChannels*sizeof( short ) );
  525. }
  526. numCopiedSamples += numRequestedSamples;
  527. }
  528. if ( snd_xma_spew_drain.GetBool() )
  529. {
  530. char *pOperation = ( numSamplesToCopy && !pData ) ? "Flushed" : "Copied";
  531. Msg( "XMA: 0x%8.8x, SamplePosition: %d, Ready: %d, Requested: %d, %s: %d, Elapsed: %d ms '%s'\n",
  532. (unsigned int)this, m_SamplePosition, numReadySamples, numSamplesToCopy, pOperation, numCopiedSamples, Plat_MSTime() - m_LastDrainTime, m_pData->Source().GetFileName() );
  533. }
  534. m_LastDrainTime = Plat_MSTime();
  535. if ( numSamplesToCopy )
  536. {
  537. // could be actual flushed or actual copied
  538. return numCopiedSamples;
  539. }
  540. if ( !pData )
  541. {
  542. // satify query for available
  543. return numReadySamples;
  544. }
  545. return 0;
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Stall mixing until initial buffer of decoded samples are available.
  549. //-----------------------------------------------------------------------------
  550. bool CAudioMixerWaveXMA::IsReadyToMix()
  551. {
  552. // XMA mixing cannot be driven from the main thread
  553. Assert( ThreadInMainThread() == false );
  554. if ( m_Error )
  555. {
  556. // error has been set
  557. // let mixer try to get unavailable samples, which casues the real abort
  558. return true;
  559. }
  560. if ( m_bStartedMixing )
  561. {
  562. // decoding process has started
  563. return true;
  564. }
  565. if ( !m_pXMAPlayback )
  566. {
  567. // first time, finish setup
  568. int numBuffers;
  569. if ( m_bLooped || m_TotalBytes > XMA_INPUT_BUFFER_SIZE )
  570. {
  571. // data will cascade through multiple buffers
  572. numBuffers = 2;
  573. }
  574. else
  575. {
  576. // data can fit into a single buffer
  577. numBuffers = 1;
  578. }
  579. // xma data must be decoded from a hw friendly buffer
  580. // pool should have buffers available
  581. if ( g_XMAMemoryPool.BytesAllocated() != numBuffers * g_XMAMemoryPool.ChunkSize() )
  582. {
  583. for ( int i = 0; i < numBuffers; i++ )
  584. {
  585. m_pXMABuffers[i] = (byte*)g_XMAMemoryPool.Alloc();
  586. }
  587. XMA_PLAYBACK_INIT xmaPlaybackInit = { 0 };
  588. xmaPlaybackInit.sampleRate = m_SampleRate;
  589. xmaPlaybackInit.channelCount = m_NumChannels;
  590. xmaPlaybackInit.subframesToDecode = 4;
  591. xmaPlaybackInit.outputBufferSizeInSamples = ( m_NumChannels == 2 ) ? XMA_STEREO_OUTPUT_BUFFER_SAMPLES : XMA_MONO_OUTPUT_BUFFER_SAMPLES;
  592. XMAPlaybackCreate( 1, &xmaPlaybackInit, 0, &m_pXMAPlayback );
  593. int stagingSize = PCM_STAGING_BUFFER_TIME * m_SampleRate * m_NumChannels * sizeof( short ) * 0.001f;
  594. m_pPCMSamples = AllocateCircularBuffer( AlignValue( stagingSize, 4 ) );
  595. }
  596. else
  597. {
  598. // too many sounds playing, no xma buffers free
  599. m_Error = ERROR_OUT_OF_MEMORY;
  600. return true;
  601. }
  602. m_StartTime = Plat_MSTime();
  603. }
  604. // waiting for samples
  605. // allow decoder to work without being polled (lock causes a decoding stall)
  606. if ( Plat_MSTime() - m_LastPollTime <= MIX_DECODER_POLLING_LATENCY )
  607. {
  608. return false;
  609. }
  610. m_LastPollTime = Plat_MSTime();
  611. // must have buffers in flight before mixing can begin
  612. if ( m_DataOffset == m_LastDataOffset )
  613. {
  614. // keep trying to get data, async i/o has some allowable latency
  615. int decodeStatus = GetXMABlocksAndSubmitToDecoder( false );
  616. if ( decodeStatus < 0 && decodeStatus != ERROR_IO_NO_XMA_DATA )
  617. {
  618. m_Error = decodeStatus;
  619. return true;
  620. }
  621. else if ( !decodeStatus || decodeStatus == ERROR_IO_NO_XMA_DATA )
  622. {
  623. // async streaming latency could be to blame, check watchdog
  624. if ( Plat_MSTime() - m_StartTime >= MIX_IO_DATA_TIMEOUT )
  625. {
  626. m_Error = ERROR_IO_DATA_TIMEOUT;
  627. }
  628. return false;
  629. }
  630. }
  631. // get the available samples ready for immediate mixing
  632. if ( ServiceXMADecoder( true ) < 0 )
  633. {
  634. return true;
  635. }
  636. // can't mix until we have a minimum threshold of data or the decoder is finished
  637. int minSamplesNeeded = m_bFinished ? 0 : MIN_READYTOMIX * m_SampleRate;
  638. #if defined( ALLOW_SKIP_SAMPLES )
  639. minSamplesNeeded += m_bFinished ? 0 : m_SkipSamples;
  640. #endif
  641. int numReadySamples = GetPCMSamples( 0, NULL );
  642. if ( numReadySamples > minSamplesNeeded )
  643. {
  644. // decoder has samples ready for draining
  645. m_bStartedMixing = true;
  646. if ( snd_xma_spew_startup.GetBool() )
  647. {
  648. Msg( "XMA: 0x%8.8x, Startup Latency: %d ms, Samples Ready: %d, '%s'\n", (unsigned int)this, Plat_MSTime() - m_StartTime, numReadySamples, m_pData->Source().GetFileName() );
  649. }
  650. return true;
  651. }
  652. if ( Plat_MSTime() - m_StartTime >= MIX_DECODER_TIMEOUT )
  653. {
  654. m_Error = ERROR_DECODER_TIMEOUT;
  655. }
  656. // on startup error, let mixer start and get unavailable samples, and abort
  657. // otherwise hold off mixing until samples arrive
  658. return ( m_Error != 0 );
  659. }
  660. //-----------------------------------------------------------------------------
  661. // Returns true to mix, false to stop mixer completely. Called after
  662. // mixer requests samples.
  663. //-----------------------------------------------------------------------------
  664. bool CAudioMixerWaveXMA::ShouldContinueMixing()
  665. {
  666. if ( !IsRetail() && m_Error && snd_xma_spew_warnings.GetBool() )
  667. {
  668. const char *pErrorString;
  669. if ( m_Error < 0 && -m_Error < ARRAYSIZE( g_XMAErrorStrings ) )
  670. {
  671. pErrorString = g_XMAErrorStrings[-m_Error];
  672. }
  673. else
  674. {
  675. pErrorString = g_XMAErrorStrings[0];
  676. }
  677. Warning( "XMA: 0x%8.8x, Mixer Aborted: %s, SamplePosition: %d/%d, DataOffset: %d/%d, '%s'\n",
  678. (unsigned int)this, pErrorString, m_SamplePosition, m_SampleCount, m_DataOffset, m_TotalBytes, m_pData->Source().GetFileName() );
  679. }
  680. // an error condition is fatal to mixer
  681. return ( m_Error == 0 && BaseClass::ShouldContinueMixing() );
  682. }
  683. //-----------------------------------------------------------------------------
  684. // Read existing buffer or decompress a new block when necessary.
  685. // If no samples can be fetched, returns 0, which hints the mixer to a pending shutdown state.
  686. // This routines operates in large buffer quantums, and nothing smaller.
  687. // XMA decode performance severly degrades if the lock is too frequent.
  688. //-----------------------------------------------------------------------------
  689. int CAudioMixerWaveXMA::GetOutputData( void **pData, int numSamplesToCopy, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] )
  690. {
  691. if ( m_Error )
  692. {
  693. // mixer will eventually shutdown
  694. return 0;
  695. }
  696. if ( !m_bStartedMixing )
  697. {
  698. #if defined( ALLOW_SKIP_SAMPLES )
  699. int numMaxSamples = AUDIOSOURCE_COPYBUF_SIZE/( m_NumChannels * sizeof( short ) );
  700. numSamplesToCopy = min( numSamplesToCopy, numMaxSamples );
  701. m_SkipSamples += numSamplesToCopy;
  702. // caller requesting data before mixing has commenced
  703. V_memset( copyBuf, 0, numSamplesToCopy );
  704. *pData = (void*)copyBuf;
  705. return numSamplesToCopy;
  706. #else
  707. // not allowed, GetOutputData() should only be called by the mixing loop
  708. Assert( 0 );
  709. return 0;
  710. #endif
  711. }
  712. // XMA mixing cannot be driven from the main thread
  713. Assert( ThreadInMainThread() == false );
  714. // needs to be clocked at regular intervals
  715. if ( ServiceXMADecoder( false ) < 0 )
  716. {
  717. return 0;
  718. }
  719. #if defined( ALLOW_SKIP_SAMPLES )
  720. if ( m_SkipSamples > 0 )
  721. {
  722. // flush whatever is available
  723. // ignore
  724. m_SkipSamples -= GetPCMSamples( m_SkipSamples, NULL );
  725. if ( m_SkipSamples != 0 )
  726. {
  727. // not enough decoded data ready to flush
  728. // must flush these samples to maintain proper position
  729. m_Error = ERROR_XMA_NO_PCM_DATA;
  730. return 0;
  731. }
  732. }
  733. #endif
  734. // loopback may require flushing some decoded samples
  735. int numRequestedSamples = numSamplesToCopy;
  736. int numDiscardSamples = UpdatePositionForLooping( &numRequestedSamples );
  737. if ( numDiscardSamples > 0 )
  738. {
  739. // loopback requires discarding samples to converge to expected looppoint
  740. numDiscardSamples -= GetPCMSamples( numDiscardSamples, NULL );
  741. if ( numDiscardSamples != 0 )
  742. {
  743. // not enough decoded data ready to flush
  744. // must flush these samples to achieve looping
  745. m_Error = ERROR_XMA_NO_PCM_DATA;
  746. return 0;
  747. }
  748. }
  749. // can only drain as much as can be copied to caller
  750. int numMaxSamples = AUDIOSOURCE_COPYBUF_SIZE/( m_NumChannels * sizeof( short ) );
  751. numRequestedSamples = min( numRequestedSamples, numMaxSamples );
  752. int numCopiedSamples = GetPCMSamples( numRequestedSamples, copyBuf );
  753. if ( numCopiedSamples )
  754. {
  755. CAudioMixerWave::m_sample_max_loaded += numCopiedSamples;
  756. CAudioMixerWave::m_sample_loaded_index += numCopiedSamples;
  757. // advance position by valid samples
  758. m_SamplePosition += numCopiedSamples;
  759. *pData = (void*)copyBuf;
  760. #ifdef DEBUG_XMA
  761. if ( snd_xma_record.GetBool() )
  762. {
  763. WaveAppendTmpFile( "debug.wav", copyBuf, 16, numCopiedSamples * m_NumChannels );
  764. WaveFixupTmpFile( "debug.wav" );
  765. }
  766. #endif
  767. }
  768. else
  769. {
  770. // no samples copied
  771. if ( !m_bFinished && numRequestedSamples )
  772. {
  773. // XMA latency error occurs when decoder not finished (not at EOF) and caller wanted samples but can't get any
  774. if ( snd_xma_spew_warnings.GetInt() )
  775. {
  776. Warning( "XMA: 0x%8.8x, No Decoded Data Ready: %d samples needed, '%s'\n", (unsigned int)this, numSamplesToCopy, m_pData->Source().GetFileName() );
  777. }
  778. m_Error = ERROR_XMA_NO_PCM_DATA;
  779. }
  780. }
  781. return numCopiedSamples;
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose: Seek to a new position in the file
  785. // NOTE: In most cases, only call this once, and call it before playing
  786. // any data.
  787. // Input : newPosition - new position in the sample clocks of this sample
  788. //-----------------------------------------------------------------------------
  789. void CAudioMixerWaveXMA::SetSampleStart( int newPosition )
  790. {
  791. // cannot support this
  792. // this should be unused and thus not supporting
  793. Assert( 0 );
  794. }
  795. int CAudioMixerWaveXMA::GetPositionForSave()
  796. {
  797. if ( m_bLooped )
  798. {
  799. // A looped sample cannot be saved/restored because the decoded sample position,
  800. // which is needed for loop calc, cannot ever be correctly restored without
  801. // the XMA seek table.
  802. return 0;
  803. }
  804. // This is silly and totally wrong, but doing it anyways.
  805. // The correct thing was to have the XMA seek table and use
  806. // that to determine the correct packet. This is just a hopeful
  807. // nearby approximation. Music did not have the seek table at
  808. // the time of this code. The Seek table was added for vo
  809. // restoration later.
  810. return m_LastDataOffset;
  811. }
  812. void CAudioMixerWaveXMA::SetPositionFromSaved( int savedPosition )
  813. {
  814. // Not used here. The Mixer creation will be given the initial startup offset.
  815. }
  816. //-----------------------------------------------------------------------------
  817. // Purpose: Abstract factory function for XMA mixers
  818. //-----------------------------------------------------------------------------
  819. CAudioMixer *CreateXMAMixer( IWaveData *data, int initialStreamPosition )
  820. {
  821. return new CAudioMixerWaveXMA( data, initialStreamPosition );
  822. }