558 lines
18 KiB
C++
558 lines
18 KiB
C++
/*
|
|
Adept MobileRobots Robotics Interface for Applications (ARIA)
|
|
Copyright (C) 2004, 2005 ActivMedia Robotics LLC
|
|
Copyright (C) 2006, 2007, 2008, 2009, 2010 MobileRobots Inc.
|
|
Copyright (C) 2011, 2012, 2013 Adept Technology
|
|
|
|
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
|
|
|
|
If you wish to redistribute ARIA under different terms, contact
|
|
Adept MobileRobots for information about a commercial version of ARIA at
|
|
robots@mobilerobots.com or
|
|
Adept MobileRobots, 10 Columbia Drive, Amherst, NH 03031; +1-603-881-7960
|
|
*/
|
|
|
|
#ifndef ARSOUNDSQUEUE_H
|
|
#define ARSOUNDSQUEUE_H
|
|
|
|
|
|
#include "ariaTypedefs.h"
|
|
#include "ArASyncTask.h"
|
|
#include "ArCondition.h"
|
|
#include "ArFunctor.h"
|
|
#include "ArSpeech.h"
|
|
#include <list>
|
|
#include <string>
|
|
#include <set>
|
|
|
|
/**
|
|
* @brief This class manages a queue of items to play as WAV files or as text to
|
|
* speak using a speech synthesizer.
|
|
*
|
|
* The actual playback of sound and speech is done through callbacks
|
|
* (which you can supply in the constructor or afterwards).
|
|
* Some callbacks you can use are provided by classes like ArSoundPlayer (for sound file
|
|
* playback) and ArFestival (from the ArSpeechSynth_Festival library) and ArCepstral
|
|
* (from the ArSpeechSynth_Cepstral librrary) for speech synthesis.
|
|
*
|
|
* Add sound files to the queue with play(), and text to speak with
|
|
* speak(). Use runAsync() to run
|
|
* the processing thread in the background, or run() to run synchronously in the
|
|
* current thread.
|
|
*
|
|
*
|
|
* @sa ArSoundPlayer
|
|
* @sa @ref soundsQueueExample.cpp
|
|
*
|
|
@ingroup UtilityClasses
|
|
*/
|
|
|
|
class ArSoundsQueue: public ArASyncTask
|
|
{
|
|
public:
|
|
|
|
/** Opaque identifier for the type of an item in the sound queue. Not used
|
|
* during processing, but may be used to search for items in the queue. */
|
|
enum ItemType { SPEECH, SOUND_FILE, SOUND_DATA, OTHER };
|
|
|
|
/** Callback for playing a queue item. First argument is the "data", second is
|
|
* item type-specific "parameters". Return true to continue processing more
|
|
* callbacks in a list, false to cancel processing.
|
|
*/
|
|
typedef ArRetFunctor2<bool, const char*, const char*> PlayItemFunctor;
|
|
typedef ArFunctor InterruptItemFunctor;
|
|
|
|
/** Callback types for determining whether to commence playing an item,
|
|
* or skipping it.
|
|
*/
|
|
typedef ArRetFunctor<bool> PlaybackConditionFunctor;
|
|
|
|
/** A sound item in the queue, with callbacks for dealing with the
|
|
* item and the data to pass to those callbacks.
|
|
*/
|
|
class Item {
|
|
public:
|
|
std::string data;
|
|
ItemType type;
|
|
std::string params;
|
|
int priority;
|
|
std::list<InterruptItemFunctor*> interruptCallbacks;
|
|
std::list<PlayItemFunctor*> playCallbacks;
|
|
std::list<ArFunctor*> doneCallbacks;
|
|
std::list<PlaybackConditionFunctor*> playbackConditionCallbacks;
|
|
|
|
AREXPORT Item();
|
|
AREXPORT Item(std::string _data, ItemType _type, std::string _params = "", int priority = 0);
|
|
AREXPORT Item(std::string _data, ItemType _type, std::string _params, int priority, std::list<PlayItemFunctor*> callbacks);
|
|
|
|
AREXPORT Item(const ArSoundsQueue::Item& toCopy);
|
|
|
|
/** Note: does not compare priority! */
|
|
bool operator==(const Item& other) const
|
|
{
|
|
return (other.type == type && other.params == params && other.data == data);
|
|
}
|
|
|
|
/** Called by sound queue to play this item by calling play callbacks. */
|
|
void play();
|
|
|
|
/** Called by sound queue to interrupt this item by calling interrupt
|
|
* callbacks. */
|
|
void interrupt();
|
|
|
|
/** Called by sound queue thread after playing this item by calling done
|
|
* callbacks. */
|
|
void done();
|
|
};
|
|
|
|
|
|
AREXPORT ArSoundsQueue();
|
|
|
|
/** @deprecated
|
|
* @see addInitCallback()
|
|
* @see setSpeakCallback()
|
|
* @see setInterruptSpeechCallback()
|
|
* @see setPlayFileCallback
|
|
* @see setInterruptFileCallback
|
|
*/
|
|
AREXPORT ArSoundsQueue(ArRetFunctor<bool> *speakInitCB,
|
|
PlayItemFunctor *speakCB = 0,
|
|
InterruptItemFunctor *interruptSpeechCB = 0,
|
|
ArRetFunctor<bool> *playInitCB = 0,
|
|
PlayItemFunctor *playFileCB = 0,
|
|
InterruptItemFunctor *interruptFileCB = 0);
|
|
|
|
/** Set default speech and WAV file callbacks for use
|
|
* by the convenience methods speak() and play().
|
|
* Omit the last three arguments to use
|
|
* callbacks into ArSoundPlayer.
|
|
*/
|
|
AREXPORT ArSoundsQueue(ArSpeechSynth* speechSynthesizer,
|
|
ArRetFunctor<bool> *playInitCB = 0,
|
|
PlayItemFunctor *playFileCB = 0,
|
|
InterruptItemFunctor *interruptFileCB = 0);
|
|
|
|
AREXPORT virtual ~ArSoundsQueue();
|
|
|
|
/** Add a callback to be called when the sound queue begins to run in its
|
|
* thread. (For example, the speech synthesizers must be initialized in
|
|
* the same thread as they are used.)
|
|
*/
|
|
AREXPORT void addInitCallback(ArRetFunctor<bool> *cb) {
|
|
myInitCallbacks.push_back(cb);
|
|
}
|
|
|
|
/** @deprecated */
|
|
AREXPORT void setSpeakInitCallback(ArRetFunctor<bool> *cb) {
|
|
addInitCallback(cb);
|
|
}
|
|
|
|
/** Add (a copy of) the given item to the queue. */
|
|
AREXPORT void addItem(ArSoundsQueue::Item item);
|
|
|
|
/** Create a new queue item with the given data and add to the queue. */
|
|
AREXPORT void addItem(ItemType type, const char* data, std::list<PlayItemFunctor*> callbacks, int priority = 0, const char* params = 0);
|
|
|
|
/** Return true if all initialization callbacks have completed, false
|
|
* otherwise.
|
|
*/
|
|
AREXPORT bool isInitialized()
|
|
{
|
|
return myInitialized;
|
|
}
|
|
|
|
/** @deprecated
|
|
* @see isPlaying()
|
|
*/
|
|
AREXPORT bool isSpeakingOrPlaying(void) { return (myPlayingSomething); }
|
|
|
|
/// Returns true if an item is currently being played.
|
|
AREXPORT bool isPlaying() { return myPlayingSomething; }
|
|
|
|
|
|
/** @deprecated
|
|
* @return true if any queue item is being played.
|
|
* @see isPlaying()
|
|
*/
|
|
AREXPORT bool isSpeaking() { return myPlayingSomething; }
|
|
|
|
|
|
/// Begin processing the sounds queue synchronously (in this thread; does not return)
|
|
AREXPORT void run(void) { runInThisThread(); }
|
|
|
|
/// Begin processing the sounds queue in a background thread
|
|
AREXPORT void runAsync(void) { create(false); }
|
|
|
|
/** Temporarily stop processing the sounds queue. (Any currently playing sound
|
|
or speech utterance will finish. The sound device may remain open.)
|
|
*/
|
|
AREXPORT void pause();
|
|
|
|
/// Resume processing the sounds queue
|
|
AREXPORT void resume() ;
|
|
|
|
/** @return true if the queue is paused */
|
|
AREXPORT bool isPaused();
|
|
|
|
/// If sound is currently being played or speech is being spoken, interrupt it. (but continue processing the queue). SoundFinished callbacks will not be called.
|
|
AREXPORT void interrupt();
|
|
|
|
/** Empty the queue. If a sound is currently playing, it will not be interrupted.
|
|
QueueEmpty callbacks will be called. SoundFinished callbacks will not be
|
|
called.
|
|
*/
|
|
AREXPORT void clearQueue();
|
|
|
|
/** End the processing thread.
|
|
* This function is deprecated. Use stopRunning() instead.
|
|
* @deprecated
|
|
This shuts down the sound queue completely. To
|
|
temporarily stop the queue processing, use pause(). To interrupt the
|
|
currently playing sound, use interrupt().
|
|
*/
|
|
AREXPORT void stop() ;
|
|
|
|
/// Create and return a new a functor for pause(), which other modules can use to pause this sounds
|
|
/// queue.
|
|
AREXPORT ArFunctor* getPauseCallback()
|
|
{
|
|
return new ArFunctorC<ArSoundsQueue>(this, &ArSoundsQueue::pause);
|
|
}
|
|
|
|
/// Create and return a new functor for resume(), which other modules can use to resume this
|
|
/// sounds queue.
|
|
AREXPORT ArFunctor* getResumeCallback()
|
|
{
|
|
return new ArFunctorC<ArSoundsQueue>(this, &ArSoundsQueue::resume);
|
|
}
|
|
|
|
|
|
/// Get the current size of the speech/sound playback queue.
|
|
AREXPORT size_t getCurrentQueueSize()
|
|
{
|
|
size_t size;
|
|
lock();
|
|
size = myQueue.size();
|
|
unlock();
|
|
return size;
|
|
}
|
|
|
|
/** Add a callback functor to be invoked when playback of one sound or speech utterance starts. */
|
|
AREXPORT void addSoundStartedCallback(ArFunctor* f)
|
|
{
|
|
myStartPlaybackCBList.push_back(f);
|
|
}
|
|
|
|
/** Remove a callback functor to be invoked when playback one sound or speech utterance starts. */
|
|
AREXPORT void remSoundStartedCallback(ArFunctor* f)
|
|
{
|
|
myStartPlaybackCBList.remove(f);
|
|
}
|
|
|
|
/** Add a callback functor to be invoked when plackback of one sound or speech
|
|
* utterance finishes */
|
|
AREXPORT void addSoundFinishedCallback(ArFunctor* f)
|
|
{
|
|
myEndPlaybackCBList.push_back(f);
|
|
}
|
|
|
|
/** Remove a callback functor to be invoked when plackback of one sound or
|
|
* speech utterance finishes. */
|
|
AREXPORT void remSoundFinishedCallback(ArFunctor* f)
|
|
{
|
|
myEndPlaybackCBList.remove(f);
|
|
}
|
|
|
|
/** Add a callback functor to be invoked when playback of one sound or speech utterance starts. */
|
|
AREXPORT void addSoundItemStartedCallback(
|
|
ArFunctor1<ArSoundsQueue::Item> *f)
|
|
{
|
|
myStartItemPlaybackCBList.push_back(f);
|
|
}
|
|
|
|
/** Remove a callback functor to be invoked when playback one sound or speech utterance starts. */
|
|
AREXPORT void remSoundItemStartedCallback(
|
|
ArFunctor1<ArSoundsQueue::Item> *f)
|
|
{
|
|
myStartItemPlaybackCBList.remove(f);
|
|
}
|
|
|
|
/** Add a callback functor to be invoked when plackback of one sound or speech
|
|
* utterance finishes */
|
|
AREXPORT void addSoundItemFinishedCallback(
|
|
ArFunctor1<ArSoundsQueue::Item> *f)
|
|
{
|
|
myEndItemPlaybackCBList.push_back(f);
|
|
}
|
|
|
|
/** Remove a callback functor to be invoked when plackback of one sound or
|
|
* speech utterance finishes. */
|
|
AREXPORT void remSoundItemFinishedCallback(
|
|
ArFunctor1<ArSoundsQueue::Item> *f)
|
|
{
|
|
myEndItemPlaybackCBList.remove(f);
|
|
}
|
|
|
|
/** Add a callback functor to be invoked when a the sound queue becomes
|
|
* non-empty, that is, when a block of sounds/speech utterances begins.
|
|
*/
|
|
AREXPORT void addQueueNonemptyCallback(ArFunctor* f)
|
|
{
|
|
myQueueNonemptyCallbacks.push_back(f);
|
|
}
|
|
|
|
/** Remove a functor added by addQueueNonemptyCallback(). */
|
|
AREXPORT void remQueueNonemptyCallback(ArFunctor* f)
|
|
{
|
|
myQueueNonemptyCallbacks.remove(f);
|
|
}
|
|
|
|
/** Add a callback functor to be invoked when the sound queue becomes empty
|
|
* and the last sound has finished playing,
|
|
* that is, when a block of sounds/speech utterances ends. This will not
|
|
* be called when the sound queue first begins running.
|
|
*/
|
|
AREXPORT void addQueueEmptyCallback(ArFunctor* f)
|
|
{
|
|
myQueueEmptyCallbacks.push_back(f);
|
|
}
|
|
|
|
/** Remove a functor added by addQueueEmptyCallback() */
|
|
AREXPORT void remQueueEmptyCallback(ArFunctor* f)
|
|
{
|
|
myQueueEmptyCallbacks.remove(f);
|
|
}
|
|
|
|
|
|
|
|
/** Find items waiting in the queue. This is mainly useful in finding
|
|
* speech text.
|
|
* @param item Item to search for.
|
|
* @return A set of positions in the queue. 1 indicates the next sound that will
|
|
* play, followed by 2, etc.
|
|
* @note You have a potential race condition if an item is removed from the queue
|
|
* after this method returns, but before you on the information returned.
|
|
* For best results, pause the sound queue while using this information.
|
|
*/
|
|
AREXPORT std::set<int> findPendingItems(const char* item);
|
|
|
|
/** Remove pending items with the given data and type. */
|
|
AREXPORT void removePendingItems(const char* item, ItemType type);
|
|
|
|
/** Remove pending items with the given data. */
|
|
AREXPORT void removePendingItems(const char* data);
|
|
|
|
/** Remove pending items with a priority less than that given. */
|
|
AREXPORT void removePendingItems(int priority);
|
|
|
|
/** Remove pending items with priority less the given priority and with the given type. */
|
|
AREXPORT void removePendingItems(int priority, ItemType type);
|
|
|
|
/** Remove pending items with the given type. */
|
|
AREXPORT void removePendingItems(ItemType type);
|
|
|
|
/** Remove pending and current items with a priority less than that given. */
|
|
AREXPORT void removeItems(int priority);
|
|
|
|
/** Removes pending and current items with the same data and type as the given item **/
|
|
AREXPORT void removeItems(Item item);
|
|
|
|
AREXPORT std::string nextItem(ItemType type);
|
|
AREXPORT std::string nextItem(int priority);
|
|
AREXPORT std::string nextItem(ItemType type, int priority);
|
|
|
|
/// Convenience methods for special speech synthesis and WAV file queue items:
|
|
//@{
|
|
|
|
/**
|
|
* As a convenience, you may set a "default" speech synthesis callback,
|
|
* and then simply use the speak() method to add a speech item to the queue
|
|
* with those callbacks.
|
|
* @sa Item
|
|
*/
|
|
AREXPORT void setSpeakCallback(PlayItemFunctor *cb) {
|
|
myDefaultSpeakCB = cb;
|
|
}
|
|
|
|
/** Set the "default" callback to interrupt a current speech utterance, used
|
|
* by speak()
|
|
* @sa Item
|
|
*/
|
|
AREXPORT void setInterruptSpeechCallback(InterruptItemFunctor *cb) {
|
|
myDefaultInterruptSpeechCB = cb;
|
|
}
|
|
|
|
/** As a convenience, you may set a "default" WAV file playback callback,
|
|
* and then simply use the play() method to add the file to the queue with
|
|
* this callback.
|
|
* @sa Item
|
|
*/
|
|
AREXPORT void setPlayFileCallback(PlayItemFunctor *cb) {
|
|
myDefaultPlayFileCB = cb;
|
|
}
|
|
|
|
/** @deprecated use setPlayFileCallback() */
|
|
AREXPORT void setPlayWavFileCallback(PlayItemFunctor* cb) {
|
|
setPlayFileCallback(cb);
|
|
}
|
|
|
|
/** Set the "default" callback to interrupt current wav file playback, for use
|
|
* by the play() convenience method.
|
|
* @sa Item
|
|
*/
|
|
AREXPORT void setInterruptFileCallback(InterruptItemFunctor *cb) {
|
|
myDefaultInterruptFileCB = cb;
|
|
}
|
|
|
|
/** @deprecated use setInterruptFileCallback() */
|
|
AREXPORT void setInterruptWavFileCallback(InterruptItemFunctor* cb) {
|
|
setInterruptFileCallback(cb);
|
|
}
|
|
|
|
|
|
/** Add text string item to the queue for speech synthesis. The text will be
|
|
* sent to the "speak" callback, if set, otherwise the SynthesiseToSound and
|
|
* PlaySynthesizedSound callbacks are used, if set.
|
|
*/
|
|
AREXPORT void speak(const char *str);
|
|
|
|
/** Add a sound file to the queue for default sound file playback. */
|
|
AREXPORT void play(const char *filename);
|
|
|
|
#if !(defined(WIN32) && defined(_MANAGED)) && !defined(SWIG)
|
|
|
|
/** Add a formatted text string (like printf) to the queue configured for default speech
|
|
* synthesis. When reached in the queue while running, the text will be
|
|
* sent to the "speak" callback, if set, otherwise, the "SythesizeToSound" and
|
|
* "PlaySynthesizedSound" callbacks will be used (if they are set.)
|
|
*
|
|
* @param fmt Format string.
|
|
* @param ... Arguments to format into the format string.
|
|
*/
|
|
AREXPORT void speakf(const char *fmt, ...);
|
|
|
|
|
|
/** Speak with alternate voice. */
|
|
AREXPORT void speakWithVoice(const char* voice, const char* fmt, ...);
|
|
|
|
/** Speak with alternate priority. */
|
|
AREXPORT void speakWithPriority(int priority, const char* fmt, ...);
|
|
|
|
/** Add a sound file to the queue for default sound file playback.
|
|
*
|
|
* @param filename_fmt Format string for determining the filename of the WAV
|
|
* file, same as printf().
|
|
* @param ... If given, arguments to format into the format string.
|
|
*/
|
|
AREXPORT void playf(const char *filename_fmt, ...);
|
|
|
|
#endif // MS Managed C++ or SWIG
|
|
|
|
/** Return an item set up for speech with previously set default speech
|
|
* callbacks.
|
|
* @param speech Text to speak (optional)
|
|
* @see setSpeechCallback()
|
|
* @see addItem()
|
|
*/
|
|
AREXPORT ArSoundsQueue::Item createDefaultSpeechItem(const char* speech = 0);
|
|
|
|
/** Return an item set up for sound file playback with previously set default
|
|
* play callbacks.
|
|
* @param filename Filename to set (optional)
|
|
* @see setPlayFileCallback()
|
|
* @see addItem()
|
|
*/
|
|
AREXPORT ArSoundsQueue::Item createDefaultFileItem(const char* filename = 0);
|
|
|
|
//@}
|
|
|
|
/** Set a playback condition functor used for default speech and sound file
|
|
* items. Set to NULL to clear. */
|
|
AREXPORT void setDefaultPlayConditionCB(PlaybackConditionFunctor* f) {
|
|
myDefaultPlayConditionCB = f;
|
|
}
|
|
|
|
/// main function for thread
|
|
/** @internal */
|
|
AREXPORT virtual void *runThread(void *arg);
|
|
|
|
protected:
|
|
bool myInitialized;
|
|
std::list<Item> myQueue;
|
|
ArMutex myQueueMutex;
|
|
void lock() {
|
|
myQueueMutex.lock();
|
|
}
|
|
void unlock() {
|
|
myQueueMutex.unlock();
|
|
}
|
|
bool tryLock() {
|
|
return myQueueMutex.tryLock();
|
|
}
|
|
|
|
/// Functors to invoke when we start running in our thread
|
|
std::list< ArRetFunctor<bool>* > myInitCallbacks;
|
|
|
|
bool myPlayingSomething;
|
|
Item myLastItem; ///< The current or most recent item played.
|
|
|
|
/// Used by speak() and play() convenience methods:
|
|
//@{
|
|
PlayItemFunctor *myDefaultSpeakCB;
|
|
InterruptItemFunctor *myDefaultInterruptSpeechCB;
|
|
PlayItemFunctor *myDefaultPlayFileCB;
|
|
InterruptItemFunctor *myDefaultInterruptFileCB;
|
|
//@}
|
|
|
|
int myPauseRequestCount; ///< Semaphore for doing pausing and resuming of the queue
|
|
ArCondition myPausedCondition; ///< Condition variable used by the thread to pause
|
|
|
|
/// Functors to invoke during queue processing
|
|
//@{
|
|
std::list<ArFunctor*> myStartPlaybackCBList;
|
|
std::list<ArFunctor*> myEndPlaybackCBList;
|
|
std::list<ArFunctor1<ArSoundsQueue::Item> *> myStartItemPlaybackCBList;
|
|
std::list<ArFunctor1<ArSoundsQueue::Item> *> myEndItemPlaybackCBList;
|
|
std::list<ArFunctor*> myQueueNonemptyCallbacks;
|
|
std::list<ArFunctor*> myQueueEmptyCallbacks;
|
|
//@}
|
|
|
|
PlaybackConditionFunctor* myDefaultPlayConditionCB; ///< Used when creating default configured speech and sound file items
|
|
|
|
/// Invoke each functor in a list
|
|
void invokeCallbacks(const std::list<ArFunctor*>& lst);
|
|
|
|
/// Invoke each functor in a list, but stop if any of them return false.
|
|
void invokeCallbacks(const std::list<ArRetFunctor<bool>*>& lst);
|
|
|
|
/** push item onto queue
|
|
* @sa addItem()
|
|
*/
|
|
//@{
|
|
void pushQueueItem(Item item);
|
|
void pushQueueItem_NoLock(Item item);
|
|
//@}
|
|
|
|
/** Pop item from queue and return it */
|
|
//@{
|
|
Item popQueueItem();
|
|
Item popQueueItem_NoLock();
|
|
//@}
|
|
|
|
};
|
|
|
|
#endif
|
|
|