[asterisk-commits] russell: branch russell/bindings r126519 - in /team/russell/bindings: ./ cdr/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jun 30 08:07:36 CDT 2008


Author: russell
Date: Mon Jun 30 08:07:36 2008
New Revision: 126519

URL: http://svn.digium.com/view/asterisk?view=rev&rev=126519
Log:
resolve, reset

Modified:
    team/russell/bindings/   (props changed)
    team/russell/bindings/cdr/cdr_tds.c
    team/russell/bindings/channels/console_board.c
    team/russell/bindings/channels/console_gui.c
    team/russell/bindings/channels/console_video.c
    team/russell/bindings/channels/console_video.h
    team/russell/bindings/configure
    team/russell/bindings/configure.ac
    team/russell/bindings/doc/tex/freetds.tex
    team/russell/bindings/include/asterisk/autoconfig.h.in
    team/russell/bindings/pbx/Makefile
    team/russell/bindings/pbx/pbx_gtkconsole.c
    team/russell/bindings/pbx/pbx_lua.c

Propchange: team/russell/bindings/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/russell/bindings/
------------------------------------------------------------------------------
Binary property 'branch-1.4-blocked' - no diff available.

Propchange: team/russell/bindings/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Jun 30 08:07:36 2008
@@ -1,1 +1,1 @@
-/trunk:1-126334
+/trunk:1-126514

Modified: team/russell/bindings/cdr/cdr_tds.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/cdr/cdr_tds.c?view=diff&rev=126519&r1=126518&r2=126519
==============================================================================
--- team/russell/bindings/cdr/cdr_tds.c (original)
+++ team/russell/bindings/cdr/cdr_tds.c Mon Jun 30 08:07:36 2008
@@ -299,10 +299,10 @@
 	}
 
 	DBSETLAPP(login,     "TSQL");
-	DBSETLUSER(login,    settings->username);
-	DBSETLPWD(login,     settings->password);
-	DBSETLCHARSET(login, settings->charset);
-	DBSETLNATLANG(login, settings->language);
+	DBSETLUSER(login,    (char *) settings->username);
+	DBSETLPWD(login,     (char *) settings->password);
+	DBSETLCHARSET(login, (char *) settings->charset);
+	DBSETLNATLANG(login, (char *) settings->language);
 
 	if ((settings->dbproc = dbopen(login, (char *) settings->hostname)) == NULL) {
 		ast_log(LOG_ERROR, "Unable to connect to %s\n", settings->hostname);

Modified: team/russell/bindings/channels/console_board.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/channels/console_board.c?view=diff&rev=126519&r1=126518&r2=126519
==============================================================================
--- team/russell/bindings/channels/console_board.c (original)
+++ team/russell/bindings/channels/console_board.c Mon Jun 30 08:07:36 2008
@@ -148,7 +148,7 @@
 	b->cur_col = 0;		/* current print column */
 	b->cur_line = 0;	/* last line displayed */
 
-	ast_log(LOG_WARNING, "Message board %dx%d@%d,%d successfully initialized\n",
+	if (0) ast_log(LOG_WARNING, "Message board %dx%d@%d,%d successfully initialized\n",
 		b->p_rect->w, b->p_rect->h,
 		b->p_rect->x, b->p_rect->y);
 	return b;
@@ -313,6 +313,23 @@
 	return 1;
 }
 
+/* deletes a board.
+ * we make the free operation on any fields of the board structure allocated
+ * in dynamic memory
+ */
+void delete_board(struct board *b)
+{
+	if (b) {
+		/* deletes the text */
+		if (b->text)
+			ast_free (b->text);
+		/* deallocates the blank surface */
+		SDL_FreeSurface(b->blank);
+		/* deallocates the board */
+		ast_free(b);
+	}
+}
+
 #if 0
 /*! \brief refresh the screen, and also grab a bunch of events.
  */

Modified: team/russell/bindings/channels/console_gui.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/channels/console_gui.c?view=diff&rev=126519&r1=126518&r2=126519
==============================================================================
--- team/russell/bindings/channels/console_gui.c (original)
+++ team/russell/bindings/channels/console_gui.c Mon Jun 30 08:07:36 2008
@@ -7,30 +7,72 @@
 /*
  * GUI layout, structure and management
  
-For the GUI we use SDL to create a large surface (gui->screen)
-containing tree sections: remote video on the left, local video
-on the right, and the keypad with all controls and text windows
-in the center.
-The central section is built using an image for the skin, fonts and
-other GUI elements.  Comments embedded in the image to indicate to
-what function each area is mapped to.
+For the GUI we use SDL to create a large surface (gui->screen) with 4 areas:
+remote video on the left, local video on the right, keypad with all controls
+and text windows in the center, and source device thumbnails on the top.
+The top row is not displayed if no devices are specified in the config file.
+
+     ________________________________________________________________
+    |  ______   ______   ______   ______   ______   ______   ______  |
+    | | tn.1 | | tn.2 | | tn.3 | | tn.4 | | tn.5 | | tn.6 | | tn.7 | |
+    | |______| |______| |______| |______| |______| |______| |______| |
+    |  ______   ______   ______   ______   ______   ______   ______  |
+    | |______| |______| |______| |______| |______| |______| |______| |
+    |  _________________    __________________    _________________  |
+    | |                 |  |                  |  |                 | |
+    | |                 |  |                  |  |                 | |
+    | |                 |  |                  |  |                 | |
+    | |   remote video  |  |                  |  |   local video   | |
+    | |                 |  |                  |  |          ______ | |
+    | |                 |  |      keypad      |  |         |  PIP || |
+    | |                 |  |                  |  |         |______|| |
+    | |_________________|  |                  |  |_________________| |
+    |                      |                  |                      |
+    |                      |                  |                      |
+    |                      |__________________|                      |
+    |________________________________________________________________|
+
+
+The central section is built using an image (jpg, png, maybe gif too)
+for the skin, and other GUI elements.  Comments embedded in the image
+indicate to what function each area is mapped to.
+Another image (png with transparency) is used for the font.
 
 Mouse and keyboard events are detected on the whole surface, and
 handled differently according to their location:
-
+- center/right click on the local/remote window are used to resize
+  the corresponding window;
+- clicks on the thumbnail start/stop sources and select them as
+  primary or secondary video sources;
 - drag on the local video window are used to move the captured
-  area (in the case of X11 grabber) or the picture-in-picture
-  location (in case of camera included on the X11 grab).
-- click on the keypad are mapped to the corresponding key;
+  area (in the case of X11 grabber) or the picture-in-picture position;
+- keystrokes on the keypad are mapped to the corresponding key;
+  keystrokes are used as keypad functions, or as text input
+  if we are in text-input mode.
 - drag on some keypad areas (sliders etc.) are mapped to the
   corresponding functions;
-- keystrokes are used as keypad functions, or as text input
-  if we are in text-input mode.
 
 Configuration options control the appeareance of the gui:
 
-    keypad = /tmp/phone.jpg	; the skin
-    keypad_font = /tmp/font.ttf	; the font to use for output (XXX deprecated)
+    keypad = /tmp/kpad2.jpg	; the skin
+    keypad_font = /tmp/font.png	; the font to use for output
+
+For future implementation, intresting features can be the following:
+- freeze of the video coming from our remote party
+- save of the whole SDL window as a picture
+- oudio output device switching
+
+The audio switching feature should allow changing the device
+or switching to a recorded message for audio sent to remote party.
+The selection of the device should happen clicking on a marker in the layout.
+For this reason above the thumbnails row in the layout we would like a new row,
+the elements composing the row could be message boards, reporting the name of the
+device or the path of the message to be played.
+
+For video input freeze and entire window capture, we define 2 new key types,
+those should be activated pressing the buttons on the keypad, associated with
+new regions inside the keypad pictureas comments
+
 
  *
  */
@@ -42,13 +84,15 @@
 #include "asterisk/utils.h"	/* ast_calloc and ast_realloc */
 #include <math.h>		/* sqrt */
 
-/* We use 3 'windows' in the GUI */
-enum { WIN_LOCAL, WIN_REMOTE, WIN_KEYPAD, WIN_MAX };
+/* We use a maximum of 12 'windows' in the GUI */
+enum { WIN_LOCAL, WIN_REMOTE, WIN_KEYPAD, WIN_SRC1,
+	WIN_SRC2, WIN_SRC3, WIN_SRC4, WIN_SRC5,
+	WIN_SRC6, WIN_SRC7, WIN_SRC8, WIN_SRC9, WIN_MAX };
 
 #ifndef HAVE_SDL	/* stubs if we don't have any sdl */
 static void show_frame(struct video_desc *env, int out)	{}
 static void sdl_setup(struct video_desc *env)		{}
-static struct gui_info *cleanup_sdl(struct gui_info *gui)	{ return NULL; }
+static struct gui_info *cleanup_sdl(struct gui_info* g, int n)	{ return NULL; }
 static void eventhandler(struct video_desc *env, const char *caption)	{}
 static int keypad_cfg_read(struct gui_info *gui, const char *val)	{ return 0; }
 
@@ -64,6 +108,9 @@
 /* Need to hook into X for SDL_WINDOWID handling */
 #include <X11/Xlib.h>
 #endif
+
+#define BORDER	5		/* border around our windows */
+#define SRC_MSG_BD_H 20		/* height of the message board below those windows */
 
 enum kp_type { KP_NONE, KP_RECT, KP_CIRCLE };
 struct keypad_entry {
@@ -75,9 +122,16 @@
 /* our representation of a displayed window. SDL can only do one main
  * window so we map everything within that one
  */
-struct display_window   {   
+struct display_window {
 	SDL_Overlay	*bmp;
 	SDL_Rect	rect;	/* location of the window */
+};
+
+/* each thumbnail message board has a rectangle associated for the geometry,
+ * and a board structure, we include these two elements in a singole structure */
+struct thumb_bd {
+	SDL_Rect		rect;		/* the rect for geometry and background */
+	struct board		*board;		/* the board */
 };
 
 struct gui_info {
@@ -92,9 +146,11 @@
 	SDL_Surface		*font;		/* font to be used */ 
 	SDL_Rect		font_rects[96];	/* only printable chars */
 
-	/* each board has two rectangles,
+	/* each of the following board has two rectangles,
 	 * [0] is the geometry relative to the keypad,
 	 * [1] is the geometry relative to the whole screen
+	 * we do not use the thumb_bd for these boards because here we need
+	 * 2 rectangles for geometry
 	 */
 	SDL_Rect		kp_msg[2];		/* incoming msg, relative to kpad */
 	struct board		*bd_msg;
@@ -105,6 +161,12 @@
 	SDL_Rect		kp_dialed[2];	/* dialed number */
 	struct board		*bd_dialed;
 
+	/* other boards are one associated with the source windows
+	 * above the keypad in the layout, we only have the geometry
+	 * relative to the whole screen
+	 */
+	struct thumb_bd		thumb_bd_array[MAX_VIDEO_SOURCES];
+
 	/* variable-size array mapping keypad regions to functions */
 	int kp_size, kp_used;
 	struct keypad_entry *kp;
@@ -115,7 +177,7 @@
 /*! \brief free the resources in struct gui_info and the descriptor itself.
  *  Return NULL so we can assign the value back to the descriptor in case.
  */
-static struct gui_info *cleanup_sdl(struct gui_info *gui)
+static struct gui_info *cleanup_sdl(struct gui_info *gui, int device_num)
 {
 	int i;
 
@@ -142,11 +204,43 @@
 			SDL_FreeYUVOverlay(gui->win[i].bmp);
 	}
 	bzero(gui, sizeof(gui));
+
+	/* deallocates the space allocated for the keypad message boards */
+	if (gui->bd_dialed)
+		delete_board(gui->bd_dialed);
+	if (gui->bd_msg)
+		delete_board(gui->bd_msg);
+
+	/* deallocates the space allocated for the thumbnail message boards */
+	for (i = 0; i < device_num; i++) {
+		if (gui->thumb_bd_array[i].board) /* may be useless */
+			delete_board(gui->thumb_bd_array[i].board);
+	}
+	
 	ast_free(gui);
 	SDL_Quit();
 	return NULL;
 }
 
+/* messages to be displayed in the sources message boards
+ * below the source windows
+ */
+
+/* costants defined to describe status of devices */
+#define IS_PRIMARY 1
+#define IS_SECONDARY 2
+#define IS_ON 4
+
+char* src_msgs[] = {
+	"    OFF",
+	"1   OFF",
+	"  2 OFF",
+	"1+2 OFF",
+	"    ON",
+	"1   ON",
+	"  2 ON",
+	"1+2 ON",
+};
 /*
  * Display video frames (from local or remote stream) using the SDL library.
  * - Set the video mode to use the resolution specified by the codec context
@@ -171,7 +265,7 @@
 		b_in = &env->enc_in;
 		b_out = &env->loc_dpy;
 		p_in = NULL;
-	} else {
+	} else if (out == WIN_REMOTE) {
 		/* copy input format from the decoding context */
 		AVCodecContext *c;
 		if (env->in == NULL)	/* XXX should not happen - decoder not ready */
@@ -184,7 +278,14 @@
 
 		b_out = &env->rem_dpy;
 		p_in = (AVPicture *)env->in->d_frame;
-	}
+	} else {
+		int i = out-WIN_SRC1;
+		b_in = env->out.devices[i].dev_buf;
+		if (b_in == NULL)
+			return;
+		p_in = NULL;
+		b_out = &env->src_dpy[i];
+	}		
 	bmp = gui->win[out].bmp;
 	SDL_LockYUVOverlay(bmp);
 	/* output picture info - this is sdl, YUV420P */
@@ -236,6 +337,21 @@
 	KEY_DIALED = 203,	/* area for dialed numbers */
 	KEY_EDIT = 204,		/* area for editing user input */
 
+#ifdef notyet /* XXX for future implementation */
+	KEY_AUDIO_SRCS = 210,
+	/*indexes between 210 and 219 (or more) have been reserved for the "keys"
+	associated with the audio device markers, clicking on these markers
+	will change the source device for audio output */
+
+	KEY_FREEZE = 220,	/* freeze the incoming video */
+	KEY_CAPTURE = 221,	/* capture the whole SDL window as a picture */
+#endif
+	/* video source switching key(s) */
+	KEY_PIP = 230,
+	/*indexes between 231 and 239 have been reserved for the "keys"
+	associated with the device thumbnails, clicking on these pictures
+	will change the source device for primary or secondary (PiP) video output*/
+	KEY_SRCS_WIN = 231, /* till 239 */
 	/* areas outside the keypad - simulated */
 	KEY_OUT_OF_KEYPAD = 241,
 	KEY_REM_DPY = 242,
@@ -270,15 +386,16 @@
 	ast_log(LOG_WARNING, "keypad_toggle(%i) called\n", index);
 
 	switch (index) {
-	case KEY_SENDVIDEO:
+	case KEY_SENDVIDEO: /* send or do not send video */
 		env->out.sendvideo = !env->out.sendvideo;
 		break;
+	case KEY_PIP: /* enable or disable Picture in Picture */
+		env->out.picture_in_picture = !env->out.picture_in_picture;
+		break;
+	case KEY_MUTE: /* send or do not send audio */
+		ast_cli_command(env->gui->outfd, "console mute toggle");
+		break;
 #ifdef notyet
-	case KEY_MUTE: {
-		struct chan_oss_pvt *o = find_desc(oss_active);
-		o->mute = !o->mute;
-		}
-		break;
 	case KEY_AUTOANSWER: {
 		struct chan_oss_pvt *o = find_desc(oss_active);
 		o->autoanswer = !o->autoanswer;
@@ -357,6 +474,130 @@
 	drag->drag_window = win;
 }
 
+static int update_device_info(struct video_desc *env, int i)
+{
+	reset_board(env->gui->thumb_bd_array[i].board);
+	print_message(env->gui->thumb_bd_array[i].board,
+		src_msgs[env->out.devices[i].status_index]);
+	return 0;
+}
+
+/*! \brief Changes the video output (local video) source, controlling if
+ * it is already using that video device, 
+ * and switching the correct fields of env->out.
+ * grabbers are always open and saved in the device table.
+ * The secondary or the primary device can be changed,
+ * according to the "button" parameter:
+ * the primary device is changed if button = SDL_BUTTON_LEFT;
+ * the secondary device is changed if button = not SDL_BUTTON_LEFT;
+ * 
+ * the correct message boards of the sources are also updated
+ * with the new status
+ * 
+ * \param env = pointer to the video environment descriptor
+ * \param index = index of the device the caller wants to use are primary or secondary device
+ * \param button = button clicked on the mouse
+ *
+ * returns 0 on success,
+ * returns 1 on error 
+ */
+static int switch_video_out(struct video_desc *env, int index, Uint8 button)
+{
+	int *p; /* pointer to the index of the device to select */
+
+	if (index >= env->out.device_num) {
+		ast_log(LOG_WARNING, "no devices\n");
+		return 1;
+	}
+	/* select primary or secondary */
+	p = (button == SDL_BUTTON_LEFT) ? &env->out.device_primary :
+		&env->out.device_secondary;
+	/* controls if the device is already selected */
+	if (index == *p) {
+		ast_log(LOG_WARNING, "device %s already selected\n", env->out.devices[index].name);
+		return 0;
+	}
+	ast_log(LOG_WARNING, "switching to %s...\n", env->out.devices[index].name);
+	/* already open */
+	if (env->out.devices[index].grabber) {
+		/* we also have to update the messages in the source 
+		message boards below the source windows */
+		/* first we update the board of the previous source */
+		if (p == &env->out.device_primary)
+			env->out.devices[*p].status_index &= ~IS_PRIMARY;
+		else
+			env->out.devices[*p].status_index &= ~IS_SECONDARY;
+		update_device_info(env, *p);
+		/* update the index used as primary or secondary */
+		*p = index;
+		ast_log(LOG_WARNING, "done\n");
+		/* then we update the board of the new primary or secondary source */
+		if (p == &env->out.device_primary)
+			env->out.devices[*p].status_index |= IS_PRIMARY;
+		else
+			env->out.devices[*p].status_index |= IS_SECONDARY;
+		update_device_info(env, *p);
+		return 0;
+	}
+	/* device is off, just do nothing */
+	ast_log(LOG_WARNING, "device is down\n");
+	return 1;
+}
+
+/*! \brief tries to switch the state of a device from on to off or off to on
+ * we also have to update the status of the device and the correct message board
+ *
+ * \param index = the device that must be turned on or off
+ * \param env = pointer to the video environment descriptor
+ *
+ * returns:
+ * - 0 on falure switching from off to on
+ * - 1 on success in switching from off to on
+ * - 2 on success in switching from on to off
+*/
+static int turn_on_off(int index, struct video_desc *env)
+{
+	struct video_device *p = &env->out.devices[index];
+
+	if (index >= env->out.device_num) {
+		ast_log(LOG_WARNING, "no devices\n");
+		return 0;
+	}
+
+	if (!p->grabber) { /* device off */
+		void *g_data; /* result of grabber_open() */
+		struct grab_desc *g;
+		int i;
+
+		/* see if the device can be used by one of the existing drivers */
+		for (i = 0; (g = console_grabbers[i]); i++) {
+			/* try open the device */
+			g_data = g->open(p->name, &env->out.loc_src_geometry, env->out.fps);
+			if (!g_data)	/* no luck, try the next driver */
+				continue;
+			p->grabber = g;
+			p->grabber_data = g_data;
+			/* update the status of the source */
+			p->status_index |= IS_ON;
+			/* print the new message in the message board */
+			update_device_info(env, index);
+			return 1; /* open succeded */
+		}
+		return 0; /* failure */
+	} else {
+		/* the grabber must be closed */
+		p->grabber_data = p->grabber->close(p->grabber_data);
+		p->grabber = NULL;
+		/* dev_buf is already freed by grabber->close() */
+		p->dev_buf = NULL;
+		/* update the status of the source */
+		p->status_index &= ~IS_ON;
+		/* print the new message in the message board */
+		update_device_info(env, index);
+		return 2; /* closed */
+	}	
+}
+
 /*
  * Handle SDL_MOUSEBUTTONDOWN type, finding the palette
  * index value and calling the right callback.
@@ -367,29 +608,83 @@
 {
 	uint8_t index = KEY_OUT_OF_KEYPAD;	/* the key or region of the display we clicked on */
 	struct gui_info *gui = env->gui;
-
+		
+	int i; /* integer variable used as iterator */
+
+	int x; /* integer variable usable as a container */
+	
+	/* total width of source device thumbnails */
+	int src_wins_tot_w = env->out.device_num*(SRC_WIN_W+BORDER)+BORDER;
+
+	/* x coordinate of the center of the keypad */
+	int x0 = MAX(env->rem_dpy.w+gui->keypad->w/2+2*BORDER, src_wins_tot_w/2);
+	
 #if 0
 	ast_log(LOG_WARNING, "event %d %d have %d/%d regions at %p\n",
 		button.x, button.y, gui->kp_used, gui->kp_size, gui->kp);
 #endif
 	/* for each mousedown we end previous drag */
 	gui->drag.drag_window = DRAG_NONE;
-
+	
 	/* define keypad boundary */
-	if (button.x < env->rem_dpy.w)
-		index = KEY_REM_DPY; /* click on remote video */
-	else if (button.x > env->rem_dpy.w + gui->keypad->w)
-		index = KEY_LOC_DPY; /* click on local video */
-	else if (button.y > gui->keypad->h)
-		index = KEY_OUT_OF_KEYPAD; /* click outside the keypad */
-	else if (gui->kp) {
-		int i;
-		for (i = 0; i < gui->kp_used; i++) {
-			if (kp_match_area(&gui->kp[i], button.x - env->rem_dpy.w, button.y)) {
-				index = gui->kp[i].c;
-				break;
+	/* XXX this should be extended for clicks on different audio device markers */
+	if (button.y >= (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0)) {
+		/* if control reaches this point this means that the clicked point is
+		below the row of the additional sources windows*/
+		/* adjust the y coordinate as if additional devices windows were not present */
+		button.y -= (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
+		if (button.y < BORDER)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.y >= MAX(MAX(env->rem_dpy.h, env->loc_dpy.h), gui->keypad->h))
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.x < x0 - gui->keypad->w/2 - BORDER - env->rem_dpy.w)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.x < x0 - gui->keypad->w/2 - BORDER)
+			index = KEY_REM_DPY;
+		else if (button.x < x0 - gui->keypad->w/2)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.x >= x0 + gui->keypad->w/2 + BORDER + env->loc_dpy.w)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.x >= x0 + gui->keypad->w/2 + BORDER)
+			index = KEY_LOC_DPY;
+		else if (button.x >= x0 + gui->keypad->w/2)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (gui->kp) {
+			/* we have to calculate the first coordinate 
+			inside the keypad before calling the kp_match_area*/
+			int x_keypad = button.x - (x0 - gui->keypad->w/2);
+			/* find the key clicked (if one was clicked) */
+			for (i = 0; i < gui->kp_used; i++) {
+				if (kp_match_area(&gui->kp[i],x_keypad, button.y - BORDER)) {
+					index = gui->kp[i].c;
+					break;
+				}
 			}
 		}
+	} else if (button.y < BORDER) {
+		index = KEY_OUT_OF_KEYPAD;
+	} else {  /* we are in the thumbnail area */
+		x = x0 - src_wins_tot_w/2 + BORDER;
+		if (button.y >= BORDER + SRC_WIN_H)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.x < x)
+			index = KEY_OUT_OF_KEYPAD;
+		else if (button.x < x + src_wins_tot_w - BORDER) {
+			/* note that the additional device windows 
+			are numbered from left to right
+			starting from 0, with a maximum of 8, the index associated on a click is:
+			KEY_SRCS_WIN + number_of_the_window */
+			for (i = 1; i <= env->out.device_num; i++) {
+				if (button.x < x+i*(SRC_WIN_W+BORDER)-BORDER) {
+					index = KEY_SRCS_WIN+i-1;
+					break;
+				} else if (button.x < x+i*(SRC_WIN_W+BORDER)) {
+					index = KEY_OUT_OF_KEYPAD;
+					break;
+				}
+			}
+		} else
+			index = KEY_OUT_OF_KEYPAD;
 	}
 
 	/* exec the function */
@@ -397,6 +692,37 @@
 		keypad_digit(env, index);
 		return;
 	}
+
+	else if (index >= KEY_SRCS_WIN && index < KEY_SRCS_WIN+env->out.device_num) {
+		index -= KEY_SRCS_WIN; /* index of the window, equal to the device index in the table */
+		/* if one of the additional device windows is clicked with
+		left or right mouse button, we have to switch to that device */
+		if (button.button == SDL_BUTTON_RIGHT || button.button == SDL_BUTTON_LEFT) {
+			switch_video_out(env, index, button.button);
+			return;
+		}
+		/* turn on or off the devices selectively with other mouse buttons */
+		else {
+			int ret = turn_on_off(index, env);
+			/* print a message according to what happened */
+			if (!ret)
+				ast_log(LOG_WARNING, "unable to turn on device %s\n",
+					env->out.devices[index].name);
+			else if (ret == 1)
+				ast_log(LOG_WARNING, "device %s changed state to on\n",
+					env->out.devices[index].name);
+			else if (ret == 2)
+				ast_log(LOG_WARNING, "device %s changed state to off\n",
+					env->out.devices[index].name);
+			return;
+		}
+	}
+
+	/* XXX for future implementation
+	else if (click on audio source marker)
+		change audio source device
+	*/
+
 	switch (index) {
 	/* answer/close function */
 	case KEY_PICK_UP:
@@ -407,9 +733,10 @@
 		break;
 
 	/* other functions */
-	case KEY_MUTE:
+	case KEY_MUTE: /* send or not send the audio */
 	case KEY_AUTOANSWER:
-	case KEY_SENDVIDEO:
+	case KEY_SENDVIDEO: /* send or not send the video */
+	case KEY_PIP: /* activate/deactivate picture in picture mode */
 		keypad_toggle(env, index);
 		break;
 
@@ -417,6 +744,13 @@
 		break;
 	case KEY_REMOTEVIDEO:
 		break;
+
+#ifdef notyet /* XXX for future implementations */
+	case KEY_FREEZE:
+		break
+	case KEY_CAPTURE:
+		break;
+#endif
 
 	case KEY_MESSAGEBOARD:
 		if (button.button == SDL_BUTTON_LEFT)
@@ -427,8 +761,26 @@
 	case KEY_LOC_DPY:
 	case KEY_REM_DPY:
 		if (button.button == SDL_BUTTON_LEFT) {
-			if (index == KEY_LOC_DPY)
+			/* values used to find the position of the picture in picture (if present) */
+			int pip_loc_x = (double)env->out.pip_x/env->enc_in.w * env->loc_dpy.w;
+			int pip_loc_y = (double)env->out.pip_y/env->enc_in.h * env->loc_dpy.h;
+			/* check if picture in picture is active and the click was on it */
+			if (index == KEY_LOC_DPY && env->out.picture_in_picture &&
+			  button.x >= x0+gui->keypad->w/2+BORDER+pip_loc_x &&
+			  button.x < x0+gui->keypad->w/2+BORDER+pip_loc_x+env->loc_dpy.w/3 &&
+			  button.y >= BORDER+pip_loc_y && 
+			  button.y < BORDER+pip_loc_y+env->loc_dpy.h/3) {
+				/* set the y cordinate to his previous value */
+				button.y += (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
+				/* starts dragging the picture inside the picture */
+				set_drag(&gui->drag, button.x, button.y, DRAG_PIP);
+			}
+			else if (index == KEY_LOC_DPY) {
+				/* set the y cordinate to his previous value */
+				button.y += (env->out.device_num ? SRC_WIN_H+2*BORDER+SRC_MSG_BD_H : 0);
+				/* click in the local display, but not on the PiP */
 				set_drag(&gui->drag, button.x, button.y, DRAG_LOCAL);
+			}
 			break;
 		} else {
 			char buf[128];
@@ -437,13 +789,26 @@
 				fb->w, fb->h);
 			video_geom(fb, buf);
 			sdl_setup(env);
+			/* writes messages in the source boards, those can be 
+			modified during the execution, because of the events 
+			this must be done here, otherwise the status of sources will not be
+			shown after sdl_setup */
+			for (i = 0; i < env->out.device_num; i++) {
+				update_device_info(env, i);
+			}
+			/* we also have to refresh other boards, 
+			to avoid messages to disappear after video resize */
+			print_message(gui->bd_msg, " \b");
+			print_message(gui->bd_dialed, " \b");
 		}
 		break;
 	case KEY_OUT_OF_KEYPAD:
+		ast_log(LOG_WARNING, "nothing clicked, coordinates: %d, %d\n", button.x, button.y);
 		break;
 
 	case KEY_DIGIT_BACKGROUND:
 		break;
+
 	default:
 		ast_log(LOG_WARNING, "function not yet defined %i\n", index);
 	}
@@ -523,7 +888,7 @@
 	return;
 }
 
-static void grabber_move(struct video_out_desc *, int dx, int dy);
+static void grabber_move(struct video_device *, int dx, int dy);
 
 int compute_drag(int *start, int end, int magnifier);
 int compute_drag(int *start, int end, int magnifier)
@@ -536,6 +901,33 @@
 #undef POLARITY
 	*start = end;
 	return delta;
+}
+
+/*! \brief This function moves the picture in picture,
+ * controlling the limits of the containing buffer
+ * to avoid problems deriving from going through the limits.
+ *
+ * \param env = pointer to the descriptor of the video environment
+ * \param dx = the variation of the x position
+ * \param dy = the variation of the y position
+*/
+static void pip_move(struct video_desc* env, int dx, int dy) {
+	int new_pip_x = env->out.pip_x+dx;
+	int new_pip_y = env->out.pip_y+dy;
+	/* going beyond the left borders */
+	if (new_pip_x < 0)
+		new_pip_x = 0;
+	/* going beyond the right borders */
+	else if (new_pip_x > env->enc_in.w - env->enc_in.w/3)
+		new_pip_x = env->enc_in.w - env->enc_in.w/3;
+	/* going beyond the top borders */
+	if (new_pip_y < 0)
+		new_pip_y = 0;
+	/* going beyond the bottom borders */
+	else if (new_pip_y > env->enc_in.h - env->enc_in.h/3)
+		new_pip_y = env->enc_in.h - env->enc_in.h/3;
+	env->out.pip_x = new_pip_x;
+	env->out.pip_y = new_pip_y;
 }
 
 /*
@@ -592,11 +984,24 @@
 
 			case SDL_MOUSEMOTION:
 			case SDL_MOUSEBUTTONUP:
-				if (drag->drag_window == DRAG_LOCAL) {
+				if (drag->drag_window == DRAG_LOCAL && env->out.device_num) {
 					/* move the capture source */
 					int dx = compute_drag(&drag->x_start, ev[i].motion.x, 3);
 					int dy = compute_drag(&drag->y_start, ev[i].motion.y, 3);
-					grabber_move(&env->out, dx, dy);
+					grabber_move(&env->out.devices[env->out.device_primary], dx, dy);
+				} else if (drag->drag_window == DRAG_PIP) {
+					/* move the PiP image inside the frames of the enc_in buffers */
+					int dx = ev[i].motion.x - drag->x_start;
+					int dy = ev[i].motion.y - drag->y_start;
+					/* dx and dy value are directly applied to env->out.pip_x and
+					env->out.pip_y, so they must work as if the format was cif */
+					dx = (double)dx*env->enc_in.w/env->loc_dpy.w;
+					dy = (double)dy*env->enc_in.h/env->loc_dpy.h;
+					/* sets starts to a new value */
+					drag->x_start = ev[i].motion.x;
+					drag->y_start = ev[i].motion.y;
+					/* ast_log(LOG_WARNING, "moving: %d, %d\n", dx, dy); */
+					pip_move(env, dx, dy);
 				} else if (drag->drag_window == DRAG_MESSAGE) {
 					/* scroll up/down the window */
 					int dy = compute_drag(&drag->y_start, ev[i].motion.y, 1);
@@ -807,7 +1212,15 @@
 	const SDL_VideoInfo *info;
 	int kp_w = 0, kp_h = 0;	/* keypad width and height */
 	struct gui_info *gui = env->gui;
-
+	
+	/* Some helper variables used for filling the SDL window */
+	int x0; /* the x coordinate of the center of the keypad */
+	int x1; /* userful for calculating of the size of the parent window */
+	int y0; /* y coordinate of the keypad, the remote window and the local window */
+	int src_wins_tot_w; /* total width of the source windows */
+	int i;
+	int x; /* useful for the creation of the source windows; */
+	
 #ifdef HAVE_X11
 	const char *e = getenv("SDL_WINDOWID");
 
@@ -829,6 +1242,8 @@
 	 * initialize the SDL environment. We have one large window
 	 * with local and remote video, and a keypad.
 	 * At the moment we arrange them statically, as follows:
+	 * - top row: thumbnails for local video sources;
+	 * - next row: message boards for local video sources
 	 * - on the left, the remote video;
 	 * - on the center, the keypad
 	 * - on the right, the local video
@@ -868,13 +1283,23 @@
 			kp_h = gui->keypad->h;
 		}
 	}
-	/* XXX same for other boards */
-#define BORDER	5	/* border around our windows */
-	maxw = env->rem_dpy.w + env->loc_dpy.w + kp_w;
-	maxh = MAX( MAX(env->rem_dpy.h, env->loc_dpy.h), kp_h);
-	maxw += 4 * BORDER;
-	maxh += 2 * BORDER;
-
+	
+	/* total width of the thumbnails */
+	src_wins_tot_w = env->out.device_num*(SRC_WIN_W+BORDER)+BORDER;
+	
+	/* x coordinate of the center of the keypad */
+	x0 = MAX(env->rem_dpy.w+kp_w/2+2*BORDER, src_wins_tot_w/2);
+	
+	/* from center of the keypad to right border */
+	x1 = MAX(env->loc_dpy.w+kp_w/2+2*BORDER, src_wins_tot_w/2);
+	
+	/* total width of the SDL window to create */
+	maxw = x0+x1;
+	
+	/* total height of the mother window to create */
+	maxh = MAX( MAX(env->rem_dpy.h, env->loc_dpy.h), kp_h)+2*BORDER;
+	maxh += env->out.device_num ? (2*BORDER+SRC_WIN_H+SRC_MSG_BD_H) : 0;
+	
 	gui->screen = SDL_SetVideoMode(maxw, maxh, depth, 0);
 	if (!gui->screen) {
 		ast_log(LOG_ERROR, "SDL: could not set video mode - exiting\n");
@@ -973,24 +1398,53 @@
 	}
     } while (0);
 #endif /* HAVE_X11 */
+
+	y0 = env->out.device_num ? (3*BORDER+SRC_WIN_H+SRC_MSG_BD_H) : BORDER;
+	
 	SDL_WM_SetCaption("Asterisk console Video Output", NULL);
+	
+	/* intialize the windows for local and remote video */
 	if (set_win(gui->screen, &gui->win[WIN_REMOTE], dpy_fmt,
-			env->rem_dpy.w, env->rem_dpy.h, BORDER, BORDER))
+			env->rem_dpy.w, env->rem_dpy.h, x0-kp_w/2-BORDER-env->rem_dpy.w, y0))
 		goto no_sdl;
 	if (set_win(gui->screen, &gui->win[WIN_LOCAL], dpy_fmt,
 			env->loc_dpy.w, env->loc_dpy.h,
-			3*BORDER+env->rem_dpy.w + kp_w, BORDER))
+			x0+kp_w/2+BORDER, y0))
 		goto no_sdl;
+	
+	/* initialize device_num source windows (thumbnails) and boards
+	(for a maximum of 9 additional windows and boards) */
+	x = x0 - src_wins_tot_w/2 + BORDER;
+	for (i = 0; i < env->out.device_num; i++){
+		struct thumb_bd *p = &gui->thumb_bd_array[i];
+		if (set_win(gui->screen, &gui->win[i+WIN_SRC1], dpy_fmt,
+			SRC_WIN_W, SRC_WIN_H, x+i*(BORDER+SRC_WIN_W), BORDER))
+			goto no_sdl;
+		/* set geometry for the rect for the message board of the device */
+		p->rect.w = SRC_WIN_W;
+		p->rect.h = SRC_MSG_BD_H;
+		p->rect.x = x+i*(BORDER+SRC_WIN_W);
+		p->rect.y = 2*BORDER+SRC_WIN_H;
+		/* the white color is used as background */
+		SDL_FillRect(gui->screen, &p->rect,
+			SDL_MapRGB(gui->screen->format, 255, 255, 255));
+		/* if necessary, initialize boards for the sources */
+		if (!p->board)
+			p->board =
+				board_setup(gui->screen, &p->rect,
+				gui->font, gui->font_rects);
+		/* update board rect */
+		SDL_UpdateRect(gui->screen, p->rect.x, p->rect.y, p->rect.w, p->rect.h);
+	}
 
 	/* display the skin, but do not free it as we need it later to
-	 * restore text areas and maybe sliders too.
-	 */
+	restore text areas and maybe sliders too */
 	if (gui->keypad) {
 		struct SDL_Rect *dest = &gui->win[WIN_KEYPAD].rect;
 		struct SDL_Rect *src = (gui->kp_rect.w > 0 && gui->kp_rect.h > 0) ? & gui->kp_rect : NULL;
 		/* set the coordinates of the keypad relative to the main screen */
-		dest->x = 2*BORDER + env->rem_dpy.w;
-		dest->y = BORDER;
+		dest->x = x0-kp_w/2;
+		dest->y = y0;
 		dest->w = kp_w;
 		dest->h = kp_h;
 		SDL_BlitSurface(gui->keypad, src, gui->screen, dest);
@@ -1002,7 +1456,7 @@
 
 no_sdl:
 	/* free resources in case of errors */
-	env->gui = cleanup_sdl(gui);
+	env->gui = cleanup_sdl(gui, env->out.device_num);
 }
 
 /*
@@ -1027,7 +1481,7 @@
 		xp = ((x - e->x0)*dx + (y - e->y0)*dy)/l;
 		yp = (-(x - e->x0)*dy + (y - e->y0)*dx)/l;
 		if (e->type == KP_RECT) {
-			ret = (xp >= 0 && xp < l && yp >=0 && yp < l);
+			ret = (xp >= 0 && xp < l && yp >=0 && yp < e->h);
 		} else if (e->type == KP_CIRCLE) {
 			dx = xp*xp/(l*l) + yp*yp/(e->h*e->h);
 			ret = (dx < 1);
@@ -1042,6 +1496,7 @@
 
 struct _s_k { const char *s; int k; };
 static struct _s_k gui_key_map[] = {
+	{"PIP",		KEY_PIP},
 	{"PICK_UP",	KEY_PICK_UP },
 	{"PICKUP",	KEY_PICK_UP },
         {"HANG_UP",	KEY_HANG_UP },

Modified: team/russell/bindings/channels/console_video.c
URL: http://svn.digium.com/view/asterisk/team/russell/bindings/channels/console_video.c?view=diff&rev=126519&r1=126518&r2=126519
==============================================================================
--- team/russell/bindings/channels/console_video.c (original)
+++ team/russell/bindings/channels/console_video.c Mon Jun 30 08:07:36 2008
@@ -87,6 +87,9 @@
 
  rem_dpy	the format used to display the remote stream
 
+ src_dpy	is the format used to display the local video source streams
+	The number of these fbuf_t is determined at run time, with dynamic allocation
+
 We store the format info together with the buffer storing the data.
 As a future optimization, a format/buffer may reference another one
 if the formats are equivalent. This will save some unnecessary format
@@ -145,8 +148,26 @@
 
 
 
+/* function to scale and encode buffers */
 static void my_scale(struct fbuf_t *in, AVPicture *p_in,
 	struct fbuf_t *out, AVPicture *p_out);
+
+/*
+ * this structure will be an entry in the table containing
+ * every device specified in the file oss.conf, it contains various infomation
+ * about the device
+ */
+struct video_device {
+	char 			*name;		/* name of the device			*/
+	/* allocated dynamically (see fill_table function) */
+	struct grab_desc 	*grabber;	/* the grabber for the device type	*/
+	void 			*grabber_data;	/* device's private data structure	*/
+	struct fbuf_t		*dev_buf;	/* buffer for incoming data		*/
+	struct timeval		last_frame;	/* when we read the last frame ?	*/
+	int 			status_index;	/* what is the status of the device (source) */
+	/* status index is set using the IS_ON, IS_PRIMARY and IS_SECONDARY costants */
+	/* status_index is the index of the status message in the src_msgs array in console_gui.c */
+};
 
 struct video_codec_desc;	/* forward declaration */
 /*
@@ -157,7 +178,8 @@
  *  + the encoding and RTP info, including timestamps to generate
  *    frames at the correct rate;
  *  + source-specific info, i.e. fd for /dev/video, dpy-image for x11, etc,
- *    filled in by grabber_open
+ *    filled in by grabber_open, part of source_specific information are in 
+ *    the device table (devices member), others are shared;
  * NOTE: loc_src.data == NULL means the rest of the struct is invalid, and
  *	the video source is not available.
  */
@@ -168,7 +190,6 @@
 	 * If we are successful, webcam_bufsize > 0 and we can read.
 	 */
 	/* all the following is config file info copied from the parent */
-	char		videodevice[64];
 	int		fps;
 	int		bitrate;
 	int		qmin;
@@ -184,10 +205,21 @@
 	AVFrame		*enc_in_frame;	/* enc_in mapped into avcodec format. */
 					/* The initial part of AVFrame is an AVPicture */
 	int		mtu;
-	struct timeval	last_frame;	/* when we read the last frame ? */
-
-	struct grab_desc *grabber;
-	void		*grabber_data;
+	
+	/* Table of devices specified with "videodevice=" in oss.conf.
+	 * Static size as we have a limited number of entries.
+	 */
+	struct video_device	devices[MAX_VIDEO_SOURCES]; 
+	int 			device_num; /*number of devices in table*/
+	int			device_primary; /*index of the actual primary device in the table*/
+	int			device_secondary; /*index of the actual secondary device in the table*/
+
+	int 			picture_in_picture; /*Is the PiP mode activated? 0 = NO | 1 = YES*/
+
+	/* these are the coordinates of the picture inside the picture (visible if PiP mode is active) 
+	these coordinates are valid considering the containing buffer with cif geometry*/
+	int 			pip_x;
+	int			pip_y;
 };
 
 /*
@@ -216,7 +248,11 @@
 	struct fbuf_t		rem_dpy;	/* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
 	struct fbuf_t		loc_dpy;	/* display local source, no buffer (managed by SDL in bmp[1]) */
 
-
+	/*display for  sources in additional windows, 
+	ideally infinite additional sources could be present
+	pratically we assume a maximum of 9 sources to show*/
+	struct fbuf_t		src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
+	
 	/* local information for grabbers, codecs, gui */
 	struct gui_info		*gui;
 	struct video_dec_desc	*in;		/* remote video descriptor */
@@ -238,54 +274,108 @@
 	b->pix_fmt = x.pix_fmt;
 }
 
+#if 0
+/* helper function to print the amount of memory used by the process.
+ * Useful to track memory leaks, unfortunately this code is OS-specific
+ * so we keep it commented out.
+ */
+static int
+used_mem(const char *msg)
+{
+	char in[128];
+
+	pid_t pid = getpid();
+	sprintf(in, "ps -o vsz= -o rss= %d", pid);
+	ast_log(LOG_WARNING, "used mem (vsize, rss) %s ", msg);
+	system(in);
+	return 0;
+}
+#endif
+	
 #include "vcodecs.c"
 #include "console_gui.c"
 
-/*! \brief Try to open a video source, return 0 on success, 1 on error */
+/*! \brief Try to open video sources, return 0 on success, 1 on error
+ * opens all video sources found in the oss.conf configuration files.
+ * Saves the grabber and the datas in the device table (in the devices field
+ * of the descriptor referenced by v).
+ * Initializes the device_primary and device_secondary
+ * fields of v with the first devices that was
+ * successfully opened.
+ *
+ * \param v = video out environment descriptor
+ *
+ * returns 0 on success, 1 on error 
+*/
 static int grabber_open(struct video_out_desc *v)
 {
 	struct grab_desc *g;
 	void *g_data;
-	int i;
-
-	for (i = 0; (g = console_grabbers[i]); i++) {

[... 681 lines stripped ...]



More information about the asterisk-commits mailing list