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.

375 lines
9.1KB

  1. /* SpiralSound
  2. * Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include "ChannelHandler.h"
  19. #include <unistd.h>
  20. using namespace std;
  21. //#define CHANNEL_DEBUG
  22. ChannelHandler::ChannelHandler() :
  23. m_UpdateIndicator(false)
  24. {
  25. m_Mutex = new pthread_mutex_t;
  26. m_Command[0]=0;
  27. m_Command[1]=0;
  28. m_BulkSrc=NULL;
  29. m_BulkSize=0;
  30. m_BulkPos=-1;
  31. pthread_mutex_init(m_Mutex,NULL);
  32. }
  33. ChannelHandler::~ChannelHandler()
  34. {
  35. for(map<string,Channel*>::iterator i=m_ChannelMap.begin();
  36. i!=m_ChannelMap.end(); i++)
  37. {
  38. free(i->second->data_buf);
  39. delete i->second;
  40. }
  41. pthread_mutex_destroy(m_Mutex);
  42. delete m_Mutex;
  43. }
  44. ///////////////////////////////////////////////////////////////
  45. void ChannelHandler::UpdateDataNow()
  46. {
  47. #ifdef CHANNEL_DEBUG
  48. cerr<<"Started update"<<endl;
  49. #endif
  50. // make sure the command is cleared even if
  51. // we can't get a lock on the data
  52. m_Command[0]=0;
  53. if (pthread_mutex_trylock(m_Mutex))
  54. {
  55. #ifdef CHANNEL_DEBUG
  56. cerr<<"Got lock"<<endl;
  57. #endif
  58. m_UpdateIndicator=!m_UpdateIndicator;
  59. for(map<string, Channel*>::iterator i=m_ChannelMap.begin();
  60. i!=m_ChannelMap.end(); i++)
  61. {
  62. Channel *ch = i->second;
  63. switch (ch->type)
  64. {
  65. case INPUT :
  66. {
  67. #ifdef CHANNEL_DEBUG
  68. cerr<<"memcpy input channel: ["<<i->first<<"]"<<endl;
  69. #endif
  70. memcpy(ch->data,ch->data_buf,ch->size);
  71. } break;
  72. case OUTPUT :
  73. {
  74. #ifdef CHANNEL_DEBUG
  75. cerr<<"memcpy output channel: ["<<i->first<<"]"<<endl;
  76. #endif
  77. memcpy(ch->data_buf,ch->data,ch->size);
  78. } break;
  79. // one off request type
  80. case OUTPUT_REQUEST :
  81. {
  82. if (m_BulkID==i->first && ch->requested)
  83. {
  84. if (m_BulkPos!=-1)
  85. {
  86. // doing a bulk transfer
  87. if (m_BulkPos+ch->size>m_BulkSize)
  88. {
  89. // last transfer
  90. #ifdef CHANNEL_DEBUG
  91. cerr<<"memcpy (last) bulk output channel: ["<<i->first<<"]"<<endl;
  92. cerr<<"pos:"<<m_BulkPos<<" size:"<<m_BulkSize<<" chsize:"<<ch->size<<endl;
  93. #endif
  94. memcpy(ch->data_buf,((char*)m_BulkSrc)+m_BulkPos,m_BulkSize-m_BulkPos);
  95. m_BulkPos=-1;
  96. }
  97. else
  98. {
  99. #ifdef CHANNEL_DEBUG
  100. cerr<<"memcpy bulk output channel: ["<<i->first<<"]"<<endl;
  101. cerr<<"pos:"<<m_BulkPos<<" size:"<<m_BulkSize<<endl;
  102. #endif
  103. memcpy(ch->data_buf,((char*)m_BulkSrc)+m_BulkPos,ch->size);
  104. m_BulkPos+=ch->size;
  105. }
  106. ch->updated=true;
  107. ch->requested=false;
  108. }
  109. }
  110. else
  111. {
  112. // normal request transfer
  113. if (ch->requested)
  114. {
  115. #ifdef CHANNEL_DEBUG
  116. cerr<<"memcpy output channel: ["<<i->first<<"]"<<endl;
  117. #endif
  118. memcpy(ch->data_buf,ch->data,ch->size);
  119. ch->updated=true;
  120. ch->requested=false;
  121. }
  122. }
  123. } break;
  124. }
  125. }
  126. m_Command[0]=m_Command[1];
  127. // make sure the command only lasts one update
  128. m_Command[1]=0;
  129. pthread_mutex_unlock(m_Mutex);
  130. //cerr<<"audio out mutex"<<endl;
  131. //cerr<<"Update succeeded"<<endl;
  132. }
  133. else
  134. {
  135. //cerr<<"Couldn't get lock"<<endl;
  136. }
  137. #ifdef CHANNEL_DEBUG
  138. cerr<<"Ended update"<<endl;
  139. #endif
  140. }
  141. void ChannelHandler::RegisterData(const string &ID, Type t,void* pData, int size)
  142. {
  143. // probably don't need to lock here, as if get/set are called before
  144. // the channels have been set up they won't work anyway, but...
  145. //pthread_mutex_lock(m_Mutex);
  146. #ifdef CHANNEL_DEBUG
  147. cerr<<"Registering ["<<ID<<"] "<<hex<<pData<<dec<<" as "<<size<<" bytes big"<<endl;
  148. #endif
  149. map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
  150. if (i!=m_ChannelMap.end())
  151. {
  152. cerr<<"Channel with ID ["<<ID<<"] already exists"<<endl;
  153. }
  154. Channel *NewCh=new Channel(t);
  155. NewCh->data_buf = malloc(size);
  156. NewCh->size = size;
  157. NewCh->data = pData;
  158. NewCh->requested = false;
  159. NewCh->updated = false;
  160. memcpy(NewCh->data_buf,NewCh->data,size);
  161. m_ChannelMap[ID]=NewCh;
  162. //pthread_mutex_unlock(m_Mutex);
  163. }
  164. /////////////////////////////////////////////////////////////////////////
  165. void ChannelHandler::GetData(const string &ID, void *data)
  166. {
  167. map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
  168. if (i==m_ChannelMap.end())
  169. {
  170. cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
  171. return;
  172. }
  173. if (!data)
  174. {
  175. cerr<<"ChannelHandler: Can't copy data to uninitialised mem"<<endl;
  176. return;
  177. }
  178. pthread_mutex_lock(m_Mutex);
  179. if (i->second->type==OUTPUT || i->second->type==OUTPUT_REQUEST)
  180. {
  181. memcpy(data,i->second->data_buf,i->second->size);
  182. }
  183. else
  184. {
  185. cerr<<"ChannelHandler: Tried to Get() data registered as input"<<endl;
  186. }//cerr<<"unlock 1"<<endl;
  187. pthread_mutex_unlock(m_Mutex);
  188. }
  189. void ChannelHandler::ReplaceData(const std::string &ID, void *pData, int size)
  190. {
  191. map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
  192. if (i==m_ChannelMap.end())
  193. {
  194. cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
  195. return;
  196. }
  197. pthread_mutex_lock(m_Mutex);
  198. i->second->data = pData;
  199. i->second->size = size;
  200. free(i->second->data_buf);
  201. i->second->data_buf = malloc(size);
  202. memcpy(i->second->data_buf,i->second->data,size);
  203. pthread_mutex_unlock(m_Mutex);
  204. }
  205. void ChannelHandler::SetData(const string &ID, void *s)
  206. {
  207. map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
  208. if (i==m_ChannelMap.end())
  209. {
  210. cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
  211. return;
  212. }
  213. //cerr<<"lock 2"<<endl;
  214. pthread_mutex_lock(m_Mutex);
  215. //cerr<<"lock 2 ok"<<endl;
  216. if (i->second->type==INPUT)
  217. {
  218. memcpy(i->second->data_buf,s,i->second->size);
  219. }
  220. else
  221. {
  222. cerr<<"ChannelHandler: Tried to Set() data registered as output"<<endl;
  223. }//cerr<<"unlock 2"<<endl;
  224. pthread_mutex_unlock(m_Mutex);
  225. }
  226. void ChannelHandler::SetCommand(char command)
  227. {
  228. pthread_mutex_lock(m_Mutex);
  229. m_Command[1]=command;
  230. pthread_mutex_unlock(m_Mutex);
  231. }
  232. void ChannelHandler::FlushChannels()
  233. {
  234. pthread_mutex_lock(m_Mutex);
  235. for(map<string, Channel*>::iterator i=m_ChannelMap.begin();
  236. i!=m_ChannelMap.end(); i++)
  237. {
  238. memcpy(i->second->data_buf,i->second->data,i->second->size);
  239. }
  240. pthread_mutex_unlock(m_Mutex);
  241. }
  242. void ChannelHandler::RequestChannelAndWait(const string &ID)
  243. {
  244. map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
  245. if (i==m_ChannelMap.end())
  246. {
  247. cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
  248. return;
  249. }
  250. if (i->second->type!=OUTPUT_REQUEST)
  251. {
  252. cerr<<"ChannelHandler: Trying to request ["<<ID<<"] which is not a requestable channel"<<endl;
  253. return;
  254. }
  255. pthread_mutex_lock(m_Mutex);
  256. i->second->requested=true;
  257. pthread_mutex_unlock(m_Mutex);
  258. bool ready=false;
  259. while (!ready)
  260. {
  261. usleep(10); // random amount of time :)
  262. pthread_mutex_lock(m_Mutex);
  263. ready=i->second->updated;
  264. pthread_mutex_unlock(m_Mutex);
  265. }
  266. pthread_mutex_lock(m_Mutex);
  267. i->second->requested=false;
  268. i->second->updated=false;
  269. pthread_mutex_unlock(m_Mutex);
  270. }
  271. void ChannelHandler::BulkTransfer(const string &ID, void *dest, int size)
  272. {
  273. map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
  274. if (i==m_ChannelMap.end())
  275. {
  276. cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
  277. return;
  278. }
  279. if (i->second->type!=OUTPUT_REQUEST)
  280. {
  281. cerr<<"ChannelHandler: Trying to bulk transfer on ["<<ID<<"] which is not a OUTPUT_REQUEST channel"<<endl;
  282. return;
  283. }
  284. m_BulkPos=0;
  285. m_BulkSize = size;
  286. m_BulkID = ID;
  287. int pos=0;
  288. int buffersize=i->second->size;
  289. // fill up the destination buffer
  290. while (m_BulkPos!=-1)
  291. {
  292. RequestChannelAndWait(ID);
  293. if (pos+buffersize>size)
  294. {
  295. // last copy
  296. char *tempbuf = (char*)malloc(buffersize);
  297. GetData(ID,(void*)tempbuf);
  298. memcpy(((char*)dest)+pos,(void*)tempbuf,size-pos);
  299. free(tempbuf);
  300. }
  301. else
  302. {
  303. GetData(ID,((char*)dest)+pos);
  304. }
  305. pos+=buffersize;
  306. }
  307. }
  308. void ChannelHandler::Wait()
  309. {
  310. bool current;
  311. bool last;
  312. for (int n=0; n<2; n++)
  313. {
  314. pthread_mutex_lock(m_Mutex);
  315. current=m_UpdateIndicator;
  316. last=m_UpdateIndicator;
  317. pthread_mutex_unlock(m_Mutex);
  318. while (current==last)
  319. {
  320. usleep(10);
  321. pthread_mutex_lock(m_Mutex);
  322. current=m_UpdateIndicator;
  323. pthread_mutex_unlock(m_Mutex);
  324. }
  325. }
  326. }