Author: mmichelson Date: Wed Jun 26 14:02:39 2013 New Revision: 392971 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392971 Log: Add pull method for atxfer bridges.
This way, we can detect if the transfer target or the transferee has hung up. With this in place, I tested the following scenarios: 1) Transfer target hangs up while ringing 2) Transfer target hangs up during consultation 3) Transferee hangs up during target ringing I have not tested what happens when a transferee hangs up during consultation because I'm not 100% sure how I'm going to handle it. Modified: team/mmichelson/atxfer_features/main/bridging_basic.c Modified: team/mmichelson/atxfer_features/main/bridging_basic.c URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/atxfer_features/main/bridging_basic.c?view=diff&rev=392971&r1=392970&r2=392971 ============================================================================== --- team/mmichelson/atxfer_features/main/bridging_basic.c (original) +++ team/mmichelson/atxfer_features/main/bridging_basic.c Wed Jun 26 14:02:39 2013 @@ -164,6 +164,19 @@ } return ast_bridge_base_v_table.push(self, bridge_channel, swap); +} + +static void bridge_basic_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel) +{ + struct bridge_basic_personality *personality = self->personality; + + ast_assert(personality != NULL); + + if (personality->v_table->pull) { + personality->v_table->pull(self, bridge_channel); + } + + ast_bridge_base_v_table.pull(self, bridge_channel); } static void bridge_basic_destroy(struct ast_bridge *self) @@ -638,6 +651,10 @@ case STIMULUS_TRANSFERER_ANSWER: ast_assert(0); case STIMULUS_TRANSFEREE_HANGUP: + /* We soft hangup the transferer to prevent him from sitting in + * a bridge by himself after the transfer fails + */ + ast_softhangup(props->transferer, AST_SOFTHANGUP_EXPLICIT); return TRANSFER_FAIL; case STIMULUS_DTMF_ATXFER_COMPLETE: case STIMULUS_TRANSFERER_HANGUP: @@ -669,8 +686,7 @@ static int resume_enter(struct attended_transfer_properties *props) { - ast_bridge_basic_change_personality_normal(props->transferee_bridge); - return ast_bridge_destroy(props->target_bridge); + return 0; } static int threeway_enter(struct attended_transfer_properties *props) @@ -762,6 +778,10 @@ case STIMULUS_TRANSFERER_ANSWER: ast_assert(0); case STIMULUS_TRANSFEREE_HANGUP: + /* We soft hangup the transferer to prevent him from sitting in + * a bridge by himself after the transfer fails + */ + ast_softhangup(props->transferer, AST_SOFTHANGUP_EXPLICIT); return TRANSFER_FAIL; case STIMULUS_TRANSFERER_HANGUP: case STIMULUS_DTMF_ATXFER_COMPLETE: @@ -1069,6 +1089,44 @@ return 0; } +static void bridge_personality_atxfer_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel) +{ + struct bridge_basic_personality *personality = self->personality; + struct attended_transfer_properties *props = personality->pvt; + + if (self->num_channels > 1) { + return; + } + + if (self->num_channels == 1) { + RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup); + + ast_channel_lock(props->transferer); + transferer_bridge_channel = ast_channel_get_bridge_channel(props->transferer); + ast_channel_unlock(props->transferer); + + if (!transferer_bridge_channel) { + return; + } + + if (AST_LIST_FIRST(&self->channels) != transferer_bridge_channel) { + return; + } + } + + /* Reaching this point means that either + * 1) The bridge has no channels in it + * 2) The bridge has one channel, and it's the transferer + * In either case, it indicates that the non-transferer parties + * are no longer in the bridge. + */ + if (self == props->transferee_bridge) { + stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP); + } else { + stimulate_attended_transfer(props, STIMULUS_TARGET_HANGUP); + } +} + static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfer_properties *props) { RAII_VAR(struct stimulus_list *, list, NULL, ast_free_ptr); @@ -1338,6 +1396,7 @@ void ast_bridge_basic_change_personality_normal(struct ast_bridge *bridge) { + struct ast_bridge_channel *bridge_channel; struct bridge_basic_personality *personality; SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock); @@ -1350,6 +1409,11 @@ ast_clear_flag(&bridge->feature_flags, AST_FLAGS_ALL); ast_set_flag(&bridge->feature_flags, NORMAL_FLAGS); remove_hooks_on_personality_change(bridge); + + AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { + ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook, NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL); + ast_bridge_channel_setup_features(bridge_channel); + }; } void ast_bridge_basic_change_personality_atxfer(struct ast_bridge *bridge, @@ -1388,6 +1452,7 @@ ast_bridge_basic_v_table = ast_bridge_base_v_table; ast_bridge_basic_v_table.name = "basic"; ast_bridge_basic_v_table.push = bridge_basic_push; + ast_bridge_basic_v_table.pull = bridge_basic_pull; ast_bridge_basic_v_table.destroy = bridge_basic_destroy; personality_normal_v_table = ast_bridge_base_v_table; @@ -1397,6 +1462,7 @@ personality_atxfer_v_table = ast_bridge_base_v_table; personality_atxfer_v_table.name = "attended transfer"; personality_atxfer_v_table.push = bridge_personality_atxfer_push; + personality_atxfer_v_table.pull = bridge_personality_atxfer_pull; ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL); } -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits