summaryrefslogtreecommitdiff
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
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
-rw-r--r--pjsip-apps/src/swig/pjsua2.i3
-rw-r--r--pjsip-apps/src/swig/python/test.py59
-rw-r--r--pjsip-apps/src/swig/symbols.i34
-rw-r--r--pjsip-apps/src/swig/symbols.lst1
-rw-r--r--pjsip/include/pjsua2/media.hpp139
-rw-r--r--pjsip/src/pjsua2/media.cpp163
6 files changed, 396 insertions, 3 deletions
diff --git a/pjsip-apps/src/swig/pjsua2.i b/pjsip-apps/src/swig/pjsua2.i
index 2cc41d4a..aff740b4 100644
--- a/pjsip-apps/src/swig/pjsua2.i
+++ b/pjsip-apps/src/swig/pjsua2.i
@@ -94,6 +94,9 @@ using namespace pj;
%template(SipMultipartPartVector) std::vector<pj::SipMultipartPart>;
%template(BuddyVector) std::vector<pj::Buddy*>;
%template(AudioMediaVector) std::vector<pj::AudioMedia*>;
+%template(ToneDescVector) std::vector<pj::ToneDesc>;
+%template(ToneDigitVector) std::vector<pj::ToneDigit>;
+%template(ToneDigitMapVector) std::vector<pj::ToneDigitMapDigit>;
%template(MediaFormatVector) std::vector<pj::MediaFormat*>;
%template(AudioDevInfoVector) std::vector<pj::AudioDevInfo*>;
%template(CodecInfoVector) std::vector<pj::CodecInfo*>;
diff --git a/pjsip-apps/src/swig/python/test.py b/pjsip-apps/src/swig/python/test.py
index dc805c77..24801ed6 100644
--- a/pjsip-apps/src/swig/python/test.py
+++ b/pjsip-apps/src/swig/python/test.py
@@ -1,5 +1,6 @@
import pjsua2 as pj
import sys
+import time
#
# Basic data structure test, to make sure basic struct
@@ -100,6 +101,61 @@ def ua_run_ua_test():
ep.libDestroy()
#
+# Tone generator
+#
+def ua_tonegen_test():
+ print "UA tonegen test.."
+ ep_cfg = pj.EpConfig()
+
+ ep = pj.Endpoint()
+ ep.libCreate()
+ ep.libInit(ep_cfg)
+ ep.libStart()
+
+ tonegen = pj.ToneGenerator()
+ tonegen.createToneGenerator()
+
+ tone = pj.ToneDesc()
+ tone.freq1 = 400
+ tone.freq2 = 600
+ tone.on_msec = 1000
+ tone.off_msec = 1000
+ tones = pj.ToneDescVector()
+ tones.append(tone)
+
+ digit = pj.ToneDigit()
+ digit.digit = '0'
+ digit.on_msec = 1000
+ digit.off_msec = 1000
+ digits = pj.ToneDigitVector()
+ digits.append(digit)
+
+ adm = ep.audDevManager()
+ spk = adm.getPlaybackDevMedia()
+
+ tonegen.play(tones, True)
+ tonegen.startTransmit(spk)
+ time.sleep(5)
+
+ tonegen.stop()
+ tonegen.playDigits(digits, True)
+ time.sleep(5)
+
+ dm = tonegen.getDigitMap()
+ print dm[0].digit
+ dm[0].freq1 = 400
+ dm[0].freq2 = 600
+ tonegen.setDigitMap(dm)
+
+ tonegen.stop()
+ tonegen.playDigits(digits, True)
+ time.sleep(5)
+
+ tonegen = None
+
+ ep.libDestroy()
+
+#
# main()
#
if __name__ == "__main__":
@@ -107,6 +163,7 @@ if __name__ == "__main__":
ua_run_test_exception()
ua_run_log_test()
ua_run_ua_test()
+ ua_tonegen_test()
sys.exit(0)
- \ No newline at end of file
+
diff --git a/pjsip-apps/src/swig/symbols.i b/pjsip-apps/src/swig/symbols.i
index 79146006..1e37d729 100644
--- a/pjsip-apps/src/swig/symbols.i
+++ b/pjsip-apps/src/swig/symbols.i
@@ -1,4 +1,5 @@
// This file is autogenerated by importsym script, do not modify!
+
typedef int pj_status_t;
enum pj_constants_ {PJ_SUCCESS = 0, PJ_TRUE = 1, PJ_FALSE = 0};
@@ -29,7 +30,7 @@ typedef struct pj_qos_params
pj_qos_wmm_prio wmm_prio;
} pj_qos_params;
-typedef enum pj_ssl_cipher {PJ_TLS_NULL_WITH_NULL_NULL = 0x00000000, PJ_TLS_RSA_WITH_NULL_MD5 = 0x00000001, PJ_TLS_RSA_WITH_NULL_SHA = 0x00000002, PJ_TLS_RSA_WITH_NULL_SHA256 = 0x0000003B, PJ_TLS_RSA_WITH_RC4_128_MD5 = 0x00000004, PJ_TLS_RSA_WITH_RC4_128_SHA = 0x00000005, PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x0000000A, PJ_TLS_RSA_WITH_AES_128_CBC_SHA = 0x0000002F, PJ_TLS_RSA_WITH_AES_256_CBC_SHA = 0x00000035, PJ_TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x0000003C, PJ_TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x0000003D, PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x0000000D, PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x00000010, PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x00000013, PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x00000016, PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x00000030, PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x00000031, PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x00000032, PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x00000033, PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x00000036, PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x00000037, PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x00000038, PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x00000039, PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x0000003E, PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x0000003F, PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x00000040, PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x00000067, PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x00000068, PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x00000069, PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x0000006A, PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x0000006B, PJ_TLS_DH_anon_WITH_RC4_128_MD5 = 0x00000018, PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x0000001B, PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x00000034, PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x0000003A, PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x0000006C, PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x0000006D, PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x00000003, PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x00000006, PJ_TLS_RSA_WITH_IDEA_CBC_SHA = 0x00000007, PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x00000008, PJ_TLS_RSA_WITH_DES_CBC_SHA = 0x00000009, PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0000000B, PJ_TLS_DH_DSS_WITH_DES_CBC_SHA = 0x0000000C, PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0000000E, PJ_TLS_DH_RSA_WITH_DES_CBC_SHA = 0x0000000F, PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x00000011, PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x00000012, PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x00000014, PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x00000015, PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x00000017, PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x00000019, PJ_TLS_DH_anon_WITH_DES_CBC_SHA = 0x0000001A, PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA = 0x0000001C, PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 0x0000001D, PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA = 0x0000001E, PJ_SSL_CK_RC4_128_WITH_MD5 = 0x00010080, PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5 = 0x00020080, PJ_SSL_CK_RC2_128_CBC_WITH_MD5 = 0x00030080, PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 = 0x00040080, PJ_SSL_CK_IDEA_128_CBC_WITH_MD5 = 0x00050080, PJ_SSL_CK_DES_64_CBC_WITH_MD5 = 0x00060040, PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5 = 0x000700C0} pj_ssl_cipher;
+typedef enum pj_ssl_cipher {PJ_TLS_UNKNOWN_CIPHER = -1, PJ_TLS_NULL_WITH_NULL_NULL = 0x00000000, PJ_TLS_RSA_WITH_NULL_MD5 = 0x00000001, PJ_TLS_RSA_WITH_NULL_SHA = 0x00000002, PJ_TLS_RSA_WITH_NULL_SHA256 = 0x0000003B, PJ_TLS_RSA_WITH_RC4_128_MD5 = 0x00000004, PJ_TLS_RSA_WITH_RC4_128_SHA = 0x00000005, PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x0000000A, PJ_TLS_RSA_WITH_AES_128_CBC_SHA = 0x0000002F, PJ_TLS_RSA_WITH_AES_256_CBC_SHA = 0x00000035, PJ_TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x0000003C, PJ_TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x0000003D, PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x0000000D, PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x00000010, PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x00000013, PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x00000016, PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x00000030, PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x00000031, PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x00000032, PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x00000033, PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x00000036, PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x00000037, PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x00000038, PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x00000039, PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x0000003E, PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x0000003F, PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x00000040, PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x00000067, PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x00000068, PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x00000069, PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x0000006A, PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x0000006B, PJ_TLS_DH_anon_WITH_RC4_128_MD5 = 0x00000018, PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x0000001B, PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x00000034, PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x0000003A, PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x0000006C, PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x0000006D, PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x00000003, PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x00000006, PJ_TLS_RSA_WITH_IDEA_CBC_SHA = 0x00000007, PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x00000008, PJ_TLS_RSA_WITH_DES_CBC_SHA = 0x00000009, PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0000000B, PJ_TLS_DH_DSS_WITH_DES_CBC_SHA = 0x0000000C, PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0000000E, PJ_TLS_DH_RSA_WITH_DES_CBC_SHA = 0x0000000F, PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x00000011, PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x00000012, PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x00000014, PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x00000015, PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x00000017, PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x00000019, PJ_TLS_DH_anon_WITH_DES_CBC_SHA = 0x0000001A, PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA = 0x0000001C, PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 0x0000001D, PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA = 0x0000001E, PJ_SSL_CK_RC4_128_WITH_MD5 = 0x00010080, PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5 = 0x00020080, PJ_SSL_CK_RC2_128_CBC_WITH_MD5 = 0x00030080, PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 = 0x00040080, PJ_SSL_CK_IDEA_128_CBC_WITH_MD5 = 0x00050080, PJ_SSL_CK_DES_64_CBC_WITH_MD5 = 0x00060040, PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5 = 0x000700C0} pj_ssl_cipher;
typedef enum pj_stun_nat_type {PJ_STUN_NAT_TYPE_UNKNOWN, PJ_STUN_NAT_TYPE_ERR_UNKNOWN, PJ_STUN_NAT_TYPE_OPEN, PJ_STUN_NAT_TYPE_BLOCKED, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP, PJ_STUN_NAT_TYPE_FULL_CONE, PJ_STUN_NAT_TYPE_SYMMETRIC, PJ_STUN_NAT_TYPE_RESTRICTED, PJ_STUN_NAT_TYPE_PORT_RESTRICTED} pj_stun_nat_type;
@@ -53,6 +54,35 @@ enum pjmedia_file_writer_option {PJMEDIA_FILE_WRITE_PCM = 0, PJMEDIA_FILE_WRITE_
enum pjmedia_file_player_option {PJMEDIA_FILE_NO_LOOP = 1};
+typedef struct pjmedia_tone_digit
+{
+ char digit;
+ short on_msec;
+ short off_msec;
+ short volume;
+} pjmedia_tone_digit;
+
+typedef struct pjmedia_tone_digit_map
+{
+ unsigned count;
+ struct
+ {
+ char digit;
+ short freq1;
+ short freq2;
+ } digits[16];
+} pjmedia_tone_digit_map;
+
+typedef struct pjmedia_tone_desc
+{
+ short freq1;
+ short freq2;
+ short on_msec;
+ short off_msec;
+ short volume;
+ short flags;
+} pjmedia_tone_desc;
+
typedef enum pjmedia_type {PJMEDIA_TYPE_NONE, PJMEDIA_TYPE_AUDIO, PJMEDIA_TYPE_VIDEO, PJMEDIA_TYPE_APPLICATION, PJMEDIA_TYPE_UNKNOWN} pjmedia_type;
typedef enum pjmedia_dir {PJMEDIA_DIR_NONE = 0, PJMEDIA_DIR_ENCODING = 1, PJMEDIA_DIR_CAPTURE = PJMEDIA_DIR_ENCODING, PJMEDIA_DIR_DECODING = 2, PJMEDIA_DIR_PLAYBACK = PJMEDIA_DIR_DECODING, PJMEDIA_DIR_RENDER = PJMEDIA_DIR_DECODING, PJMEDIA_DIR_ENCODING_DECODING = 3, PJMEDIA_DIR_CAPTURE_PLAYBACK = PJMEDIA_DIR_ENCODING_DECODING, PJMEDIA_DIR_CAPTURE_RENDER = PJMEDIA_DIR_ENCODING_DECODING} pjmedia_dir;
@@ -75,7 +105,7 @@ typedef enum pjsip_transport_type_e {PJSIP_TRANSPORT_UNSPECIFIED, PJSIP_TRANSPOR
enum pjsip_transport_flags_e {PJSIP_TRANSPORT_RELIABLE = 1, PJSIP_TRANSPORT_SECURE = 2, PJSIP_TRANSPORT_DATAGRAM = 4};
-typedef enum pjsip_transport_state {PJSIP_TP_STATE_CONNECTED, PJSIP_TP_STATE_DISCONNECTED} pjsip_transport_state;
+typedef enum pjsip_transport_state {PJSIP_TP_STATE_CONNECTED, PJSIP_TP_STATE_DISCONNECTED, PJSIP_TP_STATE_SHUTDOWN, PJSIP_TP_STATE_DESTROY} pjsip_transport_state;
typedef enum pjsip_ssl_method {PJSIP_SSL_UNSPECIFIED_METHOD = 0, PJSIP_TLSV1_METHOD = 31, PJSIP_SSLV2_METHOD = 20, PJSIP_SSLV3_METHOD = 30, PJSIP_SSLV23_METHOD = 23} pjsip_ssl_method;
diff --git a/pjsip-apps/src/swig/symbols.lst b/pjsip-apps/src/swig/symbols.lst
index 685c3713..b5e7b6e2 100644
--- a/pjsip-apps/src/swig/symbols.lst
+++ b/pjsip-apps/src/swig/symbols.lst
@@ -13,6 +13,7 @@ pjmedia/vid_stream.h pjmedia_vid_stream_rc_method
pjmedia-videodev/videodev.h pjmedia_vid_dev_index pjmedia_vid_dev_std_index
pjmedia-audiodev/audiodev.h pjmedia_aud_dev_route pjmedia_aud_dev_cap
pjmedia/wav_port.h pjmedia_file_writer_option pjmedia_file_player_option
+pjmedia/tonegen.h pjmedia_tone_digit pjmedia_tone_digit_map pjmedia_tone_desc
pjmedia/types.h pjmedia_type pjmedia_dir pjmedia_tp_proto
pjmedia/format.h pjmedia_format_id
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;