Revision
16110
Author
anthm
Date
2009-12-31 14:08:57 -0600 (Thu, 31 Dec 2009)

Log Message

nut 'n honey

Modified Paths

Diff

Modified: freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c (16109 => 16110)


--- freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c	2009-12-31 19:41:47 UTC (rev 16109)
+++ freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c	2009-12-31 20:08:57 UTC (rev 16110)
@@ -175,7 +175,8 @@
 	CFLAG_ANSWERED = (1 << 5),
 	CFLAG_BRIDGE_TO = (1 << 6),
 	CFLAG_WAIT_MOD = (1 << 7),
-	CFLAG_VID_FLOOR = (1 << 8)
+	CFLAG_VID_FLOOR = (1 << 8),
+	CFLAG_WASTE_BANDWIDTH = (1 << 9)
 } conf_flag_t;
 
 typedef enum {
@@ -297,6 +298,7 @@
 	uint32_t eflags;
 	uint32_t verbose_events;
 	int end_count;
+	uint32_t relationship_total;
 } conference_obj_t;
 
 /* Relationship with another member */
@@ -571,7 +573,11 @@
 
 	rel->id = id;
 
+
 	lock_member(member);
+	switch_mutex_lock(member->conference->member_mutex);
+	member->conference->relationship_total++;
+	switch_mutex_unlock(member->conference->member_mutex);
 	rel->next = member->relationships;
 	member->relationships = rel;
 	unlock_member(member);
@@ -599,6 +605,11 @@
 			} else {
 				member->relationships = rel->next;
 			}
+
+			switch_mutex_lock(member->conference->member_mutex);
+			member->conference->relationship_total--;
+			switch_mutex_unlock(member->conference->member_mutex);
+
 		}
 		last = rel;
 	}
@@ -970,6 +981,9 @@
 	switch_event_t *event;
 	uint8_t *file_frame;
 	uint8_t *async_file_frame;
+	int16_t *bptr;
+	int x;
+	int32_t z = 0;
 
 	file_frame = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
 	async_file_frame = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
@@ -1111,7 +1125,7 @@
 
 						for (x = 0; x < file_sample_len; x++) {
 							int32_t z;
-							int16_t *bptr, *muxed;
+							int16_t *muxed;
 
 							muxed = (int16_t *) file_frame;
 							bptr = (int16_t *) async_file_frame;
@@ -1127,99 +1141,183 @@
 			}
 		}
 
-		if (ready || has_file_data) {
-			/* Build a muxed frame for every member that contains the mixed audio of everyone else */
+		if (switch_test_flag(conference, CFLAG_WASTE_BANDWIDTH) && !has_file_data) {
+			file_sample_len = bytes / 2;
 
-			for (omember = conference->members; omember; omember = omember->next) {
+			if (conference->comfort_noise_level) {
+				switch_generate_sln_silence((int16_t *) file_frame, file_sample_len, conference->comfort_noise_level);
+			} else {
+				memset(file_frame, 255, bytes);
+			}
+			has_file_data = 1;
+		}
+
+		if (!conference->relationship_total) {
+			/* If there are no relationships meaning (user x can specificly not speal to and/or hear user y), use a more efficient muxing technique. */
+			if (ready || has_file_data) {
+				/* Use more bits in the main_frame to preserve the exact sum of the audio samples. */
+				int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
+				int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
+
+
+				/* Init the main frame with file data if there is any. */
+				bptr = (int16_t *) file_frame;
 				if (has_file_data && file_sample_len) {
-					uint32_t sample_bytes = file_sample_len * 2;
-					memcpy(omember->mux_frame, file_frame, sample_bytes);
-					if (sample_bytes < bytes) {
-						if (conference->comfort_noise_level) {
-							switch_generate_sln_silence((int16_t *) omember->mux_frame + sample_bytes,
-														(bytes - sample_bytes) / 2, conference->comfort_noise_level);
+					for (x = 0; x < bytes / 2; x++) {
+						if (x <= file_sample_len) {
+							main_frame[x] = (int32_t) bptr[x];
 						} else {
-							memset(omember->mux_frame + sample_bytes, 255, bytes - sample_bytes);
+							main_frame[x] = 255;
 						}
 					}
-				} else {
-					if (conference->comfort_noise_level) {
-						switch_generate_sln_silence((int16_t *) omember->mux_frame, bytes / 2, conference->comfort_noise_level);
-					} else {
-						memset(omember->mux_frame, 255, bytes);
+				}
+
+				/* Copy audio from every member known to be producing audio into the main frame. */
+				for (omember = conference->members; omember; omember = omember->next) {
+					if (!(switch_test_flag(omember, MFLAG_RUNNING) && switch_test_flag(omember, MFLAG_HAS_AUDIO))) {
+						continue;
 					}
+					bptr = (int16_t *) omember->frame;
+					for (x = 0; x < omember->read / 2; x++) {
+						main_frame[x] += (int32_t) bptr[x];
+					}
 				}
-				for (imember = conference->members; imember; imember = imember->next) {
-					uint32_t x;
-					int16_t *bptr, *muxed;
 
-					if (imember == omember || !imember->read) {
-						/* Don't add audio from yourself or if you didn't read any */
+				/* Create write frame once per member who is not deaf for each sample in the main frame
+				   check if our audio is involved and if so, subtract it from the sample so we don't hear ourselves.
+				   Since main frame was 32 bit int, we did not lose any detail, now that we have to convert to 16 bit we can
+				   cut it off at the min and max range if need be and write the frame to the output buffer.
+				*/
+				for (omember = conference->members; omember; omember = omember->next) {
+					switch_size_t ok = 1;
+
+					if (!switch_test_flag(omember, MFLAG_RUNNING)) {
 						continue;
 					}
 
-					/* If they are not supposed to talk to us then don't let them */
-					if (omember->relationships) {
-						conference_relationship_t *rel;
+					if (!switch_test_flag(omember, MFLAG_CAN_HEAR) && !switch_test_flag(omember, MFLAG_WASTE_BANDWIDTH) 
+						&& !switch_test_flag(conference, CFLAG_WASTE_BANDWIDTH)) {
+						continue;
+					}
 
-						if ((rel = member_get_relationship(omember, imember))) {
-							if (!switch_test_flag(rel, RFLAG_CAN_HEAR)) {
-								continue;
+					bptr = (int16_t *) omember->frame;
+					for (x = 0; x < bytes / 2; x++) {
+						z = main_frame[x];
+						/* bptr[x] represents my own contribution to this audio sample */
+						if (switch_test_flag(omember, MFLAG_HAS_AUDIO) && x <= omember->read / 2) {
+							z -= (int32_t) bptr[x];
+						}
+						/* Now we can convert to 16 bit.*/
+						switch_normalize_to_16bit(z);
+						write_frame[x] = (int16_t) z;
+					}
+				
+					switch_mutex_lock(omember->audio_out_mutex);
+					ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes);
+					switch_mutex_unlock(omember->audio_out_mutex);
+				
+					if (!ok) {
+						goto end;
+					}
+				}
+
+			}
+		} else {
+			if (ready || has_file_data) {
+				/* Build a muxed frame for every member that contains the mixed audio of everyone else */
+
+				for (omember = conference->members; omember; omember = omember->next) {
+					if (has_file_data && file_sample_len) {
+						uint32_t sample_bytes = file_sample_len * 2;
+						memcpy(omember->mux_frame, file_frame, sample_bytes);
+						if (sample_bytes < bytes) {
+							if (conference->comfort_noise_level) {
+								switch_generate_sln_silence((int16_t *) omember->mux_frame + sample_bytes,
+															(bytes - sample_bytes) / 2, conference->comfort_noise_level);
+							} else {
+								memset(omember->mux_frame + sample_bytes, 255, bytes - sample_bytes);
 							}
 						}
+					} else {
+						if (conference->comfort_noise_level) {
+							switch_generate_sln_silence((int16_t *) omember->mux_frame, bytes / 2, conference->comfort_noise_level);
+						} else {
+							memset(omember->mux_frame, 255, bytes);
+						}
 					}
+					for (imember = conference->members; imember; imember = imember->next) {
+						uint32_t x;
+						int16_t *muxed;
 
-					/* If we are not supposed to hear them then don't let it happen */
-					if (imember->relationships) {
-						conference_relationship_t *rel;
+						if (imember == omember || !imember->read) {
+							/* Don't add audio from yourself or if you didn't read any */
+							continue;
+						}
 
-						if ((rel = member_get_relationship(imember, omember))) {
-							if (!switch_test_flag(rel, RFLAG_CAN_SPEAK)) {
-								continue;
+						/* If they are not supposed to talk to us then don't let them */
+						if (omember->relationships) {
+							conference_relationship_t *rel;
+
+							if ((rel = member_get_relationship(omember, imember))) {
+								if (!switch_test_flag(rel, RFLAG_CAN_HEAR)) {
+									continue;
+								}
 							}
 						}
-					}
+
+						/* If we are not supposed to hear them then don't let it happen */
+						if (imember->relationships) {
+							conference_relationship_t *rel;
+
+							if ((rel = member_get_relationship(imember, omember))) {
+								if (!switch_test_flag(rel, RFLAG_CAN_SPEAK)) {
+									continue;
+								}
+							}
+						}
 #if 0
-					if (nt && conference->not_talking_buf_len && !switch_test_flag(omember, MFLAG_HAS_AUDIO)) {
-						memcpy(omember->mux_frame, conference->not_talking_buf, conference->not_talking_buf_len);
-						continue;
-					}
+						if (nt && conference->not_talking_buf_len && !switch_test_flag(omember, MFLAG_HAS_AUDIO)) {
+							memcpy(omember->mux_frame, conference->not_talking_buf, conference->not_talking_buf_len);
+							continue;
+						}
 #endif
-					bptr = (int16_t *) imember->frame;
-					muxed = (int16_t *) omember->mux_frame;
+						bptr = (int16_t *) imember->frame;
+						muxed = (int16_t *) omember->mux_frame;
 
-					for (x = 0; x < imember->read / 2; x++) {
-						int32_t z = muxed[x] + bptr[x];
-						switch_normalize_to_16bit(z);
-						muxed[x] = (int16_t) z;
-					}
+						for (x = 0; x < imember->read / 2; x++) {
+							int32_t z = muxed[x] + bptr[x];
+							switch_normalize_to_16bit(z);
+							muxed[x] = (int16_t) z;
+						}
 #if 0
-					if (total - ready > 1) {
-						conference->not_talking_buf_len = imember->read;
-						if (!conference->not_talking_buf) {
-							conference->not_talking_buf = switch_core_alloc(conference->pool, imember->read + 128);
+						if (total - ready > 1) {
+							conference->not_talking_buf_len = imember->read;
+							if (!conference->not_talking_buf) {
+								conference->not_talking_buf = switch_core_alloc(conference->pool, imember->read + 128);
+							}
+							memcpy(conference->not_talking_buf, muxed, conference->not_talking_buf_len);
+							nt++;
 						}
-						memcpy(conference->not_talking_buf, muxed, conference->not_talking_buf_len);
-						nt++;
+#endif
 					}
-#endif
 				}
-			}
-			if (bytes) {
-				/* Go back and write each member his dedicated copy of the audio frame that does not contain his own audio. */
-				for (imember = conference->members; imember; imember = imember->next) {
-					if (switch_test_flag(imember, MFLAG_RUNNING)) {
-						switch_size_t ok = 1;
-						switch_mutex_lock(imember->audio_out_mutex);
-						ok = switch_buffer_write(imember->mux_buffer, imember->mux_frame, bytes);
-						switch_mutex_unlock(imember->audio_out_mutex);
-						if (!ok) {
-							goto end;
+				if (bytes) {
+					/* Go back and write each member his dedicated copy of the audio frame that does not contain his own audio. */
+					for (imember = conference->members; imember; imember = imember->next) {
+						if (switch_test_flag(imember, MFLAG_RUNNING)) {
+							switch_size_t ok = 1;
+							switch_mutex_lock(imember->audio_out_mutex);
+							ok = switch_buffer_write(imember->mux_buffer, imember->mux_frame, bytes);
+							switch_mutex_unlock(imember->audio_out_mutex);
+							if (!ok) {
+								goto end;
+							}
 						}
 					}
 				}
 			}
 		}
+
 		if (conference->async_fnode && conference->async_fnode->done) {
 			switch_memory_pool_t *pool;
 			switch_core_file_close(&conference->async_fnode->fh);
@@ -2367,7 +2465,7 @@
 				}
 
 				switch_mutex_unlock(member->audio_out_mutex);
-			} else {
+			} else if (!switch_test_flag(member->conference, CFLAG_WASTE_BANDWIDTH)) {
 				if (switch_test_flag(member, MFLAG_WASTE_BANDWIDTH)) {
 					if (member->conference->comfort_noise_level) {
 						switch_generate_sln_silence(write_frame.data, samples, member->conference->comfort_noise_level);
@@ -4800,6 +4898,8 @@
 				*f |= CFLAG_WAIT_MOD;
 			} else if (!strcasecmp(argv[i], "video-floor-only")) {
 				*f |= CFLAG_VID_FLOOR;
+			} else if (!strcasecmp(argv[i], "waste-bandwidth")) {
+				*f |= CFLAG_WASTE_BANDWIDTH;
 			}
 		}