Beruflich Dokumente
Kultur Dokumente
1. Introduction
1.1 Brief Description of the Project……
2
1.2 Module
Description…………………….3
2. Feasibility Study…………………………………..4
3. Protocol Overview
3.1 SIP Functionality……………………….5
3.2 SIP Architecture………………………..6
3.3 SIP Entities……………………………….7
3.4 SIP Methods………………………………
20
3.5 SIP Session
Setup……………………….21
3.6 SIP Mobility
Modes……………………..27
3.7 SIP
Messages……………………………..29
4. Softphone Overview………………………………
31
5. Linphone Implementation………………………
31
5.1 User Frontend
5.2 Liblinlibrary
5.2.1
eXoSIP2………………………….32
5.2.2 Mediadtreamer2………………
33
5.2.3
ortp……………………………….34
6. Coding
Section……………………………………...35
7. Output
Screens……………………………………..67
8. Implementation and
Maintenance……………73
9. Conclusion……………………………………………
74
10. Bibliography…………………………………………
75
Title of the project
The project is entitled as “SIP based Softphone”
MAIN MODULES:
Init API - manage mediastreamer2 library.
CLASS INDEX
JB Parameters
RTP Profile
RTP Session
DIRECTORIES
linphone-3.2.1
• Console
• CoreApi
• gtk/glade
• Mediastreamer2
FEASIBILITY STUDY
TECHNICAL FEASIBILTY:
Evaluating the technical feasibility is the trickiest part of a
feasibility study. This is because, at this point of time, not
too many detailed design of the system is available, making
it difficult issues like performance, costs on account of the
kind of technology to be deployed.
1. For Programming: C
OPERATIONAL FEASIBILITY:
The communication scenario should be user centric and
device centric. Since the proposed technology lead towards
the unification of different technologies and is independent
of the communicative devices, the new system was
considered to be operational feasible.
ECONOMIC FEASIBILTY
Economic feasibility attempt to outweigh the costs of
developing and implementing a new system. This feasibility
study gives economic justification for the system. The other
benefit includes increased customer satisfaction,
improvement in quality, improved accuracy of operations,
better documentation and increased productivity.
PROTOCOL OVERVIEW
The Session Initiation Protocol (SIP) is part of the Internet
Multimedia Architecture, which consists of many precise
protocols that have been designed to perform one function.
New services and applications can be created by combining
multiple protocols together in a manner best suited for the
implementations purpose. This type of design is very flexible
and is a driver for constant innovation and development. It is
not likely that a service could be created using SIP alone,
although SIP does not depend on any other protocol. The
current excitement around SIP has made some developers
forget that SIP has been designed to be a signaling protocol
and should not be used for tasks that are better suited for
other protocols, such as data transport.
Fig: Internet Multimedia Architecture
SIP FUNCTIONALITY
SIP ARCHITECTURE
The SIP protocol defines four logical entities: User Agents,
Proxy Servers, Redirect Servers and Registrars. Most
implementations combine the Proxy Server, Redirect
Sever and/or Registrar into one server that is commonly
called the SIP Server. The SIP Server also often includes a
non-SIP entity called the Location Server that provides
location services and Presence Sever that provides
presence information about the users.
SIP SERVER
SIP Servers are essential network elements that enable
SIP endpoints to exchange messages, register user
location, and seamlessly move between networks. SIP
Servers enable network operators to install routing and
security policies, authenticate users and manage user
locations.
REGISTRAR SERVER
Registrar server is a database that contains the location
of all User Agents within a domain. The Registrar
authenticates and registers users when they come online,
and stores information on the users’ logical identities and
the communications devices or physical entities (IP
address) of the communication devices they can use. It
accepts registration requests and maps client’s address
to user’s sign-in name or SIP URI. The devices are
identified by their URIs. In SIP messaging, these servers
retrieve and send participants’ IP addresses and other
pertinent information to the SIP Proxy Server.
The SIP standard defines a registrar server as “a server
that accepts REGISTER requests and places the
information it receives in those requests into the location
service for the domain it handles”. REGISTER requests
are generated by clients in order to establish or remove a
mapping between their externally known SIP address and
the address they wish to be contacted at. The REGISTER
request can also be used to retrieve all the existing
mappings saved for a specific address.
REDIRECT SERVER
Redirect Server allow SIP Proxy Servers to direct SIP
session invitations to external domains. Upon receiving
SIP request, it directs the client to contact an alternate
set of SIP addresses SIP Redirect Servers may reside in
the same hardware as SIP Registrar Severs and SIP Proxy
Servers. For example, if a call is destined for
bob@amway.com and the user is on the road, the
company’s redirect server may reply to the caller’s UA (or
to the requesting proxy server) with the contact address
of the user’s mobile phone, so that the incoming call can
be redirected to the mobile phone.
PROXY SERVER:
Proxy Server route SIP requests to User Agent Servers
(UAS) and SIP responses to User Agent Clients (UAC). It
primarily plays the role of routing. A Proxy Server is
designed to be mostly transparent to UAs. It accept
session requests made by a SIP UA and query the SIP
Registrar Server to obtain the recipient UA’s addressing
information. It then forwards the session invitation
directly to the recipient UA if it is located in the same
domain or to a Proxy Server via Redirect Server if the UA
resides in another domain. A proxy is involved only in the
setup and teardown of a communication session. After
user agents establish a session, communications occur
directly between the parties. The SIP standard allows
proxies to perform actions such as validate requests,
authenticate users, fork requests, resolve addresses,
cancel pending calls, Record-Route and Loose-Route, and
detect and handle loops. A Proxy interprets, and, if
necessary, rewrites a request message before forwarding
it. Proxy servers are allowed to change messages only in
specific and limited ways. For example, a proxy is not
allowed to modify the SDP body of an INVITE. Apart from
a few exceptions, proxies cannot generate requests at
their own initiative. Therefore a proxy cannot terminate
an existing call by generating a BYE request.
STATEFUL PROXY
REQUEST VALIDATION
(3)Max-Forwards check
Max-Forwards is a message field that indicates how many more
hops the message is allowed to traverse. Each proxy that handles
the message decrements this number by one. If the message
contains a Max-Forwards value of zero, the proxy must return a
483 (Too many hops) response. This mechanism allows
preventing a message from going into an endless loop between a
set of proxies.
(4)Proxy-Require
The client may indicate certain SIP extensions in the Proxy-
Require fields that the proxy must support in order to successfully
handle this request. The proxy must inspect this field and verify
that it supports all the extensions listed in the field.
(5)Authentication
If the SIP Server determines it has to authenticate the originator
of the message, it has to make sure the message contains
credentials that authenticate the user. If the message does not
contain credentials or the credentials failed to authenticate the
user, the proxy may return a 407 response containing a
challenge.
• Predefined Target-Set
This is the simpler case, where the destination address of the
request is such that the proxy must automatically forward to the
destination address without trying to resolve to other addresses.
One such case is where the request-URI is in a domain for which
the SIP Server is not responsible. For example, a proxy
sip:proxy1.acme.com which is responsible for the domain
acme.com receiving a request for sip:bob@example.com must
proxy the request to sip:bob@example.com.
CANCEL
The scenario shows CANCEL processing. A stateful proxy may
choose to generate a CANCEL request for any pending INVITE
request it has previously forwarded.
A proxy receiving a CANCEL request must try and match it to an
existing INVITE context and cancel any pending client
transactions associated with this INVITE. If an INVITE context is
not found, the proxy must statelessly forward the CANCEL
request.
AUTHENTICATION
Session information:
Session name and purpose.
Time(s) the session is active.
Information about the bandwidth to be used by the session.
Contact information for the person responsible for the
session.
Media information:
Type of media, such as video and audio.
Transport protocol, such as RTP/UDP/IP and H.320
Media format, such as H.261 video and MPEG video.
Multicast address and Transport Port for media (IP multicast
session).
Remote addresses for media and Transport port for contact
address (IP unicast session).
SIP MOBILITY MODES
SIP Pioneer Henning Schulzrinne defines 3 Modes for SIP Mobility:
(4)SESSION MOBILITY
Session mobility means that it is possible to move an on-going
session to new terminal(s) without terminating the session.
Session mobility also incorporates the ability to split a session
across end devices into one collaborative application e.g. wall
display, cell phone and pc (softphone). Session mobility is
handled in SIP with the REFER method. SIP only needs to know
that the entity of the new device is the same entity as it was for
the previous address (not who the person really is). To initiate the
session transfer a REFER request is sent that indicates the new
address where the session is moved to. The receiver of the REFER
request then negotiates a new session to the new address using
the normal INVITE exchange. If the session is to be split across
multiple participants, each participant must be invited separately.
For example additional media (e.g. video streaming) could be
added to a call after moving the call from a cell phone to a PC
softphone. The Cell phone might have not supported video
streaming or the user might simply not have been willing to pay
for video over the mobile network. The session can be modified
with the SIP MODIFY method.
Features:
• Audio with the following codec: Speex (narrow band and
wideband), G711 (ulaw,alaw), GSM, and iLBC (through an
optional plug-in)
• Video with codec: H263-1998, MPEG4, theora and H264
(thanks to a plug-in based on x264), with resolutions from
QCIF (176x144) to SVGA (800x600) provided that network
bandwidth and CPU power are sufficient.
• Supports any webcam with V4L or V4L2 driver under Linux
• Text instant messaging and presence
• Address book
• DTMF (telephone tones) support using SIP INFO or RFC2833
• Echo cancelation using the Speex Echo Canceller
• SIP proxy support: registrar, proxies, with digest
authentication
• STUN support for traversal of UDP NATs
• Sound backend using either ALSA (the most efficient), OSS,
or arts (KDE sound daemon)
• Supports IPv6
• Bandwidth limitations are signaled using SDP resulting in
audio and video session established with bitrates that fits
the user's network capabilities.
• Can use plug-in: to add new codec, or new core
functionalities.
Features:
• Read/Write from to an alsa device, an oss device, a windows
waveapi device
• Send and receive RTP packets
• Encode and decode the following formats: speex, G711,
GSM, H263, theora, iLBC, MPEG4, and H264.
• Read and write from/to a wav file
• Read YUV pictures from a webcam (provided that it has
video4linux v1 or v2 driver)
• Display YUV pictures (using SDL library or native apis on
windows)
• Dual tones generation
• Echo cancelation, using the extraordinary echo canceler
algorithm from the speex library
• Audio conferencing
• Audio parametric equalizer using a FIR filter
• Volume control, automatic gain control
• Works on linux, windows XP
• macos X audio only, video support in progress
liblinphone
liblinphone is a high level library to make a SIP phone.
config.h
/* config.h. Generated from config.h.in by configure. */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
#define ENABLE_NLS 1
CoreFoundation framework. */
/* #undef HAVE_CFLOCALECOPYCURRENT */
/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
*/
#define HAVE_DCGETTEXT 1
#define HAVE_DLFCN_H 1
#define HAVE_EXOSIP_GET_VERSION 1
#define HAVE_GETIFADDRS 1
#define HAVE_GETTEXT 1
#define HAVE_GET_CURRENT_DIR_NAME 1
/* #undef HAVE_HISTORY_H */
/* #undef HAVE_ICONV */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `eXosip2' library (-leXosip2). */
#define HAVE_LIBEXOSIP2 1
/* #undef HAVE_LIBINTL */
/* #undef HAVE_LIBORTP */
#define HAVE_MEMORY_H 1
/* #undef HAVE_READLINE_H */
#define HAVE_READLINE_HISTORY_H 1
#define HAVE_READLINE_READLINE_H 1
#define HAVE_STDINT_H 1
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `stpcpy' function. */
#define HAVE_STPCPY 1
#define HAVE_STRINGS_H 1
#define HAVE_STRING_H 1
#define HAVE_STRNDUP 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_UNISTD_H 1
*/
/* #undef NO_MINUS_C_MINUS_O */
/* Name of package */
/* #undef PACKAGE */
/* Define to the address where bug reports for this package should be sent. */
/* #undef PACKAGE_BUGREPORT */
/* #undef PACKAGE_NAME */
/* #undef PACKAGE_STRING */
/* #undef PACKAGE_TARNAME */
/* #undef PACKAGE_URL */
/* #undef PACKAGE_VERSION */
/* #undef STDC_HEADERS */
/* #undef USE_BUILDDATE_VERSION */
#define VIDEO_ENABLED 1
/* #undef VINCENT_MAURY_RSVP */
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
/* #undef __ARM__ */
#ifndef __cplusplus
/* #undef inline */
#endif
Linphonec.c
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <limits.h>
#include <ctype.h>
#include <linphonecore.h>
#include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */
#include "linphonec.h"
#ifdef WIN32
#include <ws2tcpip.h>
#include <ctype.h>
#include <conio.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <sys/un.h>
#include <sys/stat.h>
#endif
#ifdef HAVE_GETTEXT
#include <libintl.h>
#ifndef _
#endif
#else
#endif
/***************************************************************************
*
* Types
*
***************************************************************************/
typedef struct {
LinphoneAuthInfo *elem[MAX_PENDING_AUTH];
int nitems;
} LPC_AUTH_STACK;
/***************************************************************************
*
* Forward declarations
*
***************************************************************************/
LinphoneCore linphonec;
FILE *mylogfile;
#ifdef HAVE_READLINE
static char *histfile_name=NULL;
static char last_in_history[256];
#endif
//auto answer (-a) option
static bool_t auto_answer=FALSE;
static bool_t answer_call=FALSE;
static bool_t vcap_enabled=FALSE;
static bool_t display_enabled=FALSE;
static bool_t preview_enabled=FALSE;
static bool_t show_general_state=FALSE;
static bool_t unix_socket=FALSE;
static bool_t linphonec_running=TRUE;
LPC_AUTH_STACK auth_stack;
static int trace_level = 0;
static char *logfile_name = NULL;
static char configfile_name[PATH_MAX];
static char *sipAddr = NULL; /* for autocall */
static ortp_pipe_t client_sock=ORTP_PIPE_INVALID;
char prompt[PROMPT_MAX_LEN];
LinphoneCoreVTable linphonec_vtable = {
.show =(ShowInterfaceCb) stub,
.inv_recv = linphonec_call_received,
.bye_recv = linphonec_bye_received,
.notify_recv = linphonec_notify_received,
.new_unknown_subscriber = linphonec_new_unknown_subscriber,
.auth_info_requested = linphonec_prompt_for_auth,
.display_status = linphonec_display_status,
.display_message=linphonec_display_something,
#ifdef VINCENT_MAURY_RSVP
/* the yes/no dialog box */
.display_yes_no= (DisplayMessageCb) stub,
#endif
.display_warning=linphonec_display_warning,
.display_url=linphonec_display_url,
.display_question=(DisplayQuestionCb)stub,
.text_received=linphonec_text_received,
.general_state=linphonec_general_state,
.dtmf_received=linphonec_dtmf_received
};
/***************************************************************************
*
* Linphone core callbacks
*
***************************************************************************/
/*
* Linphone core callback
*/
static void
linphonec_display_something (LinphoneCore * lc, const char *something)
{
fprintf (stdout, "%s\n%s", something,prompt);
fflush(stdout);
}
/*
* Linphone core callback
*/
static void
linphonec_display_status (LinphoneCore * lc, const char *something)
{
fprintf (stdout, "%s\n%s", something,prompt);
fflush(stdout);
}
/*
* Linphone core callback
*/
static void
linphonec_display_warning (LinphoneCore * lc, const char *something)
{
fprintf (stdout, "Warning: %s\n%s", something,prompt);
fflush(stdout);
}
/*
* Linphone core callback
*/
static void
linphonec_display_url (LinphoneCore * lc, const char *something, const char
*url)
{
fprintf (stdout, "%s : %s\n", something, url);
}
/*
* Linphone core callback
*/
static void
linphonec_call_received(LinphoneCore *lc, const char *from)
{
linphonec_set_caller(from);
if ( auto_answer) {
answer_call=TRUE;
}
}
/*
* Linphone core callback
*/
static void
linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char
*username)
{
/* no prompt possible when using pipes or tcp mode*/
if (unix_socket){
linphone_core_abort_authentication(lc,NULL);
}else{
LinphoneAuthInfo *pending_auth;
pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm
);
auth_stack.elem[auth_stack.nitems++]=pending_auth;
}
}
/*
* Linphone core callback
*/
static void
linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid,
const char *from, const char *status, const char *img)
{
printf("Friend %s is %s\n", from, status);
// todo: update Friend list state (unimplemented)
}
/*
* Linphone core callback
*/
static void
linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
const char *url)
{
printf("Friend %s requested subscription "
"(accept/deny is not implemented yet)\n", url);
// This means that this person wishes to be notified
// of your presence information (online, busy, away...).
static void
linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
{
if (show_general_state) {
switch(gstate->new_state) {
case GSTATE_POWER_OFF:
printf("GSTATE_POWER_OFF");
break;
case GSTATE_POWER_STARTUP:
printf("GSTATE_POWER_STARTUP");
break;
case GSTATE_POWER_ON:
printf("GSTATE_POWER_ON");
break;
case GSTATE_POWER_SHUTDOWN:
printf("GSTATE_POWER_SHUTDOWN");
break;
case GSTATE_REG_NONE:
printf("GSTATE_REG_NONE");
break;
case GSTATE_REG_OK:
printf("GSTATE_REG_OK");
break;
case GSTATE_REG_FAILED:
printf("GSTATE_REG_FAILED");
break;
case GSTATE_CALL_IDLE:
printf("GSTATE_CALL_IDLE");
break;
case GSTATE_CALL_OUT_INVITE:
printf("GSTATE_CALL_OUT_INVITE");
break;
case GSTATE_CALL_OUT_CONNECTED:
printf("GSTATE_CALL_OUT_CONNECTED");
break;
case GSTATE_CALL_IN_INVITE:
printf("GSTATE_CALL_IN_INVITE");
break;
case GSTATE_CALL_IN_CONNECTED:
printf("GSTATE_CALL_IN_CONNECTED");
break;
case GSTATE_CALL_END:
printf("GSTATE_CALL_END");
break;
case GSTATE_CALL_ERROR:
printf("GSTATE_CALL_ERROR");
break;
default:
printf("GSTATE_UNKNOWN_%d",gstate->new_state);
}
if (gstate->message) printf(" %s", gstate->message);
printf("\n");
}
}
/***************************************************************************/
/*
* Main
*
* Use globals:
*
* - char *histfile_name
* - FILE *mylogfile
*/
int
main (int argc, char *argv[])
{
linphonec_finish(EXIT_SUCCESS);
/*
* Initialize linphonec
*/
static int
linphonec_init(int argc, char **argv)
{
//g_mem_set_vtable(&dbgtable);
/*
* Set initial values for global variables
*/
mylogfile = NULL;
snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
getenv("HOME"));
void
print_usage (int exit_status)
{
fprintf (stdout, "\n\
usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
linphonec -v\n\
\n\
-c file specify path of configuration file.\n\
-d level be verbose. 0 is no output. 6 is all output\n\
-l logfile specify the log file for your SIP phone\n\
-s sipaddress specify the sip call to do at startup\n\
-a enable auto answering for incoming calls\n\
-V enable video features globally (disabled by default)\n\
-C enable video capture only (disabled by default)\n\
-D enable video display only (disabled by default)\n\
-S show general state messages (disabled by default)\n\
-v or --version display version and exits.\n");
exit(exit_status);
}
/*
*
* Called every second from main read loop.
*
* Will use the following globals:
*
* - LinphoneCore linphonec
* - LPC_AUTH_STACK auth_stack;
*
*/
static int
linphonec_idle_call ()
{
LinphoneCore *opm=&linphonec;
linphone_core_iterate(opm);
if (answer_call){
fprintf (stdout, "-------auto answering to call-------\n" );
linphone_core_accept_call(opm,NULL);
answer_call=FALSE;
}
if ( auth_stack.nitems )
{
/*
* Inhibit command completion
* during password prompts
*/
#ifdef HAVE_READLINE
rl_inhibit_completion=1;
#endif
linphonec_prompt_for_auth_final(opm);
#ifdef HAVE_READLINE
rl_inhibit_completion=0;
#endif
}
return 0;
}
#ifdef HAVE_READLINE
/*
* Use globals:
*
* - char *histfile_name (also sets this)
* - char *last_in_history (allocates it)
*/
static int
/*
* Parse command line switches
*
* Use globals:
*
* - int trace_level
* - char *logfile_name
* - char *configfile_name
* - char *sipAddr
*/
static int
linphonec_parse_cmdline(int argc, char **argv)
{
int arg_num=1;
if (access(argv[arg_num],F_OK)!=0 )
{
fprintf (stderr,
"Cannot open config file %s.\n",
argv[arg_num]);
exit(EXIT_FAILURE);
}
snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
}
else if (strncmp ("-s", argv[arg_num], 2) == 0)
{
arg_num++;
if (arg_num < argc)
sipAddr = argv[arg_num];
}
else if (strncmp ("-a", argv[arg_num], 2) == 0)
{
auto_answer = TRUE;
}
else if (strncmp ("-C", argv[arg_num], 2) == 0)
{
vcap_enabled = TRUE;
}
else if (strncmp ("-D", argv[arg_num], 2) == 0)
{
display_enabled = TRUE;
}
else if (strncmp ("-V", argv[arg_num], 2) == 0)
{
display_enabled = TRUE;
vcap_enabled = TRUE;
preview_enabled=TRUE;
}
else if ((strncmp ("-v", argv[arg_num], 2) == 0)
||
(strncmp
("--version", argv[arg_num],
strlen ("--version")) == 0))
{
printf ("version: " LINPHONE_VERSION "\n");
exit (EXIT_SUCCESS);
}
return 1;
}
/*
* Prevent readline from falling
* back to filename-completion
*/
rl_attempted_completion_over=1;
/*
* If this is the start of line we complete with commands
*/
if ( ! start )
{
return rl_completion_matches(text, linphonec_command_generator);
}
/*
* Otherwise, we should peek at command name
* or context to implement a smart completion.
* For example: "call .." could return
* friends' sip-uri as matches
*/
return matches;
}
#endif
/*
* Strip blanks from a string.
* Return a pointer into the provided string.
* Modifies input adding a NULL at first
* of trailing blanks.
*/
char *
lpc_strip_blanks(char *input)
{
char *iptr;
shell.c
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#include <winbase.h>
#include <ws2tcpip.h>
#include <ctype.h>
#include <conio.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <sys/un.h>
#endif
#include "ortp/ortp.h"
int ret=0;
if (strstr(status_string,"registered, identity=")){
ret|=STATUS_REGISTERED;
if (strstr(status_string,"registered=-1")){
ret|=STATUS_REGISTERING;
if (strstr(status_string,"autoanswer=1")){
ret|=STATUS_AUTOANSWER;
if (strstr(status_string,"dialing")){
ret|=STATUS_DIALING;
if (strstr(status_string,"Call out")){
ret|=STATUS_OUT_CONNECTED;
if (strstr(status_string,"hook=answered")){
ret|=STATUS_IN_CONNECTED;
return ret;
static int send_command(const char *command, char *reply, int reply_len, int
print_errors){
ortp_pipe_t pp;
int i;
int err;
char path[128];
#ifndef WIN32
snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
#else
{
char username[128];
DWORD size=sizeof(username)-1;
GetUserName(username,&size);
snprintf(path,sizeof(path)-1,"linphonec-%s",username);
#endif
if ((pp=ortp_client_pipe_connect(path))==ORTP_PIPE_INVALID){
return -1;
if (ortp_pipe_write(pp,(uint8_t*)command,strlen(command))==-1){
ortp_client_pipe_close(pp);
return -1;
i=0;
while ((err=ortp_pipe_read(pp,(uint8_t*)&reply[i],reply_len-i-1))>0){
i+=err;
reply[i]='\0';
ortp_client_pipe_close(pp);
return 0;
}
static void print_usage(void){
"\tunregister\t: unregister\n"
);
exit(-1);
#define MAX_ARGS 10
#ifndef WIN32
static void spawn_linphonec(int argc, char *argv[]){
char * args[10];
int i,j;
pid_t pid;
j=0;
args[j++]="linphonec";
args[j++]="--pipe";
args[j++]="-c";
args[j++]="/dev/null";
for(i=0;i<argc;++i){
args[j++]=argv[i];
args[j++]=NULL;
pid = fork();
exit(-1);
if (pid == 0) {
int fd;
setsid();
fd = open("/dev/null", O_RDWR);
if (fd==-1){
fprintf(stderr,"Could not open /dev/null\n");
exit(-1);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
if (execvp("linphonec",args)==-1){
exit(-1);
#else
PROCESS_INFORMATION pinfo;
STARTUPINFO si;
si.cb = sizeof(si);
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pinfo);
if (!ret){
}else{
WaitForInputIdle(pinfo.hProcess,1000);
#endif
char reply[DEFAULT_REPLY_SIZE];
int err;
err=send_command(command,reply,sizeof(reply),print_result);
printf("%s",reply);
fflush(stdout);
return err;
}
static int register_execute(int argc, char *argv[]){
char cmd[512];
char *username=NULL;
char *host=NULL;
char *passwd=NULL;
int i;
for(i=0;i<argc;++i){
if (strcmp(argv[i],"--host")==0){
i++;
if (i<argc){
host=argv[i];
}else print_usage();
}else if (strcmp(argv[i],"--username")==0){
i++;
if (i<argc){
username=argv[i];
}else print_usage();
}else if (strcmp(argv[i],"--password")==0){
i++;
if (i<argc){
passwd=argv[i];
}else print_usage();
}else print_usage();
if (username==NULL) {
fprintf(stderr,"Missing --username\n");
print_usage();
if (host==NULL) {
fprintf(stderr,"Missing --host\n");
print_usage();
return send_generic_command(cmd,TRUE);
return send_generic_command("unregister",FALSE);
char cmd[512];
if (argc==1){
snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
return send_generic_command(cmd,TRUE);
}else{
print_usage();
return -1;
}
static int status_execute(int argc, char *argv[]){
char cmd[512];
char reply[DEFAULT_REPLY_SIZE];
int err;
if (argc==1){
snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
err=send_command(cmd,reply,sizeof(reply),TRUE);
if (err==0) {
printf("%s",reply);
err=make_status_value(reply);
return err;
}else{
print_usage();
return -1;
int index=-1;
reply=strstr(reply,"device #");
return index;
}
static int soundcard_execute(int argc, char *argv[]){
char cmd[512];
char reply[DEFAULT_REPLY_SIZE];
int err;
if (argc==1){
snprintf(cmd,sizeof(cmd),"soundcard %s",argv[0]);
err=send_command(cmd,reply,sizeof(reply),TRUE);
if (err==0) {
printf("%s",reply);
return parse_card_index(reply);
snprintf(cmd,sizeof(cmd),"soundcard %s %s",argv[0],argv[1]);
err=send_command(cmd,reply,sizeof(reply),TRUE);
if (err==0) {
printf("%s",reply);
return 0;
}else{
print_usage();
return -1;
int argi;
if (argc<2){
print_usage();
return -1;
ortp_init();
for(argi=1;argi<argc;++argi){
if (strcmp(argv[argi],"init")==0){
if (send_generic_command("help",0)==0){
return 0;
spawn_linphonec(argc-argi-1,&argv[argi+1]);
return 0;
}else if (strcmp(argv[argi],"generic")==0){
if (argi+1<argc){
return send_generic_command(argv[argi+1],1);
}else print_usage();
}else if (strcmp(argv[argi],"register")==0){
return register_execute(argc-argi-1,&argv[argi+1]);
}else if (strcmp(argv[argi],"unregister")==0){
return unregister_execute(argc-argi-1,&argv[argi+1]);
}else if (strcmp(argv[argi],"dial")==0){
return dial_execute(argc-argi-1,&argv[argi+1]);
}else if (strcmp(argv[argi],"hangup")==0){
send_generic_command("terminate",FALSE);
send_generic_command("duration",TRUE);
}else if (strcmp(argv[argi],"status")==0){
return status_execute(argc-argi-1,&argv[argi+1]);
}else if (strcmp(argv[argi],"soundcard")==0){
return soundcard_execute(argc-argi-1,&argv[argi+1]);
}else if (strcmp(argv[argi],"exit")==0){
return send_generic_command("quit",TRUE);
}else print_usage();
return 0;
IMPLEMENTATION SCREENS
1.LINPHONE INTERFACE
2.INCOMING CALL
3.CALLING USERAGENT
4.CALLEE USERAGENT
5.PRESENCE MANAGEABILITY
6.LINPHONE-CALL HISTORY
7
.LINPHONE-AUDIO AND VIDEO MODE
8.LINPHONE-NETWORK SETTINGS
9.LINPHONE-MULTIMEDIA SETTINGS