From efcdda1b8767504ab29b4933b20a5eb2ac03ce2c Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 20 Mar 2012 10:07:12 +0100 Subject: [PATCH 001/231] Add daemon --- Makefile.am | 3 +- configure.ac | 1 + daemon/Makefile.am | 25 ++ daemon/daemon-pipetest.c | 59 +++++ daemon/daemon.cc | 503 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 daemon/Makefile.am create mode 100644 daemon/daemon-pipetest.c create mode 100644 daemon/daemon.cc diff --git a/Makefile.am b/Makefile.am index 5be271da4..62ef80a60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,8 @@ ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ - coreapi console gtk share scripts + coreapi console gtk share scripts daemon + diff --git a/configure.ac b/configure.ac index ce3604451..82c4e64a5 100644 --- a/configure.ac +++ b/configure.ac @@ -600,6 +600,7 @@ coreapi/help/Makefile coreapi/help/Doxyfile gtk/Makefile console/Makefile +daemon/Makefile share/Makefile share/C/Makefile share/fr/Makefile diff --git a/daemon/Makefile.am b/daemon/Makefile.am new file mode 100644 index 000000000..a644c9823 --- /dev/null +++ b/daemon/Makefile.am @@ -0,0 +1,25 @@ + + +bin_PROGRAMS=linphone-daemon linphone-daemon-pipetest + +linphone_daemon_SOURCES=daemon.cc + +linphone_daemon_pipetest_SOURCES=daemon-pipetest.c + +linphone_daemon_pipetest_LDADD=$(ORTP_LIBS) + +linphone_daemon_LDADD=$(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \ + $(MEDIASTREAMER_LIBS) \ + $(ORTP_LIBS) \ + $(SPEEX_LIBS) \ + $(OSIP_LIBS) + +AM_CFLAGS=$(READLINE_CFLAGS) -DIN_LINPHONE $(STRICT_OPTIONS) +AM_CXXFLAGS=$(READLINE_CXXFLAGS) -DIN_LINPHONE $(STRICT_OPTIONS) + +INCLUDES = \ + -I$(top_srcdir)\ + -I$(top_srcdir)/coreapi\ + $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) + diff --git a/daemon/daemon-pipetest.c b/daemon/daemon-pipetest.c new file mode 100644 index 000000000..2da3f77e6 --- /dev/null +++ b/daemon/daemon-pipetest.c @@ -0,0 +1,59 @@ +#define _GNU_SOURCE +#include + +#include + + + +#include "ortp/ortp.h" + +static int running=1; + +int main(int argc, char *argv[]){ + int fd=ortp_client_pipe_connect("ha-linphone"); + struct pollfd pfds[2]={{0}}; + char buf[4096]; + + ortp_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + if (fd==-1){ + ortp_error("Could not connect to control pipe: %s",strerror(errno)); + return -1; + } + pfds[0].fd=fd; + pfds[0].events=POLLIN; + pfds[1].fd=1; + pfds[1].events=POLLIN; + while (running){ + int err; + int bytes; + err=poll(pfds,2,-1); + if (err>0){ + /*splice to stdout*/ + if (pfds[0].revents & POLLIN){ + if ((bytes=read(pfds[0].fd,buf,sizeof(buf)))>0){ + if (write(0,buf,bytes)==-1){ + ortp_error("Fail to write to stdout?"); + break; + } + fprintf(stdout,"\n"); + }else if (bytes==0){ + break; + } + } + /*splice from stdin to pipe */ + if (pfds[1].revents & POLLIN){ + if ((bytes=read(pfds[1].fd,buf,sizeof(buf)))>0){ + if (write(pfds[0].fd,buf,bytes)==-1){ + ortp_error("Fail to write to unix socket"); + break; + } + }else if (bytes==0){ + break; + } + } + } + } + return 0; +} + diff --git a/daemon/daemon.cc b/daemon/daemon.cc new file mode 100644 index 000000000..325869fcf --- /dev/null +++ b/daemon/daemon.cc @@ -0,0 +1,503 @@ + +#include "linphonecore.h" +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; + + +class Daemon; + +class DaemonCommand{ + public: + virtual void exec(Daemon *app, const char *args)=0; + bool matches(const char *name)const; + const std::string &getProto()const{ + return mProto; + } + const std::string &getHelp()const{ + return mHelp; + } + protected: + DaemonCommand(const char *name, const char *proto, const char *help); + const std::string mName; + const std::string mProto; + const std::string mHelp; +}; + +class Response{ + public: + enum Status { Ok, Error}; + virtual ~Response(){ + } + Response() : mStatus(Ok){ + } + Response(const char *errormsg) : mStatus(Error), mReason(errormsg){ + } + void setStatus(Status st){ + mStatus=st; + } + void setReason(const char *reason){ + mReason=reason; + } + void setBody(const char *body){ + mBody=body; + } + const std::string &getBody()const{ + return mBody; + } + virtual int toBuf(char *dst, int dstlen)const{ + int i=0; + i+=snprintf(dst+i,dstlen-i,"Status: %s\n",mStatus==Ok ? "Ok" : "Error"); + if (mReason.size()>0){ + i+=snprintf(dst+i,dstlen-i,"Reason: %s\n",mReason.c_str()); + } + if (mBody.size()>0){ + i+=snprintf(dst+i,dstlen-i,"\n%s\n",mBody.c_str()); + } + return i; + } + private: + Status mStatus; + string mReason; + string mBody; +}; + +class EventResponse : public Response{ + public: + EventResponse(LinphoneCall *call, LinphoneCallState state); + private: +}; + +class Daemon{ + friend class DaemonCommand; + public: + typedef Response::Status Status; + Daemon(const char *config_path, bool using_pipes); + ~Daemon(); + int run(); + void quit(); + void sendResponse(const Response &resp); + LinphoneCore *getCore(); + const list &getCommandList()const; + LinphoneCall *findCall(int id); + bool pullEvent(); + static int getCallId(LinphoneCall *call); + void setCallId(LinphoneCall *call); + private: + + static void callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg); + static int readlineHook(); + void callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg); + void execCommand(const char *cl); + void initReadline(); + char *readPipe(char *buffer, int buflen); + void iterate(); + void initCommands(); + LinphoneCore *mLc; + std::list mCommands; + queue mEventQueue; + int mServerFd; + int mChildFd; + string mHistfile; + bool mRunning; + static Daemon *sZis; + static int sCallIds; + static const int sLineSize=512; +}; + +class CallCommand : public DaemonCommand{ + public: + CallCommand() : DaemonCommand("call", "call ","Place a call."){ + } + virtual void exec(Daemon *app, const char *args){ + LinphoneCall *call; + call=linphone_core_invite(app->getCore(),args); + if (call==NULL){ + app->sendResponse(Response("Call creation failed.")); + }else{ + Response resp; + ostringstream ostr; + app->setCallId(call); + ostr<<"Id: "<sendResponse(resp); + } + } +}; + +class TerminateCommand : public DaemonCommand{ + public: + TerminateCommand() : DaemonCommand("terminate", "call ","Terminate a call."){ + } + virtual void exec(Daemon *app, const char *args){ + LinphoneCall *call = NULL; + int cid; + const MSList *elem; + if (sscanf(args,"%i",&cid)==1){ + call=app->findCall(cid); + if (call==NULL){ + app->sendResponse(Response("No call with such id.")); + return; + } + } + elem=linphone_core_get_calls(app->getCore()); + if (elem!=NULL && elem->next==NULL){ + call=(LinphoneCall*)elem->data; + } + if (call==NULL){ + app->sendResponse(Response("No active call.")); + return; + } + linphone_core_terminate_call(app->getCore(),call); + app->sendResponse(Response()); + } +}; + +class QuitCommand : public DaemonCommand{ + public: + QuitCommand() : DaemonCommand("quit", "quit","Quit the application."){ + } + virtual void exec(Daemon *app, const char *args){ + app->quit(); + app->sendResponse(Response()); + } +}; + +class HelpCommand : public DaemonCommand{ + public: + HelpCommand() : DaemonCommand("help", "help","Show available commands."){ + } + virtual void exec(Daemon *app, const char *args){ + char str[4096]={0}; + int written=0; + list::const_iterator it; + const list &l=app->getCommandList(); + for(it=l.begin();it!=l.end();++it){ + written+=snprintf(str+written,sizeof(str)-written,"%s\t%s\n",(*it)->getProto().c_str(),(*it)->getHelp().c_str()); + } + Response resp; + resp.setBody(str); + app->sendResponse(resp); + } +}; + +class PopEventCommand :public DaemonCommand{ + public: + PopEventCommand() : DaemonCommand("pop-event", "pop-event","Pop an event from event queue and display it."){ + } + virtual void exec(Daemon *app, const char *args){ + app->pullEvent(); + } +}; + +class AnswerCommand :public DaemonCommand{ + public: + AnswerCommand() : DaemonCommand("answer", "answer","Answer an incoming call."){ + } + virtual void exec(Daemon *app, const char *args){ + LinphoneCore *lc=app->getCore(); + const MSList* elem=linphone_core_get_calls(lc); + for(;elem!=NULL;elem=elem->next){ + LinphoneCall *call=(LinphoneCall*)elem->data; + LinphoneCallState cstate=linphone_call_get_state(call); + if (cstate==LinphoneCallIncomingReceived || cstate==LinphoneCallIncomingEarlyMedia){ + if (linphone_core_accept_call(lc,call)==0){ + app->sendResponse(Response()); + return; + } + } + } + app->sendResponse(Response("No call to accept.")); + } +}; + +EventResponse::EventResponse(LinphoneCall *call, LinphoneCallState state){ + ostringstream ostr; + char *remote=linphone_call_get_remote_address_as_string(call); + ostr<<"Event-type: call-state-changed\nEvent: "< &Daemon::getCommandList()const{ + return mCommands; +} + +LinphoneCore * Daemon::getCore(){ + return mLc; +} + +void Daemon::setCallId(LinphoneCall *call){ + linphone_call_set_user_pointer(call,(void*)(long)++sCallIds); +} + +LinphoneCall * Daemon::findCall(int id){ + const MSList *elem=linphone_core_get_calls(mLc); + for (;elem!=NULL;elem=elem->next){ + LinphoneCall *call=(LinphoneCall *)elem->data; + if (linphone_call_get_user_pointer(call)==(void*)(long)id) + return call; + } + return NULL; +} + +void Daemon::initCommands(){ + mCommands.push_back(new CallCommand()); + mCommands.push_back(new TerminateCommand()); + mCommands.push_back(new PopEventCommand()); + mCommands.push_back(new AnswerCommand()); + mCommands.push_back(new QuitCommand()); + mCommands.push_back(new HelpCommand()); + +} + +bool Daemon::pullEvent(){ + if (!mEventQueue.empty()){ + Response *r=mEventQueue.front(); + mEventQueue.pop(); + sendResponse(*r); + delete r; + return true; + }else{ + sendResponse(Response()); + } + return false; +} + +int Daemon::getCallId(LinphoneCall *call){ + return (int)(long)linphone_call_get_user_pointer(call); +} + +void Daemon::callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg){ + switch(state){ + case LinphoneCallOutgoingProgress: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + case LinphoneCallError: + case LinphoneCallEnd: + mEventQueue.push(new EventResponse(call,state)); + break; + default: + break; + } +} + +void Daemon::callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg){ + Daemon *app=(Daemon*)linphone_core_get_user_data(lc); + app->callStateChanged(call,state,msg); +} + +void Daemon::iterate(){ + linphone_core_iterate(mLc); + if (mChildFd==-1){ + if (!mEventQueue.empty()){ + Response *r=mEventQueue.front(); + mEventQueue.pop(); + fprintf(stdout,"%s\n",r->getBody().c_str()); + fflush(stdout); + delete r; + } + } +} + +int Daemon::readlineHook(){ + sZis->iterate(); + return 0; +} + +void Daemon::initReadline() +{ + const char *homedir=getenv("HOME"); + rl_readline_name = "ha"; + + rl_set_keyboard_input_timeout(20000); + rl_event_hook=readlineHook; + + if (homedir==NULL) homedir="."; + mHistfile=string(homedir) + string("/.linphone_history"); + read_history(mHistfile.c_str()); + setlinebuf(stdout); +} + +void Daemon::execCommand(const char *cl){ + char args[sLineSize]={0}; + char name[sLineSize]={0}; + sscanf(cl,"%s %s",name,args); + list::iterator it=find_if(mCommands.begin(),mCommands.end(),bind2nd(mem_fun(&DaemonCommand::matches),name)); + if (it!=mCommands.end()){ + (*it)->exec(this,args); + }else{ + sendResponse(Response("Unknown command.")); + } +} + +void Daemon::sendResponse(const Response &resp){ + char buf[4096]={0}; + int size; + size=resp.toBuf(buf,sizeof(buf)); + if (mChildFd!=-1){ + if (write(mChildFd,buf,size)==-1){ + ms_error("Fail to write to pipe: %s",strerror(errno)); + } + }else{ + fprintf(stdout,"%s",buf); + fflush(stdout); + } +} + +char *Daemon::readPipe(char *buffer, int buflen){ + struct pollfd pfd[2]={{0},{0}}; + int nfds=1; + if (mServerFd!=-1){ + pfd[0].events=POLLIN; + pfd[0].fd=mServerFd; + } + if (mChildFd!=-1){ + pfd[1].events=POLLIN; + pfd[1].fd=mChildFd; + nfds++; + } + iterate(); + int err=poll(pfd,nfds,50); + if (err>0){ + if (mServerFd!=-1 && (pfd[0].revents & POLLIN)){ + struct sockaddr_storage addr; + socklen_t addrlen=sizeof(addr); + int childfd=accept(mServerFd,(struct sockaddr*)&addr,&addrlen); + if (childfd!=-1){ + if (mChildFd!=-1){ + ms_error("Cannot accept two client at the same time"); + close(childfd); + }else{ + mChildFd=childfd; + return NULL; + } + } + } + if (mChildFd!=-1 && (pfd[1].revents & POLLIN)){ + int ret; + if ((ret=read(mChildFd,buffer,buflen))==-1){ + ms_error("Fail to read from pipe: %s", strerror(errno)); + }else{ + if (ret==0){ + ms_message("Client disconnected"); + close(mChildFd); + mChildFd=-1; + return NULL; + } + buffer[ret]=0; + return buffer; + } + } + } + return NULL; +} + +static void printHelp(){ + fprintf(stdout,"ha-linphone []\n" + "where options are :\n" + "\t--help\t\tPrint this notice.\n" + "\t--pipe\t\tCreate an unix server socket to receive commands.\n" + "\t--config \tSupply a linphonerc style config file to start with.\n"); +} + +int Daemon::run(){ + char line[sLineSize]="ha-linphone>"; + char *ret; + mRunning=true; + while(mRunning){ + if (mServerFd==-1){ + ret=readline(line); + if (ret && ret[0]!='\0') { + add_history(ret); + } + }else{ + ret=readPipe(line,sLineSize); + } + if (ret && ret[0]!='\0') { + execCommand(ret); + } + } + return 0; +} + +void Daemon::quit(){ + mRunning=false; +} + +Daemon::~Daemon(){ + if (mChildFd!=-1){ + close(mChildFd); + } + if (mServerFd!=-1){ + ortp_server_pipe_close(mServerFd); + } + stifle_history(30); + write_history(mHistfile.c_str()); +} + +int main(int argc, char *argv[]){ + const char *config_path=NULL; + bool using_pipes=false; + int i; + + for(i=1;i Date: Tue, 20 Mar 2012 11:58:14 +0100 Subject: [PATCH 002/231] Add register command --- daemon/daemon.cc | 137 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 110 insertions(+), 27 deletions(-) diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 325869fcf..42125d7d0 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -81,7 +81,7 @@ class Daemon{ friend class DaemonCommand; public: typedef Response::Status Status; - Daemon(const char *config_path, bool using_pipes); + Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video); ~Daemon(); int run(); void quit(); @@ -136,7 +136,7 @@ class CallCommand : public DaemonCommand{ class TerminateCommand : public DaemonCommand{ public: - TerminateCommand() : DaemonCommand("terminate", "call ","Terminate a call."){ + TerminateCommand() : DaemonCommand("terminate", "terminate ","Terminate a call."){ } virtual void exec(Daemon *app, const char *args){ LinphoneCall *call = NULL; @@ -148,10 +148,11 @@ class TerminateCommand : public DaemonCommand{ app->sendResponse(Response("No call with such id.")); return; } - } - elem=linphone_core_get_calls(app->getCore()); - if (elem!=NULL && elem->next==NULL){ - call=(LinphoneCall*)elem->data; + } else { + elem=linphone_core_get_calls(app->getCore()); + if (elem!=NULL && elem->next==NULL){ + call=(LinphoneCall*)elem->data; + } } if (call==NULL){ app->sendResponse(Response("No active call.")); @@ -190,6 +191,63 @@ class HelpCommand : public DaemonCommand{ } }; +class RegisterCommand : public DaemonCommand{ + public: + RegisterCommand() : DaemonCommand("register", "register ","Register the daemon to a SIP proxy"){ + } + virtual void exec(Daemon *app, const char *args){ + LinphoneCore *lc=app->getCore(); + if (!args || args[0]=='\0') + { + /* it means that you want to register the default proxy */ + LinphoneProxyConfig *cfg=NULL; + linphone_core_get_default_proxy(lc,&cfg); + if (cfg) + { + if(!linphone_proxy_config_is_registered(cfg)) { + linphone_proxy_config_enable_register(cfg,TRUE); + linphone_proxy_config_done(cfg); + }else{ + app->sendResponse(Response("default proxy already registered")); + } + }else{ + app->sendResponse(Response("we do not have a default proxy")); + return; + } + return; + } + + char proxy[256]={0}, identity[128]={0}, password[64]={0}; + if (sscanf(args,"%255s %127s %63s", identity, proxy, password) >= 2){ + LinphoneProxyConfig *cfg = linphone_proxy_config_new(); + if (password[0]!='\0'){ + LinphoneAddress *from = linphone_address_new(identity); + if(from!=NULL) { + LinphoneAuthInfo *info =linphone_auth_info_new(linphone_address_get_username(from),NULL,password, NULL,NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + linphone_address_destroy(from); + linphone_auth_info_destroy(info); + } + } + const MSList * elem=linphone_core_get_proxy_config_list(lc); + if (elem) { + cfg=(LinphoneProxyConfig*)elem->data; + linphone_proxy_config_edit(cfg); + } + else cfg=linphone_proxy_config_new(); + linphone_proxy_config_set_identity(cfg,identity); + linphone_proxy_config_set_server_addr(cfg,proxy); + linphone_proxy_config_enable_register(cfg,TRUE); + if (elem) linphone_proxy_config_done(cfg); + else linphone_core_add_proxy_config(lc,cfg); + linphone_core_set_default_proxy(lc,cfg); + app->sendResponse(Response()); + } else { + app->sendResponse(Response("Missing parameters")); + } + } +}; + class PopEventCommand :public DaemonCommand{ public: PopEventCommand() : DaemonCommand("pop-event", "pop-event","Pop an event from event queue and display it."){ @@ -201,18 +259,37 @@ class PopEventCommand :public DaemonCommand{ class AnswerCommand :public DaemonCommand{ public: - AnswerCommand() : DaemonCommand("answer", "answer","Answer an incoming call."){ + AnswerCommand() : DaemonCommand("answer", "answer ","Answer an incoming call."){ } virtual void exec(Daemon *app, const char *args){ LinphoneCore *lc=app->getCore(); - const MSList* elem=linphone_core_get_calls(lc); - for(;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - LinphoneCallState cstate=linphone_call_get_state(call); - if (cstate==LinphoneCallIncomingReceived || cstate==LinphoneCallIncomingEarlyMedia){ - if (linphone_core_accept_call(lc,call)==0){ - app->sendResponse(Response()); - return; + int cid; + LinphoneCall *call; + if (sscanf(args,"%i",&cid)==1){ + call=app->findCall(cid); + if (call==NULL){ + app->sendResponse(Response("No call with such id.")); + return; + } else { + LinphoneCallState cstate=linphone_call_get_state(call); + if (cstate==LinphoneCallIncomingReceived || cstate==LinphoneCallIncomingEarlyMedia){ + if (linphone_core_accept_call(lc,call)==0){ + app->sendResponse(Response()); + return; + } + } + app->sendResponse(Response("Can't accept this call.")); + return; + } + } else { + for(const MSList* elem=linphone_core_get_calls(lc); elem!=NULL;elem=elem->next){ + call=(LinphoneCall*)elem->data; + LinphoneCallState cstate=linphone_call_get_state(call); + if (cstate==LinphoneCallIncomingReceived || cstate==LinphoneCallIncomingEarlyMedia){ + if (linphone_core_accept_call(lc,call)==0){ + app->sendResponse(Response()); + return; + } } } } @@ -240,24 +317,21 @@ bool DaemonCommand::matches(const char *name)const{ Daemon * Daemon::sZis=NULL; int Daemon::sCallIds=0; -Daemon::Daemon(const char *config_path, bool using_pipes){ +Daemon::Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video){ sZis=this; mServerFd=-1; mChildFd=-1; if (!using_pipes){ initReadline(); }else{ - mServerFd=ortp_server_pipe_create("ha-linphone"); + mServerFd=ortp_server_pipe_create("linphone-daemon"); listen(mServerFd,2); fprintf(stdout,"Server unix socket created, fd=%i\n",mServerFd); } LinphoneCoreVTable vtable={0}; vtable.call_state_changed=callStateChanged; mLc=linphone_core_new(&vtable,NULL,config_path,this); - linphone_core_enable_video(mLc,false,false); - linphone_core_set_playback_device(mLc,"HEADACOUSTICS"); - linphone_core_set_ringer_device(mLc,"HEADACOUSTICS"); - linphone_core_set_capture_device(mLc,"HEADACOUSTICS"); + linphone_core_enable_video(mLc,display_video,capture_video); linphone_core_enable_echo_cancellation(mLc,false); initCommands(); } @@ -285,6 +359,7 @@ LinphoneCall * Daemon::findCall(int id){ } void Daemon::initCommands(){ + mCommands.push_back(new RegisterCommand()); mCommands.push_back(new CallCommand()); mCommands.push_back(new TerminateCommand()); mCommands.push_back(new PopEventCommand()); @@ -353,7 +428,7 @@ int Daemon::readlineHook(){ void Daemon::initReadline() { const char *homedir=getenv("HOME"); - rl_readline_name = "ha"; + rl_readline_name = "daemon"; rl_set_keyboard_input_timeout(20000); rl_event_hook=readlineHook; @@ -367,7 +442,7 @@ void Daemon::initReadline() void Daemon::execCommand(const char *cl){ char args[sLineSize]={0}; char name[sLineSize]={0}; - sscanf(cl,"%s %s",name,args); + sscanf(cl,"%511s %511[^\n]",name,args); //Read the rest of line in args list::iterator it=find_if(mCommands.begin(),mCommands.end(),bind2nd(mem_fun(&DaemonCommand::matches),name)); if (it!=mCommands.end()){ (*it)->exec(this,args); @@ -439,15 +514,17 @@ char *Daemon::readPipe(char *buffer, int buflen){ } static void printHelp(){ - fprintf(stdout,"ha-linphone []\n" + fprintf(stdout,"daemon-linphone []\n" "where options are :\n" "\t--help\t\tPrint this notice.\n" "\t--pipe\t\tCreate an unix server socket to receive commands.\n" - "\t--config \tSupply a linphonerc style config file to start with.\n"); + "\t--config \tSupply a linphonerc style config file to start with.\n" + "\t-C\t\tenable video capture.\n" + "\t-D\t\tenable video display.\n"); } int Daemon::run(){ - char line[sLineSize]="ha-linphone>"; + char line[sLineSize]="daemon-linphone>"; char *ret; mRunning=true; while(mRunning){ @@ -484,6 +561,8 @@ Daemon::~Daemon(){ int main(int argc, char *argv[]){ const char *config_path=NULL; bool using_pipes=false; + bool capture_video=false; + bool display_video=false; int i; for(i=1;i Date: Tue, 20 Mar 2012 14:52:48 +0100 Subject: [PATCH 003/231] Status/Register/Unregister --- daemon/daemon.cc | 161 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 124 insertions(+), 37 deletions(-) diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 42125d7d0..a50656348 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -40,7 +40,12 @@ class Response{ } Response() : mStatus(Ok){ } - Response(const char *errormsg) : mStatus(Error), mReason(errormsg){ + Response(const char *msg, Status status = Error) : mStatus(status){ + if(status == Ok) { + mBody = msg; + } else { + mReason = msg; + } } void setStatus(Status st){ mStatus=st; @@ -89,9 +94,12 @@ class Daemon{ LinphoneCore *getCore(); const list &getCommandList()const; LinphoneCall *findCall(int id); + LinphoneProxyConfig *findProxy(int id); bool pullEvent(); static int getCallId(LinphoneCall *call); - void setCallId(LinphoneCall *call); + int setCallId(LinphoneCall *call); + static int getProxyId(LinphoneProxyConfig *proxy); + int setProxyId(LinphoneProxyConfig *proxy); private: static void callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg); @@ -111,6 +119,7 @@ class Daemon{ bool mRunning; static Daemon *sZis; static int sCallIds; + static int sProxyIds; static const int sLineSize=512; }; @@ -126,8 +135,7 @@ class CallCommand : public DaemonCommand{ }else{ Response resp; ostringstream ostr; - app->setCallId(call); - ostr<<"Id: "<setCallId(call)<<"\n"; resp.setBody(ostr.str().c_str()); app->sendResponse(resp); } @@ -193,30 +201,10 @@ class HelpCommand : public DaemonCommand{ class RegisterCommand : public DaemonCommand{ public: - RegisterCommand() : DaemonCommand("register", "register ","Register the daemon to a SIP proxy"){ + RegisterCommand() : DaemonCommand("register", "register ","Register the daemon to a default SIP proxy"){ } virtual void exec(Daemon *app, const char *args){ LinphoneCore *lc=app->getCore(); - if (!args || args[0]=='\0') - { - /* it means that you want to register the default proxy */ - LinphoneProxyConfig *cfg=NULL; - linphone_core_get_default_proxy(lc,&cfg); - if (cfg) - { - if(!linphone_proxy_config_is_registered(cfg)) { - linphone_proxy_config_enable_register(cfg,TRUE); - linphone_proxy_config_done(cfg); - }else{ - app->sendResponse(Response("default proxy already registered")); - } - }else{ - app->sendResponse(Response("we do not have a default proxy")); - return; - } - return; - } - char proxy[256]={0}, identity[128]={0}, password[64]={0}; if (sscanf(args,"%255s %127s %63s", identity, proxy, password) >= 2){ LinphoneProxyConfig *cfg = linphone_proxy_config_new(); @@ -229,25 +217,43 @@ class RegisterCommand : public DaemonCommand{ linphone_auth_info_destroy(info); } } - const MSList * elem=linphone_core_get_proxy_config_list(lc); - if (elem) { - cfg=(LinphoneProxyConfig*)elem->data; - linphone_proxy_config_edit(cfg); - } - else cfg=linphone_proxy_config_new(); linphone_proxy_config_set_identity(cfg,identity); linphone_proxy_config_set_server_addr(cfg,proxy); linphone_proxy_config_enable_register(cfg,TRUE); - if (elem) linphone_proxy_config_done(cfg); - else linphone_core_add_proxy_config(lc,cfg); - linphone_core_set_default_proxy(lc,cfg); - app->sendResponse(Response()); + app->setProxyId(cfg); + ostringstream ostr; + ostr<<"Id: "<sendResponse(Response(ostr.str().c_str(), Response::Ok)); } else { - app->sendResponse(Response("Missing parameters")); + app->sendResponse(Response("Missing/Incorrect parameter(s).")); } } }; +class UnregisterCommand : public DaemonCommand{ + public: + UnregisterCommand() : DaemonCommand("unregister", "unregister ","Unregister from default proxy"){ + } + virtual void exec(Daemon *app, const char *args){ + LinphoneCore *lc=app->getCore(); + LinphoneProxyConfig *cfg = NULL; + int pid; + if (sscanf(args,"%i",&pid)==1){ + cfg=app->findProxy(pid); + if (cfg==NULL){ + app->sendResponse(Response("No register with such id.")); + return; + } + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + return; + } + linphone_core_remove_proxy_config(lc, cfg); + app->sendResponse(Response()); + } +}; + class PopEventCommand :public DaemonCommand{ public: PopEventCommand() : DaemonCommand("pop-event", "pop-event","Pop an event from event queue and display it."){ @@ -257,6 +263,64 @@ class PopEventCommand :public DaemonCommand{ } }; +class StatusCommand :public DaemonCommand{ + public: + StatusCommand() : DaemonCommand("status", "status ","Return status of a call."){ + } + virtual void exec(Daemon *app, const char *args){ + LinphoneCore *lc=app->getCore(); + int cid; + LinphoneCall *call = NULL; + if (sscanf(args,"%i",&cid)==1){ + call=app->findCall(cid); + if(call == NULL) { + app->sendResponse(Response("No call with such id.")); + return; + } + } else { + call = linphone_core_get_current_call (lc); + if(call == NULL) { + app->sendResponse(Response("No current call available.")); + return; + } + } + + LinphoneCallState call_state=LinphoneCallIdle; + call_state=linphone_call_get_state(call); + const LinphoneAddress *remoteAddress=linphone_call_get_remote_address(call); + char buffer[512] = {0}; + switch(call_state){ + case LinphoneCallOutgoingInit: + snprintf(buffer, sizeof(buffer) - 1, "outgoing_init sip:%s", linphone_address_as_string(remoteAddress)); + break; + case LinphoneCallOutgoingProgress: + snprintf(buffer, sizeof(buffer) - 1, "dialing sip:%s", linphone_address_as_string(remoteAddress)); + break; + case LinphoneCallOutgoingRinging: + snprintf(buffer, sizeof(buffer) - 1, "ringing sip:%s", linphone_address_as_string(remoteAddress)); + break; + case LinphoneCallPaused: + snprintf(buffer, sizeof(buffer) - 1, "paused sip:%s", linphone_address_as_string(remoteAddress)); + break; + case LinphoneCallIdle: + snprintf(buffer, sizeof(buffer) - 1, "offhook"); + break; + case LinphoneCallStreamsRunning: + case LinphoneCallConnected: + snprintf(buffer, sizeof(buffer) - 1, "running %s sip:%s, duration=%i", + linphone_call_get_dir(call)==LinphoneCallOutgoing?"out":"in", + linphone_address_as_string(remoteAddress), linphone_call_get_duration(call)); + break; + case LinphoneCallIncomingReceived: + snprintf(buffer, sizeof(buffer) - 1, "incoming sip:%s", linphone_address_as_string(remoteAddress)); + break; + default: + break; + } + app->sendResponse(Response(buffer, Response::Ok)); + } +}; + class AnswerCommand :public DaemonCommand{ public: AnswerCommand() : DaemonCommand("answer", "answer ","Answer an incoming call."){ @@ -316,6 +380,7 @@ bool DaemonCommand::matches(const char *name)const{ Daemon * Daemon::sZis=NULL; int Daemon::sCallIds=0; +int Daemon::sProxyIds=0; Daemon::Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video){ sZis=this; @@ -344,8 +409,9 @@ LinphoneCore * Daemon::getCore(){ return mLc; } -void Daemon::setCallId(LinphoneCall *call){ +int Daemon::setCallId(LinphoneCall *call){ linphone_call_set_user_pointer(call,(void*)(long)++sCallIds); + return sCallIds; } LinphoneCall * Daemon::findCall(int id){ @@ -358,12 +424,29 @@ LinphoneCall * Daemon::findCall(int id){ return NULL; } +int Daemon::setProxyId(LinphoneProxyConfig *cfg){ + linphone_proxy_config_set_user_data(cfg,(void*)(long)++sProxyIds); + return sProxyIds; +} + +LinphoneProxyConfig * Daemon::findProxy(int id){ + const MSList *elem=linphone_core_get_proxy_config_list(mLc); + for (;elem!=NULL;elem=elem->next){ + LinphoneProxyConfig *proxy=(LinphoneProxyConfig *)elem->data; + if (linphone_proxy_config_get_user_data(proxy)==(void*)(long)id) + return proxy; + } + return NULL; +} + void Daemon::initCommands(){ mCommands.push_back(new RegisterCommand()); + mCommands.push_back(new UnregisterCommand()); mCommands.push_back(new CallCommand()); mCommands.push_back(new TerminateCommand()); mCommands.push_back(new PopEventCommand()); mCommands.push_back(new AnswerCommand()); + mCommands.push_back(new StatusCommand()); mCommands.push_back(new QuitCommand()); mCommands.push_back(new HelpCommand()); @@ -386,6 +469,10 @@ int Daemon::getCallId(LinphoneCall *call){ return (int)(long)linphone_call_get_user_pointer(call); } +int Daemon::getProxyId(LinphoneProxyConfig *proxy){ + return (int)(long)linphone_proxy_config_get_user_data(proxy); +} + void Daemon::callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg){ switch(state){ case LinphoneCallOutgoingProgress: From d76e2129ebea6e864190800ac7505ee42f6f3f68 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 26 Mar 2012 12:56:06 +0200 Subject: [PATCH 004/231] Add openembedded build --- build/openembedded/README | 51 +++++++++++++ .../files/igep0020/alsa_8khz.patch | 13 ++++ build/openembedded/libexosip2_3.5.0.bb | 17 +++++ build/openembedded/linphone-common.inc | 74 +++++++++++++++++++ build/openembedded/linphone-common_git.inc | 33 +++++++++ build/openembedded/linphone_+git-nogtk.bb | 13 ++++ build/openembedded/spandsp_0.0.6-pre18.bb | 23 ++++++ build/openembedded/speex_git.bb | 45 +++++++++++ 8 files changed, 269 insertions(+) create mode 100644 build/openembedded/README create mode 100644 build/openembedded/files/igep0020/alsa_8khz.patch create mode 100644 build/openembedded/libexosip2_3.5.0.bb create mode 100644 build/openembedded/linphone-common.inc create mode 100644 build/openembedded/linphone-common_git.inc create mode 100644 build/openembedded/linphone_+git-nogtk.bb create mode 100644 build/openembedded/spandsp_0.0.6-pre18.bb create mode 100644 build/openembedded/speex_git.bb diff --git a/build/openembedded/README b/build/openembedded/README new file mode 100644 index 000000000..b8e895451 --- /dev/null +++ b/build/openembedded/README @@ -0,0 +1,51 @@ +Recipes for open embedded: http://www.openembedded.org + + +Documentations: +http://docs.openembedded.org/usermanual/ +http://bitbake.berlios.de/manual/ + + + +Instructions for compilation from sources: (requires 10 Go of free space) +- Choose a distribution and build it. + For example, to build Angstrom follow the guide at http://www.angstrom-distribution.org/building-angstrom + For IGEPv2 use environment variable MACHINE=igep0020 + +- Add recipes to the pool with an higher priority). + See http://bitbake.berlios.de/manual/ch04s02.html#id870544 Example 4.8. Using “bbfile collections” + Example: + BBFILES = "/Data/work/angstrom/angstrom-setup-scripts/sources/openembedded/recipes/*/*.bb /home/guillaume/dev/linphone-daemon/build/openembedded/*.bb" + BBFILE_COLLECTIONS = "upstream local" + BBFILE_PATTERN_upstream = "^/Data/" + BBFILE_PATTERN_local = "^/home/" + BBFILE_PRIORITY_upstream = "5" + BBFILE_PRIORITY_local = "10" + +- Prepare compilation + Source appropriate environment with "~/.oe/enviro*" + Change directory to where you launched Angstrom install script. + +- Compile linphone / linphonec + bitbake -c clean linphone + bitbake linphone + + +- Find the generated packages "*.ipk" + Example: /Data/work/angstrom/angstrom-setup-scripts/build/tmp-angstrom_2008_1/deploy/glibc/ipk/armv7a/ + + + + +Installation +- check network connectivity + * ping linphone.org + * see "route -n" + * see "/etc/resolv.conf" +- update package list + * opkg update +- copy ipk files to install to /tmp +- eventually remove previously installed packages +- install with "opkg install libortp*.ipk libmediastreamer*.ipk liblinphone*.ipk linphonec*.ipk" + + diff --git a/build/openembedded/files/igep0020/alsa_8khz.patch b/build/openembedded/files/igep0020/alsa_8khz.patch new file mode 100644 index 000000000..17774d4e6 --- /dev/null +++ b/build/openembedded/files/igep0020/alsa_8khz.patch @@ -0,0 +1,13 @@ +--- linphone/mediastreamer2/src/alsa.c_orig 2011-05-24 12:39:33.824600109 +0200 ++++ linphone/mediastreamer2/src/alsa.c 2011-05-24 12:40:04.760407404 +0200 +@@ -32,8 +32,8 @@ + /*in case of troubles with a particular driver, try incrementing ALSA_PERIOD_SIZE + to 512, 1024, 2048, 4096... + then try incrementing the number of periods*/ +-#define ALSA_PERIODS 8 +-#define ALSA_PERIOD_SIZE 256 ++#define ALSA_PERIODS 4 ++#define ALSA_PERIOD_SIZE 512 + + /*uncomment the following line if you have problems with an alsa driver + having sound quality trouble:*/ diff --git a/build/openembedded/libexosip2_3.5.0.bb b/build/openembedded/libexosip2_3.5.0.bb new file mode 100644 index 000000000..706494064 --- /dev/null +++ b/build/openembedded/libexosip2_3.5.0.bb @@ -0,0 +1,17 @@ +DESCRIPTION = "High level Session Initiation Protocol (SIP) library" +SECTION = "libs" +PRIORITY = "optional" +LICENSE = "GPL" +DEPENDS = "libosip2" +SRCNAME = "libeXosip2" +LEAD_SONAME = "libeXosip2" + +PR = "r1" +SRC_URI = "http://download.savannah.nongnu.org/releases/exosip/${SRCNAME}-${PV}.tar.gz" +S = "${WORKDIR}/${SRCNAME}-${PV}" + +inherit autotools pkgconfig +EXTRA_OECONF = "--disable-josua" +DEFAULT_PREFERENCE = "3" +SRC_URI[md5sum] = "51e85725571870614e448f63c33c8996" +SRC_URI[sha256sum] = "46010e62a6f675df13e5be759d033b6bce1bd5882eebb4acd553f9dd3b461afc" diff --git a/build/openembedded/linphone-common.inc b/build/openembedded/linphone-common.inc new file mode 100644 index 000000000..cd595b7df --- /dev/null +++ b/build/openembedded/linphone-common.inc @@ -0,0 +1,74 @@ +SECTION = "x11/network" +SECTION_liblinphone = "libs/network" +SECTION_libmediastreamer = "libs/network" +SECTION_libortp = "libs/network" +SECTION_linphonec = "console/network" + +SRC_URI_append_igep0020 = " file://alsa_8khz.patch" + +DEPENDS = "intltool readline libosip2 libexosip2 speex alsa-lib spandsp" +DEPENDS_append_video = " libxv ffmpeg libv4l" +DEPENDS_append_gtk = " gtk+" +DEPENDS_${PN} = "intltool liblinphone" +DEPENDS_${PN}_append_gtk = " gtk+" +DEPENDS_${PN}_append_video = " libxv" +DEPENDS_${PN}c = "liblinphone readline" +DEPENDS_liblinphone = "libmediastreamer libortp libosip2 libexosip2" +DEPENDS_libmediastreamer = "speex alsa-lib libortp" +DEPENDS_libmediastreamer_append_video = " ffmpeg libv4l" + +PROVIDES = "linphonec liblinphone libmediastreamer libortp" +PROVIDES_gtk = "linphone linphonec liblinphone libmediastreamer libortp" + +inherit autotools pkgconfig gettext + +export PKG_CONFIG=${STAGING_BINDIR_NATIVE}/pkg-config + +LINPHONE_OE_ENABLE_TESTS = "--disable-tests" +LINPHONE_OE_ENABLE_VIDEO = "--disable-video" +LINPHONE_OE_ENABLE_VIDEO_video = "--with-ffmpeg=${STAGING_DIR_HOST}${layout_exec_prefix} --enable-video" + +LINPHONE_OE_ENABLE_CONSOLE_UI = "no" +LINPHONE_OE_ENABLE_CONSOLE_UI_console = "yes" + +LINPHONE_OE_ENABLE_GTK_UI = "no" +LINPHONE_OE_ENABLE_GTK_UI_gtk = "yes" + +do_install_append(){ + install -d ${D}${bindir} +} + +EXTRA_OECONF = " \ + ${LINPHONE_OE_ENABLE_TESTS} \ + ${LINPHONE_OE_ENABLE_VIDEO} \ + --enable-alsa \ + --with-osip=${STAGING_DIR_HOST}${layout_exec_prefix} \ + --with-readline=${STAGING_DIR_HOST}${layout_exec_prefix} \ + --with-speex=${STAGING_DIR_HOST}${layout_exec_prefix} \ + --disable-manual --enable-tests=yes \ + --enable-console_ui=${LINPHONE_OE_ENABLE_CONSOLE_UI} \ + --enable-gtk_ui=${LINPHONE_OE_ENABLE_GTK_UI} \ + --with-realprefix=/usr \ + " + +PACKAGES_gtk = "${PN}-dbg ${PN} ${PN}-doc ${PN}-dev ${PN}-locale ${PN}c linphone-rings liblinphone libmediastreamer-bin libmediastreamer libortp ${PN}-utils" +PACKAGES = "${PN}c linphone-rings liblinphone libmediastreamer-bin libmediastreamer libortp ${PN}-utils" + +FILES_${PN} = " \ + ${bindir}/linphone \ + ${datadir}/linphone \ + ${datadir}/pixmaps \ + ${datadir}/applications \ + ${datadir}/gnome/apps \ + ${datadir}/sounds/linphone/hello8000.wav \ + ${datadir}/sounds/linphone/hello16000.wav \ + ${datadir}/images/nowebcamCIF.jpg \ + " +FILES_${PN}c = "${bindir}/linphonec ${bindir}/linphone-daemon ${bindir}/linphone-daemon-pipetest ${bindir}/linphonecsh ${bindir}/sipomatic ${datadir}/sounds/linphone/ringback.wav" +FILES_${PN}-rings = "${datadir}/sounds/linphone/rings" +FILES_liblinphone = "${libdir}/liblinphone.so.*" +FILES_libmediastreamer-bin = "/usr/libexec/mediastream" +FILES_libmediastreamer = "${libdir}/libmediastreamer.so.*" +FILES_libortp = "${libdir}/libortp.so.*" +FILES_${PN}-dev += "${libdir}/*.a ${libdir}/*.la ${libdir}/pkgconfig ${includedir}" +FILES_${PN}-utils = "${bindir}/test_ecc ${bindir}/test_lsd" diff --git a/build/openembedded/linphone-common_git.inc b/build/openembedded/linphone-common_git.inc new file mode 100644 index 000000000..399890e70 --- /dev/null +++ b/build/openembedded/linphone-common_git.inc @@ -0,0 +1,33 @@ + +SRCREV = "c65a7ee79d66ee2c0eb19cde129221be650c07ca" +L_GIT_SRC_URI = "gitosis@git.linphone.org:linphone-daemon" +PR_append = "+gitr${SRCREV}" + +LINPHONE_TMP_DIR="${HOME}/LINPHONE_TMP_${SRCREV}" +SRC_URI = "file://${LINPHONE_TMP_DIR}/linphone.tar.gz" + +S = "${WORKDIR}/linphone" + +# bitbake git fetcher currently doesn't handle git submodules +# There is also a problem with autogen and AC_SUBST +do_fetch_prepend () { + import os,bb + bb.note("Hack preparing clone in %s" %"${LINPHONE_TMP_DIR}") + os.system("rm -rf ${LINPHONE_TMP_DIR}") + os.system("mkdir -p ${LINPHONE_TMP_DIR}") + + bb.note("Hack cloning linphone !recursively") + os.system("cd ${LINPHONE_TMP_DIR}; git clone --depth 1 --recursive ${L_GIT_SRC_URI} linphone; tag=${SRCREV};") + + bb.note("Hack launching autogen.sh manually") + os.system("cd ${LINPHONE_TMP_DIR}/linphone; ./autogen.sh") + + bb.note("Hack preparing linphone.tar.gz") + os.system("cd ${LINPHONE_TMP_DIR}; tar czf linphone.tar.gz --exclude .git linphone") +} + +require linphone-common.inc + + +#Required to avoid compile errors on May 2011. +EXTRA_OECONF +=" --disable-strict" diff --git a/build/openembedded/linphone_+git-nogtk.bb b/build/openembedded/linphone_+git-nogtk.bb new file mode 100644 index 000000000..8a8896c9f --- /dev/null +++ b/build/openembedded/linphone_+git-nogtk.bb @@ -0,0 +1,13 @@ +## THIS unusable work in progress ## + +DESCRIPTION = "Audio/video SIP-based IP phone (console edition)" +HOMEPAGE = "http://www.linphone.org/?lang=us" +LICENSE = "GPLv2" +PR="r9" + +DEFAULT_PREFERENCE = "3" +OVERRIDES_append = ":console" + +#PARALLEL_MAKE="V=1" + +require linphone-common_git.inc diff --git a/build/openembedded/spandsp_0.0.6-pre18.bb b/build/openembedded/spandsp_0.0.6-pre18.bb new file mode 100644 index 000000000..53d25f2c2 --- /dev/null +++ b/build/openembedded/spandsp_0.0.6-pre18.bb @@ -0,0 +1,23 @@ +PR = "r0" + +SRC_URI = "http://www.soft-switch.org/downloads/spandsp/${PN}-0.0.6pre18.tgz" + +S = "${WORKDIR}/spandsp-0.0.6" + +# *cough* +do_configure_append() { + rm config.log +} + +DESCRIPTION = "A library of many DSP functions for telephony." +HOMEPAGE = "http://www.soft-switch.org" +SECTION = "libs" +LICENSE = "LGPL" +DEPENDS = "tiff libxml2" + +inherit autotools + +PARALLEL_MAKE = "" + +SRC_URI[md5sum] = "98330bc00a581ed8d71ebe34afabbcf9" +SRC_URI[sha256sum] = "835cd886105e4e39791f0e8cfe004c39b069f2e6dcb0795a68a6c79b5d14af2c" diff --git a/build/openembedded/speex_git.bb b/build/openembedded/speex_git.bb new file mode 100644 index 000000000..b61a2eed1 --- /dev/null +++ b/build/openembedded/speex_git.bb @@ -0,0 +1,45 @@ +DESCRIPTION = "Speex is an Open Source/Free Software patent-free audio compression format designed for speech." +SECTION = "libs/multimedia" +LICENSE = "BSD" +HOMEPAGE = "http://www.speex.org" +DEPENDS = "libogg" +PV = "1.1+git" +PR = "r3" +SPEEX_TMP_DIR="${HOME}/SPEEX_TMP" +SRC_URI = "file://${SPEEX_TMP_DIR}/speex.tar.gz" + +S = "${WORKDIR}/speex" + +PARALLEL_MAKE = "" + +inherit autotools pkgconfig + +LEAD_SONAME = "libspeex.so" + +#check for TARGET_FPU=soft and inform configure of the result so it can disable some floating points +EXTRA_OECONF += "--enable-fixed-point --enable-armv7neon-asm" + +do_fetch_prepend () { + import os,bb + bb.note("Hack preparing clone in %s" %"${SPEEX_TMP_DIR}") + os.system("rm -rf ${SPEEX_TMP_DIR}") + os.system("mkdir -p ${SPEEX_TMP_DIR}") + + os.system("cd ${SPEEX_TMP_DIR}; git clone --depth 1 git://git.linphone.org/speex") + + os.system("cd ${SPEEX_TMP_DIR}/speex; ./autogen.sh") + + os.system("cd ${SPEEX_TMP_DIR}; tar czf speex.tar.gz --exclude .git speex") +} + +do_configure_append() { + sed -i s/"^OGG_CFLAGS.*$"/"OGG_CFLAGS = "/g Makefile */Makefile */*/Makefile + sed -i s/"^OGG_LIBS.*$"/"OGG_LIBS = -logg"/g Makefile */Makefile */*/Makefile + find . -name "Makefile" -exec sed -i s,-I/usr/include,, {} \; +} + +PACKAGES =+ "${PN}-utils ${PN}-dsp" +FILES_${PN}-utils = "${bindir}/speex*" +FILES_${PN}-dsp = "${libdir}/libspeexdsp.so.*" +FILES_${PN} = "${libdir}/libspeex.so.*" + From b8bca601d9c79f3e101d8f9263fdca54ba3f111e Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 30 Mar 2012 09:34:22 +0200 Subject: [PATCH 005/231] Modify command description --- daemon/daemon-pipetest.c | 2 +- daemon/daemon.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/daemon/daemon-pipetest.c b/daemon/daemon-pipetest.c index 2da3f77e6..068e58462 100644 --- a/daemon/daemon-pipetest.c +++ b/daemon/daemon-pipetest.c @@ -10,7 +10,7 @@ static int running=1; int main(int argc, char *argv[]){ - int fd=ortp_client_pipe_connect("ha-linphone"); + int fd=ortp_client_pipe_connect("linphone-daemon"); struct pollfd pfds[2]={{0}}; char buf[4096]; diff --git a/daemon/daemon.cc b/daemon/daemon.cc index a50656348..49ef0f463 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -201,7 +201,7 @@ class HelpCommand : public DaemonCommand{ class RegisterCommand : public DaemonCommand{ public: - RegisterCommand() : DaemonCommand("register", "register ","Register the daemon to a default SIP proxy"){ + RegisterCommand() : DaemonCommand("register", "register ","Register the daemon to a SIP proxy."){ } virtual void exec(Daemon *app, const char *args){ LinphoneCore *lc=app->getCore(); @@ -233,7 +233,7 @@ class RegisterCommand : public DaemonCommand{ class UnregisterCommand : public DaemonCommand{ public: - UnregisterCommand() : DaemonCommand("unregister", "unregister ","Unregister from default proxy"){ + UnregisterCommand() : DaemonCommand("unregister", "unregister ","Unregister the daemon from proxy."){ } virtual void exec(Daemon *app, const char *args){ LinphoneCore *lc=app->getCore(); From 4f27360317112c590c12fdd81b54a9625cbb9e44 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 3 Apr 2012 16:43:41 +0200 Subject: [PATCH 006/231] Add audio codec commands --- daemon/daemon.cc | 1130 +++++++++++++++++++++++++++------------------- 1 file changed, 663 insertions(+), 467 deletions(-) diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 49ef0f463..5706f3e18 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -1,4 +1,3 @@ - #include "linphonecore.h" #include #include @@ -13,586 +12,778 @@ using namespace std; - class Daemon; -class DaemonCommand{ - public: - virtual void exec(Daemon *app, const char *args)=0; - bool matches(const char *name)const; - const std::string &getProto()const{ - return mProto; - } - const std::string &getHelp()const{ - return mHelp; - } - protected: - DaemonCommand(const char *name, const char *proto, const char *help); - const std::string mName; - const std::string mProto; - const std::string mHelp; +class DaemonCommand { +public: + virtual void exec(Daemon *app, const char *args)=0; + bool matches(const char *name) const; + const std::string &getProto() const { + return mProto; + } + const std::string &getHelp() const { + return mHelp; + } +protected: + DaemonCommand(const char *name, const char *proto, const char *help); + const std::string mName; + const std::string mProto; + const std::string mHelp; }; -class Response{ - public: - enum Status { Ok, Error}; - virtual ~Response(){ +class Response { +public: + enum Status { + Ok, Error + }; + virtual ~Response() { + } + Response() : + mStatus(Ok) { + } + Response(const char *msg, Status status = Error) : + mStatus(status) { + if (status == Ok) { + mBody = msg; + } else { + mReason = msg; } - Response() : mStatus(Ok){ + } + void setStatus(Status st) { + mStatus = st; + } + void setReason(const char *reason) { + mReason = reason; + } + void setBody(const char *body) { + mBody = body; + } + const std::string &getBody() const { + return mBody; + } + virtual int toBuf(char *dst, int dstlen) const { + int i = 0; + i += snprintf(dst + i, dstlen - i, "Status: %s\n", mStatus == Ok ? "Ok" : "Error"); + if (mReason.size() > 0) { + i += snprintf(dst + i, dstlen - i, "Reason: %s\n", mReason.c_str()); } - Response(const char *msg, Status status = Error) : mStatus(status){ - if(status == Ok) { - mBody = msg; - } else { - mReason = msg; - } + if (mBody.size() > 0) { + i += snprintf(dst + i, dstlen - i, "\n%s\n", mBody.c_str()); } - void setStatus(Status st){ - mStatus=st; - } - void setReason(const char *reason){ - mReason=reason; - } - void setBody(const char *body){ - mBody=body; - } - const std::string &getBody()const{ - return mBody; - } - virtual int toBuf(char *dst, int dstlen)const{ - int i=0; - i+=snprintf(dst+i,dstlen-i,"Status: %s\n",mStatus==Ok ? "Ok" : "Error"); - if (mReason.size()>0){ - i+=snprintf(dst+i,dstlen-i,"Reason: %s\n",mReason.c_str()); - } - if (mBody.size()>0){ - i+=snprintf(dst+i,dstlen-i,"\n%s\n",mBody.c_str()); - } - return i; - } - private: - Status mStatus; - string mReason; - string mBody; + return i; + } +private: + Status mStatus; + string mReason; + string mBody; }; -class EventResponse : public Response{ - public: - EventResponse(LinphoneCall *call, LinphoneCallState state); - private: +class EventResponse: public Response { +public: + EventResponse(LinphoneCall *call, LinphoneCallState state); +private: }; -class Daemon{ +class PayloadTypeResponse: public Response { +public: + PayloadTypeResponse(LinphoneCore *core, PayloadType *payloadType, int index); +private: +}; + +class Daemon { friend class DaemonCommand; - public: - typedef Response::Status Status; - Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video); - ~Daemon(); - int run(); - void quit(); - void sendResponse(const Response &resp); - LinphoneCore *getCore(); - const list &getCommandList()const; - LinphoneCall *findCall(int id); - LinphoneProxyConfig *findProxy(int id); - bool pullEvent(); - static int getCallId(LinphoneCall *call); - int setCallId(LinphoneCall *call); - static int getProxyId(LinphoneProxyConfig *proxy); - int setProxyId(LinphoneProxyConfig *proxy); - private: - - static void callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg); - static int readlineHook(); - void callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg); - void execCommand(const char *cl); - void initReadline(); - char *readPipe(char *buffer, int buflen); - void iterate(); - void initCommands(); - LinphoneCore *mLc; - std::list mCommands; - queue mEventQueue; - int mServerFd; - int mChildFd; - string mHistfile; - bool mRunning; - static Daemon *sZis; - static int sCallIds; - static int sProxyIds; - static const int sLineSize=512; +public: + typedef Response::Status Status; + Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video); + ~Daemon(); + int run(); + void quit(); + void sendResponse(const Response &resp); + LinphoneCore *getCore(); + const list &getCommandList() const; + LinphoneCall *findCall(int id); + LinphoneProxyConfig *findProxy(int id); + bool pullEvent(); + static int getCallId(LinphoneCall *call); + int setCallId(LinphoneCall *call); + static int getProxyId(LinphoneProxyConfig *proxy); + int setProxyId(LinphoneProxyConfig *proxy); +private: + + static void callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg); + static int readlineHook(); + void callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg); + void execCommand(const char *cl); + void initReadline(); + char *readPipe(char *buffer, int buflen); + void iterate(); + void initCommands(); + void uninitCommands(); + LinphoneCore *mLc; + std::list mCommands; + queue mEventQueue; + int mServerFd; + int mChildFd; + string mHistfile; + bool mRunning; + static Daemon *sZis; + static int sCallIds; + static int sProxyIds; + static const int sLineSize = 512; }; -class CallCommand : public DaemonCommand{ - public: - CallCommand() : DaemonCommand("call", "call ","Place a call."){ - } - virtual void exec(Daemon *app, const char *args){ - LinphoneCall *call; - call=linphone_core_invite(app->getCore(),args); - if (call==NULL){ - app->sendResponse(Response("Call creation failed.")); - }else{ - Response resp; - ostringstream ostr; - ostr<<"Id: "<< app->setCallId(call)<<"\n"; - resp.setBody(ostr.str().c_str()); - app->sendResponse(resp); - } - } -}; - -class TerminateCommand : public DaemonCommand{ - public: - TerminateCommand() : DaemonCommand("terminate", "terminate ","Terminate a call."){ - } - virtual void exec(Daemon *app, const char *args){ - LinphoneCall *call = NULL; - int cid; - const MSList *elem; - if (sscanf(args,"%i",&cid)==1){ - call=app->findCall(cid); - if (call==NULL){ - app->sendResponse(Response("No call with such id.")); - return; - } - } else { - elem=linphone_core_get_calls(app->getCore()); - if (elem!=NULL && elem->next==NULL){ - call=(LinphoneCall*)elem->data; - } - } - if (call==NULL){ - app->sendResponse(Response("No active call.")); - return; - } - linphone_core_terminate_call(app->getCore(),call); - app->sendResponse(Response()); - } -}; - -class QuitCommand : public DaemonCommand{ - public: - QuitCommand() : DaemonCommand("quit", "quit","Quit the application."){ - } - virtual void exec(Daemon *app, const char *args){ - app->quit(); - app->sendResponse(Response()); - } -}; - -class HelpCommand : public DaemonCommand{ - public: - HelpCommand() : DaemonCommand("help", "help","Show available commands."){ - } - virtual void exec(Daemon *app, const char *args){ - char str[4096]={0}; - int written=0; - list::const_iterator it; - const list &l=app->getCommandList(); - for(it=l.begin();it!=l.end();++it){ - written+=snprintf(str+written,sizeof(str)-written,"%s\t%s\n",(*it)->getProto().c_str(),(*it)->getHelp().c_str()); - } +class CallCommand: public DaemonCommand { +public: + CallCommand() : + DaemonCommand("call", "call ", "Place a call.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneCall *call; + call = linphone_core_invite(app->getCore(), args); + if (call == NULL) { + app->sendResponse(Response("Call creation failed.")); + } else { Response resp; - resp.setBody(str); + ostringstream ostr; + ostr << "Id: " << app->setCallId(call) << "\n"; + resp.setBody(ostr.str().c_str()); app->sendResponse(resp); } + } }; -class RegisterCommand : public DaemonCommand{ - public: - RegisterCommand() : DaemonCommand("register", "register ","Register the daemon to a SIP proxy."){ - } - virtual void exec(Daemon *app, const char *args){ - LinphoneCore *lc=app->getCore(); - char proxy[256]={0}, identity[128]={0}, password[64]={0}; - if (sscanf(args,"%255s %127s %63s", identity, proxy, password) >= 2){ - LinphoneProxyConfig *cfg = linphone_proxy_config_new(); - if (password[0]!='\0'){ - LinphoneAddress *from = linphone_address_new(identity); - if(from!=NULL) { - LinphoneAuthInfo *info =linphone_auth_info_new(linphone_address_get_username(from),NULL,password, NULL,NULL); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - linphone_address_destroy(from); - linphone_auth_info_destroy(info); - } - } - linphone_proxy_config_set_identity(cfg,identity); - linphone_proxy_config_set_server_addr(cfg,proxy); - linphone_proxy_config_enable_register(cfg,TRUE); - app->setProxyId(cfg); - ostringstream ostr; - ostr<<"Id: "<sendResponse(Response(ostr.str().c_str(), Response::Ok)); - } else { - app->sendResponse(Response("Missing/Incorrect parameter(s).")); - } - } -}; - -class UnregisterCommand : public DaemonCommand{ - public: - UnregisterCommand() : DaemonCommand("unregister", "unregister ","Unregister the daemon from proxy."){ - } - virtual void exec(Daemon *app, const char *args){ - LinphoneCore *lc=app->getCore(); - LinphoneProxyConfig *cfg = NULL; - int pid; - if (sscanf(args,"%i",&pid)==1){ - cfg=app->findProxy(pid); - if (cfg==NULL){ - app->sendResponse(Response("No register with such id.")); - return; - } - } else { - app->sendResponse(Response("Missing/Incorrect parameter(s).")); +class TerminateCommand: public DaemonCommand { +public: + TerminateCommand() : + DaemonCommand("terminate", "terminate ", "Terminate a call.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneCall *call = NULL; + int cid; + const MSList *elem; + if (sscanf(args, "%i", &cid) == 1) { + call = app->findCall(cid); + if (call == NULL) { + app->sendResponse(Response("No call with such id.")); return; } - linphone_core_remove_proxy_config(lc, cfg); - app->sendResponse(Response()); + } else { + elem = linphone_core_get_calls(app->getCore()); + if (elem != NULL && elem->next == NULL) { + call = (LinphoneCall*) elem->data; + } } + if (call == NULL) { + app->sendResponse(Response("No active call.")); + return; + } + linphone_core_terminate_call(app->getCore(), call); + app->sendResponse(Response()); + } }; -class PopEventCommand :public DaemonCommand{ - public: - PopEventCommand() : DaemonCommand("pop-event", "pop-event","Pop an event from event queue and display it."){ - } - virtual void exec(Daemon *app, const char *args){ - app->pullEvent(); - } +class QuitCommand: public DaemonCommand { +public: + QuitCommand() : + DaemonCommand("quit", "quit", "Quit the application.") { + } + virtual void exec(Daemon *app, const char *args) { + app->quit(); + app->sendResponse(Response()); + } }; -class StatusCommand :public DaemonCommand{ - public: - StatusCommand() : DaemonCommand("status", "status ","Return status of a call."){ +class HelpCommand: public DaemonCommand { +public: + HelpCommand() : + DaemonCommand("help", "help", "Show available commands.") { + } + virtual void exec(Daemon *app, const char *args) { + char str[4096] = { 0 }; + int written = 0; + list::const_iterator it; + const list &l = app->getCommandList(); + for (it = l.begin(); it != l.end(); ++it) { + written += snprintf(str + written, sizeof(str) - written, "%s\t%s\n", (*it)->getProto().c_str(), (*it)->getHelp().c_str()); } - virtual void exec(Daemon *app, const char *args){ - LinphoneCore *lc=app->getCore(); - int cid; - LinphoneCall *call = NULL; - if (sscanf(args,"%i",&cid)==1){ - call=app->findCall(cid); - if(call == NULL) { - app->sendResponse(Response("No call with such id.")); - return; - } - } else { - call = linphone_core_get_current_call (lc); - if(call == NULL) { - app->sendResponse(Response("No current call available.")); - return; + Response resp; + resp.setBody(str); + app->sendResponse(resp); + } +}; + +class RegisterCommand: public DaemonCommand { +public: + RegisterCommand() : + DaemonCommand("register", "register ", "Register the daemon to a SIP proxy.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneCore *lc = app->getCore(); + char proxy[256] = { 0 }, identity[128] = { 0 }, password[64] = { 0 }; + if (sscanf(args, "%255s %127s %63s", identity, proxy, password) >= 2) { + LinphoneProxyConfig *cfg = linphone_proxy_config_new(); + if (password[0] != '\0') { + LinphoneAddress *from = linphone_address_new(identity); + if (from != NULL) { + LinphoneAuthInfo *info = linphone_auth_info_new(linphone_address_get_username(from), NULL, password, NULL, NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc, info); /*add authentication info to LinphoneCore*/ + linphone_address_destroy(from); + linphone_auth_info_destroy(info); } } - - LinphoneCallState call_state=LinphoneCallIdle; - call_state=linphone_call_get_state(call); - const LinphoneAddress *remoteAddress=linphone_call_get_remote_address(call); - char buffer[512] = {0}; - switch(call_state){ - case LinphoneCallOutgoingInit: - snprintf(buffer, sizeof(buffer) - 1, "outgoing_init sip:%s", linphone_address_as_string(remoteAddress)); - break; - case LinphoneCallOutgoingProgress: - snprintf(buffer, sizeof(buffer) - 1, "dialing sip:%s", linphone_address_as_string(remoteAddress)); - break; - case LinphoneCallOutgoingRinging: - snprintf(buffer, sizeof(buffer) - 1, "ringing sip:%s", linphone_address_as_string(remoteAddress)); - break; - case LinphoneCallPaused: - snprintf(buffer, sizeof(buffer) - 1, "paused sip:%s", linphone_address_as_string(remoteAddress)); - break; - case LinphoneCallIdle: - snprintf(buffer, sizeof(buffer) - 1, "offhook"); - break; - case LinphoneCallStreamsRunning: - case LinphoneCallConnected: - snprintf(buffer, sizeof(buffer) - 1, "running %s sip:%s, duration=%i", - linphone_call_get_dir(call)==LinphoneCallOutgoing?"out":"in", - linphone_address_as_string(remoteAddress), linphone_call_get_duration(call)); - break; - case LinphoneCallIncomingReceived: - snprintf(buffer, sizeof(buffer) - 1, "incoming sip:%s", linphone_address_as_string(remoteAddress)); - break; - default: - break; - } - app->sendResponse(Response(buffer, Response::Ok)); + linphone_proxy_config_set_identity(cfg, identity); + linphone_proxy_config_set_server_addr(cfg, proxy); + linphone_proxy_config_enable_register(cfg, TRUE); + app->setProxyId(cfg); + ostringstream ostr; + ostr << "Id: " << Daemon::getProxyId(cfg) << "\n"; + linphone_core_add_proxy_config(lc, cfg); + app->sendResponse(Response(ostr.str().c_str(), Response::Ok)); + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); } + } }; -class AnswerCommand :public DaemonCommand{ - public: - AnswerCommand() : DaemonCommand("answer", "answer ","Answer an incoming call."){ +class UnregisterCommand: public DaemonCommand { +public: + UnregisterCommand() : + DaemonCommand("unregister", "unregister ", "Unregister the daemon from proxy.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneCore *lc = app->getCore(); + LinphoneProxyConfig *cfg = NULL; + int pid; + if (sscanf(args, "%i", &pid) == 1) { + cfg = app->findProxy(pid); + if (cfg == NULL) { + app->sendResponse(Response("No register with such id.")); + return; + } + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + return; } - virtual void exec(Daemon *app, const char *args){ - LinphoneCore *lc=app->getCore(); - int cid; - LinphoneCall *call; - if (sscanf(args,"%i",&cid)==1){ - call=app->findCall(cid); - if (call==NULL){ - app->sendResponse(Response("No call with such id.")); - return; - } else { - LinphoneCallState cstate=linphone_call_get_state(call); - if (cstate==LinphoneCallIncomingReceived || cstate==LinphoneCallIncomingEarlyMedia){ - if (linphone_core_accept_call(lc,call)==0){ - app->sendResponse(Response()); - return; - } - } - app->sendResponse(Response("Can't accept this call.")); + linphone_core_remove_proxy_config(lc, cfg); + app->sendResponse(Response()); + } +}; + +class PopEventCommand: public DaemonCommand { +public: + PopEventCommand() : + DaemonCommand("pop-event", "pop-event", "Pop an event from event queue and display it.") { + } + virtual void exec(Daemon *app, const char *args) { + app->pullEvent(); + } +}; + +class RegisterStatusCommand: public DaemonCommand { +public: + RegisterStatusCommand() : + DaemonCommand("register-status", "register-status ", "Return status of a register.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneProxyConfig *cfg = NULL; + int pid; + if (sscanf(args, "%i", &pid) == 1) { + cfg = app->findProxy(pid); + if (cfg == NULL) { + app->sendResponse(Response("No register with such id.")); + return; + } + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + return; + } + + app->sendResponse(Response(linphone_registration_state_to_string(linphone_proxy_config_get_state(cfg)), Response::Ok)); + } +}; + +class CallStatusCommand: public DaemonCommand { +public: + CallStatusCommand() : + DaemonCommand("call-status", "call-status ", "Return status of a call.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneCore *lc = app->getCore(); + int cid; + LinphoneCall *call = NULL; + if (sscanf(args, "%i", &cid) == 1) { + call = app->findCall(cid); + if (call == NULL) { + app->sendResponse(Response("No call with such id.")); + return; + } + } else { + call = linphone_core_get_current_call(lc); + if (call == NULL) { + app->sendResponse(Response("No current call available.")); + return; + } + } + + LinphoneCallState call_state = LinphoneCallIdle; + call_state = linphone_call_get_state(call); + const LinphoneAddress *remoteAddress = linphone_call_get_remote_address(call); + ostringstream ostr; + ostr << linphone_call_state_to_string(call_state) << "\n"; + + switch (call_state) { + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallPaused: + case LinphoneCallStreamsRunning: + case LinphoneCallConnected: + case LinphoneCallIncomingReceived: + ostr << "From: " << linphone_address_as_string(remoteAddress) << "\n"; + break; + default: + break; + } + switch (call_state) { + case LinphoneCallStreamsRunning: + case LinphoneCallConnected: + ostr << "Direction: " << ((linphone_call_get_dir(call) == LinphoneCallOutgoing) ? "out" : "in") << "\n"; + ostr << "Duration: " << linphone_call_get_duration(call) << "\n"; + default: + break; + } + app->sendResponse(Response(ostr.str().c_str(), Response::Ok)); + } +}; + +class AudioCodecGetCommand: public DaemonCommand { +public: + AudioCodecGetCommand() : + DaemonCommand("audio-codec-get", "audio-codec-get ", "Get an audio codec if codec-mime is defined, otherwise return the audio codec list.") { + } + virtual void exec(Daemon *app, const char *args) { + char mime[256]; + bool list = sscanf(args, "%255s", mime) != 1; + bool find = list; + int index = 0; + for (const MSList *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL; node = ms_list_next(node)) { + PayloadType *payload = reinterpret_cast(node->data); + if (list) { + app->sendResponse(PayloadTypeResponse(app->getCore(), payload, index)); + } else if (strcmp(mime, payload->mime_type) == 0) { + app->sendResponse(PayloadTypeResponse(app->getCore(), payload, index)); + find = true; + break; + } + ++index; + } + if (!find) { + app->sendResponse(Response("Audio codec not found.")); + } + } +}; + +class AudioCodecMoveCommand: public DaemonCommand { +public: + AudioCodecMoveCommand() : + DaemonCommand("audio-codec-move", "audio-codec-move ", "Move a codec to the an index.") { + } + virtual void exec(Daemon *app, const char *args) { + char mime[256]; + int index; + if (sscanf(args, "%255s %d", mime, &index) == 2 && index >= 0) { + PayloadType *selected_payload = NULL; + for (const MSList *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL; node = ms_list_next(node)) { + PayloadType *payload = reinterpret_cast(node->data); + if (strcmp(mime, payload->mime_type) == 0) { + selected_payload = payload; + break; + } + } + if (selected_payload == NULL) { + app->sendResponse(Response("Audio codec not found.")); + return; + } + int i = 0; + MSList *mslist = NULL; + for (const MSList *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL; node = ms_list_next(node)) { + PayloadType *payload = reinterpret_cast(node->data); + if (i == index) + mslist = ms_list_append(mslist, selected_payload); + if (selected_payload != payload) + mslist = ms_list_append(mslist, payload); + ++i; + } + if (i <= index) { + index = i; + mslist = ms_list_append(mslist, selected_payload); + } + linphone_core_set_audio_codecs(app->getCore(), mslist); + + app->sendResponse(PayloadTypeResponse(app->getCore(), selected_payload, index)); + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + } + } +}; + +class AudioCodecEnableCommand: public DaemonCommand { +public: + AudioCodecEnableCommand() : + DaemonCommand("audio-codec-enable", "audio-codec-enable ", "Enable an audio codec.") { + } + virtual void exec(Daemon *app, const char *args) { + char mime[256]; + if (sscanf(args, "%255s", mime) == 1) { + int index = 0; + for (const MSList *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL; node = ms_list_next(node)) { + PayloadType *payload = reinterpret_cast(node->data); + if (strcmp(mime, payload->mime_type) == 0) { + linphone_core_enable_payload_type(app->getCore(), payload, true); + app->sendResponse(PayloadTypeResponse(app->getCore(), payload, index)); return; } + ++index; + } + app->sendResponse(Response("Audio codec not found.")); + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + } + } +}; + +class AudioCodecDisableCommand: public DaemonCommand { +public: + AudioCodecDisableCommand() : + DaemonCommand("audio-codec-disable", "audio-codec-disable ", "Disable an audio codec.") { + } + virtual void exec(Daemon *app, const char *args) { + char mime[256]; + if (sscanf(args, "%255s", mime) == 1) { + int index = 0; + for (const MSList *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL; node = ms_list_next(node)) { + PayloadType *payload = reinterpret_cast(node->data); + if (strcmp(mime, payload->mime_type) == 0) { + linphone_core_enable_payload_type(app->getCore(), payload, false); + app->sendResponse(PayloadTypeResponse(app->getCore(), payload, index)); + return; + } + ++index; + } + app->sendResponse(Response("Audio codec not found.")); + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + } + } +}; + +class AnswerCommand: public DaemonCommand { +public: + AnswerCommand() : + DaemonCommand("answer", "answer ", "Answer an incoming call.") { + } + virtual void exec(Daemon *app, const char *args) { + LinphoneCore *lc = app->getCore(); + int cid; + LinphoneCall *call; + if (sscanf(args, "%i", &cid) == 1) { + call = app->findCall(cid); + if (call == NULL) { + app->sendResponse(Response("No call with such id.")); + return; } else { - for(const MSList* elem=linphone_core_get_calls(lc); elem!=NULL;elem=elem->next){ - call=(LinphoneCall*)elem->data; - LinphoneCallState cstate=linphone_call_get_state(call); - if (cstate==LinphoneCallIncomingReceived || cstate==LinphoneCallIncomingEarlyMedia){ - if (linphone_core_accept_call(lc,call)==0){ - app->sendResponse(Response()); - return; - } + LinphoneCallState cstate = linphone_call_get_state(call); + if (cstate == LinphoneCallIncomingReceived || cstate == LinphoneCallIncomingEarlyMedia) { + if (linphone_core_accept_call(lc, call) == 0) { + app->sendResponse(Response()); + return; + } + } + app->sendResponse(Response("Can't accept this call.")); + return; + } + } else { + for (const MSList* elem = linphone_core_get_calls(lc); elem != NULL; elem = elem->next) { + call = (LinphoneCall*) elem->data; + LinphoneCallState cstate = linphone_call_get_state(call); + if (cstate == LinphoneCallIncomingReceived || cstate == LinphoneCallIncomingEarlyMedia) { + if (linphone_core_accept_call(lc, call) == 0) { + app->sendResponse(Response()); + return; } } } - app->sendResponse(Response("No call to accept.")); } + app->sendResponse(Response("No call to accept.")); + } }; -EventResponse::EventResponse(LinphoneCall *call, LinphoneCallState state){ +EventResponse::EventResponse(LinphoneCall *call, LinphoneCallState state) { ostringstream ostr; - char *remote=linphone_call_get_remote_address_as_string(call); - ostr<<"Event-type: call-state-changed\nEvent: "<type << "\n"; + ostr << "Clock-rate: " << payloadType->clock_rate << "\n"; + ostr << "Bits-per-sample: " << (int) payloadType->bits_per_sample << "\n"; + ostr << "Bitrate: " << payloadType->normal_bitrate << "\n"; + ostr << "Mime: " << payloadType->mime_type << "\n"; + ostr << "Channels: " << payloadType->channels << "\n"; + ostr << "Recv-fmtp: " << ((payloadType->recv_fmtp) ? payloadType->recv_fmtp : "") << "\n"; + ostr << "Send-fmtp: " << ((payloadType->send_fmtp) ? payloadType->send_fmtp : "") << "\n"; + ostr << "Flags: " << payloadType->flags << "\n"; + ostr << "Enabled: " << (linphone_core_payload_type_enabled(core, payloadType) == TRUE ? "true" : "false") << "\n"; + setBody(ostr.str().c_str()); } -bool DaemonCommand::matches(const char *name)const{ - return strcmp(name,mName.c_str())==0; +DaemonCommand::DaemonCommand(const char *name, const char *proto, const char *help) : + mName(name), mProto(proto), mHelp(help) { } -Daemon * Daemon::sZis=NULL; -int Daemon::sCallIds=0; -int Daemon::sProxyIds=0; +bool DaemonCommand::matches(const char *name) const { + return strcmp(name, mName.c_str()) == 0; +} -Daemon::Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video){ - sZis=this; - mServerFd=-1; - mChildFd=-1; - if (!using_pipes){ - initReadline(); - }else{ - mServerFd=ortp_server_pipe_create("linphone-daemon"); - listen(mServerFd,2); - fprintf(stdout,"Server unix socket created, fd=%i\n",mServerFd); +Daemon * Daemon::sZis = NULL; +int Daemon::sCallIds = 0; +int Daemon::sProxyIds = 0; + +Daemon::Daemon(const char *config_path, bool using_pipes, bool display_video, bool capture_video) { + sZis = this; + mServerFd = -1; + mChildFd = -1; + if (!using_pipes) { + initReadline(); + } else { + mServerFd = ortp_server_pipe_create("linphone-daemon"); + listen(mServerFd, 2); + fprintf(stdout, "Server unix socket created, fd=%i\n", mServerFd); } - LinphoneCoreVTable vtable={0}; - vtable.call_state_changed=callStateChanged; - mLc=linphone_core_new(&vtable,NULL,config_path,this); - linphone_core_enable_video(mLc,display_video,capture_video); - linphone_core_enable_echo_cancellation(mLc,false); + + linphone_core_disable_logs(); + + LinphoneCoreVTable vtable = { 0 }; + vtable.call_state_changed = callStateChanged; + mLc = linphone_core_new(&vtable, NULL, config_path, this); + linphone_core_enable_video(mLc, display_video, capture_video); + linphone_core_enable_echo_cancellation(mLc, false); initCommands(); } -const list &Daemon::getCommandList()const{ +const list &Daemon::getCommandList() const { return mCommands; } -LinphoneCore * Daemon::getCore(){ +LinphoneCore * Daemon::getCore() { return mLc; } -int Daemon::setCallId(LinphoneCall *call){ - linphone_call_set_user_pointer(call,(void*)(long)++sCallIds); +int Daemon::setCallId(LinphoneCall *call) { + linphone_call_set_user_pointer(call, (void*) (long) ++sCallIds); return sCallIds; } -LinphoneCall * Daemon::findCall(int id){ - const MSList *elem=linphone_core_get_calls(mLc); - for (;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall *)elem->data; - if (linphone_call_get_user_pointer(call)==(void*)(long)id) +LinphoneCall * Daemon::findCall(int id) { + const MSList *elem = linphone_core_get_calls(mLc); + for (; elem != NULL; elem = elem->next) { + LinphoneCall *call = (LinphoneCall *) elem->data; + if (linphone_call_get_user_pointer(call) == (void*) (long) id) return call; } return NULL; } -int Daemon::setProxyId(LinphoneProxyConfig *cfg){ - linphone_proxy_config_set_user_data(cfg,(void*)(long)++sProxyIds); +int Daemon::setProxyId(LinphoneProxyConfig *cfg) { + linphone_proxy_config_set_user_data(cfg, (void*) (long) ++sProxyIds); return sProxyIds; } -LinphoneProxyConfig * Daemon::findProxy(int id){ - const MSList *elem=linphone_core_get_proxy_config_list(mLc); - for (;elem!=NULL;elem=elem->next){ - LinphoneProxyConfig *proxy=(LinphoneProxyConfig *)elem->data; - if (linphone_proxy_config_get_user_data(proxy)==(void*)(long)id) +LinphoneProxyConfig * Daemon::findProxy(int id) { + const MSList *elem = linphone_core_get_proxy_config_list(mLc); + for (; elem != NULL; elem = elem->next) { + LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) elem->data; + if (linphone_proxy_config_get_user_data(proxy) == (void*) (long) id) return proxy; } return NULL; } -void Daemon::initCommands(){ +void Daemon::initCommands() { mCommands.push_back(new RegisterCommand()); + mCommands.push_back(new RegisterStatusCommand()); mCommands.push_back(new UnregisterCommand()); mCommands.push_back(new CallCommand()); mCommands.push_back(new TerminateCommand()); mCommands.push_back(new PopEventCommand()); mCommands.push_back(new AnswerCommand()); - mCommands.push_back(new StatusCommand()); + mCommands.push_back(new CallStatusCommand()); + mCommands.push_back(new AudioCodecGetCommand()); + mCommands.push_back(new AudioCodecEnableCommand()); + mCommands.push_back(new AudioCodecDisableCommand()); + mCommands.push_back(new AudioCodecMoveCommand()); mCommands.push_back(new QuitCommand()); mCommands.push_back(new HelpCommand()); - + } -bool Daemon::pullEvent(){ - if (!mEventQueue.empty()){ - Response *r=mEventQueue.front(); +void Daemon::uninitCommands() { + while (!mCommands.empty()) { + delete mCommands.front(); + mCommands.pop_front(); + } +} + +bool Daemon::pullEvent() { + bool status = false; + if (!mEventQueue.empty()) { + Response *r = mEventQueue.front(); mEventQueue.pop(); sendResponse(*r); delete r; - return true; - }else{ - sendResponse(Response()); + status = true; } - return false; + ostringstream ostr; + ostr << "Size: " << mEventQueue.size(); + sendResponse(Response(ostr.str().c_str(), Response::Ok)); + return status; } -int Daemon::getCallId(LinphoneCall *call){ - return (int)(long)linphone_call_get_user_pointer(call); +int Daemon::getCallId(LinphoneCall *call) { + return (int) (long) linphone_call_get_user_pointer(call); } -int Daemon::getProxyId(LinphoneProxyConfig *proxy){ - return (int)(long)linphone_proxy_config_get_user_data(proxy); +int Daemon::getProxyId(LinphoneProxyConfig *proxy) { + return (int) (long) linphone_proxy_config_get_user_data(proxy); } -void Daemon::callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg){ - switch(state){ - case LinphoneCallOutgoingProgress: - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallConnected: - case LinphoneCallStreamsRunning: - case LinphoneCallError: - case LinphoneCallEnd: - mEventQueue.push(new EventResponse(call,state)); +void Daemon::callStateChanged(LinphoneCall *call, LinphoneCallState state, const char *msg) { + switch (state) { + case LinphoneCallOutgoingProgress: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + case LinphoneCallError: + case LinphoneCallEnd: + mEventQueue.push(new EventResponse(call, state)); break; - default: + default: break; - } + } } -void Daemon::callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg){ - Daemon *app=(Daemon*)linphone_core_get_user_data(lc); - app->callStateChanged(call,state,msg); +void Daemon::callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg) { + Daemon *app = (Daemon*) linphone_core_get_user_data(lc); + app->callStateChanged(call, state, msg); } -void Daemon::iterate(){ +void Daemon::iterate() { linphone_core_iterate(mLc); - if (mChildFd==-1){ - if (!mEventQueue.empty()){ - Response *r=mEventQueue.front(); + if (mChildFd == -1) { + if (!mEventQueue.empty()) { + Response *r = mEventQueue.front(); mEventQueue.pop(); - fprintf(stdout,"%s\n",r->getBody().c_str()); + fprintf(stdout, "%s\n", r->getBody().c_str()); fflush(stdout); delete r; } } } -int Daemon::readlineHook(){ +int Daemon::readlineHook() { sZis->iterate(); return 0; } -void Daemon::initReadline() -{ - const char *homedir=getenv("HOME"); +void Daemon::initReadline() { + const char *homedir = getenv("HOME"); rl_readline_name = "daemon"; rl_set_keyboard_input_timeout(20000); - rl_event_hook=readlineHook; + rl_event_hook = readlineHook; - if (homedir==NULL) homedir="."; - mHistfile=string(homedir) + string("/.linphone_history"); + if (homedir == NULL) + homedir = "."; + mHistfile = string(homedir) + string("/.linphone_history"); read_history(mHistfile.c_str()); - setlinebuf(stdout); + setlinebuf(stdout); } -void Daemon::execCommand(const char *cl){ - char args[sLineSize]={0}; - char name[sLineSize]={0}; - sscanf(cl,"%511s %511[^\n]",name,args); //Read the rest of line in args - list::iterator it=find_if(mCommands.begin(),mCommands.end(),bind2nd(mem_fun(&DaemonCommand::matches),name)); - if (it!=mCommands.end()){ - (*it)->exec(this,args); - }else{ +void Daemon::execCommand(const char *cl) { + char args[sLineSize] = { 0 }; + char name[sLineSize] = { 0 }; + sscanf(cl, "%511s %511[^\n]", name, args); //Read the rest of line in args + list::iterator it = find_if(mCommands.begin(), mCommands.end(), bind2nd(mem_fun(&DaemonCommand::matches), name)); + if (it != mCommands.end()) { + (*it)->exec(this, args); + } else { sendResponse(Response("Unknown command.")); } } -void Daemon::sendResponse(const Response &resp){ - char buf[4096]={0}; +void Daemon::sendResponse(const Response &resp) { + char buf[4096] = { 0 }; int size; - size=resp.toBuf(buf,sizeof(buf)); - if (mChildFd!=-1){ - if (write(mChildFd,buf,size)==-1){ - ms_error("Fail to write to pipe: %s",strerror(errno)); + size = resp.toBuf(buf, sizeof(buf)); + if (mChildFd != -1) { + if (write(mChildFd, buf, size) == -1) { + ms_error("Fail to write to pipe: %s", strerror(errno)); } - }else{ - fprintf(stdout,"%s",buf); + } else { + fprintf(stdout, "%s", buf); fflush(stdout); } } -char *Daemon::readPipe(char *buffer, int buflen){ - struct pollfd pfd[2]={{0},{0}}; - int nfds=1; - if (mServerFd!=-1){ - pfd[0].events=POLLIN; - pfd[0].fd=mServerFd; +char *Daemon::readPipe(char *buffer, int buflen) { + struct pollfd pfd[2] = { { 0 }, { 0 } }; + int nfds = 1; + if (mServerFd != -1) { + pfd[0].events = POLLIN; + pfd[0].fd = mServerFd; } - if (mChildFd!=-1){ - pfd[1].events=POLLIN; - pfd[1].fd=mChildFd; + if (mChildFd != -1) { + pfd[1].events = POLLIN; + pfd[1].fd = mChildFd; nfds++; } iterate(); - int err=poll(pfd,nfds,50); - if (err>0){ - if (mServerFd!=-1 && (pfd[0].revents & POLLIN)){ + int err = poll(pfd, nfds, 50); + if (err > 0) { + if (mServerFd != -1 && (pfd[0].revents & POLLIN)) { struct sockaddr_storage addr; - socklen_t addrlen=sizeof(addr); - int childfd=accept(mServerFd,(struct sockaddr*)&addr,&addrlen); - if (childfd!=-1){ - if (mChildFd!=-1){ + socklen_t addrlen = sizeof(addr); + int childfd = accept(mServerFd, (struct sockaddr*) &addr, &addrlen); + if (childfd != -1) { + if (mChildFd != -1) { ms_error("Cannot accept two client at the same time"); close(childfd); - }else{ - mChildFd=childfd; + } else { + mChildFd = childfd; return NULL; } } } - if (mChildFd!=-1 && (pfd[1].revents & POLLIN)){ + if (mChildFd != -1 && (pfd[1].revents & POLLIN)) { int ret; - if ((ret=read(mChildFd,buffer,buflen))==-1){ + if ((ret = read(mChildFd, buffer, buflen)) == -1) { ms_error("Fail to read from pipe: %s", strerror(errno)); - }else{ - if (ret==0){ + } else { + if (ret == 0) { ms_message("Client disconnected"); close(mChildFd); - mChildFd=-1; + mChildFd = -1; return NULL; } - buffer[ret]=0; + buffer[ret] = 0; return buffer; } } @@ -600,8 +791,8 @@ char *Daemon::readPipe(char *buffer, int buflen){ return NULL; } -static void printHelp(){ - fprintf(stdout,"daemon-linphone []\n" +static void printHelp() { + fprintf(stdout, "daemon-linphone []\n" "where options are :\n" "\t--help\t\tPrint this notice.\n" "\t--pipe\t\tCreate an unix server socket to receive commands.\n" @@ -610,64 +801,69 @@ static void printHelp(){ "\t-D\t\tenable video display.\n"); } -int Daemon::run(){ - char line[sLineSize]="daemon-linphone>"; +int Daemon::run() { + char line[sLineSize] = "daemon-linphone>"; char *ret; - mRunning=true; - while(mRunning){ - if (mServerFd==-1){ - ret=readline(line); - if (ret && ret[0]!='\0') { + mRunning = true; + while (mRunning) { + if (mServerFd == -1) { + ret = readline(line); + if (ret && ret[0] != '\0') { add_history(ret); } - }else{ - ret=readPipe(line,sLineSize); + } else { + ret = readPipe(line, sLineSize); } - if (ret && ret[0]!='\0') { + if (ret && ret[0] != '\0') { execCommand(ret); - } + } + if (mServerFd == -1) { + free(ret); + } } return 0; } -void Daemon::quit(){ - mRunning=false; +void Daemon::quit() { + mRunning = false; } -Daemon::~Daemon(){ - if (mChildFd!=-1){ +Daemon::~Daemon() { + uninitCommands(); + linphone_core_destroy(mLc); + if (mChildFd != -1) { close(mChildFd); } - if (mServerFd!=-1){ + if (mServerFd != -1) { ortp_server_pipe_close(mServerFd); } stifle_history(30); write_history(mHistfile.c_str()); } -int main(int argc, char *argv[]){ - const char *config_path=NULL; - bool using_pipes=false; - bool capture_video=false; - bool display_video=false; +int main(int argc, char *argv[]) { + const char *config_path = NULL; + bool using_pipes = false; + bool capture_video = false; + bool display_video = false; int i; - for(i=1;i Date: Wed, 4 Apr 2012 10:29:46 +0200 Subject: [PATCH 007/231] Fix audio-codec-move Add ptime command --- daemon/daemon.cc | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 5706f3e18..238013b98 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -356,6 +356,31 @@ public: } }; +class PtimeCommand: public DaemonCommand { +public: + PtimeCommand() : + DaemonCommand("ptime", "ptime ", "Set the if ms is defined, otherwise return the ptime.") { + } + virtual void exec(Daemon *app, const char *args) { + int ms; + int ret = sscanf(args, "%d", &ms); + if(ret <= 0) { + ostringstream ostr; + ms = linphone_core_get_upload_ptime(app->getCore()); + ostr << "Ptime: " << ms << "\n"; + app->sendResponse(Response(ostr.str().c_str(), Response::Ok)); + } else if (ret == 1) { + ostringstream ostr; + linphone_core_set_upload_ptime(app->getCore(), ms); + ms = linphone_core_get_upload_ptime(app->getCore()); + ostr << "Ptime: " << ms << "\n"; + app->sendResponse(Response(ostr.str().c_str(), Response::Ok)); + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + } + } +}; + class AudioCodecGetCommand: public DaemonCommand { public: AudioCodecGetCommand() : @@ -408,11 +433,14 @@ public: MSList *mslist = NULL; for (const MSList *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL; node = ms_list_next(node)) { PayloadType *payload = reinterpret_cast(node->data); - if (i == index) + if (i == index) { mslist = ms_list_append(mslist, selected_payload); - if (selected_payload != payload) + ++i; + } + if (selected_payload != payload) { mslist = ms_list_append(mslist, payload); - ++i; + ++i; + } } if (i <= index) { index = i; @@ -629,6 +657,7 @@ void Daemon::initCommands() { mCommands.push_back(new AudioCodecEnableCommand()); mCommands.push_back(new AudioCodecDisableCommand()); mCommands.push_back(new AudioCodecMoveCommand()); + mCommands.push_back(new PtimeCommand()); mCommands.push_back(new QuitCommand()); mCommands.push_back(new HelpCommand()); From 9a1dba163bf0942dc8162d6810d8d0c255dbc767 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 4 Apr 2012 15:48:23 +0200 Subject: [PATCH 008/231] Add audio stream functions --- daemon/daemon.cc | 125 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 21 deletions(-) diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 238013b98..b711ba780 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -1,4 +1,5 @@ -#include "linphonecore.h" +#include +#include #include #include @@ -8,6 +9,7 @@ #include #include #include +#include #include using namespace std; @@ -103,11 +105,13 @@ public: const list &getCommandList() const; LinphoneCall *findCall(int id); LinphoneProxyConfig *findProxy(int id); + AudioStream *findAudioStream(int id); bool pullEvent(); static int getCallId(LinphoneCall *call); int setCallId(LinphoneCall *call); static int getProxyId(LinphoneProxyConfig *proxy); int setProxyId(LinphoneProxyConfig *proxy); + int setAudioStreamId(AudioStream *audio_stream); private: static void callStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *msg); @@ -129,7 +133,9 @@ private: static Daemon *sZis; static int sCallIds; static int sProxyIds; + static int sAudioStreamIds; static const int sLineSize = 512; + std::map mAudioStreams; }; class CallCommand: public DaemonCommand { @@ -279,6 +285,62 @@ public: } }; +class AudioStreamStartCommand: public DaemonCommand { +public: + AudioStreamStartCommand() : + DaemonCommand("audio-stream-start", "audio-stream-start ", "Start an audio stream.") { + } + virtual void exec(Daemon *app, const char *args) { + char addr[256]; + int port; + char mime[64]; + if (sscanf(args, "%255s %d %63s", addr, &port, mime) == 3) { + int local_port = linphone_core_get_audio_port(app->getCore()); + const int jitt = linphone_core_get_audio_jittcomp(app->getCore()); + const bool_t echo_canceller = linphone_core_echo_cancellation_enabled(app->getCore()); + MSSndCardManager *manager = ms_snd_card_manager_get(); + MSSndCard *capture_card = ms_snd_card_manager_get_card(manager, linphone_core_get_capture_device(app->getCore())); + MSSndCard *play_card = ms_snd_card_manager_get_card(manager, linphone_core_get_playback_device(app->getCore())); + int payload_type = rtp_profile_get_payload_number_from_mime(&av_profile, mime); + if (payload_type < 0) { + app->sendResponse(Response("Payload not found")); + return; + } + + AudioStream *stream = audio_stream_new(local_port, false); + if (audio_stream_start_now(stream, &av_profile, addr, port, port + 1, payload_type, jitt, play_card, capture_card, echo_canceller) != 0) { + app->sendResponse(Response("Error during audio stream creation.")); + } + ostringstream ostr; + ostr << "Id: " << app->setAudioStreamId(stream) << "\n"; + app->sendResponse(Response(ostr.str().c_str(), Response::Ok)); + } else { + app->sendResponse(Response("Missing/Incorrect parameter(s).")); + } + } +}; + +class AudioStreamStopCommand: public DaemonCommand { +public: + AudioStreamStopCommand() : + DaemonCommand("audio-stream-stop", "audio-stream-stop