[svn-commits] elguero: trunk r381256 - /trunk/apps/app_confbridge.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Feb 11 21:31:50 CST 2013


Author: elguero
Date: Mon Feb 11 21:31:46 2013
New Revision: 381256

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381256
Log:
Adding Some More Manager Events To ConfBridge

Currently, ConfBridge does not send manager events for ConfbridgeMute,
ConfbridgeUnmute, ConfbridgeStartRecord and ConfbridgeStopRecord.  This patch
adds these events to the manager.

The reporter's patch moves some other events up to the beginning of the file.

The patch being committed is based on the patch contributed from the reporter of
this issue.  I have made a lot of modifications to the patch in order for it to
fit in better with what we currently are doing in the code when it comes to
manager events.  I also made a few changes to the <see-also> elements on some of
the events.

(closes issue ASTERISK-20827)
Reported by: Clint Davis
Tested by: Clint Davis, Michael L. Young
Patches:
    20827.diff uploaded by Clint Davis (license 6453)
    asterisk-20827-confbridge-events.diff uploaded by 
                                                 Michael L. Young (license 5026)

Review: https://reviewboard.asterisk.org/r/2309/

Modified:
    trunk/apps/app_confbridge.c

Modified: trunk/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_confbridge.c?view=diff&rev=381256&r1=381255&r2=381256
==============================================================================
--- trunk/apps/app_confbridge.c (original)
+++ trunk/apps/app_confbridge.c Mon Feb 11 21:31:46 2013
@@ -379,211 +379,6 @@
 	return "";
 }
 
-static struct ast_frame *rec_read(struct ast_channel *ast)
-{
-	return &ast_null_frame;
-}
-static int rec_write(struct ast_channel *ast, struct ast_frame *f)
-{
-	return 0;
-}
-static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
-static struct ast_channel_tech record_tech = {
-	.type = "ConfBridgeRec",
-	.description = "Conference Bridge Recording Channel",
-	.requester = rec_request,
-	.read = rec_read,
-	.write = rec_write,
-};
-static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
-{
-	struct ast_channel *tmp;
-	struct ast_format fmt;
-	const char *conf_name = data;
-	if (!(tmp = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", NULL, 0,
-		"ConfBridgeRecorder/conf-%s-uid-%d",
-		conf_name,
-		(int) ast_random()))) {
-		return NULL;
-	}
-	ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0);
-	ast_channel_tech_set(tmp, &record_tech);
-	ast_format_cap_add_all(ast_channel_nativeformats(tmp));
-	ast_format_copy(ast_channel_writeformat(tmp), &fmt);
-	ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt);
-	ast_format_copy(ast_channel_readformat(tmp), &fmt);
-	ast_format_copy(ast_channel_rawreadformat(tmp), &fmt);
-	return tmp;
-}
-
-static void *record_thread(void *obj)
-{
-	struct conference_bridge *conference_bridge = obj;
-	struct ast_app *mixmonapp = pbx_findapp("MixMonitor");
-	struct ast_channel *chan;
-	struct ast_str *filename = ast_str_alloca(PATH_MAX);
-
-	ast_mutex_lock(&conference_bridge->record_lock);
-	if (!mixmonapp) {
-		ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
-		conference_bridge->record_thread = AST_PTHREADT_NULL;
-		ast_mutex_unlock(&conference_bridge->record_lock);
-		ao2_ref(conference_bridge, -1);
-		return NULL;
-	}
-
-	/* XXX If we get an EXIT right here, START will essentially be a no-op */
-	while (conference_bridge->record_state != CONF_RECORD_EXIT) {
-		if (!(ast_strlen_zero(conference_bridge->b_profile.rec_file))) {
-			ast_str_append(&filename, 0, "%s", conference_bridge->b_profile.rec_file);
-		} else {
-			time_t now;
-			time(&now);
-			ast_str_append(&filename, 0, "confbridge-%s-%u.wav",
-				conference_bridge->name,
-				(unsigned int) now);
-		}
-
-		chan = ast_channel_ref(conference_bridge->record_chan);
-		ast_answer(chan);
-		pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
-		ast_bridge_join(conference_bridge->bridge, chan, NULL, NULL, NULL);
-
-		ast_hangup(chan); /* This will eat this thread's reference to the channel as well */
-		/* STOP has been called. Wait for either a START or an EXIT */
-		ast_cond_wait(&conference_bridge->record_cond, &conference_bridge->record_lock);
-	}
-	ast_mutex_unlock(&conference_bridge->record_lock);
-	ao2_ref(conference_bridge, -1);
-	return NULL;
-}
-
-/*! \brief Returns whether or not conference is being recorded.
- * \param conference_bridge The bridge to check for recording
- * \retval 1, conference is recording.
- * \retval 0, conference is NOT recording.
- */
-static int conf_is_recording(struct conference_bridge *conference_bridge)
-{
-	return conference_bridge->record_state == CONF_RECORD_START;
-}
-
-/*! \brief Stop recording a conference bridge
- * \internal
- * \param conference_bridge The conference bridge on which to stop the recording
- * \retval -1 Failure
- * \retval 0 Success
- */
-static int conf_stop_record(struct conference_bridge *conference_bridge)
-{
-	struct ast_channel *chan;
-	if (conference_bridge->record_thread == AST_PTHREADT_NULL || !conf_is_recording(conference_bridge)) {
-		return -1;
-	}
-	conference_bridge->record_state = CONF_RECORD_STOP;
-	chan = ast_channel_ref(conference_bridge->record_chan);
-	ast_bridge_remove(conference_bridge->bridge, chan);
-	ast_queue_frame(chan, &ast_null_frame);
-	chan = ast_channel_unref(chan);
-	ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
-
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Stops the confbridge recording thread.
- *
- * \note Must be called with the conference_bridge locked
- */
-static int conf_stop_record_thread(struct conference_bridge *conference_bridge)
-{
-	if (conference_bridge->record_thread == AST_PTHREADT_NULL) {
-		return -1;
-	}
-	conf_stop_record(conference_bridge);
-
-	ast_mutex_lock(&conference_bridge->record_lock);
-	conference_bridge->record_state = CONF_RECORD_EXIT;
-	ast_cond_signal(&conference_bridge->record_cond);
-	ast_mutex_unlock(&conference_bridge->record_lock);
-
-	pthread_join(conference_bridge->record_thread, NULL);
-	conference_bridge->record_thread = AST_PTHREADT_NULL;
-
-	/* this is the reference given to the channel during the channel alloc */
-	if (conference_bridge->record_chan) {
-		conference_bridge->record_chan = ast_channel_unref(conference_bridge->record_chan);
-	}
-
-	return 0;
-}
-
-/*! \brief Start recording the conference
- * \internal
- * \note conference_bridge must be locked when calling this function
- * \param conference_bridge The conference bridge to start recording
- * \retval 0 success
- * \rteval non-zero failure
- */
-static int conf_start_record(struct conference_bridge *conference_bridge)
-{
-	struct ast_format_cap *cap;
-	struct ast_format tmpfmt;
-	int cause;
-
-	if (conference_bridge->record_state != CONF_RECORD_STOP) {
-		return -1;
-	}
-
-	if (!pbx_findapp("MixMonitor")) {
-		ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
-		return -1;
-	}
-
-	if (!(cap = ast_format_cap_alloc_nolock())) {
-		return -1;
-	}
-
-	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
-
-	if (!(conference_bridge->record_chan = ast_request("ConfBridgeRec", cap, NULL, conference_bridge->name, &cause))) {
-		cap = ast_format_cap_destroy(cap);
-		return -1;
-	}
-
-	cap = ast_format_cap_destroy(cap);
-
-	conference_bridge->record_state = CONF_RECORD_START;
-	ast_mutex_lock(&conference_bridge->record_lock);
-	ast_cond_signal(&conference_bridge->record_cond);
-	ast_mutex_unlock(&conference_bridge->record_lock);
-	ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
-
-	return 0;
-}
-
-/*! \brief Start the recording thread on a conference bridge
- * \internal
- * \param conference_bridge The conference bridge on which to start the recording thread
- * \retval 0 success
- * \retval -1 failure
- */
-static int start_conf_record_thread(struct conference_bridge *conference_bridge)
-{
-	ao2_ref(conference_bridge, +1); /* give the record thread a ref */
-
-	conf_start_record(conference_bridge);
-
-	if (ast_pthread_create_background(&conference_bridge->record_thread, NULL, record_thread, conference_bridge)) {
-		ast_log(LOG_WARNING, "Failed to create recording channel for conference %s\n", conference_bridge->name);
-		ao2_ref(conference_bridge, -1); /* error so remove ref */
-		return -1;
-	}
-
-	return 0;
-}
-
 static void send_conf_start_event(const char *conf_name)
 {
 	/*** DOCUMENTATION
@@ -596,6 +391,7 @@
 			</syntax>
 			<see-also>
 				<ref type="managerEvent">ConfbridgeEnd</ref>
+				<ref type="application">ConfBridge</ref>
 			</see-also>
 		</managerEventInstance>
 	***/
@@ -612,7 +408,6 @@
 			</syntax>
 			<see-also>
 				<ref type="managerEvent">ConfbridgeStart</ref>
-				<ref type="application">ConfBridge</ref>
 			</see-also>
 		</managerEventInstance>
 	***/
@@ -674,6 +469,303 @@
 	);
 }
 
+static void send_start_record_event(const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a conference recording starts.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeStopRecord</ref>
+				<ref type="application">ConfBridge</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+
+	manager_event(EVENT_FLAG_CALL, "ConfbridgeStartRecord", "Conference: %s\r\n", conf_name);
+}
+
+static void send_stop_record_event(const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a conference recording stops.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeStartRecord</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "ConfbridgeStopRecord", "Conference: %s\r\n", conf_name);
+}
+
+static void send_mute_event(struct ast_channel *chan, const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a Confbridge participant mutes.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeUnmute</ref>
+				<ref type="application">ConfBridge</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeMute",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Conference: %s\r\n"
+		"CallerIDnum: %s\r\n"
+		"CallerIDname: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		conf_name,
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>")
+	);
+}
+
+static void send_unmute_event(struct ast_channel *chan, const char *conf_name)
+{
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when a Confbridge participant unmutes.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
+			</syntax>
+			<see-also>
+				<ref type="managerEvent">ConfbridgeMute</ref>
+			</see-also>
+		</managerEventInstance>
+	***/
+	ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeUnmute",
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Conference: %s\r\n"
+		"CallerIDnum: %s\r\n"
+		"CallerIDname: %s\r\n",
+		ast_channel_name(chan),
+		ast_channel_uniqueid(chan),
+		conf_name,
+		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>")
+	);
+}
+
+
+static struct ast_frame *rec_read(struct ast_channel *ast)
+{
+	return &ast_null_frame;
+}
+static int rec_write(struct ast_channel *ast, struct ast_frame *f)
+{
+	return 0;
+}
+static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel_tech record_tech = {
+	.type = "ConfBridgeRec",
+	.description = "Conference Bridge Recording Channel",
+	.requester = rec_request,
+	.read = rec_read,
+	.write = rec_write,
+};
+static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct ast_channel *tmp;
+	struct ast_format fmt;
+	const char *conf_name = data;
+	if (!(tmp = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", NULL, 0,
+		"ConfBridgeRecorder/conf-%s-uid-%d",
+		conf_name,
+		(int) ast_random()))) {
+		return NULL;
+	}
+	ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0);
+	ast_channel_tech_set(tmp, &record_tech);
+	ast_format_cap_add_all(ast_channel_nativeformats(tmp));
+	ast_format_copy(ast_channel_writeformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt);
+	ast_format_copy(ast_channel_readformat(tmp), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(tmp), &fmt);
+	return tmp;
+}
+
+static void *record_thread(void *obj)
+{
+	struct conference_bridge *conference_bridge = obj;
+	struct ast_app *mixmonapp = pbx_findapp("MixMonitor");
+	struct ast_channel *chan;
+	struct ast_str *filename = ast_str_alloca(PATH_MAX);
+
+	ast_mutex_lock(&conference_bridge->record_lock);
+	if (!mixmonapp) {
+		ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
+		conference_bridge->record_thread = AST_PTHREADT_NULL;
+		ast_mutex_unlock(&conference_bridge->record_lock);
+		ao2_ref(conference_bridge, -1);
+		return NULL;
+	}
+
+	/* XXX If we get an EXIT right here, START will essentially be a no-op */
+	while (conference_bridge->record_state != CONF_RECORD_EXIT) {
+		if (!(ast_strlen_zero(conference_bridge->b_profile.rec_file))) {
+			ast_str_append(&filename, 0, "%s", conference_bridge->b_profile.rec_file);
+		} else {
+			time_t now;
+			time(&now);
+			ast_str_append(&filename, 0, "confbridge-%s-%u.wav",
+				conference_bridge->name,
+				(unsigned int) now);
+		}
+
+		chan = ast_channel_ref(conference_bridge->record_chan);
+		ast_answer(chan);
+		pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
+		ast_bridge_join(conference_bridge->bridge, chan, NULL, NULL, NULL);
+
+		ast_hangup(chan); /* This will eat this thread's reference to the channel as well */
+		/* STOP has been called. Wait for either a START or an EXIT */
+		ast_cond_wait(&conference_bridge->record_cond, &conference_bridge->record_lock);
+	}
+	ast_mutex_unlock(&conference_bridge->record_lock);
+	ao2_ref(conference_bridge, -1);
+	return NULL;
+}
+
+/*! \brief Returns whether or not conference is being recorded.
+ * \param conference_bridge The bridge to check for recording
+ * \retval 1, conference is recording.
+ * \retval 0, conference is NOT recording.
+ */
+static int conf_is_recording(struct conference_bridge *conference_bridge)
+{
+	return conference_bridge->record_state == CONF_RECORD_START;
+}
+
+/*! \brief Stop recording a conference bridge
+ * \internal
+ * \param conference_bridge The conference bridge on which to stop the recording
+ * \retval -1 Failure
+ * \retval 0 Success
+ */
+static int conf_stop_record(struct conference_bridge *conference_bridge)
+{
+	struct ast_channel *chan;
+	if (conference_bridge->record_thread == AST_PTHREADT_NULL || !conf_is_recording(conference_bridge)) {
+		return -1;
+	}
+	conference_bridge->record_state = CONF_RECORD_STOP;
+	chan = ast_channel_ref(conference_bridge->record_chan);
+	ast_bridge_remove(conference_bridge->bridge, chan);
+	ast_queue_frame(chan, &ast_null_frame);
+	chan = ast_channel_unref(chan);
+	ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
+	send_stop_record_event(conference_bridge->name);
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Stops the confbridge recording thread.
+ *
+ * \note Must be called with the conference_bridge locked
+ */
+static int conf_stop_record_thread(struct conference_bridge *conference_bridge)
+{
+	if (conference_bridge->record_thread == AST_PTHREADT_NULL) {
+		return -1;
+	}
+	conf_stop_record(conference_bridge);
+
+	ast_mutex_lock(&conference_bridge->record_lock);
+	conference_bridge->record_state = CONF_RECORD_EXIT;
+	ast_cond_signal(&conference_bridge->record_cond);
+	ast_mutex_unlock(&conference_bridge->record_lock);
+
+	pthread_join(conference_bridge->record_thread, NULL);
+	conference_bridge->record_thread = AST_PTHREADT_NULL;
+
+	/* this is the reference given to the channel during the channel alloc */
+	if (conference_bridge->record_chan) {
+		conference_bridge->record_chan = ast_channel_unref(conference_bridge->record_chan);
+	}
+
+	return 0;
+}
+
+/*! \brief Start recording the conference
+ * \internal
+ * \note conference_bridge must be locked when calling this function
+ * \param conference_bridge The conference bridge to start recording
+ * \retval 0 success
+ * \rteval non-zero failure
+ */
+static int conf_start_record(struct conference_bridge *conference_bridge)
+{
+	struct ast_format_cap *cap;
+	struct ast_format tmpfmt;
+	int cause;
+
+	if (conference_bridge->record_state != CONF_RECORD_STOP) {
+		return -1;
+	}
+
+	if (!pbx_findapp("MixMonitor")) {
+		ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
+		return -1;
+	}
+
+	if (!(cap = ast_format_cap_alloc_nolock())) {
+		return -1;
+	}
+
+	ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+
+	if (!(conference_bridge->record_chan = ast_request("ConfBridgeRec", cap, NULL, conference_bridge->name, &cause))) {
+		cap = ast_format_cap_destroy(cap);
+		return -1;
+	}
+
+	cap = ast_format_cap_destroy(cap);
+
+	conference_bridge->record_state = CONF_RECORD_START;
+	ast_mutex_lock(&conference_bridge->record_lock);
+	ast_cond_signal(&conference_bridge->record_cond);
+	ast_mutex_unlock(&conference_bridge->record_lock);
+	ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
+	send_start_record_event(conference_bridge->name);
+
+	return 0;
+}
+
+/*! \brief Start the recording thread on a conference bridge
+ * \internal
+ * \param conference_bridge The conference bridge on which to start the recording thread
+ * \retval 0 success
+ * \retval -1 failure
+ */
+static int start_conf_record_thread(struct conference_bridge *conference_bridge)
+{
+	ao2_ref(conference_bridge, +1); /* give the record thread a ref */
+
+	conf_start_record(conference_bridge);
+
+	if (ast_pthread_create_background(&conference_bridge->record_thread, NULL, record_thread, conference_bridge)) {
+		ast_log(LOG_WARNING, "Failed to create recording channel for conference %s\n", conference_bridge->name);
+		ao2_ref(conference_bridge, -1); /* error so remove ref */
+		return -1;
+	}
+
+	return 0;
+}
+
 /*!
  * \internal
  * \brief Complain if the given sound file does not exist.
@@ -1735,6 +1827,11 @@
 	if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_WAITMARKED) || conference_bridge->markedusers) {
 		conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0);
 		ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(chan), conference_bridge_user->features.mute ? "muted" : "unmuted", conference_bridge_user->b_profile.name, ast_channel_name(chan));
+		if (conference_bridge_user->features.mute) {
+			send_mute_event(chan, conference_bridge->name);
+		} else { 
+			send_unmute_event(chan, conference_bridge->name);
+		}
 	}
 	return ast_stream_and_wait(chan, (conference_bridge_user->features.mute ?
 		conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) :




More information about the svn-commits mailing list