diff --git a/chan_capi_chat.c b/chan_capi_chat.c index 87955d2..547e14c 100644 --- a/chan_capi_chat.c +++ b/chan_capi_chat.c @@ -226,7 +226,19 @@ static struct capichat_s* update_capi_mixer_part( return (new_chat_start); } -static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i, deffered_chat_capi_message_t* update_segment) +/*! + * \note CAPI updates LI state on PLCI removal. + * If expect_plci_removal is true then do not send + * CAPI LI commands. All other actions are taken to + * ensure all side effects apply. CAPI updates LI + * state on PLCI removal. + */ +static void update_capi_mixer( + int remove, + unsigned int roomnumber, + struct capi_pvt *i, + deffered_chat_capi_message_t* update_segment, + int expect_plci_removal) { struct capichat_s *room; unsigned int overall_found; @@ -280,15 +292,17 @@ static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_p if (update_segment == 0) { for (nr = 0; nr < segment_nr; nr++) { if (segments[nr].busy != 0) { - cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME - " mixer: %s PLCI=0x%04x LI=0x%x\n", i->vname, i->PLCI, segments[nr].datapath); + if (expect_plci_removal == 0) { + cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME + " mixer: %s PLCI=0x%04x LI=0x%x\n", i->vname, i->PLCI, segments[nr].datapath); - capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), - "w(w(dc))", - FACILITYSELECTOR_LINE_INTERCONNECT, - 0x0001, /* CONNECT */ - segments[nr].datapath, - &segments[nr].p_struct); + capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(w(dc))", + FACILITYSELECTOR_LINE_INTERCONNECT, + 0x0001, /* CONNECT */ + segments[nr].datapath, + &segments[nr].p_struct); + } } } } @@ -330,7 +344,7 @@ static void update_all_capi_mixers(unsigned int roomnumber) for (nr = 0; nr < nr_segments; nr++) { segment[nr].busy = 0; } - update_capi_mixer(0, roomnumber, room->i, segment); + update_capi_mixer(0, roomnumber, room->i, segment, 0); if (segment[0].busy != 0) { PLCIS[i++] = room->i->PLCI; } @@ -362,7 +376,7 @@ static void update_all_capi_mixers(unsigned int roomnumber) /* * delete a chat member */ -static void del_chat_member(struct capichat_s *room) +static void del_chat_member(struct capichat_s *room, int expect_plci_removal) { struct capichat_s *tmproom; struct capichat_s *tmproom2 = NULL; @@ -387,7 +401,7 @@ static void del_chat_member(struct capichat_s *room) } cc_mutex_unlock(&chat_lock); - update_capi_mixer(1, roomnumber, i, 0); + update_capi_mixer(1, roomnumber, i, 0, expect_plci_removal); } /* @@ -453,7 +467,7 @@ static struct capichat_s *add_chat_member(const char *roomname, struct capi_pvt cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' %s(%d)\n", i->vname, roomname, room_member_type_2_name(room_member_type), roomnumber); - update_capi_mixer(0, roomnumber, i, 0); + update_capi_mixer(0, roomnumber, i, 0, 0); return room; } @@ -463,7 +477,7 @@ static struct capichat_s *add_chat_member(const char *roomname, struct capi_pvt */ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i, struct capichat_s *room, unsigned int flags, struct capi_pvt* iline, - FILE* voice_message, unsigned int hangup_timeout) + FILE* voice_message, unsigned int hangup_timeout, int* pbx_detected_hangup) { struct ast_frame *f; int ms; @@ -476,6 +490,10 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i, int moh_active = 0, voice_message_moh_active = 0; int write_block_nr = 2; time_t alone_since = time(NULL); + int local_detected_hangup; + int* detected_hangup = (pbx_detected_hangup != NULL) ? pbx_detected_hangup : &local_detected_hangup; + + *detected_hangup = 0; if (voice_message == NULL) { ast_indicate(chan, -1); @@ -521,6 +539,7 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i, continue; cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: no frame, hangup.\n", i->vname); + *detected_hangup = 1; break; } if ((f->frametype == AST_FRAME_CONTROL) && @@ -528,6 +547,7 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i, cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: hangup frame.\n", i->vname); ast_frfree(f); + *detected_hangup = 1; break; } else if (f->frametype == AST_FRAME_VOICE) { cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: voice frame.\n", @@ -642,6 +662,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param) int largeConferenceMode = 0; unsigned int selectedGroup = 0; unsigned int bridgeUsers = 0; + int expect_plci_removal; roomname = strsep(¶m, COMMANDSEPARATOR); options = strsep(¶m, COMMANDSEPARATOR); @@ -756,7 +777,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param) conferenceConnectTime = time(NULL); /* main loop */ - chat_handle_events(c, i, room, flags, 0, 0, hangup_timeout); + chat_handle_events(c, i, room, flags, 0, 0, hangup_timeout, &expect_plci_removal); pbx_capi_chat_leave_event(c, room, time(NULL)-conferenceConnectTime); if (room->active == 1) { @@ -764,7 +785,9 @@ int pbx_capi_chat(struct ast_channel *c, char *param) pbx_capi_chat_room_state_event(room->name, 0); } - del_chat_member(room); + expect_plci_removal |= (i->channeltype == CAPI_CHANNELTYPE_NULL); /* NULL PLCI is removed, no need to update CAPI LI state */ + + del_chat_member(room, expect_plci_removal); out: capi_remove_nullif(i); @@ -894,9 +917,9 @@ int pbx_capi_chat_play(struct ast_channel *c, char *param) } /* main loop */ - chat_handle_events(c, i, room, flags, (c->tech == &capi_tech) ? (CC_CHANNEL_PVT(c)) : 0, f, 0); + chat_handle_events(c, i, room, flags, (c->tech == &capi_tech) ? (CC_CHANNEL_PVT(c)) : 0, f, 0, NULL); - del_chat_member(room); + del_chat_member(room, 1); out: fclose (f); @@ -1445,7 +1468,7 @@ pbx_capi_create_conference_bridge(const char* mainName, if (error != 0) { for (i = 0; i < sizeof(name)/sizeof(name[0]); i++) { if (room[i] != 0) { - del_chat_member(room[i]); + del_chat_member(room[i], 1); } if (capi_ifc[i] != 0) { capi_remove_nullif(capi_ifc[i]); @@ -1855,8 +1878,8 @@ static void pbx_capi_cleanup_bridge(const char* roomName, unsigned int groupNumb cc_verbose(2, 0, VERBOSE_PREFIX_2 CC_MESSAGE_NAME " Delete bridge '%s' <-> '%s'\n", mainFullName, additionalFullName); - del_chat_member(additionalGroup); - del_chat_member(mainGroup); + del_chat_member(additionalGroup, 1); + del_chat_member(mainGroup, 1); #ifdef DIVA_STREAMING capi_DivaStreamLock(); #endif