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 {
uint32_t eflags;
uint32_t verbose_events;
int end_count;
+ uint32_t relationship_total;
} conference_obj_t;
/* Relationship with another member */
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);
} 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;
}
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);
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;
}
}
- 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;
+
+ 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 };
+
- for (omember = conference->members; omember; omember = omember->next) {
+ /* 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;
+ }
+
+ 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;
+ }
+ }
- if ((rel = member_get_relationship(omember, imember))) {
- if (!switch_test_flag(rel, RFLAG_CAN_HEAR)) {
- continue;
+ }
+ } 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 we are not supposed to hear them then don't let it happen */
- if (imember->relationships) {
- conference_relationship_t *rel;
+ /* 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(imember, omember))) {
- if (!switch_test_flag(rel, RFLAG_CAN_SPEAK)) {
- continue;
+ 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
+ }
}
- }
- 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);
}
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);
*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;
}
}