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.

368 lines
8.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "sentence.h"
  9. #include "wavefile.h"
  10. #include "tier2/riff.h"
  11. #include "filesystem.h"
  12. #include <io.h>
  13. #include <fcntl.h>
  14. #include <sys/types.h>
  15. #include "IFileLoader.h"
  16. bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io );
  17. //-----------------------------------------------------------------------------
  18. // Purpose: Implements the RIFF i/o interface on stdio
  19. //-----------------------------------------------------------------------------
  20. class ThreadIOReadBinary : public IFileReadBinary
  21. {
  22. public:
  23. int open( const char *pFileName )
  24. {
  25. char filename[ 512 ];
  26. Q_snprintf( filename, sizeof( filename ), "%s%s", SceneManager_GetGameDirectory(), pFileName );
  27. return (int)_open( filename, _O_BINARY | _O_RDONLY );
  28. }
  29. int read( void *pOutput, int size, int file )
  30. {
  31. if ( file == -1 )
  32. return 0;
  33. return _read( file, pOutput, size );
  34. }
  35. void seek( int file, int pos )
  36. {
  37. if ( file == -1 )
  38. return;
  39. _lseek( file, pos, SEEK_SET );
  40. }
  41. unsigned int tell( int file )
  42. {
  43. if ( file == -1 )
  44. return 0;
  45. return _tell( file );
  46. }
  47. unsigned int size( int file )
  48. {
  49. if ( file == -1 )
  50. return 0;
  51. long curpos = tell( file );
  52. _lseek( file, 0, SEEK_END );
  53. int s = tell( file );
  54. _lseek( file, curpos, SEEK_SET );
  55. return s;
  56. }
  57. void close( int file )
  58. {
  59. if ( file == -1 )
  60. return;
  61. _close( file );
  62. }
  63. };
  64. //-----------------------------------------------------------------------------
  65. // Purpose: All wavefile I/O occurs on a thread
  66. //-----------------------------------------------------------------------------
  67. class CFileLoaderThread : public IFileLoader
  68. {
  69. public:
  70. struct SentenceRequest
  71. {
  72. SentenceRequest()
  73. {
  74. filename[ 0 ] = 0;
  75. sentence.Reset();
  76. wavefile = NULL;
  77. valid = false;
  78. }
  79. bool valid;
  80. char filename[ 256 ];
  81. CSentence sentence;
  82. CWaveFile *wavefile;
  83. };
  84. // Construction
  85. CFileLoaderThread( void );
  86. virtual ~CFileLoaderThread( void );
  87. // Sockets add/remove themselves via their constructor
  88. virtual void AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles );
  89. // Lock changes to wavefile list, etc.
  90. virtual void Lock( void );
  91. // Unlock wavefile list, etc.
  92. virtual void Unlock( void );
  93. // Retrieve handle to shutdown event
  94. virtual HANDLE GetShutdownHandle( void );
  95. // Caller should call lock before accessing any of these methods and unlock afterwards!!!
  96. virtual int ProcessCompleted();
  97. int DoThreadWork();
  98. virtual void Start();
  99. private:
  100. // Critical section used for synchronizing access to wavefile list
  101. CRITICAL_SECTION cs;
  102. // List of wavefiles we are listening on
  103. CUtlVector< SentenceRequest * > m_FileList;
  104. CUtlVector< SentenceRequest * > m_Pending;
  105. CUtlVector< SentenceRequest * > m_Completed;
  106. // Thread handle
  107. HANDLE m_hThread;
  108. // Thread id
  109. DWORD m_nThreadId;
  110. // Event to set when we want to tell the thread to shut itself down
  111. HANDLE m_hShutdown;
  112. ThreadIOReadBinary m_ThreadIO;
  113. bool m_bLocked;
  114. int m_nTotalAdds;
  115. int m_nTotalPending;
  116. int m_nTotalProcessed;
  117. int m_nTotalCompleted;
  118. };
  119. // Singleton handler
  120. static CFileLoaderThread g_WaveLoader;
  121. extern IFileLoader *fileloader = &g_WaveLoader;
  122. int CFileLoaderThread::DoThreadWork()
  123. {
  124. int i;
  125. // Check for shutdown event
  126. if ( WAIT_OBJECT_0 == WaitForSingleObject( GetShutdownHandle(), 0 ) )
  127. {
  128. return 0;
  129. }
  130. // No changes to list right now
  131. Lock();
  132. // Move new items to work list
  133. int newItems = m_FileList.Count();
  134. for ( i = 0; i < newItems; i++ )
  135. {
  136. // Move to pending and issue async i/o calls
  137. m_Pending.AddToTail( m_FileList[ i ] );
  138. m_nTotalPending++;
  139. }
  140. m_FileList.RemoveAll();
  141. // Done adding new work items
  142. Unlock();
  143. int remaining = m_Pending.Count();
  144. if ( !remaining )
  145. return 1;
  146. int workitems = remaining; // min( remaining, 1000 );
  147. CUtlVector< SentenceRequest * > transfer;
  148. for ( i = 0; i < workitems; i++ )
  149. {
  150. SentenceRequest *r = m_Pending[ 0 ];
  151. m_Pending.Remove( 0 );
  152. transfer.AddToTail( r );
  153. // Do the work
  154. m_nTotalProcessed++;
  155. r->valid = SceneManager_LoadSentenceFromWavFileUsingIO( r->filename, r->sentence, m_ThreadIO );
  156. }
  157. // Now move to completed list
  158. Lock();
  159. for ( i = 0; i < workitems; i++ )
  160. {
  161. SentenceRequest *r = transfer[ i ];
  162. if ( r->valid )
  163. {
  164. m_nTotalCompleted++;
  165. m_Completed.AddToTail( r );
  166. }
  167. else
  168. {
  169. delete r;
  170. }
  171. }
  172. Unlock();
  173. return 1;
  174. }
  175. int CFileLoaderThread::ProcessCompleted()
  176. {
  177. Lock();
  178. int c = m_Completed.Count();
  179. for ( int i = c - 1; i >= 0 ; i-- )
  180. {
  181. SentenceRequest *r = m_Completed[ i ];
  182. r->wavefile->SetThreadLoadedSentence( r->sentence );
  183. delete r;
  184. }
  185. m_Completed.RemoveAll();
  186. Unlock();
  187. return c;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose: Main winsock processing thread
  191. // Input : threadobject -
  192. // Output : static DWORD WINAPI
  193. //-----------------------------------------------------------------------------
  194. static DWORD WINAPI FileLoaderThreadFunc( LPVOID threadobject )
  195. {
  196. // Get pointer to CFileLoaderThread object
  197. CFileLoaderThread *wavefilethread = ( CFileLoaderThread * )threadobject;
  198. Assert( wavefilethread );
  199. if ( !wavefilethread )
  200. {
  201. return 0;
  202. }
  203. // Keep looking for data until shutdown event is triggered
  204. while ( 1 )
  205. {
  206. if( !wavefilethread->DoThreadWork() )
  207. break;
  208. // Yield a small bit of time to main app
  209. Sleep( 100 );
  210. }
  211. ExitThread( 0 );
  212. return 0;
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: Construction
  216. //-----------------------------------------------------------------------------
  217. CFileLoaderThread::CFileLoaderThread( void )
  218. {
  219. m_nTotalAdds = 0;
  220. m_nTotalProcessed = 0;
  221. m_nTotalCompleted = 0;
  222. m_nTotalPending = 0;
  223. m_bLocked = false;
  224. InitializeCriticalSection( &cs );
  225. m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL );
  226. Assert( m_hShutdown );
  227. m_hThread = NULL;
  228. Start();
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. //-----------------------------------------------------------------------------
  233. void CFileLoaderThread::Start()
  234. {
  235. m_hThread = CreateThread( NULL, 0, FileLoaderThreadFunc, (void *)this, 0, &m_nThreadId );
  236. Assert( m_hThread );
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. //-----------------------------------------------------------------------------
  241. CFileLoaderThread::~CFileLoaderThread( void )
  242. {
  243. Lock();
  244. {
  245. SetEvent( m_hShutdown );
  246. Sleep( 2 );
  247. TerminateThread( m_hThread, 0 );
  248. }
  249. Unlock();
  250. // Kill the wavefile
  251. //!! need to validate this line
  252. // Assert( !m_FileList );
  253. CloseHandle( m_hThread );
  254. CloseHandle( m_hShutdown );
  255. DeleteCriticalSection( &cs );
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose: Returns handle of shutdown event
  259. // Output : HANDLE
  260. //-----------------------------------------------------------------------------
  261. HANDLE CFileLoaderThread::GetShutdownHandle( void )
  262. {
  263. return m_hShutdown;
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Purpose: Locks object and adds wavefile to thread
  267. // Input : *wavefile -
  268. //-----------------------------------------------------------------------------
  269. void CFileLoaderThread::AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles )
  270. {
  271. Lock();
  272. int c = wavefiles.Count();
  273. for ( int i = 0; i < c; i++ )
  274. {
  275. SentenceRequest *request = new SentenceRequest;
  276. request->wavefile = wavefiles[ i ];
  277. Q_strncpy( request->filename, request->wavefile->GetFileName(), sizeof( request->filename ) );
  278. m_FileList.AddToTail( request );
  279. m_nTotalAdds++;
  280. }
  281. Unlock();
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose:
  285. //-----------------------------------------------------------------------------
  286. void CFileLoaderThread::Lock( void )
  287. {
  288. EnterCriticalSection( &cs );
  289. Assert( !m_bLocked );
  290. m_bLocked = true;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose:
  294. //-----------------------------------------------------------------------------
  295. void CFileLoaderThread::Unlock( void )
  296. {
  297. Assert( m_bLocked );
  298. m_bLocked = false;
  299. LeaveCriticalSection( &cs );
  300. }