From 58c313c2af55c264c9c164663fca37bc9c2d530b Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthony.minessale@gmail.com>
Date: Sun, 27 May 2007 18:14:49 +0000
Subject: [PATCH] update

git-svn-id: http://svn.openzap.org/svn/openzap/trunk@166 a93c3328-9c30-0410-af19-c9cd2b2d52af
---
 libs/freetdm/mod_openzap/mod_openzap.c | 93 +++++++++++++++++++++-----
 libs/freetdm/src/include/openzap.h     | 11 ++-
 libs/freetdm/src/include/zap_types.h   | 11 ++-
 libs/freetdm/src/zap_analog.c          | 65 +++++++++++++++---
 libs/freetdm/src/zap_io.c              | 55 +++++++++++++--
 5 files changed, 197 insertions(+), 38 deletions(-)

diff --git a/libs/freetdm/mod_openzap/mod_openzap.c b/libs/freetdm/mod_openzap/mod_openzap.c
index 72060facba..19530cf755 100644
--- a/libs/freetdm/mod_openzap/mod_openzap.c
+++ b/libs/freetdm/mod_openzap/mod_openzap.c
@@ -52,7 +52,8 @@ typedef enum {
 	TFLAG_OUTBOUND = (1 << 1),
 	TFLAG_DTMF = (1 << 2),
 	TFLAG_CODEC = (1 << 3),
-	TFLAG_BREAK = (1 << 4)
+	TFLAG_BREAK = (1 << 4),
+	TFLAG_HOLD = (1 << 5)
 } TFLAGS;
 
 static struct {
@@ -76,6 +77,8 @@ struct private_object {
 	switch_codec_t write_codec;
 	switch_frame_t read_frame;
 	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	switch_frame_t cng_frame;
+	unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
 	switch_core_session_t *session;
 	switch_caller_profile_t *caller_profile;
 	unsigned int codec;
@@ -84,6 +87,7 @@ struct private_object {
 	switch_mutex_t *mutex;
 	switch_mutex_t *flag_mutex;
 	zap_channel_t *zchan;
+	int32_t token_id;
 };
 
 typedef struct private_object private_t;
@@ -111,6 +115,9 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
 	tech_pvt->zchan = zchan;
 	tech_pvt->read_frame.data = tech_pvt->databuf;
 	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+	tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
+	tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
+	memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen);
 	switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
 	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
 	switch_core_session_set_private(session, tech_pvt);
@@ -241,7 +248,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
 	tech_pvt = switch_core_session_get_private(session);
 	assert(tech_pvt != NULL);
 
-	zap_channel_set_token(tech_pvt->zchan, NULL);
+	zap_channel_clear_token(tech_pvt->zchan, tech_pvt->token_id);
 	
 	switch (tech_pvt->zchan->type) {
 	case ZAP_CHAN_TYPE_FXO:
@@ -367,6 +374,17 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
 
 	assert(tech_pvt->zchan != NULL);
 
+	if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+		switch_yield(tech_pvt->zchan->effective_interval * 1000);
+		*frame = &tech_pvt->cng_frame;
+		tech_pvt->cng_frame.datalen = tech_pvt->zchan->packet_len;
+		tech_pvt->cng_frame.samples = tech_pvt->cng_frame.datalen;
+		if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) {
+			tech_pvt->cng_frame.samples /= 2;
+		}
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
 	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
 		return SWITCH_STATUS_FALSE;
 	}
@@ -420,6 +438,10 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
 
 	assert(tech_pvt->zchan != NULL);
 
+	if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+		return SWITCH_STATUS_SUCCESS;
+	}
+
 	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
 		return SWITCH_STATUS_FALSE;
 	}
@@ -593,12 +615,26 @@ zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t
 		return ZAP_FAIL;
 	}
 
-	switch_copy_string(sigmsg->channel->token, switch_core_session_get_uuid(session), sizeof(sigmsg->channel->token));
+	if ((tech_pvt->token_id = zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session))) < 0) {
+		switch_core_session_destroy(&session);
+		return ZAP_FAIL;
+	}
 	*sp = session;
 
     return ZAP_SUCCESS;
 }
 
+static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id)
+{
+	switch_core_session_t *session = NULL;
+
+	if (!switch_strlen_zero(channel->tokens[id])) {
+		session = switch_core_session_locate(channel->tokens[id]);
+	}
+
+	return session;
+}
+
 static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
 {
 	zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
@@ -609,18 +645,11 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
 {
 	switch_core_session_t *session = NULL;
 	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
 	zap_status_t status;
-	int rwlock = 0;
 
     zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
 
-	if (!switch_strlen_zero(sigmsg->channel->token)) {
-		if ((session = switch_core_session_locate(sigmsg->channel->token))) {
-			channel = switch_core_session_get_channel(session);
-			rwlock++;
-		}
-	}
-
     switch(sigmsg->event_id) {
     case ZAP_SIGEVENT_START:
 		{
@@ -632,16 +661,48 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
 		break;
     case ZAP_SIGEVENT_STOP:
 		{
-			if (channel) {
+			while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				zap_channel_clear_token(sigmsg->channel, 0);
+				channel = switch_core_session_get_channel(session);
 				switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
-				zap_channel_set_token(sigmsg->channel, NULL);
+				switch_core_session_rwunlock(session);
 			}
 		}
 		break;
-	}
 
-	if (session && rwlock) {
-		switch_core_session_rwunlock(session);
+    case ZAP_SIGEVENT_FLASH:
+		{
+			uint32_t i = 0;
+			for (i = 0; i < sigmsg->channel->token_count; i++) {
+				if ((session = zap_channel_get_session(sigmsg->channel, i))) {
+					tech_pvt = switch_core_session_get_private(session);
+					if (i) {
+						switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+					} else {
+						switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+					}
+					switch_core_session_rwunlock(session);
+				}
+			}
+		}
+    case ZAP_SIGEVENT_HOLD:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, sigmsg->channel->token_count-1))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_UNHOLD:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, sigmsg->channel->token_count-1))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
 	}
 
 	return status;
diff --git a/libs/freetdm/src/include/openzap.h b/libs/freetdm/src/include/openzap.h
index a4e24f2394..3f47bc7a68 100644
--- a/libs/freetdm/src/include/openzap.h
+++ b/libs/freetdm/src/include/openzap.h
@@ -157,6 +157,7 @@
 #define zap_channel_test_feature(obj, flag) ((obj)->features & flag)
 #define zap_channel_set_feature(obj, flag) (obj)->features |= (flag)
 #define zap_channel_clear_feature(obj, flag) (obj)->features &= ~(flag)
+#define zap_channel_set_member_locked(obj, _m, _v) zap_mutex_lock(obj->mutex); obj->_m = _v; zap_mutex_unlock(obj->mutex)
 
 /*!
   \brief Test for the existance of a flag on an arbitary object
@@ -218,6 +219,9 @@ struct zap_event {
 	void *data;
 };
 
+#define ZAP_TOKEN_STRLEN 128
+#define ZAP_MAX_TOKENS 10
+
 struct zap_channel {
 	uint32_t span_id;
 	uint32_t chan_id;
@@ -245,7 +249,8 @@ struct zap_channel {
 	uint32_t dtmf_off;
 	teletone_generation_session_t tone_session;
 	zap_time_t last_event_time;
-	char token[128];
+	char tokens[ZAP_MAX_TOKENS+1][ZAP_TOKEN_STRLEN];
+	uint32_t token_count;
 	char chan_name[128];
 	char chan_number[32];
 	struct zap_span *span;
@@ -322,7 +327,9 @@ struct zap_io_interface {
 	struct zap_span spans[ZAP_MAX_SPANS_INTERFACE];
 };
 
-zap_status_t zap_channel_set_token(zap_channel_t *zchan, char *token);
+void zap_channel_rotate_tokens(zap_channel_t *zchan);
+zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id);
+zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token);
 zap_status_t zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state);
 zap_status_t zap_span_load_tones(zap_span_t *span, char *mapname);
 zap_size_t zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len);
diff --git a/libs/freetdm/src/include/zap_types.h b/libs/freetdm/src/include/zap_types.h
index 236217278f..d1fcb9248d 100644
--- a/libs/freetdm/src/include/zap_types.h
+++ b/libs/freetdm/src/include/zap_types.h
@@ -101,13 +101,16 @@ typedef enum {
 	ZAP_SIGEVENT_TRANSFER,
 	ZAP_SIGEVENT_ANSWER,
 	ZAP_SIGEVENT_UP,
+	ZAP_SIGEVENT_HOLD,
+	ZAP_SIGEVENT_UNHOLD,
+	ZAP_SIGEVENT_FLASH,
 	ZAP_SIGEVENT_PROGRESS,
 	ZAP_SIGEVENT_PROGRESS_MEDIA,
 	ZAP_SIGEVENT_NOTIFY,
 	ZAP_SIGEVENT_MISC,
 	ZAP_SIGEVENT_INVALID
 } zap_signal_event_t;
-#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "PROGRESS", "PROGRESS_MEDIA", "NOTIFY", "MISC", "INVALID"
+#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "HOLD", "UNHOLD", "FLASH", "PROGRESS", "PROGRESS_MEDIA", "NOTIFY", "MISC", "INVALID"
 ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t)
 
 typedef enum {
@@ -193,6 +196,7 @@ typedef enum {
 	ZAP_CHANNEL_STATE_DOWN,
 	ZAP_CHANNEL_STATE_UP,
 	ZAP_CHANNEL_STATE_HANGUP,
+	ZAP_CHANNEL_STATE_HOLD,
 	ZAP_CHANNEL_STATE_DIALTONE,
 	ZAP_CHANNEL_STATE_COLLECT,
 	ZAP_CHANNEL_STATE_RING,
@@ -201,7 +205,7 @@ typedef enum {
 	ZAP_CHANNEL_STATE_IDLE,
 	ZAP_CHANNEL_STATE_INVALID
 } zap_channel_state_t;
-#define CHANNEL_STATE_STRINGS "DOWN", "UP", "HANGUP", "DIALTONE", "COLLECT", "RING", "BUSY", "ATTN", "IDLE", "INVALID"
+#define CHANNEL_STATE_STRINGS "DOWN", "UP", "HANGUP", "HOLD", "DIALTONE", "COLLECT", "RING", "BUSY", "ATTN", "IDLE", "INVALID"
 ZAP_STR2ENUM_P(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t)
 
 typedef enum {
@@ -216,7 +220,8 @@ typedef enum {
 	ZAP_CHANNEL_INTHREAD = (1 << 8),
 	ZAP_CHANNEL_WINK = (1 << 9),
 	ZAP_CHANNEL_FLASH = (1 << 10),
-	ZAP_CHANNEL_STATE_CHANGE = (1 << 11)
+	ZAP_CHANNEL_STATE_CHANGE = (1 << 11),
+	ZAP_CHANNEL_HOLD = (1 << 12)
 } zap_channel_flag_t;
 
 
diff --git a/libs/freetdm/src/zap_analog.c b/libs/freetdm/src/zap_analog.c
index 3032e0200b..b6314dc339 100644
--- a/libs/freetdm/src/zap_analog.c
+++ b/libs/freetdm/src/zap_analog.c
@@ -87,7 +87,7 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
 	uint8_t frame[1024];
 	zap_size_t len, rlen;
 	zap_tone_type_t tt = ZAP_TONE_DTMF;
-	char dtmf[128];
+	char dtmf[128] = "";
 	zap_size_t dtmf_offset = 0;
 	zap_analog_data_t *data = chan->span->analog_data;
 	zap_channel_t *closed_chan;
@@ -119,6 +119,12 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
 
 	zap_channel_command(chan, ZAP_COMMAND_GET_INTERVAL, &interval);
 	zap_buffer_set_loops(dt_buffer, -1);
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = chan->chan_id;
+	sig.span_id = chan->span_id;
+	sig.channel = chan;
+	sig.span = chan->span;
 
 	while (zap_test_flag(chan, ZAP_CHANNEL_INTHREAD)) {
 		zap_wait_flag_t flags = ZAP_READ;
@@ -169,20 +175,18 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
 			switch(chan->state) {
 			case ZAP_CHANNEL_STATE_UP:
 				{
-					sig.event_id = ZAP_SIGEVENT_UP;
+					if (zap_test_flag(chan, ZAP_CHANNEL_HOLD)) {
+						sig.event_id = ZAP_SIGEVENT_UNHOLD;
+					} else {
+						sig.event_id = ZAP_SIGEVENT_UP;
+					}
 					data->sig_cb(&sig);
-					
 					continue;
 				}
 				break;
 			case ZAP_CHANNEL_STATE_IDLE:
 				{
-					memset(&sig, 0, sizeof(sig));
 					sig.event_id = ZAP_SIGEVENT_START;
-					sig.chan_id = chan->chan_id;
-					sig.span_id = chan->span_id;
-					sig.channel = chan;
-					sig.span = chan->span;
 					zap_copy_string(sig.dnis, dtmf, sizeof(sig.dnis));
 					data->sig_cb(&sig);
 					continue;
@@ -195,8 +199,18 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
 					goto done;
 				}
 				break;
+			case ZAP_CHANNEL_STATE_HOLD:
+				{
+					sig.event_id = ZAP_SIGEVENT_HOLD;
+					data->sig_cb(&sig);
+					zap_set_flag_locked(chan, ZAP_CHANNEL_HOLD);
+					zap_set_state_locked(chan, ZAP_CHANNEL_STATE_DIALTONE);
+				}
+				break;
 			case ZAP_CHANNEL_STATE_DIALTONE:
 				{
+					*dtmf = '\0';
+					dtmf_offset = 0;
 					zap_buffer_zero(dt_buffer);
 					teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_DIAL]);
 					indicate = 1;
@@ -245,8 +259,8 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
 			last_digit = 0;
 		}
 		
-		if (zap_channel_wait(chan, &flags, interval * 2) == ZAP_FAIL) {
-			goto done;
+		if (zap_channel_wait(chan, &flags, interval * 2) != ZAP_SUCCESS) {
+			continue;
 		}
 		
 		if (!(flags & ZAP_READ)) {
@@ -313,12 +327,41 @@ static zap_status_t process_event(zap_span_t *span, zap_event_t *event)
 {
 	zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d]\n", zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id);
 
+	zap_mutex_lock(event->channel->mutex);
+
+
 	switch(event->enum_id) {
 	case ZAP_OOB_ONHOOK:
 		{
 			zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
 		}
 		break;
+	case ZAP_OOB_FLASH:
+		{
+			zap_sigmsg_t sig;
+			zap_analog_data_t *data = event->channel->span->analog_data;
+			memset(&sig, 0, sizeof(sig));
+			sig.chan_id = event->channel->chan_id;
+			sig.span_id = event->channel->span_id;
+			sig.channel = event->channel;
+			sig.span = event->channel->span;
+			
+			if (event->channel->state == ZAP_CHANNEL_STATE_UP) {
+				if (event->channel->token_count > 1) {
+					zap_channel_rotate_tokens(event->channel);
+					sig.event_id = ZAP_SIGEVENT_FLASH;
+					data->sig_cb(&sig);
+				} else {
+					if (zap_test_flag(event->channel, ZAP_CHANNEL_HOLD)) {
+						zap_clear_flag_locked(event->channel, ZAP_CHANNEL_HOLD);
+						zap_set_state_locked(event->channel,  ZAP_CHANNEL_STATE_UP);
+					} else {
+						zap_set_state_locked(event->channel,  ZAP_CHANNEL_STATE_HOLD);
+					}
+				}
+			}
+		}
+		break;
 	case ZAP_OOB_OFFHOOK:
 		{
 			if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
@@ -328,7 +371,7 @@ static zap_status_t process_event(zap_span_t *span, zap_event_t *event)
 		}
 	}
 
-
+	zap_mutex_unlock(event->channel->mutex);
 	return ZAP_SUCCESS;
 }
 
diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c
index 1c3da3c2c7..845cba7ef9 100644
--- a/libs/freetdm/src/zap_io.c
+++ b/libs/freetdm/src/zap_io.c
@@ -370,16 +370,54 @@ zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t
 	return ZAP_SUCCESS;
 }
 
-zap_status_t zap_channel_set_token(zap_channel_t *zchan, char *token)
+zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id)
 {
+	zap_status_t status = ZAP_FAIL;
+	
 	zap_mutex_lock(zchan->mutex);
-	if (token) {
-		zap_copy_string(zchan->token, token, sizeof(zchan->token));
-	} else {
-		*zchan->token = '\0';
+	if (token_id == -1) {
+		memset(zchan->tokens, 0, sizeof(zchan->tokens));
+		zchan->token_count = 0;
+	} else if (*zchan->tokens[token_id] != '\0') {
+		char tokens[ZAP_MAX_TOKENS][ZAP_TOKEN_STRLEN];
+		int32_t i, count = zchan->token_count;
+		memcpy(tokens, zchan->tokens, sizeof(tokens));
+		memset(zchan->tokens, 0, sizeof(zchan->tokens));
+		zchan->token_count = 0;		
+
+		for (i = 0; i < count; i++) {
+			if (i != token_id) {
+				zap_copy_string(zchan->tokens[zchan->token_count], tokens[i], sizeof(zchan->tokens[zchan->token_count]));
+				zchan->token_count++;
+			}
+		}
+
+		status = ZAP_SUCCESS;
 	}
 	zap_mutex_unlock(zchan->mutex);
-	return ZAP_SUCCESS;
+
+	return status;
+}
+
+void zap_channel_rotate_tokens(zap_channel_t *zchan)
+{
+	memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
+	zap_copy_string(zchan->tokens[0], zchan->tokens[zchan->token_count], ZAP_TOKEN_STRLEN);
+	*zchan->tokens[zchan->token_count] = '\0';
+}
+
+zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token)
+{
+	zap_status_t status = ZAP_FAIL;
+
+	zap_mutex_lock(zchan->mutex);
+	if (zchan->token_count < ZAP_MAX_TOKENS) {
+		zap_copy_string(zchan->tokens[zchan->token_count], token, sizeof(zchan->tokens[zchan->token_count]));
+		zchan->token_count++;
+	}
+	zap_mutex_unlock(zchan->mutex);
+
+	return status;
 }
 
 
@@ -523,6 +561,10 @@ static zap_status_t zap_channel_reset(zap_channel_t *zchan)
 	zchan->event_callback = NULL;
 	zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
 	zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD);
+	memset(zchan->tokens, 0, sizeof(zchan->tokens));
+	zchan->token_count = 0;
+
 	if (zchan->tone_session.buffer) {
 		teletone_destroy_session(&zchan->tone_session);
 		memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
@@ -605,6 +647,7 @@ zap_status_t zap_channel_close(zap_channel_t **zchan)
 	assert(check != NULL);
 	*zchan = NULL;
 
+
 	zap_mutex_lock(check->mutex);
 	if (zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
 		status = check->zio->close(check);