From a4f8078058a90a76b574ebafeb8bea348597492e Mon Sep 17 00:00:00 2001
From: Guillaume BIENKOWSKI
 <guillaume.bienkowski@belledonne-communications.com>
Date: Thu, 2 Jan 2014 12:35:28 +0100
Subject: [PATCH] Continuing changes to linphone daemon commands.

---
 daemon/Makefile.am               |   4 +-
 daemon/commands/call-mute.cc     |  38 +++++++-
 daemon/commands/call-mute.h      |   3 +
 daemon/commands/call-pause.cc    |  21 ++++-
 daemon/commands/call-resume.cc   |  43 ++++++++-
 daemon/commands/call-resume.h    |   3 +
 daemon/commands/call-transfer.cc |  42 ++++++++-
 daemon/commands/call-transfer.h  |   3 +
 daemon/commands/conference.cc    |  66 +++++++++++++-
 daemon/commands/conference.h     |   3 +
 daemon/commands/video.cc         | 151 ++++++++++++++++++++++++++++++-
 daemon/commands/video.h          |  22 ++++-
 daemon/daemon.cc                 |   6 +-
 13 files changed, 391 insertions(+), 14 deletions(-)

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 98bd350c15..622a569602 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -18,7 +18,7 @@ linphone_daemon_SOURCES=daemon.cc \
 			commands/call-pause.cc \
 			commands/call-resume.cc \
 			commands/call-mute.cc \
-			commands/call-camera.cc \
+			commands/video.cc \
 			commands/call-transfer.cc \
 			commands/conference.cc \
 			commands/dtmf.cc \
@@ -55,7 +55,7 @@ linphone_daemon_SOURCES=daemon.cc \
 			commands/call-pause.h \
 			commands/call-resume.h \
 			commands/call-mute.h \
-			commands/call-camera.h \
+			commands/video.h \
 			commands/call-transfer.h \
 			commands/conference.h \
 			commands/dtmf.h \
diff --git a/daemon/commands/call-mute.cc b/daemon/commands/call-mute.cc
index cde7637b4f..15726eaa1f 100644
--- a/daemon/commands/call-mute.cc
+++ b/daemon/commands/call-mute.cc
@@ -1,5 +1,41 @@
 #include "call-mute.h"
 
-CallMute::CallMute()
+CallMute::CallMute() :
+	DaemonCommand("call-mute", "call-mute 0|1", "mute/unmute the microphone (1 to mute, 0 to unmute). No argument means MUTE.")
 {
+	addExample(new DaemonCommandExample("call-mute 1",
+										"Status: Ok\n\n"
+										"Microphone Muted"));
+	addExample(new DaemonCommandExample("call-mute",
+										"Status: Ok\n\n"
+										"Microphone Muted"));
+	addExample(new DaemonCommandExample("call-mute 0",
+										"Status: Ok\n\n"
+										"Microphone Unmuted"));
+	addExample(new DaemonCommandExample("call-mute 1",
+										"Status: Error\n\n"
+										"Reason: No call in progress. Can't mute."));
+}
+
+void CallMute::exec(Daemon* app, const char* args)
+{
+	LinphoneCore *lc = app->getCore();
+	int muted = TRUE; // no arg means MUTE
+	LinphoneCall *call = linphone_core_get_current_call(lc);
+	int cid;
+
+	if( call == NULL ){
+		app->sendResponse(Response("No call in progress. Can't mute."));
+		return;
+	}
+
+	if (sscanf(args, "%i", &cid) == 1) {
+		linphone_core_mute_mic(lc, (muted != 0));
+	} else {
+		linphone_core_mute_mic(lc, (muted != 0));
+	}
+
+	app->sendResponse(Response(muted?"Microphone Muted"
+									:"Microphone Unmuted",
+							   Response::Ok));
 }
diff --git a/daemon/commands/call-mute.h b/daemon/commands/call-mute.h
index 69612b299a..193b599967 100644
--- a/daemon/commands/call-mute.h
+++ b/daemon/commands/call-mute.h
@@ -1,10 +1,13 @@
 #ifndef CALLMUTE_H
 #define CALLMUTE_H
 
+#include "daemon.h"
+
 class CallMute : public DaemonCommand
 {
 public:
 	CallMute();
+	virtual void exec(Daemon *app, const char *args);
 };
 
 #endif // CALLMUTE_H
diff --git a/daemon/commands/call-pause.cc b/daemon/commands/call-pause.cc
index 7145d08577..24d722cddb 100644
--- a/daemon/commands/call-pause.cc
+++ b/daemon/commands/call-pause.cc
@@ -1,7 +1,21 @@
 #include "call-pause.h"
 
-CallPause::CallPause()
+CallPause::CallPause() :
+	DaemonCommand("call-pause",
+				  "call-pause <call id>",
+				  "Pause a call (pause current if no id is specified).")
 {
+	addExample(new DaemonCommandExample("call-pause 1",
+										"Status: Ok\n\n"
+										"Call was paused"));
+
+	addExample(new DaemonCommandExample("call-pause 2",
+										"Status: Error\n"
+										"Reason: No call with such id."));
+
+	addExample(new DaemonCommandExample("call-pause",
+										"Status: Error\n"
+										"Reason: No current call available."));
 }
 
 void CallPause::exec(Daemon* app, const char* args)
@@ -9,6 +23,7 @@ void CallPause::exec(Daemon* app, const char* args)
 	LinphoneCore *lc = app->getCore();
 	int cid;
 	LinphoneCall *call = NULL;
+	bool current = false;
 	if (sscanf(args, "%i", &cid) == 1) {
 		call = app->findCall(cid);
 		if (call == NULL) {
@@ -17,6 +32,7 @@ void CallPause::exec(Daemon* app, const char* args)
 		}
 	} else {
 		call = linphone_core_get_current_call(lc);
+		current = true;
 		if (call == NULL) {
 			app->sendResponse(Response("No current call available."));
 			return;
@@ -24,7 +40,8 @@ void CallPause::exec(Daemon* app, const char* args)
 	}
 
 	if( linphone_core_pause_call(lc, call) == 0 ) {
-		app->sendResponse(Response("Call was paused", Response::Ok));
+		app->sendResponse(Response(current?"Current call was paused":
+										   "Call was paused", Response::Ok));
 	} else {
 		app->sendResponse(Response("Error pausing call"));
 	}
diff --git a/daemon/commands/call-resume.cc b/daemon/commands/call-resume.cc
index f620df52d1..31849fa42e 100644
--- a/daemon/commands/call-resume.cc
+++ b/daemon/commands/call-resume.cc
@@ -1,5 +1,46 @@
 #include "call-resume.h"
 
-CallResume::CallResume()
+CallResume::CallResume():
+	DaemonCommand("call-resume", "call-resume <call id>", "Pause a call (pause current if no id is specified).")
 {
+	addExample(new DaemonCommandExample("call-resume 1",
+										"Status: Ok\n\n"
+										"Call was resumed"));
+
+	addExample(new DaemonCommandExample("call-resume 2",
+										"Status: Error\n"
+										"Reason: No call with such id."));
+
+	addExample(new DaemonCommandExample("call-resume",
+										"Status: Error\n"
+										"Reason: No current call available."));
+}
+
+void CallResume::exec(Daemon* app, const char* args)
+{
+	LinphoneCore *lc = app->getCore();
+	int cid;
+	LinphoneCall *call = NULL;
+	bool current = false;
+	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);
+		current = true;
+		if (call == NULL) {
+			app->sendResponse(Response("No current call available."));
+			return;
+		}
+	}
+
+	if( linphone_core_resume_call(lc, call) == 0 ) {
+		app->sendResponse(Response(current?"Current call was resumed":
+										   "Call was resumed", Response::Ok));
+	} else {
+		app->sendResponse(Response("Error pausing call"));
+	}
 }
diff --git a/daemon/commands/call-resume.h b/daemon/commands/call-resume.h
index baed7968d4..e716d94d13 100644
--- a/daemon/commands/call-resume.h
+++ b/daemon/commands/call-resume.h
@@ -1,10 +1,13 @@
 #ifndef CALLRESUME_H
 #define CALLRESUME_H
 
+#include "daemon.h"
+
 class CallResume : public DaemonCommand
 {
 public:
 	CallResume();
+	virtual void exec(Daemon *app, const char *args);
 };
 
 #endif // CALLRESUME_H
diff --git a/daemon/commands/call-transfer.cc b/daemon/commands/call-transfer.cc
index f2cb268809..2fdf7773e8 100644
--- a/daemon/commands/call-transfer.cc
+++ b/daemon/commands/call-transfer.cc
@@ -1,5 +1,45 @@
 #include "call-transfer.h"
 
-CallTransfer::CallTransfer()
+CallTransfer::CallTransfer() :
+	DaemonCommand("call-transfer",
+				  "call-transfer <call id> <sip url>",
+				  "Transfer a call that you aswered to another party")
 {
+	addExample(new DaemonCommandExample("call-transfer 1 sip:john",
+										"Status: Ok\n\n"
+										"Call ID: 1\n"
+										"Transfer to: sip:john"));
+
+	addExample(new DaemonCommandExample("call-transfer 2 sip:john",
+										"Status: Error\n"
+										"Reason: No call with such id."));
+}
+
+void CallTransfer::exec(Daemon* app, const char* args)
+{
+	LinphoneCore *lc = app->getCore();
+	int cid;
+	LinphoneCall *call = NULL;
+	char sipurl[512];
+	memset(sipurl, 0x00, 512);
+
+	if (sscanf(args, "%i %511s", &cid, sipurl) == 2) {
+		call = app->findCall(cid);
+		if (call == NULL) {
+			app->sendResponse(Response("No call with such id."));
+			return;
+		}
+	} else {
+		app->sendResponse(Response("Invalid command format."));
+		return;
+	}
+
+	if( linphone_core_transfer_call(lc, call, sipurl) == 0 ) {
+		std::ostringstream ostr;
+		ostr << "Call ID: "     << cid    << "\n";
+		ostr << "Transfer to: " << sipurl << "\n";
+		app->sendResponse(Response(ostr.str(), Response::Ok));
+	} else {
+		app->sendResponse(Response("Error pausing call"));
+	}
 }
diff --git a/daemon/commands/call-transfer.h b/daemon/commands/call-transfer.h
index 11c884dee6..089a14fa92 100644
--- a/daemon/commands/call-transfer.h
+++ b/daemon/commands/call-transfer.h
@@ -1,10 +1,13 @@
 #ifndef CALLTRANSFER_H
 #define CALLTRANSFER_H
 
+#include "daemon.h"
+
 class CallTransfer : public DaemonCommand
 {
 public:
 	CallTransfer();
+	virtual void exec(Daemon *app, const char *args);
 };
 
 #endif // CALLTRANSFER_H
diff --git a/daemon/commands/conference.cc b/daemon/commands/conference.cc
index c9d51a9a08..c9664f5989 100644
--- a/daemon/commands/conference.cc
+++ b/daemon/commands/conference.cc
@@ -1,5 +1,69 @@
 #include "conference.h"
 
-Conference::Conference()
+Conference::Conference() :
+	DaemonCommand("conference", "conference <subcommand> <call id>",
+				  "Create and manage an audio conference.\n"
+				  "Subcommands:\n"
+				  "- add   : join the call with id 'call id' into the audio conference. Creates new one if none exists.\n"
+				  "- rm    : remove the call with id 'call id' from the audio conference\n"
+				  "- leave : temporarily leave the current conference.\n"
+				  "- enter : re-join the conference after leaving it")
 {
+	addExample(new DaemonCommandExample("conference add 1",
+										"Status: Ok\n\n"
+										"Call Id: 1\n"
+										"Conference: add OK"));
+	addExample(new DaemonCommandExample("conference leave 1",
+										"Status: Ok\n\n"
+										"Call Id: 1\n"
+										"Conference: leave OK"));
+	addExample(new DaemonCommandExample("conference azerty 1",
+										"Status: Error\n\n"
+										"Reason: Invalid command format"));
+	addExample(new DaemonCommandExample("conference leave 2",
+										"Status: Error\n\n"
+										"Reason: No call with such id."));
+}
+
+void Conference::exec(Daemon* app, const char* args)
+{
+	LinphoneCore* lc = app->getCore();
+	long id;
+	char subcommand[32]={0};
+	int n;
+	n=sscanf(args, "%31s %li", subcommand,&id);
+	if (n == 2){
+		LinphoneCall *call=app->findCall(id);
+		if (call==NULL){
+			app->sendResponse(Response("No call with such id."));
+			return;
+		}
+
+		if (strcmp(subcommand,"add")==0){
+			n = linphone_core_add_to_conference(lc,call);
+
+		}else if (strcmp(subcommand,"rm")==0){
+			n = linphone_core_remove_from_conference(lc,call);
+
+		}else if (strcmp(subcommand,"enter")==0){
+			n = linphone_core_enter_conference(lc);
+
+		}else if (strcmp(subcommand,"leave")==0){
+			n = linphone_core_leave_conference(lc);
+		} else {
+			app->sendResponse("Invalid command format.");
+		}
+
+		if ( n == 0 ){
+			std::ostringstream ostr;
+			ostr << "Call ID: " << id << "\n";
+			ostr << "Conference: " << subcommand << " OK" << "\n";
+			app->sendResponse(Response(ostr.str(), Response::Ok));
+		} else {
+			app->sendResponse("Conference: command failed");
+		}
+
+	} else {
+		app->sendResponse("Invalid command format.");
+	}
 }
diff --git a/daemon/commands/conference.h b/daemon/commands/conference.h
index db442c33d5..5cc66c530e 100644
--- a/daemon/commands/conference.h
+++ b/daemon/commands/conference.h
@@ -1,10 +1,13 @@
 #ifndef CONFERENCE_H
 #define CONFERENCE_H
 
+#include "daemon.h"
+
 class Conference : public DaemonCommand
 {
 public:
 	Conference();
+	virtual void exec(Daemon *app, const char *args);
 };
 
 #endif // CONFERENCE_H
diff --git a/daemon/commands/video.cc b/daemon/commands/video.cc
index d6e631e615..569e6c79c6 100644
--- a/daemon/commands/video.cc
+++ b/daemon/commands/video.cc
@@ -1,5 +1,152 @@
-#include "call-camera.h"
+#include "commands/video.h"
 
-CallCamera::CallCamera()
+Video::Video() :
+	DaemonCommand("video",
+				  "video <call id>",
+				  "Toggles camera on current call."
+				  "If no call is specified, the current call is taken.")
 {
+	addExample(new DaemonCommandExample("video on 1",
+										"Status: Ok\n\n"
+										"Camera activated."));
+
+	addExample(new DaemonCommandExample("video off 1",
+										"Status: Ok\n\n"
+										"Camera deactivated."));
+
+	addExample(new DaemonCommandExample("video on",
+										"Status: Error\n\n"
+										"Reason: No current call available."));
+
+	addExample(new DaemonCommandExample("video on 2",
+										"Status: Error\n\n"
+										"Reason: No call with such id."));
+}
+
+void Video::exec(Daemon* app, const char* args)
+{
+	LinphoneCore *lc = app->getCore();
+	int cid;
+	LinphoneCall *call = NULL;
+	bool current = false;
+	bool activate = false;
+	int argc = sscanf(args, "%i", &cid);
+
+	if ( argc == 1) { // should take current call
+		call = linphone_core_get_current_call(lc);
+		if (call == NULL) {
+			app->sendResponse(Response("No current call available."));
+			return;
+		}
+	} else {
+		call = app->findCall(cid);
+		current = true;
+		if (call == NULL) {
+			app->sendResponse(Response("No call with such id."));
+			return;
+		}
+	}
+
+	if (linphone_call_get_state(call)==LinphoneCallStreamsRunning){
+		LinphoneCallParams *new_params = linphone_call_params_copy(linphone_call_get_current_params(call));
+		activate = !linphone_call_params_video_enabled(new_params);
+
+		linphone_call_params_enable_video(new_params,activate);
+		linphone_core_update_call(lc,call,new_params);
+		linphone_call_params_destroy(new_params);
+
+	} else {
+		app->sendResponse(Response("No streams running: can't [de]activate video"));
+		return;
+	}
+
+	app->sendResponse(Response(activate?"Camera deactivated.":
+										"Camera activated", Response::Ok));
+}
+
+
+VideoSource::VideoSource():
+	DaemonCommand("videosource",
+				  "videosource <cam|dummy> <call-id>",
+				  "Toggles camera source for specified call."
+				  "If no call is specified, the current call is taken.")
+{
+	addExample(new DaemonCommandExample("videosource cam 1",
+										"Status: Ok\n\n"
+										"Webcam source selected."));
+
+	addExample(new DaemonCommandExample("videosource dummy 1",
+										"Status: Ok\n\n"
+										"Dummy source selected."));
+
+	addExample(new DaemonCommandExample("videosource cam",
+										"Status: Error\n\n"
+										"Reason: No current call available."));
+
+	addExample(new DaemonCommandExample("videosource cam 2",
+										"Status: Error\n\n"
+										"Reason: No call with such id."));
+}
+
+void VideoSource::exec(Daemon* app, const char* args)
+{
+	LinphoneCore *lc = app->getCore();
+	LinphoneCall *call = NULL;
+	int cid;
+	int argc = 0;
+	bool current = false;
+	bool activate = false;
+	char command[6];
+
+	argc = sscanf(args, "%5s %i", command, &cid);
+	command[5] = 0;
+
+	if ( argc == 1) { // should take current call
+		call = linphone_core_get_current_call(lc);
+		if (call == NULL) {
+			app->sendResponse(Response("No current call available."));
+			return;
+		}
+	} else if( argc == 2 ) {
+		call = app->findCall(cid);
+		current = true;
+		if (call == NULL) {
+			app->sendResponse(Response("No call with such id."));
+			return;
+		}
+	} else {
+		app->sendResponse(Response("Invalid command"));
+		return;
+	}
+
+	activate = (strcmp(command,"cam") == 0);
+
+	linphone_call_enable_camera(call,activate);
+
+	app->sendResponse(Response(activate?"Dummy source selected.":
+										"Webcam source selected.", Response::Ok));
+}
+
+
+AutoVideo::AutoVideo():
+	DaemonCommand("autovideo",
+				  "autovideo <on|off>",
+				  "Enables/disables automatic video setup when a call is issued")
+{
+	addExample(new DaemonCommandExample("autovideo on",
+										"Status: Ok\n\n"
+										"Auto video ON"));
+
+	addExample(new DaemonCommandExample("autovideo off",
+										"Status: Ok\n\n"
+										"Auto video OFF"));
+}
+
+void AutoVideo::exec(Daemon* app, const char* args)
+{
+	bool enable = (strcmp(args,"on") == 0);
+
+	app->setAutoVideo(enable);
+	app->sendResponse(Response(enable?"Auto video ON":
+										"Auto video OFF", Response::Ok));
 }
diff --git a/daemon/commands/video.h b/daemon/commands/video.h
index b210895356..05cd7e1eb3 100644
--- a/daemon/commands/video.h
+++ b/daemon/commands/video.h
@@ -1,10 +1,28 @@
 #ifndef CALLCAMERA_H
 #define CALLCAMERA_H
 
-class CallCamera : public DaemonCommand
+#include "daemon.h"
+
+class Video : public DaemonCommand
+{
+public:
+	Video();
+	virtual void exec(Daemon *app, const char *args);
+};
+
+
+class VideoSource : public DaemonCommand
+{
+public:
+	VideoSource();
+	virtual void exec(Daemon *app, const char *args);
+};
+
+class AutoVideo : public DaemonCommand
 {
 public:
-	CallCamera();
+	AutoVideo();
+	virtual void exec(Daemon *app, const char *args);
 };
 
 #endif // CALLCAMERA_H
diff --git a/daemon/daemon.cc b/daemon/daemon.cc
index 903d7d3e0d..384e81b11e 100644
--- a/daemon/daemon.cc
+++ b/daemon/daemon.cc
@@ -29,7 +29,7 @@
 #include "commands/call-pause.h"
 #include "commands/call-mute.h"
 #include "commands/call-resume.h"
-#include "commands/call-camera.h"
+#include "commands/video.h"
 #include "commands/call-transfer.h"
 #include "commands/conference.h"
 #include "commands/contact.h"
@@ -423,7 +423,9 @@ void Daemon::initCommands() {
 	mCommands.push_back(new CallMute());
 	mCommands.push_back(new CallResume());
 	mCommands.push_back(new CallTransfer());
-	mCommands.push_back(new CallCamera());
+	mCommands.push_back(new Video());
+	mCommands.push_back(new VideoSource());
+	mCommands.push_back(new AutoVideo());
 	mCommands.push_back(new Conference());
 	mCommands.push_back(new AudioCodecGetCommand());
 	mCommands.push_back(new AudioCodecEnableCommand());
-- 
GitLab