đây cũng là các ứng dụng trong Asterisk, và các ứng dụng này ựược hỗ trợ trong thư viện Asterisk dot net với mục ựắch ựiều khiển Asterisk.
1 Answer() Nhận cuộc gọi
2 Hangup() Kết thúc cuộc gọi
3 SetAutoHangup(int time)
Tự ựộng kết thúc cuộc gọi sau khoảng thời gian time ( tắnh bằng giây ) .
4 SetCallerId(string callerId)
đặt callerId cho người gọi trên kênh thoại hiện thời . 5 PlayMusicOnHold() Thực hiện chức năng Music On Hold
6 GetChannelStatus() Cho biết trạng thái kênh thoại , kết quả trả về là giá trị số nguyên như sau :
0 Kênh thoại rảnh, có thể gọi .
1 Kênh thoại rảnh , nhưng ựã bị ựặt trước , không thể gọi 2 Kênh thoại không có tone ( offhook )
3 Số ựã ựược gọi
4 Line ựang reo chuông 5 đầu cuối ựang reo chuông 6 Line ựang nhấc máy 7 Line bận
7 GetData(string file, long timeout, int maxDigits)
Hàm này sẽ ra lệnh cho Asterisk phát file âm thanh. Trong thời gian phát âm thanh , người gọi có thể nhập số vào và kết thúc bằng dấu # . Nếu hết thời gian chờ timeout (ms) thì kênh thoại sẽ kết thúc . maxDigits là số tối ựa người gọi có thể nhập vào .
8 GetOption(string file, string escapeDigits, int timeout)
Hàm này sẽ ra lệnh cho Asterisk phát file âm thanh. Trong thời gian phát âm thanh , nếu người gọi nhấn một phắm trùng với escapeDigits thì hàm này sẽ trả lại kết quả là phắm người gọi ựã bấm. Nếu hết thời gian timeout mà không có phắm nào ựược nhấn thì cuộc gọi sẽ kết thúc. 9 Exec(string
application, string options)
Thực thi một lệnh trong Asterisk . Application là tên chương trình của Asterisk cần thực thi , options là thông số của chương trình . Vắ dụ ựể thực hiện lệnh
Dial(SIP/1000) , ta viết như sau : Exec(ỘDialỢ, ỘSIP/1000Ợ)
10 SetContext(string context)
Chuyển ựến context trong Dialplan khi kết thúc AGI Script
11 SetExtension(string extension)
Chuyển ựến extension trong Dialplan khi kết thúc AGI Script
12 SetPriority(int priority)
Chuyển ựến priority trong Dialplan khi kết thúc AGI Script
13 SetPriority(string label)
Chuyển ựến label trong Dialplan khi kết thúc AGI Script 14 StreamFile(string
file)
Asterisk phát file âm thanh. Chuỗi file chức ựường dẫn vị trắ của file âm thanh. Mặc ựịnh ựường dẫn là
/var/lib/asterisk/sounds nên khi ta cần phát file
/var/lib/asterisk/sounds/abc.gsm thì ta cần lập trình như sau : StreamFile(ỘabcỢ)
15 SayDigits(string digits)
Asterisk ựọc số digits giới hạn là 0 Ờ 999999999 . Các file âm thanh ựược chứa tại /var/lib/asterisk/sounds/digits . Vắ dụ khi thực hiện lệnh SayDigits (Ộ1000Ợ) thì Asterisk ựọc là Ộone thousandỢ .
16 SayNumber(string number)
Asterisk sẽ ựọc rời rạc từng số trong number. Vắ dụ khi có lệnh SayNumber(::100ữ110::) thì Asterisk sẽ ựọc là Ộone two threeỢ
17 SayAlpha(string text) Asterisk sẽ ựọc rời rạc từng chữ trong text. 18 SayTime(long time) Asterisk sẽ ựọc giờ trong time.
19 SayDateTime(long time)
Asterisk sẽ ựọc ngày giờ trong time. 20 GetVariable(string
name)
Hàm lấy giá trị biến của kênh thoại. Vắ dụ ựể lấy giá trị biến ${EXTEN}, ta làm như sau :
- Cấu hình trong Dialplan như sau : exten =>
100,1,AGI(agi://192.168.16.70/noaction?extension=${EX TEN})
- Trong AGI Script , ta lập trình như sau : GetVariable(extension);
Kết quả trả về của hàm này sẽ cho giá trị của biến ${EXTEN}
21 SetVariable(string name, string val)
Hàm ựặt giá trị biến của kênh thoại . 22 WaitForDigit(int
timeout)
Hàm này sẽ chờ cho ựến khi có một phắm ựược nhấn hoặc khi timeout thì kết thúc cuộc gọi.
23 ControlStreamFile(str ing file, string
escapeDigits, int offset, string
forwardDigit, string rewindDigit, string pauseDigit)
Asterisk phát file âm thanh , người nghe có thể ựiều khiển việc nghe , tạm dừng , tắt , phát nhanh , hoặc phát chậm âm thanh .
24 RecordFile(string file, string format, string escapeDigits, int timeout, int offset, bool beep, int
maxSilence)
Thu âm cuộc gọi. file : là tên file lưu.
format : là ựịnh dạng file , thường là wav.
escapeDigits : là phắm quy ựịnh ựể khi nhấn thì việc thu âm dừng lại.
timeout : là thời gian thu âm tối ựa , -1 thì sẽ không giới hạn.
beep : nếu là true thì sẽ có tiếng beep trước khi thu âm. maxSilence : khoảng im lặng tối ựa ( tắnh theo giây) .
CHƯƠNG III: Xây dựng phần mềm thoại máy trạm
để có thể lập trình phần mềm thoại máy trạm, nhóm dựa trên thư viện cung cấp giao thức SIP và xử lý âm thanh. Trong số các thư viện mã nguồn mở có trên Internet thì PJSIP là một thư viện hỗ trợ ựầy ựủ các tắnh năng nhóm cần.
3.1 Gii thi u t&ng quát v th5 vi n PJSIP . 3.1.1 Tổng quan:
PJSIP là một thư viện mã nguồn mở, giúp dễ dàng lập trình phần mềm thoại có hỗ trợ giao thức SIP và xử lý âm thanh. Toàn bộ thư viện ựược viết theo ngôn ngữ C. Ta có thể download dễ dàng thư viện này tại http://pjsip.org/ . Sau ựây là một số ựặc ựiểm quan trọng của thư viện này :
- đặc ựiểm hỗ trợ SIP :
Ớ đăng ký nhiều tài khoản
Ớ Nhiều cuộc gọi
Ớ PRACK (100rel, RFC 3262).
Ớ UPDATE (RFC 3311).
Ớ OPTIONS.
Ớ Giữ cuộc gọi ( Hold )
Ớ Chuyển cuộc gọi ( RFC 3515, 3891, 3892, 4488).
Ớ SIMPLE với PIDF và XPIDF (SUBSCRIBE/NOTIFY, RFC 3265, 3856, 3863).
Ớ Hỗ trợ tên trạng thái tùy chọn (RPID, RFC 4480).
Ớ Hỗ trợ PUBLISH (RFC 3903).
Ớ Hỗ trợ chức năng chat ( Instant Messaging - RFC 3428, 3994)
Ớ UDP, TCP, và TLS .
Ớ Chức năng DNS SRV ựể chuyển ựổi IP và DNS cho SIP servers (RFC 3263).
Ớ DTMF với INFO (RFC 2976).
Ớ STUN (RFC 3489bis).
Ớ Chứng thực Digest AKA ( RFC 3310, 4169).
- đặc ựiểm hỗ trợ về âm thanh :
Ớ Nhiều cuộc gọi cùng lúc
Ớ Hội thảo
Ớ Codec : Speex, iLBC, GSM, G711, và L16
Ớ Hỗ trợ thu âm thoại , phát , truyền file âm thanh dạng WAV.
Ớ RTCP
Ớ Theo dõi chất lượng cuộc gọi.
Ớ DTMF Dialing ( RFC 2833 ) .
Ớ Auto-answer, auto-play file, auto-loop RTP Phát tone.
Ớ AEC (Accoustic echo cancellation).
Ớ Adaptive jitter buffer.
Ớ Adaptive silence detection.
Ớ PLC (Packet Lost Concealment).
Ớ Giả lập mất gói.
Ớ Gởi nhiều khung trong một gói RTP .
Ớ Bảo mật SRTP (còn ựang phát triển )
- đặc ựiểm hỗ trợ NAT:
Ớ ICE (Interactive Connectivity Establishment).
Ớ STUN (rfc3489-bis).
Ớ Luôn cập nhật SIP TCP và TLS.
Ớ Tự ựộng phát hiện và phục hồi ựịa chỉ SIP UDP bị thay ựổi.
Ớ Tự ựộng phát hiện sự thay ựổi khi truyền âm thanh thanh ICE.
- Hiệu năng cao: hàng ngàn cuộc gọi có thể ựược xử lý trên một máy tắnh ựể bàn
Intel/2.66Ghz. Sau ựây là kết quả ựo vào ngày 11 tháng 07 năm 2006 , phiên bản PJSIP 0.5.6.5. Kết quả cho thấy chỉ cần một máy P4/2.66GHz cũng có thể xử lý ựược 7000 giao dịch trên 1 giây (Số liệu lấy từ http://pjsip.org/).
Hình 3.1: Hiệu suất xử lý cuộc gọi của máy chủ khi dùng PJSIP
- Có thể hoạt ựộng trên nhiều hệ ựiều hành: Linux, BSD, Windows 95 (win95/win98/winME), WinNT (WinNT/2000/XP/2003/Vista), Symbian, Microsoft Windows Mobile , Windows CE (WinCE), PocketPC, SmartPhone, Solaris Ầ. Có thể biên dịch bởi nhiều loại compiler như : MSVC 6, VS.NET 2003, VC.NET 2005, GCC.
Sau ựây là cấu trúc của thư viện PJSIP :
Hình 3.2: Cấu trúc thư viện PJSIP
- PJLIB : đây là thư viện nền tảng của tất cả các thư viện khác trong cấu trúc của PJSIP. PJLIB cung cấp các hàm giao tiếp trực tiếp với hệ ựiều hành, quản lý các luồng ( thread), thời gian timestamp, quản lý các socket cấp thấp Ầ.
- PJLIB-UTIL : đây là thư viện cung cấp các hàm mã hóa và giải mã như CRC32, MD5, SHA1 Ầphân tắch DNS, quét văn bảnẦ
- PJSIP : đây là thư viện cung cấp các hàm của lớp giao dịch , vân chuyển , hộp thoại , chứng thực Ầ của giao thức SIP. đây là thư viện chắnh cung cấp các hàm thực thi toàn bộ giao thức SIP.
- PJSIP-SIMPLE : đây là phần mở rộng của giao thức SIP , nó cung cấp các chức năng chat ( Instant Message ) , trạng thái tài khoản SIP ( presence ) Ầ
- PJSIP-UA : đây là phần thư viện lớp cao của giao thức SIP, nó cung cấp các hàm ựể gởi quản lý các phiên INVITE bao gồm quản lý yêu cầu INVITE và SDP, quản lý việc ựăng ký của tài khoản SIP, chức năng chuyển cuộc gọi.
- PJNATH : hỗ trợ các chức năng ựi qua NAT gồm các giao thức như : STUN, ICE , TURN. - PJMEDIA: đây là bộ thư viện hoàn chỉnh về quản lý âm thanh , truyền âm thanh theo giao thức RTP/RTCP, UDP, quản lý phiên SDP, quản lý khung ựể ựảm bảo chất lượng âm thanh , hạn chế jitter, mất góiẦ
- PJMEDIA-CODEC : đây là bộ thư viện codec dùng trong PJMEDIA, gồm có các codec : GSM, ILBC, Speex, G.711Ầ.
- PJSUA-LIB: đây là bộ thư viện cấp cao , kết hợp quản lý giữa PJSIP và PJMEDIA. Khi lập trình ta có thể dùng các hàm trong thư viện này là ựủ , nếu không ta có thể dùng trực tiếp các PJSIP và PJMEDIA khi lập trình các ứng dụng VoIP client .
3.1.2 Kiến trúc thư viện PJSIP:
Lược ựồ chỉ ra các thông ựiệp (SIP) tương tác với các thành phần như thế nào trong hệ thống:
Hình 3.2: Lược ựồ tương tác của các khối trong thư viện PJSIP
3.1.2.1 Giới thiệu về Endpoint:
Tại trung tâm của khối SIP là Endpoint, Endpoint có những thuộc tắnh và ựáp ứng như sau:
Ớ Nó có pool factory, và chứa các pool cho tất cả các thành phần SIP.
Ớ Nó có timer heap instance, và các schedule timer cho tất cả các thành phần SIP.
Ớ Nó có transport manager instance. Transport manager có các SIP transport và ựiều khiển message parsing và print.
Ớ Nó tùy thuộc một ựối tượng ựơn của PJLIBỖs ioqueue.
Ớ Nó cung cấp một thread yêu cầu chọn hàm, ựể các thread của ứng dụng có thể yêu cầu lấy các timer và các sự kiện socket (PJSIP không tự tạo ra bất kỳ thread nào).
Ớ Nó quản lý các module PJSIP. Module PJSIP là primary ý nghĩa cho việc mở rộng stack các message parsing và transport ở xa.
Ớ Nó nhận các thông ựiệp SIP từ transport manager và phân bố các thông ựiệp này ựến các module.
3.1.2.2 Các Module:
Module framework có ý nghĩa quan trọng cho các thông ựiệp SIP phân bố trong các thành phần phần mềm trong ứng dụng PJSIP. Tất cả các thành phần phần mềm trong PJSIP, bao gồm các lớp transaction và lớp dialog, ựược thực thi như module. Không có các module, core stack sẽ không biết ựiều khiển các thông ựiệp SIP như thế nào.
đối với các thông ựiệp ngõ vào, endpoint phân bố các thông ựiệp ựến tất cả module, bắt ựầu từ module có ưu tiên cao nhất, cho ựến khi có một trong số các module thông báo lại là nó ựã xử lý hoàn tất một thông ựiệp. đối với các thông ựiệp ngõ ra, endpoint phân bố các thông ựiệp ngõ ra trước khi chúng ựược phát ra mạng, cho phép các module ựặt sự hiệu chỉnh cuối cùng lên thông ựiệp nếu chúng mong muốn.
Tất cả các pointer của hàm là tùy ý, nếu chúng không ựược chỉ ựịnh, chúng sẽ tự ựiều chỉnh phù hợp nếu chúng ựược trả lại giá trị thành công.
Có bốn pointer là load, start, stop, và unload ựược gọi bởi endpoint ựể ựiều khiển trạng thái endpoint. Lược ựồ sau chỉ ra trạng thái của module
Hình 3.4: Lược ựồ trạng thái module
Các pointer hàm on_rx_request() và on_rx_response() là ưu tiên cho module nhận các thông ựiệp SIP từ endpoint (pjsip_endpt) hoặc từ các module khác. Giá trị trả lại của các callback này là quan trọng.
Các pointer hàm on_tx_request() và on_tx_response() ựược gọi bởi transport manager trước khi một thông ựiệp SIP ựược phát. điều này nó tạo cơ hội cho một vài module thay ựổi ựể hiệu chỉnh cuối cùng lên thông ựiệp. Tất cả các module phải trả lại giá trị PJ_SUCCESS, hoặc ngược lại sự truyền sẽ bị hủy.
Pointer on_tsx_state() ựược sử dụng ựể nhận ghi chú mỗi lần trạng thái giao dịch thay ựổi, cái mà có thể do nguyên nhân bởi việc nhận thông ựiệp, các sự kiện timer, hoặc sự kiện lỗi do transport.
Lược ựồ sau chỉ ra cách thức các module gọi các module khác như thế nào.
3.1.2.3 Sự quản lý Module:
Các module ựược quản lý bởi endpoint của PJSIP (pjsip_endpoint). Ứng dụng phải ựăng ký mỗi module ựến endpoint vì vậy nó có thể ựược nhận bởi stack.
a) Module management API:
Module management API ựược khai báo trong <pjsip/sip_endpt.h> như sau:
PJ_DECL(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt, pjsip_module *module );
đăng ký một module ựến endpoint. Endpoint sau khi gọi sự khởi ựộng và bắt ựầu hàm trong module ựể khởi tạo module, và gán một module ID cho module.
PJ_DECL(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,pjsip_module *module );
Không ựăng ký một module từ endpoint. Endpoint sau ựó gọi sự dừng và không khởi ựộng hàm trong module ựể tắt module.
b) Khả năng của module:
Module có thể khai báo thuộc tắnh mới ựến endpoint. Thông thường thì endpoint quản lý tất cả thuộc tắnh của module:
_ Cho phép các phương thức SIP (cho phép header field). _ Hỗ trợ các nhánh SIP (hỗ trợ header field).
_ Hỗ trợ loại nội dung (chấp nhận header field).
Các vùng header này sẽ ựược tự ựộng thêm vào các request hoặc các response, vào nơi phù hợp.
Một module khai báo thuộc tắnh mới bằng gọi hàm pjsip_endpt_add_capability().
PJ_DECL(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt, pjsip_module *mod,
int htype,
const pj_str_t *hname, unsigned count,
const pj_str_t tags[]);
đăng ký các thuộc tắnh mới ựến endpoint. Thông số htype chỉ ựịnh header ựể thêm vào thuộc tắnh, như là: PJSIP_H_ACCEPT, PJSIP_H_ALLOW, PJSIP_H_SUPPORTED. Thông số hname là tùy ý, nó chỉ ựược dùng ựể chỉ ựịnh thuộc tắnh trong vùng header mà nó không ựược nhận ra bởi core stack. Các thông số tags và count chỉ ựịnh mảng các chuỗi tag ựược thêm vào vùng header .
PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,int htype,const pj_str_t *hname);
Lấy một thuộc tắnh trong vùng, nó chứa tất cả thuộc tắnh mà nó ựược ựăng ký ựến endpoint cho vùng header chỉ ựịnh.
3.2 Th5 vi n PJSUA ( PJSUA-LIB) 3.2.1 Giới thiệu PJSUA:
Thư viện PJSUA là tập hợp các hàm API ựược viết bằng C/C++, dùng ựể lập trình các ứng dụng thoại ựa phương tiện và giao thức SIP. Nó bao bọc các chức năng báo hiệu SIP và xử lý âm thanh cùng với nhau , giúp lập trình viên thuận tiện trong việc gọi các hàm API, cung cấp chức năng quản lý tài khoản SIP, buddy, chat, và các chức năng thoại khác như : hội thảo , thu âm thoại Ầ Nó phụ thuộc vào các thư viện khác như : pjsip-ua, pjsip-simple, pjsip-core, pjmedia, pjmedia-codec, pjlib-util, và pjlib.
Sau ựây là phần hướng dẫn sử dụng một số hàm trong thư viện PJSUA . Phần này ựược viết dựa trên PJSUA Manual ( http://pjsip.org/pjsip/docs/html/group__PJSUA__ LIB.htm ) và chương trình mẫu pjsua_app.c .
3.2.2 Tạo và khởi ựộng PJSUA
Trước khi gọi bất kỳ hàm nào của PJSUA, ta cần gọi hàm pjsua_create() ựể tạo PJSUA. Hàm này sẽ giúp khởi ựộng PJLIB, tạo nền tảng cho mọi hàm khác, và tạo một ựầu cuối SIP (SIP endpoint) .
Tiếp theo ta cần gọi tiếp hàm pjsua_pool_create() ựể tạo ra vùng bộ nhớ dùng cho chương trình .
Ta thực hiện việc gán các biến ban ựầu của chương trình , gồm : thông số các port , cấu hình media , cấu hình transport (RTP, UDP) , thiết bị thu phát giọng nói , tài khoản SIP , các buddy Ầ.
static void default_config(struct app_config *cfg) {
char tmp[80]; unsigned i;
pjsua_config_default(&cfg->cfg);
pj_ansi_sprintf(tmp, "PJSUA v%s/%s", pj_get_version(), PJ_OS_NAME);
pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp); pjsua_logging_config_default(&cfg->log_cfg); pjsua_media_config_default(&cfg->media_cfg); pjsua_transport_config_default(&cfg->udp_cfg); cfg->udp_cfg.port = 5060; pjsua_transport_config_default(&cfg->rtp_cfg); cfg->rtp_cfg.port = 4000; cfg->duration = NO_LIMIT; cfg->wav_id = PJSUA_INVALID_ID; cfg->rec_id = PJSUA_INVALID_ID; cfg->wav_port = PJSUA_INVALID_ID; cfg->rec_port = PJSUA_INVALID_ID; cfg->mic_level = cfg->speaker_level = 1.0;
cfg->playback_dev = PJSUA_INVALID_ID;
for (i=0; i<PJ_ARRAY_SIZE(cfg->acc_cfg); ++i) pjsua_acc_config_default(&cfg->acc_cfg[i]); for (i=0; i<PJ_ARRAY_SIZE(cfg->buddy_cfg); ++i)
pjsua_buddy_config_default(&cfg->buddy_cfg[i]); }
Sau ựó ta khai báo các hàm callback, các hàm này sẽ làm việc khi chương trình nhận ựáp ứng từ server gởi ựến như: báo cuộc gọi ựến, báo trạng thái tài khoản SIP, báo có tin nhắn (chat), báo trạng thái buddy, báo chuyển cuộc gọi Ầ.
app_config.cfg.cb.on_call_state = &on_call_state; app_config.cfg.cb.on_call_media_state = &on_call_media_state; app_config.cfg.cb.on_incoming_call = &on_incoming_call; app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state; app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback; app_config.cfg.cb.on_reg_state = &on_reg_state; app_config.cfg.cb.on_buddy_state = &on_buddy_state; app_config.cfg.cb.on_pager = &on_pager; app_config.cfg.cb.on_typing = &on_typing; app_config.cfg.cb.on_call_transfer_status = &on_call_transfer_status; app_config.cfg.cb.on_call_replaced = &on_call_replaced; app_config.cfg.cb.on_nat_detect = &on_nat_detect;
Sau khi gán các thông số khởi ựộng chương trình xong , ta gọi hàm pjsua_init() ựể khởi ựộng PJSUA , nếu ta không thiết lập các thông số ở bước trên , thì hàm pjsua_init() sẽ tự ựộng gán các giá trị mặc ựịnh của chương trình .
3.2.3 đăng ký và hủy tài khoản SIP trong PJSUA
Các thông số của tài khoản SIP ựược chứa trong biến struct pjsua_acc_config. Sau ựây là các thông số chắnh của biến struct pjsua_acc_config.
typedef struct pjsua_acc_config {
int priority; độ ưu tiên của tài khoản.
pj_str_t id; địa chỉ SIP URL của tài khoản , thường có dạng "sip:account@domain".
pj_str_t reg_uri; địa chỉ URL dùng trong yêu cầu ựăng ký tài khoản , thường có dạng