]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Add a trigger mode that triggers on both read and write. The actual function that...
authorJoshua Colp <jcolp@digium.com>
Wed, 12 Mar 2008 18:26:37 +0000 (18:26 +0000)
committerJoshua Colp <jcolp@digium.com>
Wed, 12 Mar 2008 18:26:37 +0000 (18:26 +0000)
(closes issue #11945)
Reported by: xheliox

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@108083 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_mixmonitor.c
include/asterisk/audiohook.h
main/audiohook.c

index 14057c0556740b9869e5f822286f0a6844a40cd0..3cf79b1fc2850cbf707423815ec80433083fcc22 100644 (file)
@@ -265,7 +265,7 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
                return;
        }
        
-       ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_WRITE);
+       ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
        
        if (readvol)
                mixmonitor->audiohook.options.read_volume = readvol;
index a7de27460fdfa2d3dbd5f64efe63245fee9cf018..cafc5ef14687925b4eeb3ebe7361b38ba92469ed 100644 (file)
@@ -53,6 +53,7 @@ enum ast_audiohook_flags {
        AST_AUDIOHOOK_TRIGGER_READ = (1 << 0),  /*!< Audiohook wants to be triggered when reading audio in */
        AST_AUDIOHOOK_TRIGGER_WRITE = (2 << 0), /*!< Audiohook wants to be triggered when writing audio out */
        AST_AUDIOHOOK_WANTS_DTMF = (1 << 1),    /*!< Audiohook also wants to receive DTMF frames */
+       AST_AUDIOHOOK_TRIGGER_SYNC = (1 << 2),  /*!< Audiohook wants to be triggered when both sides have combined audio available */
 };
 
 struct ast_audiohook;
@@ -82,6 +83,8 @@ struct ast_audiohook {
        unsigned int flags;                                    /*!< Flags on the audiohook */
        struct ast_slinfactory read_factory;                   /*!< Factory where frames read from the channel, or read from the whisper source will go through */
        struct ast_slinfactory write_factory;                  /*!< Factory where frames written to the channel will go through */
+       struct timeval read_time;                              /*!< Last time read factory was fed */
+       struct timeval write_time;                             /*!< Last time write factory was fed */
        int format;                                            /*!< Format translation path is setup as */
        struct ast_trans_pvt *trans_pvt;                       /*!< Translation path for reading frames */
        ast_audiohook_manipulate_callback manipulate_callback; /*!< Manipulation callback */
index 806ae0beafab7f33e07f56f54ada7e8210811cad..8fd1501c9bcc75c1cbc953a09060ecca4960d486 100644 (file)
@@ -128,22 +128,21 @@ int ast_audiohook_destroy(struct ast_audiohook *audiohook)
 int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
 {
        struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
+       struct timeval *time = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time);
 
        /* Write frame out to respective factory */
        ast_slinfactory_feed(factory, frame);
 
+       /* Update last fed time for the above factory */
+       *time = ast_tvnow();
+
        /* If we need to notify the respective handler of this audiohook, do so */
-       switch (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE)) {
-       case AST_AUDIOHOOK_TRIGGER_READ:
-               if (direction == AST_AUDIOHOOK_DIRECTION_READ)
-                       ast_cond_signal(&audiohook->trigger);
-               break;
-       case AST_AUDIOHOOK_TRIGGER_WRITE:
-               if (direction == AST_AUDIOHOOK_DIRECTION_WRITE)
-                       ast_cond_signal(&audiohook->trigger);
-               break;
-       default:
-               break;
+       if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
+               ast_cond_signal(&audiohook->trigger);
+       } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
+               ast_cond_signal(&audiohook->trigger);
+       } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
+               ast_cond_signal(&audiohook->trigger);
        }
 
        return 0;
@@ -179,7 +178,7 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio
 
 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
 {
-       int i = 0;
+       int i = 0, usable_read, usable_write;
        short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
        struct ast_frame frame = {
                .frametype = AST_FRAME_VOICE,
@@ -189,8 +188,33 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
                .samples = samples,
        };
 
+       /* Make sure both factories have the required samples */
+       usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
+       usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
+
+       if (!usable_read && !usable_write) {
+               /* If both factories are unusable bail out */
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
+               return NULL;
+       }
+
+       /* If we want to provide only a read factory make sure we aren't waiting for other audio */
+       if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
+               return NULL;
+       }
+
+       /* If we want to provide only a write factory make sure we aren't waiting for other audio */
+       if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
+               return NULL;
+       }
+
        /* Start with the read factory... if there are enough samples, read them in */
-       if (ast_slinfactory_available(&audiohook->read_factory) >= samples) {
+       if (usable_read && ast_slinfactory_available(&audiohook->read_factory) >= samples) {
                if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
                        read_buf = buf1;
                        /* Adjust read volume if need be */
@@ -209,7 +233,7 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
                ast_log(LOG_DEBUG, "Failed to get %zd samples from read factory %p\n", samples, &audiohook->read_factory);
 
        /* Move on to the write factory... if there are enough samples, read them in */
-       if (ast_slinfactory_available(&audiohook->write_factory) >= samples) {
+       if (usable_write && ast_slinfactory_available(&audiohook->write_factory) >= samples) {
                if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
                        write_buf = buf2;
                        /* Adjust write volume if need be */