blob: ab2d017408cdf7972d008b3e081bc72b530160f5 [file] [log] [blame]
Benny Prijonof77ba882007-01-08 01:20:07 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonof77ba882007-01-08 01:20:07 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/**
22 * simple_pjsua.c
23 *
24 * This is a very simple but fully featured SIP user agent, with the
25 * following capabilities:
26 * - SIP registration
27 * - Making and receiving call
28 * - Audio/media to sound device.
29 *
30 * Usage:
31 * - To make outgoing call, start simple_pjsua with the URL of remote
32 * destination to contact.
33 * E.g.:
34 * simpleua sip:user@remote
35 *
36 * - Incoming calls will automatically be answered with 200.
37 *
38 * This program will quit once it has completed a single call.
39 */
40
41#include <pjsua-lib/pjsua.h>
42
43#define THIS_FILE "APP"
44
45#define SIP_DOMAIN "example.com"
46#define SIP_USER "alice"
47#define SIP_PASSWD "secret"
48
49
50/* Callback called by the library upon receiving incoming call */
51static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
52 pjsip_rx_data *rdata)
53{
54 pjsua_call_info ci;
55
56 PJ_UNUSED_ARG(acc_id);
57 PJ_UNUSED_ARG(rdata);
58
59 pjsua_call_get_info(call_id, &ci);
60
61 PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
62 (int)ci.remote_info.slen,
63 ci.remote_info.ptr));
64
65 /* Automatically answer incoming calls with 200/OK */
66 pjsua_call_answer(call_id, 200, NULL, NULL);
67}
68
69/* Callback called by the library when call's state has changed */
70static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
71{
72 pjsua_call_info ci;
73
74 PJ_UNUSED_ARG(e);
75
76 pjsua_call_get_info(call_id, &ci);
77 PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
78 (int)ci.state_text.slen,
79 ci.state_text.ptr));
80}
81
82/* Callback called by the library when call's media state has changed */
83static void on_call_media_state(pjsua_call_id call_id)
84{
85 pjsua_call_info ci;
86
87 pjsua_call_get_info(call_id, &ci);
88
89 if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
90 // When media is active, connect call to sound device.
91 pjsua_conf_connect(ci.conf_slot, 0);
92 pjsua_conf_connect(0, ci.conf_slot);
93 }
94}
95
96/* Display error and exit application */
97static void error_exit(const char *title, pj_status_t status)
98{
99 pjsua_perror(THIS_FILE, title, status);
100 pjsua_destroy();
101 exit(1);
102}
103
104/*
105 * main()
106 *
107 * argv[1] may contain URL to call.
108 */
109int main(int argc, char *argv[])
110{
111 pjsua_acc_id acc_id;
112 pj_status_t status;
113
114 /* Create pjsua first! */
115 status = pjsua_create();
116 if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status);
117
118 /* If argument is specified, it's got to be a valid SIP URL */
119 if (argc > 1) {
120 status = pjsua_verify_sip_url(argv[1]);
121 if (status != PJ_SUCCESS) error_exit("Invalid URL in argv", status);
122 }
123
124 /* Init pjsua */
125 {
126 pjsua_config cfg;
127 pjsua_logging_config log_cfg;
128
129 pjsua_config_default(&cfg);
130 cfg.cb.on_incoming_call = &on_incoming_call;
131 cfg.cb.on_call_media_state = &on_call_media_state;
132 cfg.cb.on_call_state = &on_call_state;
133
134 pjsua_logging_config_default(&log_cfg);
135 log_cfg.console_level = 4;
136
137 status = pjsua_init(&cfg, &log_cfg, NULL);
138 if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status);
139 }
140
141 /* Add UDP transport. */
142 {
143 pjsua_transport_config cfg;
144
145 pjsua_transport_config_default(&cfg);
146 cfg.port = 5060;
147 status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL);
148 if (status != PJ_SUCCESS) error_exit("Error creating transport", status);
149 }
150
151 /* Initialization is done, now start pjsua */
152 status = pjsua_start();
153 if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status);
154
155 /* Register to SIP server by creating SIP account. */
156 {
157 pjsua_acc_config cfg;
158
159 pjsua_acc_config_default(&cfg);
160 cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
161 cfg.reg_uri = pj_str("sip:" SIP_DOMAIN);
162 cfg.cred_count = 1;
163 cfg.cred_info[0].realm = pj_str(SIP_DOMAIN);
164 cfg.cred_info[0].scheme = pj_str("digest");
165 cfg.cred_info[0].username = pj_str(SIP_USER);
166 cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
167 cfg.cred_info[0].data = pj_str(SIP_PASSWD);
168
169 status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id);
170 if (status != PJ_SUCCESS) error_exit("Error adding account", status);
171 }
172
173 /* If URL is specified, make call to the URL. */
174 if (argc > 1) {
175 pj_str_t uri = pj_str(argv[1]);
176 status = pjsua_call_make_call(acc_id, &uri, 0, NULL, NULL, NULL);
177 if (status != PJ_SUCCESS) error_exit("Error making call", status);
178 }
179
180 /* Wait until user press "q" to quit. */
181 for (;;) {
182 char option[10];
183
184 puts("Press 'h' to hangup all calls, 'q' to quit");
Benny Prijono32d267b2009-01-01 22:08:21 +0000185 if (fgets(option, sizeof(option), stdin) == NULL) {
186 puts("EOF while reading stdin, will quit now..");
187 break;
188 }
Benny Prijonof77ba882007-01-08 01:20:07 +0000189
190 if (option[0] == 'q')
191 break;
192
193 if (option[0] == 'h')
194 pjsua_call_hangup_all();
195 }
196
197 /* Destroy pjsua */
198 pjsua_destroy();
199
200 return 0;
201}