JSAPI2_CallbackManager.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include "JSAPI2_CallbackManager.h"
  2. #include "JSAPI2_TransportAPI.h"
  3. #include "JSAPI2_AsyncDownloader.h"
  4. #include "JSAPI2_MediaCore.h"
  5. #include "api.h"
  6. JSAPI2::CallbackManager JSAPI2::callbackManager;
  7. JSAPI2::CallbackManager::CallbackManager() : callbackGuard("JSAPI2::CallbackManager::callbackGuard")
  8. {}
  9. void JSAPI2::CallbackManager::Register( JSAPI2::TransportAPI *me )
  10. {
  11. /* benski> important note:
  12. even thought JSAPI2::Transport inherits from IUnknown,
  13. we don't call AddRef here!
  14. because this would introduce a circular reference.
  15. JSAPI2::TransportAPI will call Deregister during it's
  16. destructor.
  17. */
  18. Nullsoft::Utility::AutoLock lock( callbackGuard );
  19. transports.push_back( new TransportCallback( me ) );
  20. }
  21. void JSAPI2::CallbackManager::Deregister( JSAPI2::TransportAPI *me )
  22. {
  23. /* benski> important note:
  24. even thought JSAPI2::Transport inherits from IUnknown,
  25. we don't call Release here!
  26. because this would introduce a circular reference.
  27. JSAPI2::TransportAPI will call Deregister during it's
  28. destructor.
  29. */
  30. Nullsoft::Utility::AutoLock lock( callbackGuard );
  31. for ( size_t i = 0; i != transports.size(); i++ )
  32. {
  33. TransportCallback *callback = transports[ i ];
  34. if ( callback->api == me )
  35. {
  36. delete callback;
  37. transports.erase( transports.begin() + i );
  38. i--;
  39. }
  40. }
  41. }
  42. void JSAPI2::CallbackManager::Register( JSAPI2::MediaCoreAPI *me )
  43. {
  44. Nullsoft::Utility::AutoLock lock( callbackGuard );
  45. //if (!mediaCores.contains(me))
  46. if ( mediaCores.end() == std::find( mediaCores.begin(), mediaCores.end(), me ) )
  47. {
  48. mediaCores.push_back( me );
  49. }
  50. }
  51. void JSAPI2::CallbackManager::Deregister( JSAPI2::MediaCoreAPI *me )
  52. {
  53. Nullsoft::Utility::AutoLock lock( callbackGuard );
  54. auto it = mediaCores.begin();
  55. while ( it != mediaCores.end() )
  56. {
  57. if ( *it != me )
  58. {
  59. it++;
  60. continue;
  61. }
  62. it = mediaCores.erase( it );
  63. }
  64. }
  65. void JSAPI2::CallbackManager::Register( JSAPI2::AsyncDownloaderAPI *me )
  66. {
  67. Nullsoft::Utility::AutoLock lock( callbackGuard );
  68. asyncDownloaders.push_back( new AsyncDownloaderCallback( me ) );
  69. }
  70. void JSAPI2::CallbackManager::Deregister( JSAPI2::AsyncDownloaderAPI *me )
  71. {
  72. Nullsoft::Utility::AutoLock lock( callbackGuard );
  73. for ( size_t i = 0; i != asyncDownloaders.size(); i++ )
  74. {
  75. AsyncDownloaderCallback *callback = asyncDownloaders[ i ];
  76. if ( callback->api == me )
  77. {
  78. delete callback;
  79. asyncDownloaders.erase( asyncDownloaders.begin() + i );
  80. i--;
  81. }
  82. }
  83. }
  84. /* --- OnStop --- */
  85. struct OnStopAPCData
  86. {
  87. JSAPI2::TransportAPI *transport;
  88. int position;
  89. int is_full_stop;
  90. };
  91. static void CALLBACK CMGR_OnStopAPC(ULONG_PTR param)
  92. {
  93. OnStopAPCData *data = (OnStopAPCData *)param;
  94. data->transport->OnStop(data->position, data->is_full_stop);
  95. data->transport->Release();
  96. delete data;
  97. }
  98. void JSAPI2::CallbackManager::OnStop(int position, int is_full_stop)
  99. {
  100. DWORD threadId = GetCurrentThreadId();
  101. Nullsoft::Utility::AutoLock lock(callbackGuard);
  102. for ( TransportCallback *l_transport : transports )
  103. {
  104. OnStopAPCData *data = new OnStopAPCData;
  105. data->transport = l_transport->api;
  106. data->position = position;
  107. data->is_full_stop = is_full_stop;
  108. data->transport->AddRef(); // so it doesn't disappear while we're switching threads
  109. if ( threadId == l_transport->threadId )
  110. {
  111. // same thread! huzzah but I wonder how that happened :)
  112. CMGR_OnStopAPC( (ULONG_PTR)data );
  113. }
  114. else
  115. {
  116. // different thread, do an APC
  117. if ( QueueUserAPC( CMGR_OnStopAPC, l_transport->threadHandle, (ULONG_PTR)data ) == 0 )
  118. {
  119. data->transport->Release();
  120. delete data;
  121. }
  122. }
  123. }
  124. }
  125. /* --- --- */
  126. /* --- OnPlay --- */
  127. struct OnPlayAPC
  128. {
  129. JSAPI2::TransportAPI *transport;
  130. wchar_t *filename;
  131. };
  132. static void CALLBACK CMGR_OnPlayAPC(ULONG_PTR param)
  133. {
  134. OnPlayAPC *data = (OnPlayAPC *)param;
  135. data->transport->OnPlay(data->filename);
  136. free(data->filename);
  137. data->transport->Release();
  138. delete data;
  139. }
  140. void JSAPI2::CallbackManager::OnPlay(const wchar_t *filename)
  141. {
  142. DWORD threadId = GetCurrentThreadId();
  143. Nullsoft::Utility::AutoLock lock(callbackGuard);
  144. for ( TransportCallback *l_transport : transports )
  145. {
  146. OnPlayAPC *data = new OnPlayAPC;
  147. data->transport = l_transport->api;
  148. data->filename = _wcsdup(filename);
  149. data->transport->AddRef(); // so it doesn't disappear while we're switching threads
  150. if ( threadId == l_transport->threadId )
  151. {
  152. // same thread! huzzah but I wonder how that happened :)
  153. CMGR_OnPlayAPC( (ULONG_PTR)data );
  154. }
  155. else
  156. {
  157. // different thread, do an APC
  158. if ( QueueUserAPC( CMGR_OnPlayAPC, l_transport->threadHandle, (ULONG_PTR)data ) == 0 )
  159. {
  160. data->transport->Release();
  161. free( data->filename );
  162. delete data;
  163. }
  164. }
  165. }
  166. }
  167. /* --- --- */
  168. struct OnPauseAPC
  169. {
  170. JSAPI2::TransportAPI *transport;
  171. bool pause_state;
  172. };
  173. static void CALLBACK CMGR_OnPauseAPC(ULONG_PTR param)
  174. {
  175. OnPauseAPC *data = (OnPauseAPC *)param;
  176. data->transport->OnPause(data->pause_state);
  177. data->transport->Release();
  178. delete data;
  179. }
  180. void JSAPI2::CallbackManager::OnPause(bool pause_state)
  181. {
  182. DWORD threadId = GetCurrentThreadId();
  183. Nullsoft::Utility::AutoLock lock( callbackGuard );
  184. for ( TransportCallback *l_transport : transports )
  185. {
  186. OnPauseAPC *data = new OnPauseAPC;
  187. data->transport = l_transport->api;
  188. data->pause_state = pause_state;
  189. data->transport->AddRef(); // so it doesn't disappear while we're switching threads
  190. if (threadId == l_transport->threadId)
  191. {
  192. // same thread! huzzah but I wonder how that happened :)
  193. CMGR_OnPauseAPC((ULONG_PTR)data);
  194. }
  195. else
  196. {
  197. // different thread, do an APC
  198. if (QueueUserAPC(CMGR_OnPauseAPC, l_transport->threadHandle, (ULONG_PTR)data) == 0)
  199. {
  200. data->transport->Release();
  201. delete data;
  202. }
  203. }
  204. }
  205. }
  206. /* --- --- */
  207. bool JSAPI2::CallbackManager::OverrideMetadata( const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch )
  208. {
  209. if ( NULL != filename && NULL != tag && NULL != out )
  210. {
  211. Nullsoft::Utility::AutoLock lock( callbackGuard );
  212. for ( MediaCoreAPI *l_mediaCore : mediaCores )
  213. {
  214. if ( l_mediaCore->OverrideMetadata( filename, tag, out, outCch ) )
  215. return true;
  216. }
  217. }
  218. return false;
  219. }
  220. /* --- OnInit --- */
  221. struct OnInitAPC
  222. {
  223. JSAPI2::AsyncDownloaderAPI *asyncDownloader;
  224. wchar_t *url;
  225. };
  226. static void CALLBACK CMGR_OnInitAPC(ULONG_PTR param)
  227. {
  228. OnInitAPC *data = (OnInitAPC *)param;
  229. data->asyncDownloader->OnInit(data->url);
  230. free(data->url);
  231. data->asyncDownloader->Release();
  232. delete data;
  233. }
  234. void JSAPI2::CallbackManager::OnInit( const wchar_t *url, const wchar_t *onlinesvcId )
  235. {
  236. DWORD threadId = GetCurrentThreadId();
  237. Nullsoft::Utility::AutoLock lock( callbackGuard );
  238. for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
  239. {
  240. if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
  241. continue; //only call back to the same online service that issued the download reqeust
  242. OnInitAPC *data = new OnInitAPC;
  243. data->asyncDownloader = l_downloader->api;
  244. data->url = _wcsdup( url );
  245. data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
  246. if ( threadId == l_downloader->threadId )
  247. {
  248. // same thread! huzzah but I wonder how that happened :)
  249. CMGR_OnInitAPC( (ULONG_PTR)data );
  250. }
  251. else
  252. {
  253. // different thread, do an APC
  254. if ( QueueUserAPC( CMGR_OnInitAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
  255. {
  256. data->asyncDownloader->Release();
  257. free( data->url );
  258. delete data;
  259. }
  260. }
  261. }
  262. }
  263. /* --- OnConnect --- */
  264. struct OnConnectAPC
  265. {
  266. JSAPI2::AsyncDownloaderAPI *asyncDownloader;
  267. wchar_t *url;
  268. };
  269. static void CALLBACK CMGR_OnConnectAPC(ULONG_PTR param)
  270. {
  271. OnConnectAPC *data = (OnConnectAPC *)param;
  272. data->asyncDownloader->OnConnect(data->url);
  273. free(data->url);
  274. data->asyncDownloader->Release();
  275. delete data;
  276. }
  277. void JSAPI2::CallbackManager::OnConnect( const wchar_t *url, const wchar_t *onlinesvcId )
  278. {
  279. DWORD threadId = GetCurrentThreadId();
  280. Nullsoft::Utility::AutoLock lock( callbackGuard );
  281. for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
  282. {
  283. if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
  284. continue; //only call back to the same online service that issued the download reqeust
  285. OnConnectAPC *data = new OnConnectAPC;
  286. data->asyncDownloader = l_downloader->api;
  287. data->url = _wcsdup( url );
  288. data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
  289. if ( threadId == l_downloader->threadId )
  290. {
  291. // same thread! huzzah but I wonder how that happened :)
  292. CMGR_OnConnectAPC( (ULONG_PTR)data );
  293. }
  294. else
  295. {
  296. // different thread, do an APC
  297. if ( QueueUserAPC( CMGR_OnConnectAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
  298. {
  299. data->asyncDownloader->Release();
  300. free( data->url );
  301. delete data;
  302. }
  303. }
  304. }
  305. }
  306. /* --- OnCancel --- */
  307. struct OnCancelAPC
  308. {
  309. JSAPI2::AsyncDownloaderAPI *asyncDownloader;
  310. wchar_t *url;
  311. };
  312. static void CALLBACK CMGR_OnCancelAPC(ULONG_PTR param)
  313. {
  314. OnCancelAPC *data = (OnCancelAPC *)param;
  315. data->asyncDownloader->OnCancel(data->url);
  316. free(data->url);
  317. data->asyncDownloader->Release();
  318. delete data;
  319. }
  320. void JSAPI2::CallbackManager::OnCancel( const wchar_t *url, const wchar_t *onlinesvcId )
  321. {
  322. DWORD threadId = GetCurrentThreadId();
  323. Nullsoft::Utility::AutoLock lock( callbackGuard );
  324. for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
  325. {
  326. if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
  327. continue; //only call back to the same online service that issued the download reqeust
  328. OnCancelAPC *data = new OnCancelAPC;
  329. data->asyncDownloader = l_downloader->api;
  330. data->url = _wcsdup( url );
  331. data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
  332. if ( threadId == l_downloader->threadId )
  333. {
  334. // same thread! huzzah but I wonder how that happened :)
  335. CMGR_OnCancelAPC( (ULONG_PTR)data );
  336. }
  337. else
  338. {
  339. // different thread, do an APC
  340. if ( QueueUserAPC( CMGR_OnCancelAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
  341. {
  342. data->asyncDownloader->Release();
  343. free( data->url );
  344. delete data;
  345. }
  346. }
  347. }
  348. }
  349. /* --- OnData --- */
  350. struct OnDataAPC
  351. {
  352. JSAPI2::AsyncDownloaderAPI *asyncDownloader;
  353. wchar_t *url;
  354. size_t downloadedlen;
  355. size_t totallen;
  356. };
  357. static void CALLBACK CMGR_OnDataAPC(ULONG_PTR param)
  358. {
  359. OnDataAPC *data = (OnDataAPC *)param;
  360. data->asyncDownloader->OnData(data->url, data->downloadedlen, data->totallen);
  361. free(data->url);
  362. data->asyncDownloader->Release();
  363. delete data;
  364. }
  365. void JSAPI2::CallbackManager::OnData(const wchar_t *url, size_t downloadedlen, size_t totallen, const wchar_t *onlinesvcId)
  366. {
  367. DWORD threadId = GetCurrentThreadId();
  368. Nullsoft::Utility::AutoLock lock(callbackGuard);
  369. for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
  370. {
  371. if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
  372. continue; //only call back to the same online service that issued the download reqeust
  373. OnDataAPC *data = new OnDataAPC;
  374. data->asyncDownloader = downloader->api;
  375. data->url = _wcsdup(url);
  376. data->downloadedlen = downloadedlen;
  377. data->totallen = totallen;
  378. data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
  379. if (threadId == downloader->threadId)
  380. {
  381. // same thread! huzzah but I wonder how that happened :)
  382. CMGR_OnDataAPC((ULONG_PTR)data);
  383. }
  384. else
  385. {
  386. // different thread, do an APC
  387. if (QueueUserAPC(CMGR_OnDataAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
  388. {
  389. data->asyncDownloader->Release();
  390. free(data->url);
  391. delete data;
  392. }
  393. }
  394. }
  395. }
  396. /* --- OnError --- */
  397. struct OnErrorAPC
  398. {
  399. JSAPI2::AsyncDownloaderAPI *asyncDownloader;
  400. wchar_t *url;
  401. int error;
  402. };
  403. static void CALLBACK CMGR_OnErrorAPC(ULONG_PTR param)
  404. {
  405. OnErrorAPC *data = (OnErrorAPC *)param;
  406. data->asyncDownloader->OnError(data->url, data->error);
  407. free(data->url);
  408. data->asyncDownloader->Release();
  409. delete data;
  410. }
  411. void JSAPI2::CallbackManager::OnError(const wchar_t *url, int error, const wchar_t *onlinesvcId)
  412. {
  413. DWORD threadId = GetCurrentThreadId();
  414. Nullsoft::Utility::AutoLock lock(callbackGuard);
  415. for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
  416. {
  417. if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
  418. continue; //only call back to the same online service that issued the download reqeust
  419. OnErrorAPC *data = new OnErrorAPC;
  420. data->asyncDownloader = downloader->api;
  421. data->url = _wcsdup(url);
  422. data->error = error;
  423. data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
  424. if (threadId == downloader->threadId)
  425. {
  426. // same thread! huzzah but I wonder how that happened :)
  427. CMGR_OnErrorAPC((ULONG_PTR)data);
  428. }
  429. else
  430. {
  431. // different thread, do an APC
  432. if (QueueUserAPC(CMGR_OnErrorAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
  433. {
  434. data->asyncDownloader->Release();
  435. free(data->url);
  436. delete data;
  437. }
  438. }
  439. }
  440. }
  441. /* --- OnFinish --- */
  442. struct OnFinishAPC
  443. {
  444. JSAPI2::AsyncDownloaderAPI *asyncDownloader;
  445. wchar_t *url;
  446. wchar_t *destfilename;
  447. };
  448. static void CALLBACK CMGR_OnFinishAPC(ULONG_PTR param)
  449. {
  450. OnFinishAPC *data = (OnFinishAPC *)param;
  451. data->asyncDownloader->OnFinish(data->url, data->destfilename);
  452. free(data->url);
  453. free(data->destfilename);
  454. data->asyncDownloader->Release();
  455. delete data;
  456. }
  457. void JSAPI2::CallbackManager::OnFinish(const wchar_t *url, const wchar_t *destfilename, const wchar_t *onlinesvcId)
  458. {
  459. DWORD threadId = GetCurrentThreadId();
  460. Nullsoft::Utility::AutoLock lock(callbackGuard);
  461. for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
  462. {
  463. if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
  464. continue; //only call back to the same online service that issued the download reqeust
  465. OnFinishAPC *data = new OnFinishAPC;
  466. data->asyncDownloader = downloader->api;
  467. data->url = _wcsdup(url);
  468. data->destfilename = _wcsdup(destfilename);
  469. data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
  470. if (threadId == downloader->threadId)
  471. {
  472. // same thread! huzzah but I wonder how that happened :)
  473. CMGR_OnFinishAPC((ULONG_PTR)data);
  474. }
  475. else
  476. {
  477. // different thread, do an APC
  478. if (QueueUserAPC(CMGR_OnFinishAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
  479. {
  480. data->asyncDownloader->Release();
  481. free(data->url);
  482. free(data->destfilename);
  483. delete data;
  484. }
  485. }
  486. }
  487. }