mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-16 08:49:01 +00:00
nut 'n honey
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16110 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
49b8cfa16b
commit
c70f4a2018
@ -175,7 +175,8 @@ typedef enum {
|
|||||||
CFLAG_ANSWERED = (1 << 5),
|
CFLAG_ANSWERED = (1 << 5),
|
||||||
CFLAG_BRIDGE_TO = (1 << 6),
|
CFLAG_BRIDGE_TO = (1 << 6),
|
||||||
CFLAG_WAIT_MOD = (1 << 7),
|
CFLAG_WAIT_MOD = (1 << 7),
|
||||||
CFLAG_VID_FLOOR = (1 << 8)
|
CFLAG_VID_FLOOR = (1 << 8),
|
||||||
|
CFLAG_WASTE_BANDWIDTH = (1 << 9)
|
||||||
} conf_flag_t;
|
} conf_flag_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -297,6 +298,7 @@ typedef struct conference_obj {
|
|||||||
uint32_t eflags;
|
uint32_t eflags;
|
||||||
uint32_t verbose_events;
|
uint32_t verbose_events;
|
||||||
int end_count;
|
int end_count;
|
||||||
|
uint32_t relationship_total;
|
||||||
} conference_obj_t;
|
} conference_obj_t;
|
||||||
|
|
||||||
/* Relationship with another member */
|
/* Relationship with another member */
|
||||||
@ -571,7 +573,11 @@ static conference_relationship_t *member_add_relationship(conference_member_t *m
|
|||||||
|
|
||||||
rel->id = id;
|
rel->id = id;
|
||||||
|
|
||||||
|
|
||||||
lock_member(member);
|
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;
|
rel->next = member->relationships;
|
||||||
member->relationships = rel;
|
member->relationships = rel;
|
||||||
unlock_member(member);
|
unlock_member(member);
|
||||||
@ -599,6 +605,11 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint
|
|||||||
} else {
|
} else {
|
||||||
member->relationships = rel->next;
|
member->relationships = rel->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch_mutex_lock(member->conference->member_mutex);
|
||||||
|
member->conference->relationship_total--;
|
||||||
|
switch_mutex_unlock(member->conference->member_mutex);
|
||||||
|
|
||||||
}
|
}
|
||||||
last = rel;
|
last = rel;
|
||||||
}
|
}
|
||||||
@ -970,6 +981,9 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
|||||||
switch_event_t *event;
|
switch_event_t *event;
|
||||||
uint8_t *file_frame;
|
uint8_t *file_frame;
|
||||||
uint8_t *async_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);
|
file_frame = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
|
||||||
async_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++) {
|
for (x = 0; x < file_sample_len; x++) {
|
||||||
int32_t z;
|
int32_t z;
|
||||||
int16_t *bptr, *muxed;
|
int16_t *muxed;
|
||||||
|
|
||||||
muxed = (int16_t *) file_frame;
|
muxed = (int16_t *) file_frame;
|
||||||
bptr = (int16_t *) async_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) {
|
if (switch_test_flag(conference, CFLAG_WASTE_BANDWIDTH) && !has_file_data) {
|
||||||
/* Build a muxed frame for every member that contains the mixed audio of everyone else */
|
file_sample_len = bytes / 2;
|
||||||
|
|
||||||
for (omember = conference->members; omember; omember = omember->next) {
|
if (conference->comfort_noise_level) {
|
||||||
if (has_file_data && file_sample_len) {
|
switch_generate_sln_silence((int16_t *) file_frame, file_sample_len, conference->comfort_noise_level);
|
||||||
uint32_t sample_bytes = file_sample_len * 2;
|
} else {
|
||||||
memcpy(omember->mux_frame, file_frame, sample_bytes);
|
memset(file_frame, 255, 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 (bytes) {
|
has_file_data = 1;
|
||||||
/* 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)) {
|
if (!conference->relationship_total) {
|
||||||
switch_size_t ok = 1;
|
/* If there are no relationships meaning (user x can specificly not speal to and/or hear user y), use a more efficient muxing technique. */
|
||||||
switch_mutex_lock(imember->audio_out_mutex);
|
if (ready || has_file_data) {
|
||||||
ok = switch_buffer_write(imember->mux_buffer, imember->mux_frame, bytes);
|
/* Use more bits in the main_frame to preserve the exact sum of the audio samples. */
|
||||||
switch_mutex_unlock(imember->audio_out_mutex);
|
int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
|
||||||
if (!ok) {
|
int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
|
||||||
goto end;
|
|
||||||
|
|
||||||
|
/* 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) {
|
if (conference->async_fnode && conference->async_fnode->done) {
|
||||||
switch_memory_pool_t *pool;
|
switch_memory_pool_t *pool;
|
||||||
switch_core_file_close(&conference->async_fnode->fh);
|
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);
|
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 (switch_test_flag(member, MFLAG_WASTE_BANDWIDTH)) {
|
||||||
if (member->conference->comfort_noise_level) {
|
if (member->conference->comfort_noise_level) {
|
||||||
switch_generate_sln_silence(write_frame.data, samples, 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;
|
*f |= CFLAG_WAIT_MOD;
|
||||||
} else if (!strcasecmp(argv[i], "video-floor-only")) {
|
} else if (!strcasecmp(argv[i], "video-floor-only")) {
|
||||||
*f |= CFLAG_VID_FLOOR;
|
*f |= CFLAG_VID_FLOOR;
|
||||||
|
} else if (!strcasecmp(argv[i], "waste-bandwidth")) {
|
||||||
|
*f |= CFLAG_WASTE_BANDWIDTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user