00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "ArExport.h"
00027 #include "ArLog.h"
00028 #include "ariaUtil.h"
00029 #include "ArSoundsQueue.h"
00030 #include "ArSoundPlayer.h"
00031 #include <assert.h>
00032
00033
00034
00035
00036
00037
00038 #ifdef ARSOUNDSQUEUE_DEBUG
00039 #ifndef __PRETTY_FUNCTION__
00040 #define __PRETTY_FUNCTION__ __FUNCTION__
00041 #endif
00042 #define debuglog(msg) ArLog::log(ArLog::Verbose, "%s: %s", __PRETTY_FUNCTION__, (msg));
00043 #else
00044 #define debuglog(msg) {}
00045 #endif
00046
00047
00048 using namespace std;
00049
00050
00051 AREXPORT ArSoundsQueue::Item::Item() :
00052 data(""), type(OTHER), params(""), priority(0)
00053 {
00054 }
00055
00056 AREXPORT ArSoundsQueue::Item::Item(std::string _data, ItemType _type, std::string _params, int _priority, std::list<PlayItemFunctor*> _callbacks) :
00057 data(_data), type(_type), params(_params), priority(_priority), playCallbacks(_callbacks)
00058 {
00059 }
00060
00061 AREXPORT ArSoundsQueue::Item::Item(std::string _data, ItemType _type, std::string _params, int _priority) :
00062 data(_data), type(_type), params(_params), priority(_priority)
00063 {
00064 }
00065
00066 AREXPORT ArSoundsQueue::Item::Item(const ArSoundsQueue::Item& toCopy)
00067 {
00068 data = toCopy.data;
00069 type = toCopy.type;
00070 params = toCopy.params;
00071 priority = toCopy.priority;
00072 playCallbacks = toCopy.playCallbacks;
00073 interruptCallbacks = toCopy.interruptCallbacks;
00074 doneCallbacks = toCopy.doneCallbacks;
00075 playbackConditionCallbacks = toCopy.playbackConditionCallbacks;
00076 }
00077
00078 void ArSoundsQueue::Item::play()
00079 {
00080 for(std::list<PlayItemFunctor*>::const_iterator i = playCallbacks.begin(); i != playCallbacks.end(); i++)
00081 {
00082 if(*i) {
00083 (*i)->invokeR(data.c_str(), params.c_str());
00084 }
00085 }
00086 }
00087
00088 void ArSoundsQueue::Item::interrupt()
00089 {
00090 for(std::list<ArFunctor*>::const_iterator i = interruptCallbacks.begin(); i != interruptCallbacks.end(); i++)
00091 if(*i) (*i)->invoke();
00092 }
00093
00094
00095 void ArSoundsQueue::Item::done()
00096 {
00097 for(std::list<ArFunctor*>::const_iterator i = doneCallbacks.begin(); i != doneCallbacks.end(); i++)
00098 if(*i) {
00099 (*i)->invoke();
00100 }
00101 }
00102
00108 class ItemComparator {
00109 protected:
00110 ArSoundsQueue::Item myItem;
00111 public:
00112 ItemComparator(string data = "", ArSoundsQueue::ItemType type = ArSoundsQueue::OTHER, string params = "", int priority = 0) :
00113 myItem(data, type, params, priority)
00114 {}
00115 virtual ~ItemComparator() {}
00116 virtual bool operator()(const ArSoundsQueue::Item& other)
00117 {
00118 return (other == myItem && other.priority == myItem.priority);
00119 }
00120 };
00121
00125 class ItemComparator_OnlyData : public virtual ItemComparator {
00126 public:
00127 ItemComparator_OnlyData(string data) :
00128 ItemComparator(data)
00129 {}
00130 virtual bool operator()(const ArSoundsQueue::Item& other)
00131 {
00132 return(other.data == myItem.data);
00133 }
00134 };
00135
00139 class ItemComparator_TypeAndData : public virtual ItemComparator {
00140 public:
00141 ItemComparator_TypeAndData(string data, ArSoundsQueue::ItemType type) :
00142 ItemComparator(data, type)
00143 {}
00144 virtual bool operator()(const ArSoundsQueue::Item& other)
00145 {
00146 return(other.type == myItem.type && other.data == myItem.data);
00147 }
00148 };
00149
00153 class ItemComparator_PriorityLessThan : public virtual ItemComparator {
00154 int myPriority;
00155 public:
00156 ItemComparator_PriorityLessThan(int priority) : myPriority(priority)
00157 {}
00158 virtual bool operator()(const ArSoundsQueue::Item& other)
00159 {
00160 return(other.priority < myPriority);
00161 }
00162 };
00163
00167 class ItemComparator_WithTypePriorityLessThan : public virtual ItemComparator {
00168 ArSoundsQueue::ItemType myType;
00169 int myPriority;
00170 public:
00171 ItemComparator_WithTypePriorityLessThan(ArSoundsQueue::ItemType type, int priority) : myType(type), myPriority(priority)
00172 {}
00173 virtual bool operator()(const ArSoundsQueue::Item& other)
00174 {
00175 return(other.type == myType && other.priority < myPriority);
00176 }
00177 };
00178
00183 class ItemComparator_WithType : public virtual ItemComparator {
00184 ArSoundsQueue::ItemType myType;
00185 public:
00186 ItemComparator_WithType(ArSoundsQueue::ItemType type) : myType(type)
00187 {}
00188 virtual bool operator()(const ArSoundsQueue::Item& other)
00189 {
00190 return(other.type == myType);
00191 }
00192 };
00193
00197 AREXPORT ArSoundsQueue::ArSoundsQueue() :
00198 myInitialized(false),
00199 myPlayingSomething(false),
00200 myDefaultSpeakCB(0), myDefaultInterruptSpeechCB(0),
00201 myDefaultPlayFileCB(0), myDefaultInterruptFileCB(0),
00202 myPauseRequestCount(0),
00203 myDefaultPlayConditionCB(0)
00204 {
00205 setThreadName("ArSoundsQueue");
00206 }
00207
00208 AREXPORT ArSoundsQueue::ArSoundsQueue(ArRetFunctor<bool> *speakInitCB,
00209 PlayItemFunctor *speakCB,
00210 InterruptItemFunctor *interruptSpeechCB,
00211 ArRetFunctor<bool> *playInitCB,
00212 PlayItemFunctor *playCB,
00213 InterruptItemFunctor *interruptFileCB) :
00214 myInitialized(false), myPlayingSomething(false),
00215 myDefaultSpeakCB(speakCB), myDefaultInterruptSpeechCB(interruptSpeechCB),
00216 myDefaultPlayFileCB(playCB), myDefaultInterruptFileCB(interruptFileCB),
00217 myPauseRequestCount(0)
00218 {
00219 setThreadName("ArSoundsQueue");
00220 if(speakInitCB)
00221 myInitCallbacks.push_back(speakInitCB);
00222 if(playInitCB)
00223 myInitCallbacks.push_back(playInitCB);
00224 if(playCB == 0)
00225 myDefaultPlayFileCB = ArSoundPlayer::getPlayWavFileCallback();
00226 if(interruptFileCB == 0)
00227 myDefaultInterruptFileCB = ArSoundPlayer::getStopPlayingCallback();
00228 }
00229
00230 AREXPORT ArSoundsQueue::ArSoundsQueue(ArSpeechSynth* speechSynth,
00231 ArRetFunctor<bool> *playInitCB,
00232 PlayItemFunctor *playFileCB,
00233 InterruptItemFunctor *interruptFileCB)
00234 : myInitialized(false), myPlayingSomething(false),
00235 myDefaultSpeakCB(0), myDefaultInterruptSpeechCB(0),
00236 myDefaultPlayFileCB(playFileCB), myDefaultInterruptFileCB(interruptFileCB),
00237 myPauseRequestCount(0)
00238 {
00239 setThreadName("ArSoundsQueue");
00240 if(playInitCB)
00241 myInitCallbacks.push_back(playInitCB);
00242 if(speechSynth)
00243 {
00244 myInitCallbacks.push_back(speechSynth->getInitCallback());
00245 myDefaultSpeakCB = speechSynth->getSpeakCallback();
00246 myDefaultInterruptSpeechCB = speechSynth->getInterruptCallback();
00247 }
00248 }
00249
00250 AREXPORT ArSoundsQueue::~ArSoundsQueue()
00251 {
00252
00253 }
00254
00255
00256 void ArSoundsQueue::invokeCallbacks(const std::list<ArFunctor*>& lst)
00257 {
00258 for(std::list<ArFunctor*>::const_iterator i = lst.begin(); i != lst.end(); i++)
00259 {
00260 if(*i) (*i)->invoke();
00261 else ArLog::log(ArLog::Verbose, "ArSoundsQueue: warning: skipped NULL callback (simple functor).");
00262 }
00263 }
00264
00265 void ArSoundsQueue::invokeCallbacks(const std::list<ArRetFunctor<bool>*>& lst)
00266 {
00267 for(std::list<ArRetFunctor<bool>*>::const_iterator i = lst.begin(); i != lst.end(); i++)
00268 {
00269 if(*i) (*i)->invokeR();
00270 else ArLog::log(ArLog::Verbose, "ArSoundsQueue: warning: skipped NULL callback (bool ret. funct.).");
00271 }
00272 }
00273
00274
00275
00276
00277 AREXPORT void ArSoundsQueue::addItem(ItemType type, const char* data, std::list<PlayItemFunctor*> callbacks, int priority, const char* params)
00278 {
00279 assert(data);
00280 pushQueueItem(Item(data, type, params?params:"", priority, callbacks));
00281 }
00282
00283
00284
00285 AREXPORT void ArSoundsQueue::addItem(ArSoundsQueue::Item item)
00286 {
00287 pushQueueItem(item);
00288 }
00289
00290
00291 void ArSoundsQueue::pushQueueItem(ArSoundsQueue::Item item)
00292 {
00293 lock();
00294 pushQueueItem_NoLock(item);
00295 unlock();
00296 }
00297
00298
00299
00300 void ArSoundsQueue::pushQueueItem_NoLock(ArSoundsQueue::Item item)
00301 {
00302 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());
00303 myQueue.push_back(item);
00304 }
00305
00306 ArSoundsQueue::Item ArSoundsQueue::popQueueItem()
00307 {
00308 lock();
00309 ArSoundsQueue::Item item = *(myQueue.begin());
00310 myQueue.pop_front();
00311 unlock();
00312 return item;
00313 }
00314
00315 ArSoundsQueue::Item ArSoundsQueue::popQueueItem_NoLock()
00316 {
00317 ArSoundsQueue::Item item = *(myQueue.begin());
00318 myQueue.pop_front();
00319 return item;
00320 }
00321
00322 AREXPORT ArSoundsQueue::Item ArSoundsQueue::createDefaultSpeechItem(const char* speech)
00323 {
00324 Item item;
00325 item.type = SPEECH;
00326 if(myDefaultSpeakCB)
00327 item.playCallbacks.push_back(myDefaultSpeakCB);
00328 if(myDefaultInterruptSpeechCB)
00329 item.interruptCallbacks.push_back(myDefaultInterruptSpeechCB);
00330 if(speech)
00331 item.data = speech;
00332 if(myDefaultPlayConditionCB)
00333 item.playbackConditionCallbacks.push_back(myDefaultPlayConditionCB);
00334 return item;
00335 }
00336
00337
00338 #if !(defined(WIN32) && defined(_MANAGED)) // MS Managed C++ does not allow varargs
00339
00340 AREXPORT void ArSoundsQueue::speak(const char *str, ...)
00341 {
00342 if(myQueue.size() == 0)
00343 invokeCallbacks(myQueueNonemptyCallbacks);
00344
00345 char *buf;
00346 size_t buflen = (strlen(str) + 1000 * 2);
00347 buf = new char[buflen];
00348
00349 Item item = createDefaultSpeechItem();
00350
00351 lock();
00352 va_list ptr;
00353 va_start(ptr, str);
00354 vsnprintf(buf, buflen, str, ptr);
00355 item.data = buf;
00356 pushQueueItem_NoLock(item);
00357 va_end(ptr);
00358 delete[] buf;
00359 unlock();
00360 }
00361
00362 AREXPORT void ArSoundsQueue::speakWithVoice(const char* voice, const char* str, ...)
00363 {
00364 if(myQueue.size() == 0)
00365 invokeCallbacks(myQueueNonemptyCallbacks);
00366
00367 char *buf;
00368 size_t buflen = (strlen(str) + 1000 * 2);
00369 buf = new char[buflen];
00370
00371 Item item = createDefaultSpeechItem();
00372 string params = "name=";
00373 params += voice;
00374 item.params = params;
00375
00376 lock();
00377 va_list ptr;
00378 va_start(ptr, str);
00379 vsnprintf(buf, buflen, str, ptr);
00380 item.data = buf;
00381 pushQueueItem_NoLock(item);
00382 va_end(ptr);
00383 delete[] buf;
00384 unlock();
00385 }
00386
00387 AREXPORT void ArSoundsQueue::speakWithPriority(int priority, const char* str, ...)
00388 {
00389 if(myQueue.size() == 0)
00390 invokeCallbacks(myQueueNonemptyCallbacks);
00391
00392 char *buf;
00393 size_t buflen = (strlen(str) + 1000 * 2);
00394 buf = new char[buflen];
00395
00396 Item item = createDefaultSpeechItem();
00397 item.priority = priority;
00398
00399 lock();
00400 va_list ptr;
00401 va_start(ptr, str);
00402 vsnprintf(buf, buflen, str, ptr);
00403 item.data = buf;
00404 pushQueueItem_NoLock(item);
00405 va_end(ptr);
00406 delete[] buf;
00407 unlock();
00408 }
00409
00410
00411 AREXPORT void ArSoundsQueue::play(const char *str, ...)
00412 {
00413 if(myQueue.size() == 0)
00414 invokeCallbacks(myQueueNonemptyCallbacks);
00415
00416 char buf[2048];
00417 Item item = createDefaultFileItem();
00418
00419 lock();
00420 va_list ptr;
00421 va_start(ptr, str);
00422 vsnprintf(buf, 2048, str, ptr);
00423 item.data = buf;
00424 va_end(ptr);
00425 unlock();
00426
00427 pushQueueItem(item);
00428 }
00429
00430 #endif // MS Managed C++
00431
00432 AREXPORT ArSoundsQueue::Item ArSoundsQueue::createDefaultFileItem(const char* filename)
00433 {
00434 Item item;
00435 item.type = SOUND_FILE;
00436 if(myDefaultPlayFileCB)
00437 item.playCallbacks.push_back(myDefaultPlayFileCB);
00438 else
00439 ArLog::log(ArLog::Normal, "ArSoundsQueue: Internal Warning: no default PlayFile callback.");
00440 if(myDefaultInterruptFileCB)
00441 item.interruptCallbacks.push_back(myDefaultInterruptFileCB);
00442 if(filename)
00443 item.data = filename;
00444 if(myDefaultPlayConditionCB)
00445 item.playbackConditionCallbacks.push_back(myDefaultPlayConditionCB);
00446 return item;
00447 }
00448
00449
00450
00451 AREXPORT void *ArSoundsQueue::runThread(void *arg)
00452 {
00453 threadStarted();
00454 invokeCallbacks(myInitCallbacks);
00455 debuglog("the init callbacks were called.");
00456 myInitialized = true;
00457
00458 while (getRunning())
00459 {
00460 lock();
00461 if(myPauseRequestCount > 0)
00462 {
00463 unlock();
00464 myPausedCondition.wait();
00465 lock();
00466 }
00467 if (myQueue.size() > 0)
00468 {
00469 myLastItem = popQueueItem_NoLock();
00470
00471 #ifdef DEBUG
00472 ArLog::log(ArLog::Normal, "* DEBUG * ArSoundsQueue: Popped an item from the queue. There are %d condition callbacks for this item.", myLastItem.playbackConditionCallbacks.size());
00473 #endif
00474
00475
00476 invokeCallbacks(myStartPlaybackCBList);
00477
00478
00479 bool doPlayback = true;
00480 for(std::list<PlaybackConditionFunctor*>::const_iterator i = myLastItem.playbackConditionCallbacks.begin();
00481 i != myLastItem.playbackConditionCallbacks.end(); i++)
00482 {
00483 if( (*i) && (*i)->invokeR() == false) {
00484 ArLog::log(ArLog::Normal, "ArSoundsQueue: A condition callback prevents this item from playing. Skipping this item.");
00485 doPlayback = false;
00486 break;
00487 }
00488 #ifdef DEBUG
00489 else {
00490 ArLog::log(ArLog::Normal, "* DEBUG * ArSoundsQueue: Condition callback returned true.");
00491 }
00492 #endif
00493 }
00494
00495 if(doPlayback)
00496 {
00497
00498 myPlayingSomething = true;
00499 unlock();
00500
00501
00502 #ifdef DEBUG
00503 ArLog::log(ArLog::Normal, "* DEBUG* Acting on item. type=%d", myLastItem.type);
00504 #endif
00505 myLastItem.play();
00506
00507
00508
00509 ArUtil::sleep(200);
00510
00511 lock();
00512 myPlayingSomething = false;
00513 }
00514
00515
00516
00517 debuglog("Finished acting on item. Invoking endPlayback callbacks...");
00518 unlock();
00519 myLastItem.done();
00520 invokeCallbacks(myEndPlaybackCBList);
00521 lock();
00522
00523 if(myQueue.size() == 0)
00524 {
00525 debuglog("invoking queue-empty callbacks!");
00526 unlock();
00527 invokeCallbacks(myQueueEmptyCallbacks);
00528 }
00529 else
00530 {
00531 unlock();
00532 }
00533
00534 }
00535 else
00536 {
00537 unlock();
00538 ArUtil::sleep(20);
00539 }
00540 }
00541 return NULL;
00542 }
00543
00544
00545 AREXPORT void ArSoundsQueue::pause()
00546 {
00547 lock();
00548 myPauseRequestCount++;
00549 unlock();
00550 }
00551
00552 AREXPORT void ArSoundsQueue::resume()
00553 {
00554 ArLog::log(ArLog::Verbose, "ArSoundsQueue::resume: requested.");
00555 lock();
00556 if(--myPauseRequestCount <= 0)
00557 {
00558 myPauseRequestCount = 0;
00559 ArLog::log(ArLog::Verbose, "ArSoundsQueue::resume: unpausing.");
00560 unlock();
00561 myPausedCondition.signal();
00562 } else {
00563 unlock();
00564 }
00565 }
00566
00567 AREXPORT void ArSoundsQueue::stop()
00568 {
00569 stopRunning();
00570 }
00571
00572 AREXPORT bool ArSoundsQueue::isPaused()
00573 {
00574 return (myPauseRequestCount > 0);
00575 }
00576
00577 AREXPORT void ArSoundsQueue::interrupt()
00578 {
00579 lock();
00580
00581
00582
00583 if(myPlayingSomething)
00584 myLastItem.interrupt();
00585 myPlayingSomething = false;
00586 unlock();
00587 }
00588
00589 AREXPORT void ArSoundsQueue::clearQueue()
00590 {
00591 lock();
00592 myQueue.clear();
00593 unlock();
00594 invokeCallbacks(myQueueEmptyCallbacks);
00595 }
00596
00597 AREXPORT set<int> ArSoundsQueue::findPendingItems(const char* item)
00598 {
00599 lock();
00600 set<int> found;
00601 int pos = 0;
00602 for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00603 {
00604 if((*i).data == item)
00605 found.insert(pos);
00606 pos++;
00607 }
00608 unlock();
00609 return found;
00610 }
00611
00612 AREXPORT void ArSoundsQueue::removePendingItems(const char* item, ItemType type)
00613 {
00614 lock();
00615 myQueue.remove_if<ItemComparator_TypeAndData>(ItemComparator_TypeAndData(item, type));
00616 unlock();
00617 }
00618
00619
00620 AREXPORT void ArSoundsQueue::removePendingItems(const char* data)
00621 {
00622 lock();
00623 myQueue.remove_if<ItemComparator_OnlyData>(ItemComparator_OnlyData(data));
00624 unlock();
00625 }
00626
00627 AREXPORT void ArSoundsQueue::removePendingItems(int priority)
00628 {
00629 lock();
00630 myQueue.remove_if<ItemComparator_PriorityLessThan>(ItemComparator_PriorityLessThan(priority));
00631 unlock();
00632 }
00633
00634 AREXPORT void ArSoundsQueue::removePendingItems(int priority, ItemType type)
00635 {
00636 lock();
00637 myQueue.remove_if<ItemComparator_WithTypePriorityLessThan>(ItemComparator_WithTypePriorityLessThan(type, priority));
00638 unlock();
00639 }
00640
00641 AREXPORT void ArSoundsQueue::removePendingItems(ItemType type)
00642 {
00643 lock();
00644 myQueue.remove_if<ItemComparator_WithType>(ItemComparator_WithType(type));
00645 unlock();
00646 }
00647
00648 AREXPORT string ArSoundsQueue::nextItem(ItemType type)
00649 {
00650 lock();
00651 for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00652 {
00653 if(type == (*i).type) {
00654 string found = (*i).data;
00655 unlock();
00656 return found;
00657 }
00658 }
00659 unlock();
00660 return "";
00661 }
00662
00663 AREXPORT string ArSoundsQueue::nextItem(int priority)
00664 {
00665 lock();
00666 for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00667 {
00668 if((*i).priority >= priority) {
00669 string found = (*i).data;
00670 unlock();
00671 return found;
00672 }
00673 }
00674 unlock();
00675 return "";
00676 }
00677
00678 AREXPORT string ArSoundsQueue::nextItem(ItemType type, int priority)
00679 {
00680 lock();
00681 for(list<Item>::const_iterator i = myQueue.begin(); i != myQueue.end(); i++)
00682 {
00683 if(type == (*i).type && (*i).priority >= priority) {
00684 string found = (*i).data;
00685 unlock();
00686 return found;
00687 }
00688 }
00689 unlock();
00690 return "";
00691 }
00692
00693