From 14e7d7f5b4780e25c5cc924096bc862e04278ef2 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 19 May 2014 05:51:10 +0000 Subject: 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 --- pjsip/include/pjsua2/media.hpp | 139 +++++++++++++++++++++++++++++++++++ pjsip/src/pjsua2/media.cpp | 163 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+) (limited to 'pjsip') 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 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 ToneDigitVector; + +/** + * A digit in tone digit map + */ +struct ToneDigitMapDigit +{ +public: + string digit; + int freq1; + int freq2; +}; + +/** + * Tone digit map + */ +typedef std::vector 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 @@ -422,6 +422,169 @@ AudioMediaRecorder* AudioMediaRecorder::typecastFromAudioMedia( return static_cast(media); } +/////////////////////////////////////////////////////////////////////////////// + +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; icount; ++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