Skip to content
Snippets Groups Projects
channel.c 119 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    static void *silence_generator_alloc(struct ast_channel *chan, void *data)
    {
    	/* just store the data pointer in the channel structure */
    	return data;
    }
    
    static void silence_generator_release(struct ast_channel *chan, void *data)
    {
    	/* nothing to do */
    }
    
    
    static int silence_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
    
    	short buf[samples];
    	int x;
    	struct ast_frame frame = {
    		.frametype = AST_FRAME_VOICE,
    		.subclass = AST_FORMAT_SLINEAR,
    		.data = buf,
    		.samples = samples,
    		.datalen = sizeof(buf),
    	};
    
    	for (x = 0; x < samples; x++)
    		buf[x] = 0;
    
    	if (ast_write(chan, &frame))
    		return -1;
    
    
    	return 0;
    }
    
    static struct ast_generator silence_generator = {
    	.alloc = silence_generator_alloc,
    	.release = silence_generator_release,
    
    	.generate = silence_generator_generate,
    
    };
    
    struct ast_silence_generator {
    	int old_write_format;
    };
    
    struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan)
    {
    	struct ast_silence_generator *state;
    
    
    	if (!(state = ast_calloc(1, sizeof(*state)))) {
    
    		return NULL;
    	}
    
    	state->old_write_format = chan->writeformat;
    
    	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
    		ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n");
    		free(state);
    		return NULL;
    	}
    
    	ast_activate_generator(chan, &silence_generator, state);
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "Started silence generator on '%s'\n", chan->name);
    
    	return state;
    }
    
    void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
    {
    	if (!state)
    		return;
    
    	ast_deactivate_generator(chan);
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "Stopped silence generator on '%s'\n", chan->name);
    
    	if (ast_set_write_format(chan, state->old_write_format) < 0)
    		ast_log(LOG_ERROR, "Could not return write format to its original state\n");
    
    	free(state);
    }
    
    
    
    /*! \ brief Convert channel reloadreason (ENUM) to text string for manager event */
    
    const char *channelreloadreason2txt(enum channelreloadreason reason)
    {
    
    	case CHANNEL_MODULE_LOAD:
    		return "LOAD (Channel module load)";
    
    	case CHANNEL_MODULE_RELOAD:
    		return "RELOAD (Channel module reload)";
    
    	case CHANNEL_CLI_RELOAD:
    		return "CLIRELOAD (Channel module reload by CLI command)";
    
    	default:
    		return "MANAGERRELOAD (Channel module reload by manager)";
    
    
    #ifdef DEBUG_CHANNEL_LOCKS
    
    /*! \brief Unlock AST channel (and print debugging output) 
    \note You need to enable DEBUG_CHANNEL_LOCKS for this function
    */
    int ast_channel_unlock(struct ast_channel *chan)
    {
    	int res = 0;
    	if (option_debug > 2) 
    		ast_log(LOG_DEBUG, "::::==== Unlocking AST channel %s\n", chan->name);
    	
    	if (!chan) {
    		ast_log(LOG_DEBUG, "::::==== Unlocking non-existing channel \n");
    		return 0;
    	}
    
    	res = ast_mutex_unlock(&chan->lock);
    
    	if (option_debug > 2) {
    		/* Try to find counter if possible on your platform 
    			I've only found out how to do this on Linux
    			DEBUG_THREADS changes the lock structure
    		*/
    #ifdef __linux__
    		int count = 0;
    #ifdef DEBUG_THREADS
    		if ((count = chan->lock.mutex.__m_count))
    #else
    		if ((count = chan->lock.__m_count))
    #endif
    			ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
    #endif
    		if (!res)
    			ast_log(LOG_DEBUG, "::::==== Channel %s was unlocked\n", chan->name);
    			if (res == EINVAL) {
    				ast_log(LOG_DEBUG, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
    			}
    		}
    		if (res == EPERM) {
    			/* We had no lock, so okay any way*/
    			if (option_debug > 3)
    				ast_log(LOG_DEBUG, "::::==== Channel %s was not locked at all \n", chan->name);
    		res = 0;
    	}
    	return res;
    }
    
    /*! \brief Lock AST channel (and print debugging output)
    \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
    int ast_channel_lock(struct ast_channel *chan)
    {
    	int res;
    
    	if (option_debug > 3)
    		ast_log(LOG_DEBUG, "====:::: Locking AST channel %s\n", chan->name);
    
    	res = ast_mutex_lock(&chan->lock);
    
    	if (option_debug > 3) {
    #ifdef __linux__
    		int count = 0;
    #ifdef DEBUG_THREADS
    		if ((count = chan->lock.mutex.__m_count))
    #else
    		if ((count = chan->lock.__m_count))
    #endif
    			ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
    #endif
    		if (!res)
    			ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
    		if (res == EDEADLK) {
    		/* We had no lock, so okey any way */
    		if (option_debug > 3)
    			ast_log(LOG_DEBUG, "::::==== Channel %s was not locked by us. Lock would cause deadlock.\n", chan->name);
    		}
    		if (res == EINVAL) {
    			if (option_debug > 3)
    				ast_log(LOG_DEBUG, "::::==== Channel %s lock failed. No mutex.\n", chan->name);
    		}
    	}
    	return res;
    }
    
    /*! \brief Lock AST channel (and print debugging output)
    \note	You need to enable DEBUG_CHANNEL_LOCKS for this function */
    
    int ast_channel_trylock(struct ast_channel *chan)
    
    {
    	int res;
    
    	if (option_debug > 2)
    		ast_log(LOG_DEBUG, "====:::: Trying to lock AST channel %s\n", chan->name);
    
    	res = ast_mutex_trylock(&chan->lock);
    
    	if (option_debug > 2) {
    #ifdef __linux__
    		int count = 0;
    #ifdef DEBUG_THREADS
    		if ((count = chan->lock.mutex.__m_count))
    #else
    		if ((count = chan->lock.__m_count))
    #endif
    			ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
    #endif
    		if (!res)
    			ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
    		if (res == EBUSY) {
    			/* We failed to lock */
    			if (option_debug > 2)
    				ast_log(LOG_DEBUG, "::::==== Channel %s failed to lock. Not waiting around...\n", chan->name);
    		}
    		if (res == EDEADLK) {
    			/* We had no lock, so okey any way*/
    			if (option_debug > 2)
    				ast_log(LOG_DEBUG, "::::==== Channel %s was not locked. Lock would cause deadlock.\n", chan->name);
    		}
    		if (res == EINVAL && option_debug > 2)
    			ast_log(LOG_DEBUG, "::::==== Channel %s lock failed. No mutex.\n", chan->name);
    	}
    	return res;
    }
    
    #endif