nut 'n honey

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16110 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2009-12-31 20:08:57 +00:00
parent 49b8cfa16b
commit c70f4a2018
1 changed files with 189 additions and 89 deletions

View File

@ -175,7 +175,8 @@ typedef enum {
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 @@ typedef struct conference_obj {
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 @@ static conference_relationship_t *member_add_relationship(conference_member_t *m
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 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint
} 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 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
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 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
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 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
}
}
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 (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 *bptr, *muxed;
if (imember == omember || !imember->read) {
/* Don't add audio from yourself or if you didn't read any */
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;
}
#endif
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;
}
#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);
}
memcpy(conference->not_talking_buf, muxed, conference->not_talking_buf_len);
nt++;
}
#endif
}
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);
}
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;
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) {
for (x = 0; x < bytes / 2; x++) {
if (x <= file_sample_len) {
main_frame[x] = (int32_t) bptr[x];
} else {
main_frame[x] = 255;
}
}
}
/* 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];
}
}
/* 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 (!switch_test_flag(omember, MFLAG_CAN_HEAR) && !switch_test_flag(omember, MFLAG_WASTE_BANDWIDTH)
&& !switch_test_flag(conference, CFLAG_WASTE_BANDWIDTH)) {
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 (imember == omember || !imember->read) {
/* Don't add audio from yourself or if you didn't read any */
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;
}
#endif
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;
}
#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);
}
memcpy(conference->not_talking_buf, muxed, conference->not_talking_buf_len);
nt++;
}
#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 (conference->async_fnode && conference->async_fnode->done) {
switch_memory_pool_t *pool;
switch_core_file_close(&conference->async_fnode->fh);
@ -2367,7 +2465,7 @@ static void conference_loop_output(conference_member_t *member)
}
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 @@ static void set_cflags(const char *flags, uint32_t *f)
*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;
}
}