--- chan_dahdi-orig.c 2017-04-07 11:49:39.000000000 -0400 +++ chan_dahdi.c 2017-05-23 12:02:57.000000000 -0400 @@ -19723,6 +19723,17 @@ int size,res,fd,len,x; int bytes=0; int idx; + + /* used for hangup detection */ + struct ast_frame *f = NULL; + int ms = 50; + AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; + AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); + + struct ast_frame hangup_frame = { + .frametype = AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_HANGUP, + }; /* * Initial carrier (imaginary) @@ -19789,6 +19800,9 @@ len += END_SILENCE_LEN; fd = p->subs[idx].dfd; while (len) { + struct ast_frame *defer_frame = NULL; + struct ast_frame *dup_f = NULL; + if (ast_check_hangup(c)) { ast_free(mybuf); return -1; @@ -19799,7 +19813,13 @@ fds[0].fd = fd; fds[0].events = POLLOUT | POLLPRI; fds[0].revents = 0; + + /* clear previously set BLOCKING flag from ast_sendtext */ + ast_clear_flag(ast_channel_flags(c), AST_FLAG_BLOCKING); + CHECK_BLOCKING(c); res = poll(fds, 1, -1); + ast_clear_flag(ast_channel_flags(c), AST_FLAG_BLOCKING); + if (!res) { ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel); continue; @@ -19824,12 +19844,94 @@ } len -= size; buf += size; + + /* time to check for hangup + * but first we need to see if there is any input to read + */ + + /* since the channel is locked prior to calling this function + * in channel.c, we need to unlock prior to calling ast_waitfor + * and ast_read since they lock it as well */ + ast_channel_unlock(c); + + res = ast_waitfor(c, ms); + if (res < 0) { + ast_channel_lock(c); + /* nothing to read, go away */ + continue; + } + + f = ast_read(c); + ast_channel_lock(c); + + if (!f) { + /* No frame means the channel has been hung up. + * A hangup frame needs to be queued here as ast_waitfor() may + * never return again for the condition to be detected outside + * of sendtext. So, we'll leave a HANGUP queued up so the + * thread in charge of this channel will know. */ + + defer_frame = &hangup_frame; + if ((dup_f = ast_frdup(defer_frame))) { + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } + + /* exit since we received hangup */ + ast_debug(1, "processing HANGUP frame\n"); + len = 0; + + } else if (ast_is_deferrable_frame(f)) { + ast_debug(1, "received deferrable frame type %d\n", f->frametype); + + /* check for CONTROL frame which signals a HANGUP. + * Made the conscious decison to throw all TEXT frames + * since wo do not need to process voice or text frames while sending + * TDD text */ + + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) { + defer_frame = &hangup_frame; + if ((dup_f = ast_frisolate(defer_frame))) { + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } + if (dup_f != defer_frame) { + ast_frfree(defer_frame); + } + /* exit loop */ + len = 0; + + } else if (f->frametype != AST_FRAME_TEXT) { + defer_frame = f; + if ((dup_f = ast_frisolate(defer_frame))) { + AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); + } + if (dup_f != defer_frame) { + ast_frfree(defer_frame); + } + + } else { + /* drop other frames in case of feedback from device sending tones */ + ast_debug(1, "discarding frame\n"); + ast_frfree(f); + } + } else { + /* Can't defer. Discard and continue with next. */ + ast_debug(1, "discarding frame\n"); + ast_frfree(f); + } + } + + /* We need to queue and free all the deferred frames if any */ + ast_channel_unlock(c); + while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { + ast_queue_frame_head(c, f); + ast_frfree(f); } + ast_channel_lock(c); + ast_free(mybuf); return(0); } - static int reload(void) { int res = 0;