diff --git a/channel.c b/channel.c index 82eac1db14493e2e3b8b00652d3632214f1db261..d8b3e83ecbcd8ce51c5972365e39d155d8513970 100644 --- 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 62d69eda1d60de55995045eea40cc7a49969303c..ac1c72e05ca3bcb64479864755c269039c6d462b 100644 --- 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; diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 06a895293c48f916a08c9d92bf959e56cd6efdf6..fe2b33ed90d24090c4977324c678bbd92246df95 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -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 diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index ab9cb1b8c14568d105fbc619acb6bec40fe361ca..35cd30ac6c903489e182000e567348ecbd2e6794 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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 diff --git a/include/asterisk/slinfactory.h b/include/asterisk/slinfactory.h index be2e96e58d9915b84b702fd96d546ffbdc3256de..4bdbfa7cdf5efa8a1337e0641b8d1f059319cdc1 100644 --- a/include/asterisk/slinfactory.h +++ b/include/asterisk/slinfactory.h @@ -31,7 +31,15 @@ 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); diff --git a/slinfactory.c b/slinfactory.c index 632187ccbd7f5bd9420939ab80971fa6120fcda1..62a863d87dd21f567cd60372a1741910680ec10e 100644 --- a/slinfactory.c +++ b/slinfactory.c @@ -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));