[Freeswitch-svn] [commit] r2588 - in freeswitch/trunk/src: . include mod/applications/mod_conference mod/applications/mod_playback

Freeswitch SVN anthm at freeswitch.org
Fri Sep 8 23:39:29 EDT 2006


Author: anthm
Date: Fri Sep  8 23:39:28 2006
New Revision: 2588

Modified:
   freeswitch/trunk/src/include/switch_core.h
   freeswitch/trunk/src/include/switch_ivr.h
   freeswitch/trunk/src/include/switch_types.h
   freeswitch/trunk/src/include/switch_utils.h
   freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c
   freeswitch/trunk/src/mod/applications/mod_playback/mod_playback.c
   freeswitch/trunk/src/switch_core.c
   freeswitch/trunk/src/switch_ivr.c

Log:
Adding bugs to the core

This is the primary commit to add bugs to the core (media bugs that is)
Media bugs are kind of like what ChanSpy is in Asterisk only cooler (I wrote ChanSpy too so I can say that)

Here is an example of using them to record a call by the higher level switch_ivr functionality passed
up to the dialplan via mod_playback.

The call will be recorded while the some.wav plays then stop for the rest of the call (when some_other.wav plays)

The bugs may have bugs since this is 1 day's work so happy hunting ......

<extension name="42">
  <condition field="destination_number" expression="^42$">
   <action application="set" data="RECORD_TITLE=recording test"/>
   <action application="set" data="RECORD_ARTIST=FreeSWITCH"/>
    <action application="record_session" data="/tmp/rtest.wav"/>
    <action application="playback" data="/tmp/some.wav"/>
    <action application="stop_record_session" data="/tmp/rtest.wav"/>
    <action application="playback" data="/tmp/some_other.wav"/>
  </condition>
</extension>



Modified: freeswitch/trunk/src/include/switch_core.h
==============================================================================
--- freeswitch/trunk/src/include/switch_core.h	(original)
+++ freeswitch/trunk/src/include/switch_core.h	Fri Sep  8 23:39:28 2006
@@ -107,6 +107,50 @@
   \{ 
 */
 
+
+///\defgroup pa1 Media Bugs
+///\ingroup core1
+///\{
+
+/*!
+  \brief Add a media bug to the session
+  \param session the session to add the bug to
+  \param callback a callback for events
+  \param user_data arbitrary user data
+  \param new_bug pointer to assign new bug to
+  \return SWITCH_STATUS_SUCCESS if the operation was a success
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t *session,
+														  switch_media_bug_callback_t callback,
+														  void *user_data,
+														  switch_media_bug_t **new_bug);
+
+
+/*!
+  \brief Remove a media bug from the session
+  \param session the session to remove the bug from
+  \param bug bug to remove
+  \return SWITCH_STATUS_SUCCESS if the operation was a success
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session_t *session, switch_media_bug_t **bug);
+
+/*!
+  \brief Remove all media bugs from the session
+  \param session the session to remove the bugs from
+  \return SWITCH_STATUS_SUCCESS if the operation was a success
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(switch_core_session_t *session);
+
+/*!
+  \brief Read a frame from the bug
+  \param bug the bug to read from
+  \param frame the frame to write the data to
+  \return the amount of data 
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame);
+
+///\}
+
 ///\defgroup pa1 Port Allocation
 ///\ingroup core1
 ///\{
@@ -119,7 +163,10 @@
   \param new pointer for the return value
   \return SWITCH_STATUS_SUCCESS if the operation was a success
 */
-SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start, switch_port_t end, uint8_t inc, switch_core_port_allocator_t **new_allocator);
+SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start,
+															   switch_port_t end,
+															   uint8_t inc,
+															   switch_core_port_allocator_t **new_allocator);
 
 /*!
   \brief Get a port from the port allocator

Modified: freeswitch/trunk/src/include/switch_ivr.h
==============================================================================
--- freeswitch/trunk/src/include/switch_ivr.h	(original)
+++ freeswitch/trunk/src/include/switch_ivr.h	Fri Sep  8 23:39:28 2006
@@ -94,7 +94,24 @@
 																const char *terminators,
 																char *terminator,
 																unsigned int timeout);
-	
+
+/*!
+  \brief Record a session to disk
+  \param session the session to record
+  \param file the path to the file
+  \param fh file handle to use (NULL for builtin one)
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, char *file,  switch_file_handle_t *fh);
+
+/*!
+  \brief Stop Recording a session
+  \param session the session to stop recording
+  \param file the path to the file
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_session_t *session, char *file);
+
 /*!
   \brief play a file from the disk to the session
   \param session the session to play the file too

Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h	(original)
+++ freeswitch/trunk/src/include/switch_types.h	Fri Sep  8 23:39:28 2006
@@ -80,6 +80,12 @@
 	SWITCH_BITPACK_MODE_AAL2
 } switch_bitpack_mode_t;
 
+typedef enum {
+	SWITCH_ABC_TYPE_INIT,
+	SWITCH_ABC_TYPE_READ,
+	SWITCH_ABC_TYPE_WRITE,
+	SWITCH_ABC_TYPE_CLOSE,
+} switch_abc_type_t;
 
 typedef struct {
 	switch_byte_t *buf;
@@ -739,9 +745,8 @@
 typedef struct switch_speech_interface switch_speech_interface_t;
 typedef struct switch_directory_interface switch_directory_interface_t;
 typedef struct switch_core_port_allocator switch_core_port_allocator_t;
-typedef struct switch_audio_bug switch_audio_bug_t;
-typedef void (*switch_audio_bug_read_callback_t)(switch_audio_bug_t *);
-typedef void (*switch_audio_bug_write_callback_t)(switch_audio_bug_t *);
+typedef struct switch_media_bug switch_media_bug_t;
+typedef void (*switch_media_bug_callback_t)(switch_media_bug_t *, void *, switch_abc_type_t);
 typedef void (*switch_application_function_t)(switch_core_session_t *, char *);
 typedef void (*switch_event_callback_t)(switch_event_t *);
 typedef switch_caller_extension_t *(*switch_dialplan_hunt_function_t)(switch_core_session_t *);
@@ -787,7 +792,7 @@
 /*! \brief A core session representing a call and all of it's resources */
 struct switch_core_session;
 /*! \brief An audio bug */
-struct switch_audio_bug;
+struct switch_media_bug;
 
 SWITCH_END_EXTERN_C
 

Modified: freeswitch/trunk/src/include/switch_utils.h
==============================================================================
--- freeswitch/trunk/src/include/switch_utils.h	(original)
+++ freeswitch/trunk/src/include/switch_utils.h	Fri Sep  8 23:39:28 2006
@@ -50,6 +50,12 @@
 #endif
 
 
+#define SWITCH_SMAX 32767
+#define SWITCH_SMIN -32768
+#define switch_normalize_to_16bit(n) if (n > SWITCH_SMAX) n = SWITCH_SMAX / 2; else if (n < SWITCH_SMIN) n = SWITCH_SMIN / 2;
+
+
+
 /*!
   \brief Evaluate the truthfullness of a string expression
   \param expr a string expression

Modified: freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c	(original)
+++ freeswitch/trunk/src/mod/applications/mod_conference/mod_conference.c	Fri Sep  8 23:39:28 2006
@@ -228,10 +228,6 @@
 }
 
 
-#define SMAX 32767
-#define SMIN -32768
-#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
-
 static void switch_change_sln_volume(int16_t *data, uint32_t samples, int32_t vol)
 {
 	int16_t *p = data;
@@ -249,7 +245,7 @@
 
 	for (x = 0; x < samples; x++) {
 		b = (int32_t)((double)p[x] * mult);
-		normalize_to_16bit(b);
+		switch_normalize_to_16bit(b);
 		p[x] = (int16_t) b;
 	}
 }
@@ -600,7 +596,7 @@
 				
 						for (x = 0; x < imember->read / 2; x++) {
 							int32_t z = muxed[x] + bptr[x];
-							normalize_to_16bit(z);
+							switch_normalize_to_16bit(z);
 							muxed[x] = (int16_t)z;
 						}
 						

Modified: freeswitch/trunk/src/mod/applications/mod_playback/mod_playback.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_playback/mod_playback.c	(original)
+++ freeswitch/trunk/src/mod/applications/mod_playback/mod_playback.c	Fri Sep  8 23:39:28 2006
@@ -133,6 +133,26 @@
 }
 
 
+static void record_session_function(switch_core_session_t *session, char *data)
+{
+	switch_channel_t *channel;
+	channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+	switch_ivr_record_session(session, data, NULL);	
+}
+
+
+static void stop_record_session_function(switch_core_session_t *session, char *data)
+{
+	switch_channel_t *channel;
+	channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+	switch_ivr_stop_record_session(session, data);	
+}
+
+
 static const switch_application_interface_t speak_application_interface = {
 	/*.interface_name */ "speak",
 	/*.application_function */ speak_function
@@ -145,11 +165,27 @@
 	&speak_application_interface
 };
 
+
+static const switch_application_interface_t record_session_application_interface = {
+	/*.interface_name */ "record_session",
+	/*.application_function */ record_session_function,
+	NULL,NULL,NULL,
+	&record_application_interface
+};
+
+
+static const switch_application_interface_t stop_record_session_application_interface = {
+	/*.interface_name */ "stop_record_session",
+	/*.application_function */ stop_record_session_function,
+	NULL,NULL,NULL,
+	&record_session_application_interface
+};
+
 static const switch_application_interface_t playback_application_interface = {
 	/*.interface_name */ "playback",
 	/*.application_function */ playback_function,
 	NULL,NULL,NULL,
-	/*.next*/				  &record_application_interface
+	/*.next*/				  &stop_record_session_application_interface
 };
 
 static const switch_loadable_module_interface_t mod_playback_module_interface = {

Modified: freeswitch/trunk/src/switch_core.c
==============================================================================
--- freeswitch/trunk/src/switch_core.c	(original)
+++ freeswitch/trunk/src/switch_core.c	Fri Sep  8 23:39:28 2006
@@ -50,15 +50,15 @@
 #define SWITCH_SQL_QUEUE_LEN 2000
 
 
-struct switch_audio_bug {
-	switch_codec_t *read_codec;
-    switch_codec_t *write_codec;
+struct switch_media_bug {
 	switch_buffer_t *raw_write_buffer;
 	switch_buffer_t *raw_read_buffer;
-	uint8_t data[SWITCH_RECCOMMENDED_BUFFER_SIZE];
-	switch_audio_bug_read_callback_t read_callback;
-	switch_audio_bug_read_callback_t write_callback;
-	struct switch_audio_bug *next;
+	switch_media_bug_callback_t callback;
+	switch_mutex_t *read_mutex;
+	switch_mutex_t *write_mutex;
+	switch_core_session_t *session;
+	void *user_data;
+	struct switch_media_bug *next;
 };
 	
 struct switch_core_session {
@@ -101,6 +101,8 @@
 	void *private_info;
 	switch_queue_t *event_queue;
 	switch_queue_t *private_event_queue;
+	switch_thread_rwlock_t *bug_rwlock;
+	switch_media_bug_t *bugs;
 };
 
 SWITCH_DECLARE_DATA switch_directories SWITCH_GLOBAL_dirs;
@@ -149,6 +151,175 @@
 	}
 }
 
+static void switch_core_media_bug_destroy(switch_media_bug_t *bug)
+{
+	switch_buffer_destroy(&bug->raw_read_buffer);
+	switch_buffer_destroy(&bug->raw_write_buffer);
+}
+
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame)
+{
+	uint32_t bytes = 0;
+	uint8_t data[SWITCH_RECCOMMENDED_BUFFER_SIZE] = {0};
+	uint32_t datalen = 0;
+	int16_t *dp, *fp;
+	uint32_t x;
+	uint32_t rlen = switch_buffer_inuse(bug->raw_read_buffer);
+	uint32_t wlen = switch_buffer_inuse(bug->raw_write_buffer);
+	uint32_t blen;
+	uint32_t rdlen = 0;
+	uint32_t maxlen;
+
+	if (!rlen && !wlen) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	maxlen = sizeof(data) > frame->buflen ? frame->buflen :  sizeof(data);
+	if ((rdlen = rlen > wlen ? wlen : rlen) > maxlen) {
+		rdlen = maxlen;
+	}
+	
+	frame->datalen = 0;
+
+	if (rlen) {
+		switch_mutex_lock(bug->read_mutex);
+		
+		frame->datalen = (uint32_t) switch_buffer_read(bug->raw_read_buffer,
+													   frame->data,
+													   rdlen);
+		switch_mutex_unlock(bug->read_mutex);
+	}
+
+	if (wlen) {
+		switch_mutex_lock(bug->write_mutex);
+		datalen = (uint32_t) switch_buffer_read(bug->raw_write_buffer,
+												data,
+												rdlen);
+		switch_mutex_unlock(bug->write_mutex);
+	}
+
+	bytes = (datalen > frame->datalen) ? datalen : frame->datalen;
+
+	if (bytes) {
+		dp = (int16_t *) data;
+		fp = (int16_t *) frame->data;
+		
+		rlen = frame->datalen / 2;
+		wlen = datalen / 2;
+		blen = bytes / 2;
+		
+		for(x = 0; x < blen; x++) {
+			int32_t z = 0;
+
+			if (x < rlen) {
+				z += (int32_t) *(fp+x);
+			}
+			if (x < wlen) {
+				z += (int32_t)*(dp+x);
+			}
+			switch_normalize_to_16bit(z);
+			*(fp+x) = (int16_t) z;
+		}
+
+		frame->datalen = bytes;
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_FALSE;
+}
+
+#define MAX_BUG_BUFFER 1024 * 512
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t *session,
+														  switch_media_bug_callback_t callback,
+														  void *user_data,
+														  switch_media_bug_t **new_bug)
+
+{
+	switch_media_bug_t *bug;
+	switch_size_t bytes;
+
+	if (!(bug = switch_core_session_alloc(session, sizeof(*bug)))) {
+		return SWITCH_STATUS_MEMERR;
+	}
+
+	bug->callback = callback;
+	bug->user_data = user_data;
+	bug->session = session;
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Attaching BUG to %s\n", switch_channel_get_name(session->channel));
+	bytes = session->read_codec->implementation->bytes_per_frame * 2;
+	switch_buffer_create_dynamic(&bug->raw_read_buffer, bytes, bytes, MAX_BUG_BUFFER);
+	bytes = session->write_codec->implementation->bytes_per_frame * 2;
+	switch_buffer_create_dynamic(&bug->raw_write_buffer, bytes, bytes, MAX_BUG_BUFFER);
+	switch_mutex_init(&bug->read_mutex, SWITCH_MUTEX_NESTED, session->pool);
+	switch_mutex_init(&bug->write_mutex, SWITCH_MUTEX_NESTED, session->pool);
+
+	switch_thread_rwlock_wrlock(session->bug_rwlock);
+	bug->next = session->bugs;
+	session->bugs = bug;
+	switch_thread_rwlock_unlock(session->bug_rwlock);
+	*new_bug = bug;
+
+	if (bug->callback) {
+		bug->callback(bug, bug->user_data, SWITCH_ABC_TYPE_INIT);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(switch_core_session_t *session)
+{
+	switch_media_bug_t *bp;
+
+	if (session->bugs) {
+		switch_thread_rwlock_wrlock(session->bug_rwlock);
+		for (bp = session->bugs; bp; bp = bp->next) {
+			if (bp->callback) {
+				bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_CLOSE);
+			}
+			switch_core_media_bug_destroy(bp);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing BUG from %s\n", switch_channel_get_name(session->channel));
+		}
+		switch_thread_rwlock_unlock(session->bug_rwlock);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session_t *session, switch_media_bug_t **bug)
+{
+	switch_media_bug_t *bp = NULL, *last = NULL;
+
+	if (session->bugs) {
+		switch_thread_rwlock_wrlock(session->bug_rwlock);
+		for (bp = session->bugs; bp; bp = bp->next) {
+			if (bp == *bug) {
+				if (last) {
+					last->next = bp->next;
+				} else {
+					session->bugs = bp->next;
+				}
+				break;
+			}
+			last = bp;
+		}
+		switch_thread_rwlock_unlock(session->bug_rwlock);
+
+		if (bp) {
+			if (bp->callback) {
+				bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_CLOSE);
+			}
+			switch_core_media_bug_destroy(bp);
+			*bug = NULL;
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing BUG from %s\n", switch_channel_get_name(session->channel));
+			return SWITCH_STATUS_SUCCESS;
+		}
+	}
+
+	return SWITCH_STATUS_FALSE;
+}
+
 struct switch_core_port_allocator {
 	switch_port_t start;
 	switch_port_t end;
@@ -158,7 +329,10 @@
 	switch_memory_pool_t *pool;
 };
 
-SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start, switch_port_t end, uint8_t inc, switch_core_port_allocator_t **new_allocator)
+SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start,
+															   switch_port_t end,
+															   uint8_t inc,
+															   switch_core_port_allocator_t **new_allocator)
 {
 	switch_status_t status;
 	switch_memory_pool_t *pool;
@@ -1362,7 +1536,7 @@
 {
 	switch_io_event_hook_read_frame_t *ptr;
 	switch_status_t status;
-	int need_codec, perfect;
+	int need_codec, perfect, do_bugs = 0;
  top:
 	
 	status = SWITCH_STATUS_FALSE;
@@ -1420,6 +1594,11 @@
 		need_codec = TRUE;
 	}
 
+	if (session->bugs && !need_codec) {
+		do_bugs = 1;
+		need_codec = 1;
+	}
+
 	if (status == SWITCH_STATUS_SUCCESS && need_codec) {
 		switch_frame_t *enc_frame, *read_frame = *frame;
 
@@ -1472,6 +1651,24 @@
 			read_frame->rate = session->read_resampler->to_rate;
 		}
 
+		if (session->bugs) {
+			switch_media_bug_t *bp;
+			switch_thread_rwlock_rdlock(session->bug_rwlock);
+			for (bp = session->bugs; bp; bp = bp->next) {
+				switch_mutex_lock(bp->read_mutex);
+				switch_buffer_write(bp->raw_read_buffer, read_frame->data, read_frame->datalen);
+				if (bp->callback) {
+					bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ);
+				}
+				switch_mutex_unlock(bp->read_mutex);
+			}
+			switch_thread_rwlock_unlock(session->bug_rwlock);
+		}
+
+		if (do_bugs) {
+			goto done;
+		}
+
 		if (session->read_codec) {
 			if ((*frame)->datalen == session->read_codec->implementation->bytes_per_frame) {
 				perfect = TRUE;
@@ -1587,7 +1784,7 @@
 
 	switch_status_t status = SWITCH_STATUS_FALSE;
 	switch_frame_t *enc_frame = NULL, *write_frame = frame;
-	unsigned int flag = 0, need_codec = 0, perfect = 0;
+	unsigned int flag = 0, need_codec = 0, perfect = 0, do_bugs = 0, do_write = 0;
 	switch_io_flag_t io_flag = SWITCH_IO_FLAG_NOOP;
 
 	assert(session != NULL);
@@ -1620,6 +1817,11 @@
 		need_codec = TRUE;
 	}
 
+	if (session->bugs && !need_codec) {
+		do_bugs = 1;
+		need_codec = 1;
+	}
+
 	if (need_codec) {
 		if (frame->codec) {
 			session->raw_write_frame.datalen = session->raw_write_frame.buflen;
@@ -1680,7 +1882,23 @@
 			write_frame->rate = session->write_resampler->to_rate;
 		}
 
-
+		if (session->bugs) {
+			switch_media_bug_t *bp;
+			switch_thread_rwlock_rdlock(session->bug_rwlock);
+			for (bp = session->bugs; bp; bp = bp->next) {
+				switch_mutex_lock(bp->write_mutex);
+				switch_buffer_write(bp->raw_write_buffer, write_frame->data, write_frame->datalen);
+				switch_mutex_unlock(bp->write_mutex);
+				if (bp->callback) {
+					bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE);
+				}
+			}
+			switch_thread_rwlock_unlock(session->bug_rwlock);
+		}
+		if (do_bugs) {
+			do_write = 1;
+			goto done;
+		}
 		if (session->write_codec) {
 			if (write_frame->datalen == session->write_codec->implementation->bytes_per_frame) {
 				perfect = TRUE;
@@ -1819,6 +2037,11 @@
 			}
 		}
 	} else {
+		do_write = 1;
+	}
+
+ done:
+	if (do_write) {
 		return perform_write(session, frame, timeout, io_flag, stream_id);
 	}
 
@@ -2658,6 +2881,7 @@
 		switch_event_fire(&event);
 	}
 
+	switch_core_media_bug_remove_all(*session);
 	switch_buffer_destroy(&(*session)->raw_read_buffer);
 	switch_buffer_destroy(&(*session)->raw_write_buffer);
 	switch_channel_uninit((*session)->channel);
@@ -2889,6 +3113,7 @@
 	session->enc_read_frame.buflen = sizeof(session->enc_read_buf);
 
 	switch_mutex_init(&session->mutex, SWITCH_MUTEX_NESTED, session->pool);
+	switch_thread_rwlock_create(&session->bug_rwlock, session->pool);
 	switch_thread_cond_create(&session->cond, session->pool);
 	switch_thread_rwlock_create(&session->rwlock, session->pool);
 

Modified: freeswitch/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr.c	(original)
+++ freeswitch/trunk/src/switch_ivr.c	Fri Sep  8 23:39:28 2006
@@ -448,6 +448,138 @@
 	return status;
 }
 
+static void record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
+{
+	switch_file_handle_t *fh = (switch_file_handle_t *) user_data;
+	uint8_t data[SWITCH_RECCOMMENDED_BUFFER_SIZE];
+	switch_frame_t frame = {0};
+
+	frame.data = data;
+	frame.buflen = SWITCH_RECCOMMENDED_BUFFER_SIZE;
+	
+	switch(type) {
+	case SWITCH_ABC_TYPE_INIT:
+		break;
+	case SWITCH_ABC_TYPE_CLOSE:
+		switch_core_file_close(fh);
+	case SWITCH_ABC_TYPE_READ:
+		if (fh) {
+			switch_size_t len;
+
+			if (switch_core_media_bug_read(bug, &frame) == SWITCH_STATUS_SUCCESS) {
+				len = (switch_size_t) frame.datalen / 2;
+				switch_core_file_write(fh, frame.data, &len);
+			}
+		}
+		break;
+	case SWITCH_ABC_TYPE_WRITE:
+		break;
+	}
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_session_t *session, char *file) 
+{
+	switch_media_bug_t *bug;
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+
+	assert(channel != NULL);
+	if ((bug = switch_channel_get_private(channel, file))) {
+		switch_channel_set_private(channel, file, NULL);
+		switch_core_media_bug_remove(session, &bug);
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	return SWITCH_STATUS_FALSE;
+	
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, char *file,  switch_file_handle_t *fh)
+{
+	switch_channel_t *channel;
+	switch_codec_t *read_codec;
+	char *p;
+	const char *vval;
+	switch_media_bug_t *bug;
+	switch_status_t status;
+
+	if (!fh) {
+		if (!(fh = switch_core_session_alloc(session, sizeof(*fh)))) {
+			return SWITCH_STATUS_MEMERR;
+		}
+	}
+
+	channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+    read_codec = switch_core_session_get_read_codec(session);
+    assert(read_codec != NULL);
+
+    fh->channels = read_codec->implementation->number_of_channels;
+    fh->samplerate = read_codec->implementation->samples_per_second;
+
+
+    if (switch_core_file_open(fh,
+                              file,
+                              SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT,
+                              switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+        switch_core_session_reset(session);
+        return SWITCH_STATUS_GENERR;
+    }
+
+    switch_channel_answer(channel);
+
+	if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) {
+		vval = (const char *) switch_core_session_strdup(session, p);
+		switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_TITLE, vval);
+		switch_channel_set_variable(channel, "RECORD_TITLE", NULL);
+	}
+
+	if ((p = switch_channel_get_variable(channel, "RECORD_COPYRIGHT"))) {
+		vval = (const char *) switch_core_session_strdup(session, p);
+		switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, vval);
+		switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL);
+	}
+
+	if ((p = switch_channel_get_variable(channel, "RECORD_SOFTWARE"))) {
+		vval = (const char *) switch_core_session_strdup(session, p);
+		switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, vval);
+		switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL);
+	}
+
+	if ((p = switch_channel_get_variable(channel, "RECORD_ARTIST"))) {
+		vval = (const char *) switch_core_session_strdup(session, p);
+		switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, vval);
+		switch_channel_set_variable(channel, "RECORD_ARTIST", NULL);
+	}
+
+	if ((p = switch_channel_get_variable(channel, "RECORD_COMMENT"))) {
+		vval = (const char *) switch_core_session_strdup(session, p);
+		switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, vval);
+		switch_channel_set_variable(channel, "RECORD_COMMENT", NULL);
+	}
+
+	if ((p = switch_channel_get_variable(channel, "RECORD_DATE"))) {
+		vval = (const char *) switch_core_session_strdup(session, p);
+		switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval);
+		switch_channel_set_variable(channel, "RECORD_DATE", NULL);
+	}
+
+	
+
+	if ((status = switch_core_media_bug_add(session,
+											record_callback,
+											fh,
+											&bug)) != SWITCH_STATUS_SUCCESS) {
+		switch_core_file_close(fh);
+		return status;
+	}
+
+	switch_channel_set_private(channel, file, bug);
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
 SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *session, 
 												   switch_file_handle_t *fh,
 												   char *file,



More information about the Freeswitch-svn mailing list