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.

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