/* SpiralSound * Copyleft (C) 2002 David Griffiths * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ChannelHandler.h" #include using namespace std; //#define CHANNEL_DEBUG ChannelHandler::ChannelHandler() : m_UpdateIndicator(false) { m_Mutex = new pthread_mutex_t; m_Command[0]=0; m_Command[1]=0; m_BulkSrc=NULL; m_BulkSize=0; m_BulkPos=-1; pthread_mutex_init(m_Mutex,NULL); } ChannelHandler::~ChannelHandler() { for(map::iterator i=m_ChannelMap.begin(); i!=m_ChannelMap.end(); i++) { free(i->second->data_buf); delete i->second; } pthread_mutex_destroy(m_Mutex); delete m_Mutex; } /////////////////////////////////////////////////////////////// void ChannelHandler::UpdateDataNow() { #ifdef CHANNEL_DEBUG cerr<<"Started update"<::iterator i=m_ChannelMap.begin(); i!=m_ChannelMap.end(); i++) { Channel *ch = i->second; switch (ch->type) { case INPUT : { #ifdef CHANNEL_DEBUG cerr<<"memcpy input channel: ["<first<<"]"<data,ch->data_buf,ch->size); } break; case OUTPUT : { #ifdef CHANNEL_DEBUG cerr<<"memcpy output channel: ["<first<<"]"<data_buf,ch->data,ch->size); } break; // one off request type case OUTPUT_REQUEST : { if (m_BulkPos!=-1 && m_BulkID==i->first) { // doing a bulk transfer if (m_BulkPos+ch->size>m_BulkSize) { // last transfer #ifdef CHANNEL_DEBUG cerr<<"memcpy (last) bulk output channel: ["<first<<"]"<data_buf,((char*)m_BulkSrc)+m_BulkPos,m_BulkSize-m_BulkPos); m_BulkPos=-1; } else { #ifdef CHANNEL_DEBUG cerr<<"memcpy bulk output channel: ["<first<<"]"<data_buf,((char*)m_BulkSrc)+m_BulkPos,ch->size); m_BulkPos+=ch->size; } ch->updated=true; } else { // normal request transfer if (ch->requested) { #ifdef CHANNEL_DEBUG cerr<<"memcpy output channel: ["<first<<"]"<data_buf,ch->data,ch->size); ch->updated=true; } } } break; } } m_Command[0]=m_Command[1]; // make sure the command only lasts one update m_Command[1]=0; pthread_mutex_unlock(m_Mutex); //cerr<<"audio out mutex"<::iterator i=m_ChannelMap.find(ID); if (i!=m_ChannelMap.end()) { cerr<<"Channel with ID ["<data_buf = malloc(size); NewCh->size = size; NewCh->data = pData; NewCh->requested = false; NewCh->updated = false; memcpy(NewCh->data_buf,NewCh->data,size); m_ChannelMap[ID]=NewCh; //pthread_mutex_unlock(m_Mutex); } ///////////////////////////////////////////////////////////////////////// void ChannelHandler::GetData(const string &ID, void *data) { map::iterator i=m_ChannelMap.find(ID); if (i==m_ChannelMap.end()) { cerr<<"ChannelHandler: Channel ["<second->type==OUTPUT || i->second->type==OUTPUT_REQUEST) { memcpy(data,i->second->data_buf,i->second->size); } else { cerr<<"ChannelHandler: Tried to Get() data registered as input"<::iterator i=m_ChannelMap.find(ID); if (i==m_ChannelMap.end()) { cerr<<"ChannelHandler: Channel ["<second->type==INPUT) { memcpy(i->second->data_buf,s,i->second->size); } else { cerr<<"ChannelHandler: Tried to Set() data registered as output"<::iterator i=m_ChannelMap.begin(); i!=m_ChannelMap.end(); i++) { memcpy(i->second->data_buf,i->second->data,i->second->size); } pthread_mutex_unlock(m_Mutex); } void ChannelHandler::RequestChannelAndWait(const string &ID) { map::iterator i=m_ChannelMap.find(ID); if (i==m_ChannelMap.end()) { cerr<<"ChannelHandler: Channel ["<second->type!=OUTPUT_REQUEST) { cerr<<"ChannelHandler: Trying to request ["<second->requested=true; pthread_mutex_unlock(m_Mutex); bool ready=false; while (!ready) { usleep(10); // random amount of time :) pthread_mutex_lock(m_Mutex); ready=i->second->updated; pthread_mutex_unlock(m_Mutex); } pthread_mutex_lock(m_Mutex); i->second->requested=false; i->second->updated=false; pthread_mutex_unlock(m_Mutex); } void ChannelHandler::BulkTransfer(const string &ID, void *dest, int size) { map::iterator i=m_ChannelMap.find(ID); if (i==m_ChannelMap.end()) { cerr<<"ChannelHandler: Channel ["<second->type!=OUTPUT_REQUEST) { cerr<<"ChannelHandler: Trying to bulk transfer on ["<second->size; // fill up the destination buffer while (m_BulkPos!=-1) { RequestChannelAndWait(ID); if (pos+buffersize>size) { // last copy char *tempbuf = (char*)malloc(buffersize); GetData(ID,(void*)tempbuf); memcpy(((char*)dest)+pos,(void*)tempbuf,size-pos); free(tempbuf); } else { GetData(ID,((char*)dest)+pos); } pos+=buffersize; } } void ChannelHandler::Wait() { pthread_mutex_lock(m_Mutex); bool current=m_UpdateIndicator; bool last=m_UpdateIndicator; pthread_mutex_unlock(m_Mutex); while (current==last) { usleep(10); pthread_mutex_lock(m_Mutex); current=m_UpdateIndicator; pthread_mutex_unlock(m_Mutex); } // do this twice (messages have to get there and back?) pthread_mutex_lock(m_Mutex); current=m_UpdateIndicator; last=m_UpdateIndicator; pthread_mutex_unlock(m_Mutex); while (current==last) { usleep(10); pthread_mutex_lock(m_Mutex); current=m_UpdateIndicator; pthread_mutex_unlock(m_Mutex); } }