Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

ArSoundsQueue.cpp

00001 /*
00002 ActivMedia Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004,2005 ActivMedia Robotics, LLC
00004 
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 ActivMedia Robotics for information about a commercial version of ARIA at 
00022 robots@activmedia.com or 
00023 ActivMedia Robotics, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 
00025 */
00026 
00027 #include "ArExport.h"
00028 #include "ArLog.h"
00029 #include "ariaUtil.h"
00030 #include "ArSoundsQueue.h"
00031 #include "ArSoundPlayer.h"
00032 #include <assert.h>
00033 
00034 
00035 // For debugging:
00036 //#define debuglog(msg) ArLog::log(ArLog::Verbose, "%s: %s", __PRETTY_FUNCTION__, (msg));
00037 //#define DEBUG 1
00038 
00039 
00040 #define debuglog(msg) {}
00041 
00042 using namespace std;
00043 
00044 
00045 ArSoundsQueue::Item::Item() :
00046   data(""), type(OTHER), params(""), priority(0)
00047 {
00048 }
00049 
00050 ArSoundsQueue::Item::Item(std::string _data, ItemType _type, std::string _params, int _priority, std::list<PlayItemFunctor*> _callbacks) : 
00051       data(_data), type(_type), params(_params), priority(_priority), playCallbacks(_callbacks)
00052 {
00053 }
00054 
00055 ArSoundsQueue::Item::Item(std::string _data, ItemType _type, std::string _params, int _priority) : 
00056   data(_data), type(_type), params(_params), priority(_priority)
00057 {
00058 }
00059 
00060 ArSoundsQueue::Item::Item(const Item& toCopy) 
00061 {
00062   data = toCopy.data;
00063   type = toCopy.type;
00064   params = toCopy.params;
00065   priority = toCopy.priority;
00066   playCallbacks = toCopy.playCallbacks;
00067   interruptCallbacks = toCopy.interruptCallbacks;
00068 }
00069 
00070 void ArSoundsQueue::Item::play()
00071 {
00072   for(std::list<PlayItemFunctor*>::const_iterator i = playCallbacks.begin(); i != playCallbacks.end(); i++) 
00073     if(*i) {
00074       (*i)->invokeR(data.c_str(), params.c_str());
00075     }
00076 }
00077 
00078 void ArSoundsQueue::Item::interrupt()
00079 {
00080   for(std::list<ArFunctor*>::const_iterator i = interruptCallbacks.begin(); i != interruptCallbacks.end(); i++) 
00081     if(*i) (*i)->invoke();
00082 }
00083 
00084 
00088 class ItemComparator {
00089 protected:
00090   ArSoundsQueue::Item myItem;
00091 public:
00092   ItemComparator(string data = "", ArSoundsQueue::ItemType type = ArSoundsQueue::OTHER, string params = "", int priority = 0) : 
00093     myItem(data, type, params, priority)
00094   {}
00095   virtual ~ItemComparator() {}
00096   virtual bool operator()(const ArSoundsQueue::Item& other)
00097   {
00098     return (other == myItem && other.priority == myItem.priority);
00099   }
00100 };
00101 
00105 class ItemComparator_OnlyData : public virtual ItemComparator {
00106 public:
00107   ItemComparator_OnlyData(string data) : 
00108     ItemComparator(data)
00109   {}
00110   virtual bool operator()(const ArSoundsQueue::Item& other)
00111   {
00112     return(other.data == myItem.data);
00113   }
00114 };
00115 
00119 class ItemComparator_TypeAndData : public virtual ItemComparator {
00120 public:
00121   ItemComparator_TypeAndData(string data, ArSoundsQueue::ItemType type) : 
00122     ItemComparator(data, type)
00123   {}
00124   virtual bool operator()(const ArSoundsQueue::Item& other)
00125   {
00126     return(other.type == myItem.type && other.data == myItem.data);
00127   }
00128 };
00129 
00133 class ItemComparator_PriorityLessThan : public virtual ItemComparator {
00134   int myPriority;
00135 public:
00136   ItemComparator_PriorityLessThan(int priority) : myPriority(priority)
00137   {}
00138   virtual bool operator()(const ArSoundsQueue::Item& other)
00139   {
00140     return(other.priority < myPriority);
00141   }
00142 };
00143 
00147 class ItemComparator_WithTypePriorityLessThan : public virtual ItemComparator {
00148   ArSoundsQueue::ItemType myType;
00149   int myPriority;
00150 public:
00151   ItemComparator_WithTypePriorityLessThan(ArSoundsQueue::ItemType type, int priority) : myType(type), myPriority(priority)
00152   {}
00153   virtual bool operator()(const ArSoundsQueue::Item& other)
00154   {
00155     return(other.type == myType && other.priority < myPriority);
00156   }
00157 };
00158 
00163 class ItemComparator_WithType : public virtual ItemComparator {
00164   ArSoundsQueue::ItemType myType;
00165 public:
00166   ItemComparator_WithType(ArSoundsQueue::ItemType type) : myType(type)
00167   {}
00168   virtual bool operator()(const ArSoundsQueue::Item& other)
00169   {
00170     return(other.type == myType);
00171   }
00172 };
00173 
00174 
00175 ArSoundsQueue::ArSoundsQueue()  :
00176   myInitialized(false),
00177   myPlayingSomething(false),
00178   myDefaultSpeakCB(0), myDefaultInterruptSpeechCB(0),
00179   myDefaultPlayFileCB(0), myDefaultInterruptFileCB(0),
00180   myPauseRequestCount(0)
00181 {
00182   setThreadName("ArSoundsQueue");
00183 }
00184 
00185 ArSoundsQueue::ArSoundsQueue(ArRetFunctor<bool> *speakInitCB, 
00186                     PlayItemFunctor *speakCB, 
00187         InterruptItemFunctor *interruptSpeechCB,
00188         ArRetFunctor<bool> *playInitCB, 
00189         PlayItemFunctor *playCB,
00190         InterruptItemFunctor *interruptFileCB) :
00191   myInitialized(false), myPlayingSomething(false),
00192   myDefaultSpeakCB(speakCB), myDefaultInterruptSpeechCB(interruptSpeechCB),
00193   myDefaultPlayFileCB(playCB), myDefaultInterruptFileCB(interruptFileCB),
00194   myPauseRequestCount(0)
00195 { 
00196   setThreadName("ArSoundsQueue");
00197   if(speakInitCB)
00198     myInitCallbacks.push_back(speakInitCB);
00199   if(playInitCB)
00200     myInitCallbacks.push_back(playInitCB);
00201   if(playCB == 0)
00202     myDefaultPlayFileCB = ArSoundPlayer::getPlayWavFileCallback();
00203   if(interruptFileCB == 0)
00204     myDefaultInterruptFileCB = ArSoundPlayer::getStopPlayingCallback();
00205 }
00206 
00207 ArSoundsQueue::ArSoundsQueue(ArSpeechSynth* speechSynth, 
00208                     ArRetFunctor<bool> *playInitCB,
00209                     PlayItemFunctor *playFileCB,
00210         InterruptItemFunctor *interruptFileCB) 
00211   : myInitialized(false), myPlayingSomething(false),
00212   myDefaultSpeakCB(0), myDefaultInterruptSpeechCB(0),
00213   myDefaultPlayFileCB(playFileCB), myDefaultInterruptFileCB(interruptFileCB),
00214   myPauseRequestCount(0)
00215 {
00216   setThreadName("ArSoundsQueue");
00217   if(playInitCB)
00218     myInitCallbacks.push_back(playInitCB);
00219   if(speechSynth)
00220   {
00221     myInitCallbacks.push_back(speechSynth->getInitCallback());
00222     myDefaultSpeakCB = speechSynth->getSpeakCallback();
00223     myDefaultInterruptSpeechCB = speechSynth->getInterruptCallback();
00224   }
00225 }
00226 
00227 ArSoundsQueue::~ArSoundsQueue()
00228 {
00229 
00230 }
00231 
00232 
00233 void ArSoundsQueue::invokeCallbacks(const std::list<ArFunctor*>& lst)
00234 {
00235   for(std::list<ArFunctor*>::const_iterator i = lst.begin(); i != lst.end(); i++)
00236   {
00237     if(*i) (*i)->invoke();
00238     else ArLog::log(ArLog::Verbose, "ArSoundsQueue: warning: skipped NULL callback (simple functor).");
00239   }
00240 }
00241 
00242 void ArSoundsQueue::invokeCallbacks(const std::list<ArRetFunctor<bool>*>& lst)
00243 {
00244   for(std::list<ArRetFunctor<bool>*>::const_iterator i = lst.begin(); i != lst.end(); i++)
00245   {
00246     if(*i) (*i)->invokeR();
00247     else ArLog::log(ArLog::Verbose, "ArSoundsQueue: warning: skipped NULL callback (bool ret. funct.).");
00248   }
00249 }
00250 
00251 
00252 // This is the public method, but all we have to do is call the private push
00253 // method.
00254 void ArSoundsQueue::addItem(ItemType type, const char* data, std::list<PlayItemFunctor*> callbacks, int priority, const char* params)
00255 {
00256   assert(data);
00257   pushQueueItem(Item(data, type, params?params:"", priority, callbacks));
00258 }
00259 
00260 // This is the public method, but all we have to do is call the private push
00261 // method.
00262 void ArSoundsQueue::addItem(ArSoundsQueue::Item item)
00263 {
00264   pushQueueItem(item);
00265 }
00266 
00267 // Class-protected version.
00268 void ArSoundsQueue::pushQueueItem(ArSoundsQueue::Item item)
00269 {
00270   lock();
00271   pushQueueItem_NoLock(item);
00272   unlock();
00273 }
00274 
00275 // Class-protected version that does not lock (so caller can do it manually as
00276 // needed)
00277 void ArSoundsQueue::pushQueueItem_NoLock(ArSoundsQueue::Item item)
00278 {
00279   ArLog::log(ArLog::Verbose, "ArSoundsQueue: pushing \"%s\" with type=%d, priority=%d, params=\"%s\".", item.data.c_str(), item.type, item.priority, item.params.c_str());
00280   myQueue.push_back(item);
00281 }
00282 
00283 ArSoundsQueue::Item ArSoundsQueue::popQueueItem()
00284 {
00285   lock();
00286   ArSoundsQueue::Item item = *(myQueue.begin());
00287   myQueue.pop_front();
00288   unlock();
00289   return item;
00290 }
00291 
00292 ArSoundsQueue::Item ArSoundsQueue::popQueueItem_NoLock()
00293 {
00294   ArSoundsQueue::Item item = *(myQueue.begin());
00295   myQueue.pop_front();
00296   return item;
00297 }
00298 
00299 ArSoundsQueue::Item ArSoundsQueue::createDefaultSpeechItem(const char* speech)
00300 {
00301   Item item;
00302   item.type = SPEECH;
00303   if(myDefaultSpeakCB)
00304     item.playCallbacks.push_back(myDefaultSpeakCB);
00305   if(myDefaultInterruptSpeechCB)
00306     item.interruptCallbacks.push_back(myDefaultInterruptSpeechCB);
00307   if(speech)
00308     item.data = speech; // copy char* contents into std::string
00309   return item;
00310 }
00311 
00312 void ArSoundsQueue::speak(const char *str, ...)
00313 {
00314   if(myQueue.size() == 0)
00315     invokeCallbacks(myQueueNonemptyCallbacks);
00316 
00317   char *buf;
00318   size_t buflen = (strlen(str) + 1000 * 2);
00319   buf = new char[buflen];
00320 
00321   Item item = createDefaultSpeechItem();
00322 
00323   lock(); // need to lock out here to protect the un-threadsafe va_list functions
00324   va_list ptr;
00325   va_start(ptr, str);
00326   vsnprintf(buf, buflen, str, ptr);
00327   item.data = buf; // std::string constructor will duplicate char* contents
00328   pushQueueItem_NoLock(item); 
00329   va_end(ptr);
00330   delete[] buf;
00331   unlock();
00332 }
00333 
00334 void ArSoundsQueue::speakWithVoice(const char* voice, const char* str, ...)
00335 {
00336   if(myQueue.size() == 0)
00337     invokeCallbacks(myQueueNonemptyCallbacks);
00338 
00339   char *buf;
00340   size_t buflen = (strlen(str) + 1000 * 2);
00341   buf = new char[buflen];
00342 
00343   Item item = createDefaultSpeechItem();
00344   string params = "name=";
00345   params += voice;
00346   item.params = params;
00347 
00348   lock(); // need to lock out here to protect the un-threadsafe va_list functions
00349   va_list ptr;
00350   va_start(ptr, str);
00351   vsnprintf(buf, buflen, str, ptr);
00352   item.data = buf;// std::string constructor will duplicate char* contents
00353   pushQueueItem_NoLock(item);
00354   va_end(ptr);
00355   delete[] buf;
00356   unlock();
00357 }
00358 
00359 void ArSoundsQueue::speakWithPriority(int priority, const char* str, ...)
00360 {
00361   if(myQueue.size() == 0)
00362     invokeCallbacks(myQueueNonemptyCallbacks);
00363 
00364   char *buf;
00365   size_t buflen = (strlen(str) + 1000 * 2);
00366   buf = new char[buflen];
00367 
00368   Item item = createDefaultSpeechItem();
00369   item.priority = priority;
00370 
00371   lock(); // need to lock out here to protect the un-threadsafe va_list functions
00372   va_list ptr;
00373   va_start(ptr, str);
00374   vsnprintf(buf, buflen, str, ptr);
00375   item.data = buf;// std::string constructor will duplicate char* contents
00376   pushQueueItem_NoLock(item);
00377   va_end(ptr);
00378   delete[] buf;
00379   unlock();
00380 }
00381 
00382 ArSoundsQueue::Item ArSoundsQueue::createDefaultFileItem(const char* filename)
00383 {
00384   Item item;
00385   item.type = SOUND_FILE;
00386   if(myDefaultPlayFileCB)
00387     item.playCallbacks.push_back(myDefaultPlayFileCB);
00388   else
00389     ArLog::log(ArLog::Normal, "ArSoundsQueue: Internal Warning: no default PlayFile callback.");
00390   if(myDefaultInterruptFileCB)
00391     item.interruptCallbacks.push_back(myDefaultInterruptFileCB);
00392   if(filename)
00393     item.data = filename; // copy into std::string
00394   return item;
00395 }
00396 
00397 void ArSoundsQueue::play(const char *str, ...)
00398 {
00399   if(myQueue.size() == 0)
00400     invokeCallbacks(myQueueNonemptyCallbacks);
00401 
00402   char buf[2048];
00403   Item item = createDefaultFileItem();
00404 
00405   lock();  // va_list is not threadsafe
00406   va_list ptr;
00407   va_start(ptr, str);
00408   vsnprintf(buf, 2048, str, ptr);
00409   item.data = buf;  // std::string constructor will duplicate char* contents
00410   va_end(ptr);
00411   unlock();
00412 
00413   pushQueueItem(item);
00414 }
00415 
00416 void *ArSoundsQueue::runThread(void *arg)
00417 {
00418   threadStarted();
00419   invokeCallbacks(myInitCallbacks);
00420   debuglog("the init callbacks were called.");
00421   myInitialized = true;
00422 
00423   while (getRunning())
00424   {
00425     lock();
00426     if(myPauseRequestCount > 0) 
00427     {
00428       unlock();
00429       myPausedCondition.wait();
00430       lock();
00431     }
00432     if (myQueue.size() > 0)
00433     {
00434       myLastItem = popQueueItem_NoLock();
00435       myPlayingSomething = true;
00436       unlock();
00437 
00438       // Call some callbacks.
00439       invokeCallbacks(myStartPlaybackCBList);
00440 
00441       // Play the item.
00442 #ifdef DEBUG
00443       ArLog::log(ArLog::Normal, "Acting on item. type=%d", myLastItem.type);
00444 #endif
00445       myLastItem.play();
00446 
00447       // Call some more callbacks.
00448       debuglog("Finished acting on item. Invoking endPlayback callbacks...");
00449       invokeCallbacks(myEndPlaybackCBList);
00450 
00451       // Sleep a bit for some "recover" time (especially for sound playback
00452       // processing)
00453       ArUtil::sleep(200);
00454 
00455       lock();
00456       myPlayingSomething = false;
00457       unlock();
00458 
00459       if(myQueue.size() == 0)
00460       {
00461         debuglog("invoking queue-empty callbacks!");
00462         invokeCallbacks(myQueueEmptyCallbacks);
00463       }
00464     }
00465     else
00466     {
00467       unlock();
00468       ArUtil::sleep(20);
00469     }
00470   }
00471   return NULL;
00472 }
00473 
00474 
00475 void ArSoundsQueue::pause()
00476 {
00477   lock();
00478   myPauseRequestCount++;
00479   unlock();
00480 }
00481 
00482 void ArSoundsQueue::resume()
00483 {
00484   ArLog::log(ArLog::Verbose, "ArSoundsQueue::resume: requested.");
00485   lock();
00486   if(--myPauseRequestCount <= 0) 
00487   {
00488     myPauseRequestCount = 0;
00489     ArLog::log(ArLog::Verbose, "ArSoundsQueue::resume: unpausing.");
00490     unlock();
00491     myPausedCondition.signal();
00492   } else {
00493     unlock();
00494   }
00495 }
00496 
00497 void ArSoundsQueue::stop()
00498 {
00499   stopRunning();
00500 }
00501 
00502 bool ArSoundsQueue::isPaused()
00503 {
00504   return (myPauseRequestCount > 0);
00505 }
00506 
00507 void ArSoundsQueue::interrupt()
00508 {
00509   lock();
00510   // Don't try to interrupt the last item removed from the queue if
00511   // it's not currently being played.
00512   //printf("interrupt: myPlayingSomething=%d\n", myPlayingSomething);
00513   if(myPlayingSomething)
00514     myLastItem.interrupt();
00515   myPlayingSomething = false;
00516   unlock();
00517 }
00518 
00519 void ArSoundsQueue::clearQueue() 
00520 {
00521   lock();
00522   myQueue.clear();
00523   unlock();
00524   invokeCallbacks(myQueueEmptyCallbacks);
00525 }
00526 
00527 set<int> ArSoundsQueue::findPendingItems(const char* item)
00528 {
00529   lock();
00530   set<int> found;
00531   int pos = 0;
00532   for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00533   {
00534     if((*i).data == item)
00535       found.insert(pos);
00536     pos++;
00537   }
00538   unlock();
00539   return found;
00540 }
00541 
00542 void ArSoundsQueue::removePendingItems(const char* item, ItemType type) 
00543 {
00544   lock();
00545   myQueue.remove_if<ItemComparator_TypeAndData>(ItemComparator_TypeAndData(item, type));
00546   unlock();
00547 }
00548 
00549 
00550 void ArSoundsQueue::removePendingItems(const char* data)
00551 {
00552   lock();
00553   myQueue.remove_if<ItemComparator_OnlyData>(ItemComparator_OnlyData(data));
00554   unlock();
00555 }
00556 
00557 void ArSoundsQueue::removePendingItems(int priority) 
00558 {
00559   lock();
00560   myQueue.remove_if<ItemComparator_PriorityLessThan>(ItemComparator_PriorityLessThan(priority));
00561   unlock();
00562 }
00563 
00564 void ArSoundsQueue::removePendingItems(int priority, ItemType type)
00565 {
00566   lock();
00567   myQueue.remove_if<ItemComparator_WithTypePriorityLessThan>(ItemComparator_WithTypePriorityLessThan(type, priority));
00568   unlock();
00569 }
00570 
00571 void ArSoundsQueue::removePendingItems(ItemType type)
00572 {
00573   lock();
00574   myQueue.remove_if<ItemComparator_WithType>(ItemComparator_WithType(type));
00575   unlock();
00576 }
00577 
00578 string ArSoundsQueue::nextItem(ItemType type)
00579 {
00580   lock();
00581   for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00582   {
00583     if(type == (*i).type) {
00584       string found = (*i).data;
00585       unlock();
00586       return found;
00587     }
00588   }
00589   unlock();
00590   return "";
00591 }
00592 
00593 string ArSoundsQueue::nextItem(int priority)
00594 {
00595   lock();
00596   for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00597   {
00598     if((*i).priority >= priority) {
00599       string found = (*i).data;
00600       unlock();
00601       return found;
00602     }
00603   }
00604   unlock();
00605   return "";
00606 }
00607 
00608 string ArSoundsQueue::nextItem(ItemType type, int priority)
00609 {
00610   lock();
00611   for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00612   {
00613     if(type == (*i).type && (*i).priority >= priority) {
00614       string found = (*i).data;
00615       unlock();
00616       return found;
00617     }
00618   }
00619   unlock();
00620   return "";
00621 }
00622 
00623 

Generated on Wed Oct 19 12:56:37 2005 for Aria by  doxygen 1.4.0