]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
nut 'n honey
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 31 Dec 2009 20:08:57 +0000 (20:08 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 31 Dec 2009 20:08:57 +0000 (20:08 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16110 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/mod/applications/mod_conference/mod_conference.c

index 6588ada658df9e7f75ed62e1391648211dc9e780..750404d1bd802391d7ad25e337f75481d62005ad 100644 (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;
+
+                       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);
@@ -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;
                        }
                }