move slinfactory structure definition back to header... it's just easier to use this way
authorKevin P. Fleming <kpfleming@digium.com>
Fri, 28 Jul 2006 18:59:59 +0000 (18:59 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Fri, 28 Jul 2006 18:59:59 +0000 (18:59 +0000)
add infrastructure for whispering onto a channel

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

channel.c
frame.c
include/asterisk/channel.h
include/asterisk/frame.h
include/asterisk/slinfactory.h
slinfactory.c

index 82eac1d..d8b3e83 100644 (file)
--- a/channel.c
+++ b/channel.c
@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/transcap.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/sha1.h"
+#include "asterisk/slinfactory.h"
 
 struct channel_spy_trans {
        int last_format;
@@ -78,6 +79,12 @@ struct ast_channel_spy_list {
        AST_LIST_HEAD_NOLOCK(, ast_channel_spy) list;
 };
 
+struct ast_channel_whisper_buffer {
+       ast_mutex_t lock;
+       struct ast_slinfactory sf;
+       unsigned int original_format;
+};
+
 /* uncomment if you have problems with 'monitoring' synchronized files */
 #if 0
 #define MONITOR_CONSTANT_DELAY
@@ -987,14 +994,17 @@ void ast_channel_free(struct ast_channel *chan)
        ast_copy_string(name, chan->name, sizeof(name));
 
        /* Stop monitoring */
-       if (chan->monitor) {
+       if (chan->monitor)
                chan->monitor->stop( chan, 0 );
-       }
 
        /* If there is native format music-on-hold state, free it */
-       if(chan->music_state)
+       if (chan->music_state)
                ast_moh_cleanup(chan);
 
+       /* if someone is whispering on the channel, stop them */
+       if (chan->whisper)
+               ast_channel_whisper_stop(chan);
+
        /* Free translators */
        if (chan->readtrans)
                ast_translator_free_path(chan->readtrans);
@@ -2445,6 +2455,25 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                                }
                        }
 
+                       if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
+                               /* frame is assumed to be in SLINEAR, since that is
+                                  required for whisper mode */
+                               ast_frame_adjust_volume(f, -2);
+                               if (ast_slinfactory_available(&chan->whisper->sf) >= f->samples) {
+                                       short buf[f->samples];
+                                       struct ast_frame whisper = {
+                                               .frametype = AST_FRAME_VOICE,
+                                               .subclass = AST_FORMAT_SLINEAR,
+                                               .data = buf,
+                                               .datalen = sizeof(buf),
+                                               .samples = f->samples,
+                                       };
+
+                                       if (ast_slinfactory_read(&chan->whisper->sf, buf, f->samples))
+                                               ast_frame_slinear_sum(f, &whisper);
+                               }
+                       }
+
                        res = chan->tech->write(chan, f);
                }
                break;  
@@ -3171,6 +3200,16 @@ int ast_do_masquerade(struct ast_channel *original)
                if (x != AST_GENERATOR_FD)
                        original->fds[x] = clone->fds[x];
        }
+
+       /* move any whisperer over */
+       ast_channel_whisper_stop(original);
+       if (ast_test_flag(clone, AST_FLAG_WHISPER)) {
+               original->whisper = clone->whisper;
+               ast_set_flag(original, AST_FLAG_WHISPER);
+               clone->whisper = NULL;
+               ast_clear_flag(clone, AST_FLAG_WHISPER);
+       }
+
        /* Move data stores over */
        if (AST_LIST_FIRST(&clone->datastores))
                 AST_LIST_INSERT_TAIL(&original->datastores, AST_LIST_FIRST(&clone->datastores), entry);
@@ -4401,4 +4440,43 @@ int ast_say_digits_full(struct ast_channel *chan, int num,
         return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd);
 }
 
-/* end of file */
+int ast_channel_whisper_start(struct ast_channel *chan)
+{
+       if (chan->whisper)
+               return -1;
+
+       if (!(chan->whisper = ast_calloc(1, sizeof(*chan->whisper))))
+               return -1;
+
+       ast_mutex_init(&chan->whisper->lock);
+       ast_slinfactory_init(&chan->whisper->sf);
+       chan->whisper->original_format = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
+       ast_set_flag(chan, AST_FLAG_WHISPER);
+
+       return 0;
+}
+
+int ast_channel_whisper_feed(struct ast_channel *chan, struct ast_frame *f)
+{
+       if (!chan->whisper)
+               return -1;
+
+       ast_mutex_lock(&chan->whisper->lock);
+       ast_slinfactory_feed(&chan->whisper->sf, f);
+       ast_mutex_unlock(&chan->whisper->lock);
+
+       return 0;
+}
+
+void ast_channel_whisper_stop(struct ast_channel *chan)
+{
+       if (!chan->whisper)
+               return;
+
+       ast_clear_flag(chan, AST_FLAG_WHISPER);
+       ast_set_write_format(chan, chan->whisper->original_format);
+       ast_slinfactory_destroy(&chan->whisper->sf);
+       ast_mutex_destroy(&chan->whisper->lock);
+       free(chan->whisper);
+       chan->whisper = NULL;
+}
diff --git a/frame.c b/frame.c
index 62d69ed..ac1c72e 100644 (file)
--- a/frame.c
+++ b/frame.c
@@ -359,7 +359,7 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
        return out;
 }
 
-struct ast_frame *ast_frdup(struct ast_frame *f)
+struct ast_frame *ast_frdup(const struct ast_frame *f)
 {
        struct ast_frame *out;
        int len, srclen = 0;
index 06a8952..fe2b33e 100644 (file)
@@ -268,6 +268,7 @@ struct ast_channel_tech {
 };
 
 struct ast_channel_spy_list;
+struct ast_channel_whisper_buffer;
 
 #define        DEBUGCHAN_FLAG  0x80000000
 #define        FRAMECOUNT_INC(x)       ( ((x) & DEBUGCHAN_FLAG) | ((x++) & ~DEBUGCHAN_FLAG) )
@@ -382,6 +383,7 @@ struct ast_channel {
        int rawwriteformat;                             /*!< Raw write format */
 
        struct ast_channel_spy_list *spies;             /*!< Chan Spy stuff */
+       struct ast_channel_whisper_buffer *whisper;     /*!< Whisper Paging buffer */
        AST_LIST_ENTRY(ast_channel) chan_list;          /*!< For easy linking */
        struct ast_jb jb;                               /*!< The jitterbuffer state  */
 
@@ -397,21 +399,20 @@ struct ast_channel {
 /*! \brief Channels have this property if they can create jitter; i.e. most VoIP channels */
 #define AST_CHAN_TP_CREATESJITTER (1 << 1)
 
-/* This flag has been deprecated by the transfercapbilty data member in struct ast_channel */
-/* #define AST_FLAG_DIGITAL    (1 << 0) */     /* if the call is a digital ISDN call */
 #define AST_FLAG_DEFER_DTMF    (1 << 1)        /*!< if dtmf should be deferred */
 #define AST_FLAG_WRITE_INT     (1 << 2)        /*!< if write should be interrupt generator */
 #define AST_FLAG_BLOCKING      (1 << 3)        /*!< if we are blocking */
 #define AST_FLAG_ZOMBIE                (1 << 4)        /*!< if we are a zombie */
 #define AST_FLAG_EXCEPTION     (1 << 5)        /*!< if there is a pending exception */
 #define AST_FLAG_MOH           (1 << 6)        /*!< XXX anthm promises me this will disappear XXX listening to moh */
-#define AST_FLAG_SPYING                (1 << 7)        /*!< XXX might also go away XXX is spying on someone */
+#define AST_FLAG_SPYING                (1 << 7)        /*!< is spying on someone */
 #define AST_FLAG_NBRIDGE       (1 << 8)        /*!< is it in a native bridge */
 #define AST_FLAG_IN_AUTOLOOP   (1 << 9)        /*!< the channel is in an auto-incrementing dialplan processor,
                                                   so when ->priority is set, it will get incremented before
-                                                  finding the next priority to run
-                                               */
-#define AST_FLAG_OUTGOING (1 << 10) /*! Is this call outgoing */
+                                                  finding the next priority to run */
+#define AST_FLAG_OUTGOING      (1 << 10)       /*!< Is this call outgoing */
+#define AST_FLAG_WHISPER       (1 << 11)       /*!< Is this channel being whispered on */
+
 /* @} */
 
 #define AST_FEATURE_PLAY_WARNING       (1 << 0)
@@ -1277,6 +1278,38 @@ const char *channelreloadreason2txt(enum channelreloadreason reason);
 /*! \brief return an ast_variable list of channeltypes */
 struct ast_variable *ast_channeltype_list(void);
 
+/*!
+  \brief Begin 'whispering' onto a channel
+  \param chan The channel to whisper onto
+  \return 0 for success, non-zero for failure
+
+  This function will add a whisper buffer onto a channel and set a flag
+  causing writes to the channel to reduce the volume level of the written
+  audio samples, and then to mix in audio from the whisper buffer if it
+  is available.
+
+  Note: This function performs no locking; you must hold the channel's lock before
+  calling this function.
+ */
+int ast_channel_whisper_start(struct ast_channel *chan);
+
+/*!
+  \brief Feed an audio frame into the whisper buffer on a channel
+  \param chan The channel to whisper onto
+  \return 0 for success, non-zero for failure
+ */
+int ast_channel_whisper_feed(struct ast_channel *chan, struct ast_frame *f);
+
+/*!
+  \brief Stop 'whispering' onto a channel
+  \param chan The channel to whisper onto
+  \return 0 for success, non-zero for failure
+
+  Note: This function performs no locking; you must hold the channel's lock before
+  calling this function.
+ */
+void ast_channel_whisper_stop(struct ast_channel *chan);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
index ab9cb1b..35cd30a 100644 (file)
@@ -354,7 +354,7 @@ struct ast_frame *ast_fralloc(char *source, int len);
  */
 void ast_frfree(struct ast_frame *fr);
 
-/*! \brief Copies a frame 
+/*! \brief Makes a frame independent of any static storage
  * \param fr frame to act upon
  * Take a frame, and if it's not been malloc'd, make a malloc'd copy
  * and if the data hasn't been malloced then make the
@@ -366,10 +366,10 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr);
 
 /*! \brief Copies a frame 
  * \param fr frame to copy
- * Dupliates a frame -- should only rarely be used, typically frisolate is good enough
+ * Duplicates a frame -- should only rarely be used, typically frisolate is good enough
  * \return Returns a frame on success, NULL on error
  */
-struct ast_frame *ast_frdup(struct ast_frame *fr);
+struct ast_frame *ast_frdup(const struct ast_frame *fr);
 
 /*! \brief Reads a frame from an fd
  * Read a frame from a stream or packet fd, as written by fd_write
index be2e96e..4bdbfa7 100644 (file)
 extern "C" {
 #endif
 
-struct ast_slinfactory;
+struct ast_slinfactory {
+       struct ast_frame *queue;
+       struct ast_trans_pvt *trans;
+       short hold[1280];
+       short *offset;
+       size_t holdlen;                 /*!< in samples */
+       unsigned int size;              /*!< in samples */
+       unsigned int format;
+};
 
 void ast_slinfactory_init(struct ast_slinfactory *sf);
 void ast_slinfactory_destroy(struct ast_slinfactory *sf);
index 632187c..62a863d 100644 (file)
@@ -35,16 +35,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/logger.h"
 #include "asterisk/translate.h"
 
-struct ast_slinfactory {
-       struct ast_frame *queue;
-       struct ast_trans_pvt *trans;
-       short hold[1280];
-       short *offset;
-       size_t holdlen;                 /*! in samples */
-       unsigned int size;              /*! in samples */
-       unsigned int format;
-};
-
 void ast_slinfactory_init(struct ast_slinfactory *sf) 
 {
        memset(sf, 0, sizeof(*sf));