summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2014-05-19 05:51:10 +0000
committerBenny Prijono <bennylp@teluu.com>2014-05-19 05:51:10 +0000
commit14e7d7f5b4780e25c5cc924096bc862e04278ef2 (patch)
treea89baeb120c86e94f3686fa5b5cc4db3beea3004 /pjsip
parent1f73736beb1dadc032552bbec4c01272a499cc24 (diff)
Fixed #1767: Tone generation API in pjsua2 and SWIG wrappers
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4845 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsua2/media.hpp139
-rw-r--r--pjsip/src/pjsua2/media.cpp163
2 files changed, 302 insertions, 0 deletions
diff --git a/pjsip/include/pjsua2/media.hpp b/pjsip/include/pjsua2/media.hpp
index 2f3a6855..99dd532e 100644
--- a/pjsip/include/pjsua2/media.hpp
+++ b/pjsip/include/pjsua2/media.hpp
@@ -511,6 +511,145 @@ private:
int recorderId;
};
+/**
+ * Tone descriptor (abstraction for pjmedia_tone_desc)
+ */
+class ToneDesc : public pjmedia_tone_desc
+{
+public:
+ ToneDesc()
+ {
+ pj_bzero(this, sizeof(*this));
+ }
+ ~ToneDesc() {}
+};
+
+/**
+ * Array of tone descriptor.
+ */
+typedef std::vector<ToneDesc> ToneDescVector;
+
+/**
+ * Tone digit (abstraction for pjmedia_tone_digit)
+ */
+class ToneDigit : public pjmedia_tone_digit
+{
+public:
+ ToneDigit()
+ {
+ pj_bzero(this, sizeof(*this));
+ }
+ ~ToneDigit() {}
+};
+
+/**
+ * Array of tone digits.
+ */
+typedef std::vector<ToneDigit> ToneDigitVector;
+
+/**
+ * A digit in tone digit map
+ */
+struct ToneDigitMapDigit
+{
+public:
+ string digit;
+ int freq1;
+ int freq2;
+};
+
+/**
+ * Tone digit map
+ */
+typedef std::vector<ToneDigitMapDigit> ToneDigitMapVector;
+
+/**
+ * Tone generator.
+ */
+class ToneGenerator : public AudioMedia
+{
+public:
+ /**
+ * Constructor.
+ */
+ ToneGenerator();
+
+ /**
+ * Destructor.
+ */
+ ~ToneGenerator();
+
+ /**
+ * Create tone generator.
+ */
+ void createToneGenerator(unsigned clock_rate = 16000,
+ unsigned channel_count = 1) throw(Error);
+
+ /**
+ * Check if the tone generator is still busy producing some tones.
+ * @return Non-zero if busy.
+ */
+ bool isBusy() const;
+
+ /**
+ * Instruct the tone generator to stop current processing.
+ */
+ void stop() throw(Error);
+
+ /**
+ * Rewind the playback. This will start the playback to the first
+ * tone in the playback list.
+ */
+ void rewind() throw(Error);
+
+ /**
+ * Instruct the tone generator to play single or dual frequency tones
+ * with the specified duration. The new tones will be appended to
+ * currently playing tones, unless stop() is called before calling this
+ * function. The playback will begin as soon as the tone generator is
+ * connected to other media.
+ *
+ * @param tones Array of tones to be played.
+ * @param loop Play the tone in a loop.
+ */
+ void play(const ToneDescVector &tones,
+ bool loop=false) throw(Error);
+
+ /**
+ * Instruct the tone generator to play multiple MF digits with each of
+ * the digits having individual ON/OFF duration. Each of the digit in the
+ * digit array must have the corresponding descriptor in the digit map.
+ * The new tones will be appended to currently playing tones, unless
+ * stop() is called before calling this function. The playback will begin
+ * as soon as the tone generator is connected to a sink media.
+ *
+ * @param digits Array of MF digits.
+ * @param loop Play the tone in a loop.
+ */
+ void playDigits(const ToneDigitVector &digits,
+ bool loop=false) throw(Error);
+
+ /**
+ * Get the digit-map currently used by this tone generator.
+ *
+ * @return The digitmap currently used by the tone generator
+ */
+ ToneDigitMapVector getDigitMap() const throw(Error);
+
+ /**
+ * Set digit map to be used by the tone generator.
+ *
+ * @param digit_map Digitmap to be used by the tone generator.
+ */
+ void setDigitMap(const ToneDigitMapVector &digit_map) throw(Error);
+
+private:
+ pj_pool_t *pool;
+ pjmedia_port *tonegen;
+ pjmedia_tone_digit_map digitMap;
+};
+
+
/*************************************************************************
* Sound device management
*/
diff --git a/pjsip/src/pjsua2/media.cpp b/pjsip/src/pjsua2/media.cpp
index a6255ec2..5b149312 100644
--- a/pjsip/src/pjsua2/media.cpp
+++ b/pjsip/src/pjsua2/media.cpp
@@ -423,6 +423,169 @@ AudioMediaRecorder* AudioMediaRecorder::typecastFromAudioMedia(
}
///////////////////////////////////////////////////////////////////////////////
+
+ToneGenerator::ToneGenerator()
+: pool(NULL), tonegen(NULL)
+{
+}
+
+ToneGenerator::~ToneGenerator()
+{
+ if (tonegen) {
+ unregisterMediaPort();
+ pjmedia_port_destroy(tonegen);
+ tonegen = NULL;
+ }
+ if (pool) {
+ pj_pool_release(pool);
+ pool = NULL;
+ }
+}
+
+void ToneGenerator::createToneGenerator(unsigned clock_rate,
+ unsigned channel_count) throw(Error)
+{
+ pj_status_t status;
+
+ if (pool) {
+ PJSUA2_RAISE_ERROR(PJ_EEXISTS);
+ }
+
+ pool = pjsua_pool_create( "tonegen%p", 512, 512);
+ if (!pool) {
+ PJSUA2_RAISE_ERROR(PJ_ENOMEM);
+ }
+
+ status = pjmedia_tonegen_create( pool, clock_rate, channel_count,
+ clock_rate * 20 / 1000, 16,
+ 0, &tonegen);
+ if (status != PJ_SUCCESS) {
+ PJSUA2_RAISE_ERROR(status);
+ }
+
+ registerMediaPort(tonegen);
+}
+
+bool ToneGenerator::isBusy() const
+{
+ return tonegen && pjmedia_tonegen_is_busy(tonegen) != 0;
+}
+
+void ToneGenerator::stop() throw(Error)
+{
+ pj_status_t status;
+
+ if (!tonegen) {
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+ }
+
+ status = pjmedia_tonegen_stop(tonegen);
+ PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::stop()");
+}
+
+void ToneGenerator::rewind() throw(Error)
+{
+ pj_status_t status;
+
+ if (!tonegen) {
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+ }
+
+ status = pjmedia_tonegen_rewind(tonegen);
+ PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::rewind()");
+}
+
+void ToneGenerator::play(const ToneDescVector &tones,
+ bool loop) throw(Error)
+{
+ pj_status_t status;
+
+ if (!tonegen) {
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+ }
+ if (tones.size() == 0) {
+ PJSUA2_RAISE_ERROR(PJ_EINVAL);
+ }
+
+ status = pjmedia_tonegen_play(tonegen, tones.size(), &tones[0],
+ loop? PJMEDIA_TONEGEN_LOOP : 0);
+ PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::play()");
+}
+
+void ToneGenerator::playDigits(const ToneDigitVector &digits,
+ bool loop) throw(Error)
+{
+ pj_status_t status;
+
+ if (!tonegen) {
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+ }
+ if (digits.size() == 0) {
+ PJSUA2_RAISE_ERROR(PJ_EINVAL);
+ }
+
+ status = pjmedia_tonegen_play_digits(tonegen, digits.size(), &digits[0],
+ loop? PJMEDIA_TONEGEN_LOOP : 0);
+ PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::playDigits()");
+}
+
+ToneDigitMapVector ToneGenerator::getDigitMap() const throw(Error)
+{
+ const pjmedia_tone_digit_map *pdm;
+ ToneDigitMapVector tdm;
+ unsigned i;
+ pj_status_t status;
+
+ if (!tonegen) {
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+ }
+
+ status = pjmedia_tonegen_get_digit_map(tonegen, &pdm);
+ PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::getDigitMap()");
+
+ for (i=0; i<pdm->count; ++i) {
+ ToneDigitMapDigit d;
+ char str_digit[2];
+
+ str_digit[0] = pdm->digits[i].digit;
+ str_digit[1] = '\0';
+
+ d.digit = str_digit;
+ d.freq1 = pdm->digits[i].freq1;
+ d.freq2 = pdm->digits[i].freq2;
+
+ tdm.push_back(d);
+ }
+
+ return tdm;
+}
+
+void ToneGenerator::setDigitMap(const ToneDigitMapVector &digit_map)
+ throw(Error)
+{
+ unsigned i;
+ pj_status_t status;
+
+ if (!tonegen) {
+ PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
+ }
+
+ digitMap.count = digit_map.size();
+ if (digitMap.count > PJ_ARRAY_SIZE(digitMap.digits))
+ digitMap.count = PJ_ARRAY_SIZE(digitMap.digits);
+
+ for (i=0; i<digitMap.count; ++i) {
+ digitMap.digits[i].digit = digit_map[i].digit.c_str()[0];
+ digitMap.digits[i].freq1 = digit_map[i].freq1;
+ digitMap.digits[i].freq2 = digit_map[i].freq2;
+ }
+
+ status = pjmedia_tonegen_set_digit_map(tonegen, &digitMap);
+ PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::setDigitMap()");
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
void AudioDevInfo::fromPj(const pjmedia_aud_dev_info &dev_info)
{
name = dev_info.name;