int set_talk_volume(struct ast_conf_member *member, struct ast_frame *f, int is_talk)
{
    int ret=0;
    signed char gain_adjust;
    int volume = member->talk_volume;

    gain_adjust = gain_map[volume + 5];

    if (is_talk) {
	/* 
    	 *   attempt to make the adjustment in the channel driver first
	 */
	if ( !member->talk_volume_adjust) {
	    ret=ast_channel_setoption(member->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
	    if (ret)
		member->talk_volume_adjust=1;
	}
	if (member->talk_volume_adjust && f) {
	    ret=ast_frame_adjust_volume(f, gain_adjust);
        }
    }
    else
    {
	// Listen volume
	ret=ast_frame_adjust_volume(f, gain_adjust);
    }
    return ret;
}
Esempio n. 2
0
static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
{
	struct ast_datastore *datastore = NULL;
	struct volume_information *vi = NULL;
	int *gain = NULL;

	/* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
		return 0;

	/* Grab datastore which contains our gain information */
	if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
		return 0;

	vi = datastore->data;

	/* If this is DTMF then allow them to increase/decrease the gains */
	if (ast_test_flag(vi, VOLUMEFLAG_CHANGE)) {
		if (frame->frametype == AST_FRAME_DTMF) {
			/* Only use DTMF coming from the source... not going to it */
			if (direction != AST_AUDIOHOOK_DIRECTION_READ)
				return 0; 
			if (frame->subclass.integer == '*') {
				vi->tx_gain += 1;
				vi->rx_gain += 1;
			} else if (frame->subclass.integer == '#') {
				vi->tx_gain -= 1;
				vi->rx_gain -= 1;
			}
		}
	}

	
	if (frame->frametype == AST_FRAME_VOICE) {
		/* Based on direction of frame grab the gain, and confirm it is applicable */
		if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
			return 0;
		/* Apply gain to frame... easy as pi */
		ast_frame_adjust_volume(frame, *gain);
	}

	return 0;
}
Esempio n. 3
0
conf_frame* mix_single_speaker( conf_frame* frames_in, int volume )
{
#ifdef APP_KONFERENCE_DEBUG
    //DEBUG("returning single spoken frame\n") ;

    //
    // check input
    //

    if ( frames_in == NULL )
    {
        DEBUG("unable to mix single spoken frame with null frame\n") ;
        return NULL ;
    }

    if ( frames_in->fr == NULL )
    {
        DEBUG("unable to mix single spoken frame with null data\n") ;
        return NULL ;
    }

    if ( frames_in->member == NULL )
    {
        DEBUG("unable to mix single spoken frame with null member\n") ;
        return NULL ;
    }
#endif // APP_KONFERENCE_DEBUG

    //
    // 'mix' the frame
    //

    // copy orignal frame to converted array so listeners don't need to re-encode it
    frames_in->converted[ frames_in->member->read_format_index ] = ast_frdup( frames_in->fr ) ;

    // convert frame to slinear, if we have a path
    if (!(frames_in->fr = convert_frame_to_slinear( frames_in->member->to_slinear, frames_in->fr)))
    {
        ast_log( LOG_WARNING, "mix_single_speaker: unable to convert frame to slinear\n" ) ;
        return frames_in ;
    }

    if ( (frames_in->member->talk_volume != 0) || (volume != 0) )
    {
        ast_frame_adjust_volume(frames_in->fr, frames_in->member->talk_volume + volume);
    }

    if (!frames_in->member->spy_partner)
    {
        // speaker is neither a spyee nor a spyer
        // set the frame's member to null ( i.e. all listeners )
        frames_in->member = NULL ;
    }
    else
    {
        // speaker is either a spyee or a spyer
        if ( frames_in->member->spyee_channel_name == NULL )
        {
            conf_frame *spy_frame = copy_conf_frame(frames_in);

            if ( spy_frame != 0 )
            {
                frames_in->next = spy_frame;
                spy_frame->prev = frames_in;

                spy_frame->member = frames_in->member->spy_partner;
            }

            frames_in->member = NULL ;
        }
        else
            frames_in->member = frames_in->member->spy_partner ;
    }

    return frames_in ;
}
Esempio n. 4
0
conf_frame* mix_multiple_speakers(
    conf_frame* frames_in,
    int speakers,
    int listeners,
    int volume
)
{
#ifdef APP_KONFERENCE_DEBUG
    //
    // check input
    //

    // no frames to mix
    if ( ( frames_in == NULL ) || ( frames_in->fr == NULL ) )
    {
        DEBUG("passed spoken frame list was NULL\n") ;
        return NULL ;
    }

    // if less than two speakers, then no frames to mix
    if ( speakers < 2 )
    {
        DEBUG("mix_multiple_speakers() called with less than two speakers\n") ;
        return NULL ;
    }
#endif // APP_KONFERENCE_DEBUG

    //
    // at this point we know that there is more than one frame,
    // and that the frames need to be converted to pcm to be mixed
    //
    // now, if there are only two frames and two members,
    // we can swap them. ( but we'll get to that later. )
    //

    //
    // loop through the spoken frames, making a list of spoken members,
    // and converting gsm frames to slinear frames so we can mix them.
    //

    // pointer to the spoken frames list
    conf_frame* cf_spoken = frames_in ;

    // pointer to the new list of mixed frames
    conf_frame* cf_sendFrames = NULL ;

    while ( cf_spoken != NULL )
    {
        //
        // while we're looping through the spoken frames, we'll
        // convert the frame to a format suitable for mixing
        //
        // if the frame fails to convert, drop it and treat
        // the speaking member like a listener by not adding
        // them to the cf_sendFrames list
        //

        if ( cf_spoken->member == NULL )
        {
            ast_log( LOG_WARNING, "unable to determine frame member\n" ) ;
        }
        else
        {
            //DEBUG("converting frame to slinear, channel => %s\n", cf_spoken->member->channel_name) ;
            if ( !(cf_spoken->fr = convert_frame_to_slinear( cf_spoken->member->to_slinear, cf_spoken->fr)) )
            {
                ast_log( LOG_WARNING, "mix_multiple_speakers: unable to convert frame to slinear\n" ) ;
                continue;
            }

            if (( cf_spoken->member->talk_volume != 0 ) || (volume != 0))
            {
                ast_frame_adjust_volume(cf_spoken->fr, cf_spoken->member->talk_volume + volume);
            }

            if ( cf_spoken->member->spyee_channel_name == NULL )
            {
                // create new conf frame with last frame as 'next'
                cf_sendFrames = create_conf_frame( cf_spoken->member, cf_sendFrames, NULL ) ;
            }
            else if ( cf_spoken->member->spy_partner->local_speaking_state == 0 )
            {
                cf_sendFrames = create_conf_frame( cf_spoken->member->spy_partner, cf_sendFrames, NULL ) ;
            }
        }

        // point to the next spoken frame
        cf_spoken = cf_spoken->next ;
    }

    // if necessary, add a frame with a null member pointer.
    // this frame will hold the audio mixed for all listeners
    if ( listeners > 0 )
    {
        cf_sendFrames = create_conf_frame( NULL, cf_sendFrames, NULL ) ;
    }

    //
    // mix the audio
    //

    // convenience pointer that skips over the friendly offset
    char* cp_listenerData ;

    // pointer to the send frames list
    conf_frame* cf_send = NULL ;

    for ( cf_send = cf_sendFrames ; cf_send != NULL ; cf_send = cf_send->next )
    {
        // allocate a mix buffer which fill large enough memory to
        // hold a frame, and reset it's memory so we don't get noise
        char* cp_listenerBuffer = malloc( AST_CONF_BUFFER_SIZE ) ;
        memset( cp_listenerBuffer, 0x0, AST_CONF_BUFFER_SIZE ) ;

        // point past the friendly offset right to the data
        cp_listenerData = cp_listenerBuffer + AST_FRIENDLY_OFFSET ;

        // reset the spoken list pointer
        cf_spoken = frames_in ;

        // really mix the audio
        for ( ; cf_spoken != NULL ; cf_spoken = cf_spoken->next )
        {
            //
            // if the members are equal, and they
            // are not null, do not mix them.
            //
            if (
                ( cf_spoken->member == cf_send->member )
                || ( cf_spoken->member->spyee_channel_name != NULL
                     && cf_spoken->member->spy_partner != cf_send->member)
            )
            {
                // don't mix this frame
            }
            else if ( cf_spoken->fr == NULL )
            {
                ast_log( LOG_WARNING, "unable to mix conf_frame with null ast_frame\n" ) ;
            }
            else
            {
                // mix the new frame in with the existing buffer
                mix_slinear_frames( cp_listenerData, CASTDATA2PTR(cf_spoken->fr->data, char), AST_CONF_BLOCK_SAMPLES);//XXX NAS cf_spoken->fr->samples ) ;
            }
        }

        // copy a pointer to the frame data to the conf_frame
        cf_send->mixed_buffer = cp_listenerData ;
    }

    //
    // copy the mixed buffer to a new frame
    //

    // reset the send list pointer
    cf_send = cf_sendFrames ;

    while ( cf_send != NULL )
    {
        cf_send->fr = create_slinear_frame( cf_send->mixed_buffer ) ;
        cf_send = cf_send->next ;
    }

    //
    // clean up the spoken frames we were passed
    // ( caller will only be responsible for free'ing returns frames )
    //

    // reset the spoken list pointer
    cf_spoken = frames_in ;

    while ( cf_spoken != NULL )
    {
        struct ast_conf_member *spy_partner = cf_spoken->member->spy_partner ;

        if ( spy_partner == NULL || cf_spoken->member->spyee_channel_name != NULL )
        {
            // delete the frame
            cf_spoken = delete_conf_frame( cf_spoken ) ;
        }
        else
        {
            // move the unmixed frame to sendFrames
            //  and indicate who it's for
            conf_frame *spy_frame = cf_spoken ;

            cf_spoken = cf_spoken->next;
            if ( cf_spoken != NULL )
                cf_spoken->prev = NULL;

            spy_frame->next = cf_sendFrames;
            cf_sendFrames->prev = spy_frame;
            spy_frame->prev = NULL;

            spy_frame->member = spy_partner;

            cf_sendFrames = spy_frame;
        }
    }

    // return the list of frames for sending
    return cf_sendFrames ;
}