Пример #1
0
static void handle_video_event(struct iax_event *e, int callNo)
{
	struct iaxc_call *call;

	if ( callNo < 0 )
		return;

	if ( e->datalen == 0 )
	{
		iaxci_usermsg(IAXC_STATUS, "Received 0-size packet. Unable to decode.");
		return;
	}

	call = &calls[callNo];

	if ( callNo != selected_call )
	{
		/* drop video for unselected call? */
		return;
	}

	if ( call->vformat )
	{
		if ( video_recv_video(call, selected_call, e->data,
					e->datalen, e->ts, call->vformat) < 0 )
		{
			iaxci_usermsg(IAXC_STATUS,
				"Bad or incomplete video packet. Unable to decode.");
			return;
		}
	}
}
Пример #2
0
static THREADFUNCDECL(main_proc_thread_func)
{
	const int sleep_ms = 5;
	const int counts_per_second = 1000 / sleep_ms;
	static int refresh_registration_count = 0;
	static int audio_error_count = 0;
	static int audio_error_state = 0;

	THREADFUNCRET(ret);

	/* Increase Priority */
	iaxci_prioboostbegin();

	while ( !main_proc_thread_flag )
	{
		get_iaxc_lock();

		service_network();

		if ( !test_mode &&
				(!audio_error_state ||
				 audio_error_count++ % counts_per_second == 0) )
		{
			/* There are cases when service audio fails such
			 * as when there is no audio devices present in
			 * the system. In these cases, only call
			 * service_audio() once per second until it
			 * succeeds.
			 */
			if ( (audio_error_state = service_audio()) )
			{
				iaxci_usermsg(IAXC_NOTICE,
						"failed to service audio");

				if ( audio_error_count / counts_per_second == 5 )
					iaxci_usermsg(IAXC_TEXT_TYPE_FATALERROR,
							"cannot open audio device"
							" after several tries");
			}
		}

		// Check registration refresh once a second
		if ( refresh_registration_count++ > counts_per_second )
		{
			iaxc_refresh_registrations();
			refresh_registration_count = 0;
		}

		put_iaxc_lock();

		iaxc_millisleep(sleep_ms);
	}

	/* Decrease priority */
	iaxci_prioboostend();

	main_proc_thread_flag = -1;

	return ret;
}
Пример #3
0
static void service_network()
{
	struct iax_event *e = 0;
	int callNo;
	struct iaxc_registration *reg;

	while ( (e = iax_get_event(0)) )
	{
#ifdef WIN32
		iaxc_millisleep(0); //fd:
#endif
		// first, see if this is an event for one of our calls.
		callNo = iaxc_find_call_by_session(e->session);
		if ( e->etype == IAX_EVENT_NULL )
		{
			// Should we do something here?
			// Right now we do nothing, just go with the flow
			// and let the event be deallocated.
		} else if ( callNo >= 0 )
		{
			iaxc_handle_network_event(e, callNo);
		} else if ( (reg = iaxc_find_registration_by_session(e->session)) != NULL )
		{
			iaxc_handle_regreply(e,reg);
		} else if ( e->etype == IAX_EVENT_REGACK || e->etype == IAX_EVENT_REGREJ )
		{
			iaxci_usermsg(IAXC_ERROR, "Unexpected registration reply");
		} else if ( e->etype == IAX_EVENT_REGREQ )
		{
			iaxci_usermsg(IAXC_ERROR,
					"Registration requested by someone, but we don't understand!");
		} else if ( e->etype == IAX_EVENT_CONNECT )
		{
			iaxc_handle_connect(e);
		} else if ( e->etype == IAX_EVENT_TIMEOUT )
		{
			iaxci_usermsg(IAXC_STATUS,
					"Timeout for a non-existant session. Dropping",
					e->etype);
		} else
		{
			iaxci_usermsg(IAXC_STATUS,
					"Event (type %d) for a non-existant session. Dropping",
					e->etype);
		}
		iax_event_free(e);
	}
}
Пример #4
0
void iaxci_do_audio_callback(int callNo, unsigned int ts, int source,
		int encoded, int format, int size, unsigned char *data)
{
	iaxc_event e;

	e.type = IAXC_EVENT_AUDIO;
	e.ev.audio.ts = ts;
	e.ev.audio.encoded = encoded;
	assert(source == IAXC_SOURCE_REMOTE || source == IAXC_SOURCE_LOCAL);
	e.ev.audio.source = source;
	e.ev.audio.size = size;
	e.ev.audio.callNo = callNo;
	e.ev.audio.format = format;

	e.ev.audio.data = (unsigned char *)malloc(size);

	if ( !e.ev.audio.data )
	{
		iaxci_usermsg(IAXC_ERROR,
				"failed to allocate memory for audio event");
		return;
	}

	memcpy(e.ev.audio.data, data, size);

	iaxci_post_event(e);
}
Пример #5
0
static void iaxc_refresh_registrations()
{
	struct iaxc_registration *cur;
	struct timeval now;

	now = iax_tvnow();

	for ( cur = registrations; cur != NULL; cur = cur->next )
	{
		// If there is less than three seconds before the registration is about
		// to expire, renew it.
		if ( iaxci_usecdiff(&now, &cur->last) > (cur->refresh - 3) * 1000 *1000 )
		{
			if ( cur->session != NULL )
			{
				iax_destroy( cur->session );
			}
			cur->session = iax_session_new();
			if ( !cur->session )
			{
				iaxci_usermsg(IAXC_ERROR, "Can't make new registration session");
				return;
			}
			iax_register(cur->session, cur->host, cur->user, cur->pass, cur->refresh);
			cur->last = now;
		}
	}
}
Пример #6
0
static void iaxc_dump_one_call(int callNo)
{
	if ( callNo < 0 )
		return;
	if ( calls[callNo].state == IAXC_CALL_STATE_FREE )
		return;

	iax_hangup(calls[callNo].session,"Dumped Call");
	iaxci_usermsg(IAXC_STATUS, "Hanging up call %d", callNo);
	iaxc_clear_call(callNo);
}
Пример #7
0
static void jb_warnf(const char *fmt, ...)
{
	va_list args;
	char buf[1024];

	va_start(args, fmt);
	vsnprintf(buf, 1024, fmt, args);
	va_end(args);

	iaxci_usermsg(IAXC_NOTICE, buf);
}
Пример #8
0
EXPORT int iaxc_register_ex(const char * user, const char * pass, const char * host, int refresh)
{
	struct iaxc_registration *newreg;

	newreg = (struct iaxc_registration *)malloc(sizeof (struct iaxc_registration));
	if ( !newreg )
	{
		iaxci_usermsg(IAXC_ERROR, "Can't make new registration");
		return -1;
	}

	get_iaxc_lock();
	newreg->session = iax_session_new();
	if ( !newreg->session )
	{
		iaxci_usermsg(IAXC_ERROR, "Can't make new registration session");
		put_iaxc_lock();
		return -1;
	}

	newreg->last = iax_tvnow();
	newreg->refresh = refresh;  

	strncpy(newreg->host, host, 256);
	strncpy(newreg->user, user, 256);
	strncpy(newreg->pass, pass, 256);

	/* send out the initial registration with refresh seconds */
	iax_register(newreg->session, host, user, pass, refresh);

	/* add it to the list; */
	newreg->id = ++next_registration_id;
	newreg->next = registrations;
	registrations = newreg;

	put_iaxc_lock();
	return newreg->id;
}
Пример #9
0
/* XXX Locking??  Start/stop audio?? */
EXPORT int iaxc_select_call(int callNo)
{
	// continue if already selected?
	//if ( callNo == selected_call ) return;

	if ( callNo >= max_calls )
	{
		iaxci_usermsg(IAXC_ERROR, "Error: tried to select out_of_range call %d", callNo);
		return -1;
	}

	// callNo < 0 means no call selected (i.e. all on hold)
	if ( callNo < 0 )
	{
		if ( selected_call >= 0 )
		{
			calls[selected_call].state &= ~IAXC_CALL_STATE_SELECTED;
		}
		selected_call = callNo;
		return 0;
	}

	// de-select and notify the old call if not also the new call
	if ( callNo != selected_call )
	{
		if ( selected_call >= 0 )
		{
			calls[selected_call].state &= ~IAXC_CALL_STATE_SELECTED;
			iaxci_do_state_callback(selected_call);
		}
		selected_call = callNo;
		calls[selected_call].state |= IAXC_CALL_STATE_SELECTED;
	}

	// if it's an incoming call, and ringing, answer it.
	if ( !(calls[selected_call].state & IAXC_CALL_STATE_OUTGOING) &&
	      (calls[selected_call].state & IAXC_CALL_STATE_RINGING) )
	{
		iaxc_answer_call(selected_call);
	} else
	{
		// otherwise just update state (answer does this for us)
		iaxci_do_state_callback(selected_call);
	}

	return 0;
}
Пример #10
0
static void iaxc_handle_connect(struct iax_event * e)
{
#ifdef USE_VIDEO
	int video_format_capability;
	int video_format_preferred;
#endif
	int video_format = 0;
	int format = 0;
	int callno;

	callno = iaxc_first_free_call();

	if ( callno < 0 )
	{
		iaxci_usermsg(IAXC_STATUS,
				"%i \n Incoming Call, but no appearances",
				callno);
		// XXX Reject this call!, or just ignore?
		//iax_reject(e->session, "Too many calls, we're busy!");
		iax_accept(e->session, audio_format_preferred & e->ies.capability);
		iax_busy(e->session);
		return;
	}

	/* negotiate codec */
	/* first, try _their_ preferred format */
	format = audio_format_capability & e->ies.format;
	if ( !format )
	{
		/* then, try our preferred format */
		format = audio_format_preferred & e->ies.capability;
	}

	if ( !format )
	{
		/* finally, see if we have one in common */
		format = audio_format_capability & e->ies.capability;

		/* now choose amongst these, if we got one */
		if ( format )
		{
			format = iaxc_choose_codec(format);
		}
	}

	if ( !format )
	{
		iax_reject(e->session, "Could not negotiate common codec");
		return;
	}

#ifdef USE_VIDEO
	iaxc_video_format_get_cap(&video_format_preferred,
			&video_format_capability);

	/* first, see if they even want video */
	video_format = (e->ies.format & IAXC_VIDEO_FORMAT_MASK);

	if ( video_format )
	{
		/* next, try _their_ preferred format */
		video_format &= video_format_capability;

		if ( !video_format )
		{
			/* then, try our preferred format */
			video_format = video_format_preferred &
				(e->ies.capability & IAXC_VIDEO_FORMAT_MASK);
		}

		if ( !video_format )
		{
			/* finally, see if we have one in common */
			video_format = video_format_capability &
				(e->ies.capability & IAXC_VIDEO_FORMAT_MASK);

			/* now choose amongst these, if we got one */
			if ( video_format )
			{
				video_format = iaxc_choose_codec(video_format);
			}
		}

		/* All video negotiations failed, then warn */
		if ( !video_format )
		{
			iaxci_usermsg(IAXC_NOTICE,
					"Notice: could not negotiate common video codec");
			iaxci_usermsg(IAXC_NOTICE,
					"Notice: switching to audio-only call");
		}
	}
#endif	/* USE_VIDEO */

	calls[callno].vformat = video_format;
	calls[callno].format = format;

	if ( e->ies.called_number )
		strncpy(calls[callno].local, e->ies.called_number,
				IAXC_EVENT_BUFSIZ);
	else
		strncpy(calls[callno].local, "unknown",
				IAXC_EVENT_BUFSIZ);

	if ( e->ies.called_context )
		strncpy(calls[callno].local_context, e->ies.called_context,
				IAXC_EVENT_BUFSIZ);
	else
		strncpy(calls[callno].local_context, "",
				IAXC_EVENT_BUFSIZ);

	if ( e->ies.calling_number )
		strncpy(calls[callno].remote, e->ies.calling_number,
				IAXC_EVENT_BUFSIZ);
	else
		strncpy(calls[callno].remote, "unknown",
				IAXC_EVENT_BUFSIZ);

	if ( e->ies.calling_name )
		strncpy(calls[callno].remote_name, e->ies.calling_name,
				IAXC_EVENT_BUFSIZ);
	else
		strncpy(calls[callno].remote_name, "unknown",
				IAXC_EVENT_BUFSIZ);

	iaxc_note_activity(callno);
	iaxci_usermsg(IAXC_STATUS, "Call from (%s)", calls[callno].remote);

	codec_destroy( callno );

	calls[callno].session = e->session;
	calls[callno].state = IAXC_CALL_STATE_ACTIVE|IAXC_CALL_STATE_RINGING;

	iax_accept(calls[callno].session, format | video_format);
	iax_ring_announce(calls[callno].session);

	iaxci_do_state_callback(callno);

	iaxci_usermsg(IAXC_STATUS, "Incoming call on line %d", callno);
}
Пример #11
0
EXPORT int iaxc_initialize(int num_calls)
{
	int i;
	int port;

	os_init();

	setup_jb_output();

	MUTEXINIT(&iaxc_lock);
	MUTEXINIT(&event_queue_lock);

	iaxc_set_audio_prefs(0);

	if ( iaxc_recvfrom != (iaxc_recvfrom_t)recvfrom )
		iax_set_networking(iaxc_sendto, iaxc_recvfrom);

	/* Note that iax_init() only sets up the receive port when the
	 * sendto/recvfrom functions have not been replaced. We need
	 * to call iaxc_init in either case because there is other
	 * initialization beyond the socket setup that needs to be done.
	 */
	if ( (port = iax_init(source_udp_port)) < 0 )
	{
		iaxci_usermsg(IAXC_ERROR,
				"Fatal error: failed to initialize iax with port %d",
				port);
		return -1;
	}

	if ( iaxc_recvfrom == (iaxc_recvfrom_t)recvfrom )
		iaxci_bound_port = port;
	else
		iaxci_bound_port = -1;

	/* tweak the jitterbuffer settings */
	iax_set_jb_target_extra( jb_target_extra );

	max_calls = num_calls;
	/* initialize calls */
	if ( max_calls <= 0 )
		max_calls = 1; /* 0 == Default? */

	/* calloc zeroes for us */
	calls = (struct iaxc_call *)calloc(sizeof(struct iaxc_call), max_calls);
	if ( !calls )
	{
		iaxci_usermsg(IAXC_ERROR, "Fatal error: can't allocate memory");
		return -1;
	}

	selected_call = -1;

	for ( i = 0; i < max_calls; i++ )
	{
		strncpy(calls[i].callerid_name,   DEFAULT_CALLERID_NAME,   IAXC_EVENT_BUFSIZ);
		strncpy(calls[i].callerid_number, DEFAULT_CALLERID_NUMBER, IAXC_EVENT_BUFSIZ);
	}

	if ( !test_mode )
	{
#ifndef AUDIO_ALSA
		if ( pa_initialize(&audio_driver, 8000) )
		{
			iaxci_usermsg(IAXC_ERROR, "failed pa_initialize");
			return -1;
		}
#else
		/* TODO: It is unknown whether this stuff for direct access to
		* alsa should be left in iaxclient. We're leaving it in here for
		* the time being, but unless it becomes clear that someone cares
		* about having it, it will be removed. Also note that portaudio
		* is capable of using alsa. This is another reason why this
		* direct alsa access may be unneeded.
		*/
		if ( alsa_initialize(&audio_driver, 8000) )
			return -1;
#endif
	}
#ifdef USE_VIDEO
	if ( video_initialize() )
		iaxci_usermsg(IAXC_ERROR,
				"iaxc_initialize: cannot initialize video!\n");
#endif

	/* Default audio format capabilities */
	audio_format_capability =
	    IAXC_FORMAT_ULAW |
	    IAXC_FORMAT_ALAW |
#ifdef CODEC_GSM
	    IAXC_FORMAT_GSM |
#endif
	    IAXC_FORMAT_SPEEX;
	audio_format_preferred = IAXC_FORMAT_SPEEX;

	return 0;
}
Пример #12
0
EXPORT int iaxc_initialize(int num_calls)
{
    printf("ESTOY IAXC 0\n");
	int i;
	int port;

	os_init();

	setup_jb_output();

	MUTEXINIT(&iaxc_lock);
	MUTEXINIT(&event_queue_lock);

	iaxc_set_audio_prefs(0);

	if ( iaxc_recvfrom != (iaxc_recvfrom_t)recvfrom )
		iax_set_networking(iaxc_sendto, iaxc_recvfrom);

	/* Note that iax_init() only sets up the receive port when the
	 * sendto/recvfrom functions have not been replaced. We need
	 * to call iaxc_init in either case because there is other
	 * initialization beyond the socket setup that needs to be done.
	 */
	if ( (port = iax_init(source_udp_port)) < 0 )
	{
		iaxci_usermsg(IAXC_ERROR,
				"Fatal error: failed to initialize iax with port %d",
				port);
		return -1;
	}

	if ( iaxc_recvfrom == (iaxc_recvfrom_t)recvfrom )
		iaxci_bound_port = port;
	else
		iaxci_bound_port = -1;

	/* tweak the jitterbuffer settings */
	iax_set_jb_target_extra( jb_target_extra );

	max_calls = num_calls;
	/* initialize calls */
	if ( max_calls <= 0 )
		max_calls = 1; /* 0 == Default? */

	/* calloc zeroes for us */
	calls = (struct iaxc_call *)calloc(sizeof(struct iaxc_call), max_calls);
	if ( !calls )
	{
		iaxci_usermsg(IAXC_ERROR, "Fatal error: can't allocate memory");
		return -1;
	}

	selected_call = -1;

	for ( i = 0; i < max_calls; i++ )
	{
		strncpy(calls[i].callerid_name,   DEFAULT_CALLERID_NAME,   IAXC_EVENT_BUFSIZ);
		strncpy(calls[i].callerid_number, DEFAULT_CALLERID_NUMBER, IAXC_EVENT_BUFSIZ);
	}
    printf("ESTOY IAXC\n");

    if ( alsa_initialize(&audio_driver, 8000) )
    {
        iaxci_usermsg(IAXC_ERROR, "failed alsa_initialize");
        return -1;
    }
#ifdef USE_VIDEO
	if ( video_initialize() )
		iaxci_usermsg(IAXC_ERROR,
				"iaxc_initialize: cannot initialize video!\n");
#endif

	/* Default audio format capabilities */
	audio_format_capability =
	    IAXC_FORMAT_ULAW |
	    IAXC_FORMAT_ALAW |
#ifdef CODEC_GSM
	    IAXC_FORMAT_GSM |
#endif
	    IAXC_FORMAT_SPEEX;
	audio_format_preferred = IAXC_FORMAT_SPEEX;

	return 0;
}
Пример #13
0
// Post Events back to clients
void iaxci_post_event(iaxc_event e)
{
	if ( e.type == 0 )
	{
		iaxci_usermsg(IAXC_ERROR,
			"Error: something posted to us an invalid event");
		return;
	}

	if ( MUTEXTRYLOCK(&iaxc_lock) )
	{
		iaxc_event **tail;

		/* We could not obtain the lock. Queue the event. */
		MUTEXLOCK(&event_queue_lock);
		tail = &event_queue;
		e.next = NULL;
		while ( *tail )
			tail = &(*tail)->next;
		*tail = (iaxc_event *)malloc(sizeof(iaxc_event));
		memcpy(*tail, &e, sizeof(iaxc_event));
		MUTEXUNLOCK(&event_queue_lock);
		return;
	}

	/* TODO: This is not the best. Since we were able to get the
	 * lock, we decide that it is okay to go ahead and do the
	 * callback to the application. This is really nasty because
	 * it gives the appearance of serialized callbacks, but in
	 * reality, we could callback an application multiple times
	 * simultaneously. So, as things stand, an application must
	 * do some locking in their callback function to make it
	 * reentrant. Barf. More ideally, iaxclient would guarantee
	 * serialized callbacks to the application.
	 */
	MUTEXUNLOCK(&iaxc_lock);

	if ( iaxc_event_callback )
	{
		int rv;

		rv = iaxc_event_callback(e);

		if ( e.type == IAXC_EVENT_VIDEO )
		{
			/* We can free the frame data once it is off the
			 * event queue and has been processed by the client.
			 */
			free(e.ev.video.data);
		}
		else if ( e.type == IAXC_EVENT_AUDIO )
		{
			free(e.ev.audio.data);
		}

		if ( rv < 0 )
			default_message_callback(
				"IAXCLIENT: BIG PROBLEM, event callback returned failure!");
		// > 0 means processed
		if ( rv > 0 )
			return;

		// else, fall through to "defaults"
	}

	switch ( e.type )
	{
		case IAXC_EVENT_TEXT:
			default_message_callback(e.ev.text.message);
			// others we just ignore too
			return;
	}
}
Пример #14
0
static void handle_audio_event(struct iax_event *e, int callNo)
{
	int total_consumed = 0;
	short fr[4096];
	const int fr_samples = sizeof(fr) / sizeof(short);
	int samples, format;
#ifdef WIN32
	int cycles_max = 100; //fd:
#endif
	struct iaxc_call *call;

	if ( callNo < 0 )
		return;

	call = &calls[callNo];

	if ( callNo != selected_call )
	{
	    /* drop audio for unselected call? */
	    return;
	}

	if ( audio_prefs & IAXC_AUDIO_PREF_RECV_DISABLE)
	{
	    /* just drop silently incoming audio frames */	
	    return;
	}

	samples = fr_samples;
	format = call->format & IAXC_AUDIO_FORMAT_MASK;

	do
	{
		int bytes_decoded;

		int mainbuf_delta = fr_samples - samples;

		bytes_decoded = audio_decode_audio(call,
				fr,
				e->data + total_consumed,
				e->datalen - total_consumed,
				format,
				&samples);

		if ( bytes_decoded < 0 )
		{
			iaxci_usermsg(IAXC_STATUS,
				"Bad or incomplete voice packet. Unable to decode. dropping");
			return;
		}

		/* Pass encoded audio back to the app if required */
		if ( audio_prefs & IAXC_AUDIO_PREF_RECV_REMOTE_ENCODED )
			iaxci_do_audio_callback(callNo, e->ts, IAXC_SOURCE_REMOTE,
					1, format & IAXC_AUDIO_FORMAT_MASK,
					e->datalen - total_consumed,
					e->data + total_consumed);

#ifdef WIN32
		//fd: start: for some reason it loops here. Try to avoid it
		cycles_max--;
		if ( cycles_max < 0 )
		{
			iaxc_millisleep(0);
		}
		//fd: end
#endif
		total_consumed += bytes_decoded;
		if ( audio_prefs & IAXC_AUDIO_PREF_RECV_REMOTE_RAW )
		{
			// audio_decode_audio returns the number of samples.
			// We are using 16 bit samples, so we need to double
			// the number to obtain the size in bytes.
			// format will also be 0 since this is raw audio
			int size = (fr_samples - samples - mainbuf_delta) * 2;
			iaxci_do_audio_callback(callNo, e->ts, IAXC_SOURCE_REMOTE,
					0, 0, size, (unsigned char *)fr);
		}

		if ( iaxci_audio_output_mode )
			continue;

		if (!test_mode)
			audio_driver.output(&audio_driver, fr,
			    fr_samples - samples - mainbuf_delta);

	} while ( total_consumed < e->datalen );
}
Пример #15
0
static void iaxc_handle_network_event(struct iax_event *e, int callNo)
{
	if ( callNo < 0 )
		return;

	iaxc_note_activity(callNo);

	switch ( e->etype )
	{
	case IAX_EVENT_NULL:
		break;
	case IAX_EVENT_HANGUP:
		iaxci_usermsg(IAXC_STATUS, "Call disconnected by remote");
		// XXX does the session go away now?
		iaxc_clear_call(callNo);
		break;
	case IAX_EVENT_REJECT:
		iaxci_usermsg(IAXC_STATUS, "Call rejected by remote");
		iaxc_clear_call(callNo);
		break;
	case IAX_EVENT_ACCEPT:
		calls[callNo].format = e->ies.format & IAXC_AUDIO_FORMAT_MASK;
		calls[callNo].vformat = e->ies.format & IAXC_VIDEO_FORMAT_MASK;
		if ( !(e->ies.format & IAXC_VIDEO_FORMAT_MASK) )
		{
			iaxci_usermsg(IAXC_NOTICE,
					"Failed video codec negotiation.");
		}
		iaxci_usermsg(IAXC_STATUS,"Call %d accepted", callNo);
		break;
	case IAX_EVENT_ANSWER:
		calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;
		calls[callNo].state |= IAXC_CALL_STATE_COMPLETE;
		iaxci_do_state_callback(callNo);
		iaxci_usermsg(IAXC_STATUS,"Call %d answered", callNo);
		//iaxc_answer_call(callNo);
		// notify the user?
		break;
	case IAX_EVENT_BUSY:
		calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;
		calls[callNo].state |= IAXC_CALL_STATE_BUSY;
		iaxci_do_state_callback(callNo);
		iaxci_usermsg(IAXC_STATUS, "Call %d busy", callNo);
		break;
	case IAX_EVENT_VOICE:
		handle_audio_event(e, callNo);
		if ( (calls[callNo].state & IAXC_CALL_STATE_OUTGOING) &&
		     (calls[callNo].state & IAXC_CALL_STATE_RINGING) )
		{
			calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;
			calls[callNo].state |= IAXC_CALL_STATE_COMPLETE;
			iaxci_do_state_callback(callNo);
			iaxci_usermsg(IAXC_STATUS,"Call %d progress",
				     callNo);
		}
		break;
#ifdef USE_VIDEO
	case IAX_EVENT_VIDEO:
		handle_video_event(e, callNo);
		break;
#endif
	case IAX_EVENT_TEXT:
		handle_text_event(e, callNo);
		break;
	case IAX_EVENT_RINGA:
		calls[callNo].state |= IAXC_CALL_STATE_RINGING;
		iaxci_do_state_callback(callNo);
		iaxci_usermsg(IAXC_STATUS,"Call %d ringing", callNo);
		break;
	case IAX_EVENT_PONG:
		generate_netstat_event(callNo);
		break;
	case IAX_EVENT_URL:
		handle_url_event(e, callNo);
		break;
	case IAX_EVENT_CNG:
		/* ignore? */
		break;
	case IAX_EVENT_TIMEOUT:
		iax_hangup(e->session, "Call timed out");
		iaxci_usermsg(IAXC_STATUS, "Call %d timed out.", callNo);
		iaxc_clear_call(callNo);
		break;
	case IAX_EVENT_TRANSFER:
		calls[callNo].state |= IAXC_CALL_STATE_TRANSFER;
		iaxci_do_state_callback(callNo);
		iaxci_usermsg(IAXC_STATUS,"Call %d transfer released", callNo);
		break;
	case IAX_EVENT_DTMF:
		iaxci_do_dtmf_callback(callNo,e->subclass);
		iaxci_usermsg(IAXC_STATUS, "DTMF digit %c received", e->subclass);
        	break;
	default:
		iaxci_usermsg(IAXC_STATUS, "Unknown event: %d for call %d", e->etype, callNo);
		break;
	}
}
Пример #16
0
static int service_audio()
{
	/* TODO: maybe we shouldn't allocate 8kB on the stack here. */
	short buf [4096];

	int want_send_audio =
		selected_call >= 0 &&
		((calls[selected_call].state & IAXC_CALL_STATE_OUTGOING) ||
		 (calls[selected_call].state & IAXC_CALL_STATE_COMPLETE));
		//&& !(audio_prefs & IAXC_AUDIO_PREF_SEND_DISABLE);

	int want_local_audio =
		(audio_prefs & IAXC_AUDIO_PREF_RECV_LOCAL_RAW) ||
		(audio_prefs & IAXC_AUDIO_PREF_RECV_LOCAL_ENCODED);

	//fprintf(stdout, "service_audio() => want_send_audio=%d/want_local_audio=%d\n", want_send_audio, want_local_audio);

	if ( want_local_audio || want_send_audio )
	{
		for ( ;; )
		{
			int to_read;
			int cmin;

			audio_driver.start(&audio_driver);

			/* use codec minimum if higher */
			cmin = want_send_audio && calls[selected_call].encoder ?
				calls[selected_call].encoder->minimum_frame_size :
				1;

			to_read = cmin > minimum_outgoing_framesize ?
				cmin : minimum_outgoing_framesize;

			/* Round up to the next multiple */
			if ( to_read % cmin )
				to_read += cmin - (to_read % cmin);

			if ( to_read > (int)(sizeof(buf) / sizeof(short)) )
			{
				fprintf(stderr,
					"internal error: to_read > sizeof(buf)\n");
				exit(1);
			}

			/* Currently pa gives us either all the bits we ask for or none */
			if ( audio_driver.input(&audio_driver, buf, &to_read) )
			{
				iaxci_usermsg(IAXC_ERROR, "ERROR reading audio\n");
				break;
			}

			/* Frame was not available */
			if ( !to_read )
				break;

			if ( audio_prefs & IAXC_AUDIO_PREF_RECV_LOCAL_RAW )
				iaxci_do_audio_callback(selected_call, 0,
						IAXC_SOURCE_LOCAL, 0, 0,
						to_read * 2, (unsigned char *)buf);

			if (( want_send_audio ) && (!(audio_prefs & IAXC_AUDIO_PREF_SEND_DISABLE)))
				audio_send_encoded_audio(&calls[selected_call],
						selected_call, buf,
						calls[selected_call].format &
							IAXC_AUDIO_FORMAT_MASK,
						to_read);
		}
	}
	else
	{
		static int i = 0;

		audio_driver.stop(&audio_driver);

		/*!
			\deprecated
			Q: Why do we continuously send IAXC_EVENT_LEVELS events
		   when there is no selected call?

		 A: So that certain users of iaxclient do not have to
		   reset their vu meters when a call ends -- they can just
		   count on getting level callbacks. This is a bit of a hack
		   so any applications relying on this behavior should maybe
		   be changed.
		 */
		if ( i++ % 50 == 0 )
			iaxci_do_levels_callback(AUDIO_ENCODE_SILENCE_DB,
					AUDIO_ENCODE_SILENCE_DB);
	}

	return 0;
}
Пример #17
0
EXPORT int iaxc_call_ex(const char *num, const char* callerid_name, const char* callerid_number, int video)
{
	int video_format_capability = 0;
	int video_format_preferred = 0;
	int callNo = -1;
	struct iax_session *newsession;
	char *ext = strstr(num, "/");

	get_iaxc_lock();

	// if no call is selected, get a new appearance
	if ( selected_call < 0 )
	{
		callNo = iaxc_first_free_call();
	} else
	{
		// use selected call if not active, otherwise, get a new appearance
		if ( calls[selected_call].state  & IAXC_CALL_STATE_ACTIVE )
		{
			callNo = iaxc_first_free_call();
		} else
		{
			callNo = selected_call;
		}
	}

	if ( callNo < 0 )
	{
		iaxci_usermsg(IAXC_STATUS, "No free call appearances");
		goto iaxc_call_bail;
	}

	newsession = iax_session_new();
	if ( !newsession )
	{
		iaxci_usermsg(IAXC_ERROR, "Can't make new session");
		goto iaxc_call_bail;
	}

	calls[callNo].session = newsession;

	codec_destroy( callNo );

	if ( ext )
	{
		strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ);
		strncpy(calls[callNo].remote,    ++ext, IAXC_EVENT_BUFSIZ);
	} else
	{
		strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ);
		strncpy(calls[callNo].remote,      "" , IAXC_EVENT_BUFSIZ);
	}

	if ( callerid_number != NULL )
		strncpy(calls[callNo].callerid_number, callerid_number, IAXC_EVENT_BUFSIZ);

	if ( callerid_name != NULL )
		strncpy(calls[callNo].callerid_name, callerid_name, IAXC_EVENT_BUFSIZ);

	strncpy(calls[callNo].local        , calls[callNo].callerid_name, IAXC_EVENT_BUFSIZ);
	strncpy(calls[callNo].local_context, "default", IAXC_EVENT_BUFSIZ);

	calls[callNo].state = IAXC_CALL_STATE_ACTIVE | IAXC_CALL_STATE_OUTGOING;

	/* reset activity and ping "timers" */
	iaxc_note_activity(callNo);
	calls[callNo].last_ping = calls[callNo].last_activity;

#ifdef USE_VIDEO
	if ( video )
		iaxc_video_format_get_cap(&video_format_preferred, &video_format_capability);
#endif

	iaxci_usermsg(IAXC_NOTICE, "Originating an %s call",
			video_format_preferred ? "audio+video" : "audio only");
	iax_call(calls[callNo].session, calls[callNo].callerid_number,
			calls[callNo].callerid_name, num, NULL, 0,
			audio_format_preferred | video_format_preferred,
			audio_format_capability | video_format_capability);

	// does state stuff also
	iaxc_select_call(callNo);

iaxc_call_bail:
	put_iaxc_lock();

	return callNo;
}
Пример #18
0
struct iaxc_video_codec *codec_video_ffmpeg_new(int format, int w, int h,
						     int framerate, int bitrate,
						     int fragsize)
{
	struct encoder_ctx *e;
	struct decoder_ctx *d;
	AVCodec *codec;
	int ff_enc_id, ff_dec_id;
	char *name;

	struct iaxc_video_codec *c = calloc(sizeof(struct iaxc_video_codec), 1);

	if (!c)
	{
		fprintf(stderr,
			"codec_ffmpeg: failed to allocate video context\n");
		return NULL;
	}

	avcodec_init();
	avcodec_register_all();

	c->format = format;
	c->width = w;
	c->height = h;
	c->framerate = framerate;
	c->bitrate = bitrate;
	/* TODO: Is a fragsize of zero valid? If so, there's a divide
	 * by zero error to contend with.
	 */
	c->fragsize = fragsize;

	c->encode = encode;
	c->decode = decode_iaxc_slice;
	c->destroy = destroy;

	c->encstate = calloc(sizeof(struct encoder_ctx), 1);
	if (!c->encstate)
		goto bail;
	e = c->encstate;
	e->avctx = avcodec_alloc_context();
	if (!e->avctx)
		goto bail;
	e->picture = avcodec_alloc_frame();
	if (!e->picture)
		goto bail;
	/* The idea here is that the encoded frame that will land in this
	 * buffer will be no larger than the size of an uncompressed 32-bit
	 * rgb frame.
	 *
	 * TODO: Is this assumption really valid?
	 */
	e->frame_buf_len = w * h * 4;
	e->frame_buf = malloc(e->frame_buf_len);
	if (!e->frame_buf)
		goto bail;

	c->decstate = calloc(sizeof(struct decoder_ctx), 1);
	if (!c->decstate)
		goto bail;
	d = c->decstate;
	d->avctx = avcodec_alloc_context();
	if (!d->avctx)
		goto bail;
	d->picture = avcodec_alloc_frame();
	if (!d->picture)
		goto bail;
	d->frame_buf_len = e->frame_buf_len;
	d->frame_buf = malloc(d->frame_buf_len);
	if (!d->frame_buf)
		goto bail;

	e->slice_header.version = 0;
	srandom(time(0));
	e->slice_header.source_id = random() & 0xffff;

	e->avctx->time_base.num = 1;
	e->avctx->time_base.den = framerate;

	e->avctx->width = w;
	e->avctx->height = h;

	e->avctx->bit_rate = bitrate;

	/* This determines how often i-frames are sent */
	e->avctx->gop_size = framerate * 3;
	e->avctx->pix_fmt = PIX_FMT_YUV420P;
	e->avctx->has_b_frames = 0;

	e->avctx->mb_qmin = e->avctx->qmin = 10;
	e->avctx->mb_qmax = e->avctx->qmax = 10;

	e->avctx->lmin = 2 * FF_QP2LAMBDA;
	e->avctx->lmax = 10 * FF_QP2LAMBDA;
	e->avctx->global_quality = FF_QP2LAMBDA * 2;
	e->avctx->qblur = 0.5;
	e->avctx->global_quality = 10;

	e->avctx->flags |= CODEC_FLAG_PSNR;
	e->avctx->flags |= CODEC_FLAG_QSCALE;

	e->avctx->mb_decision = FF_MB_DECISION_SIMPLE;

	ff_enc_id = ff_dec_id = map_iaxc_codec_to_avcodec(format);

	/* Note, when fragsize is used (non-zero) ffmpeg will use a "best
	 * effort" strategy: the fragment size will be fragsize +/- 20%
	 */

	switch (format)
	{

	case IAXC_FORMAT_H261:
		/* TODO: H261 only works with specific resolutions. */
		name = "H.261";
		break;

	case IAXC_FORMAT_H263:
		/* TODO: H263 only works with specific resolutions. */
		name = "H.263";
		e->avctx->flags |= CODEC_FLAG_AC_PRED;
		if (fragsize)
		{
			c->decode = decode_rtp_slice;
			e->avctx->rtp_payload_size = fragsize;
			e->avctx->flags |=
				CODEC_FLAG_TRUNCATED | CODEC_FLAG2_STRICT_GOP;
			e->avctx->rtp_callback = encode_rtp_callback;
			d->avctx->flags |= CODEC_FLAG_TRUNCATED;
		}
		break;

	case IAXC_FORMAT_H263_PLUS:
		/* Although the encoder is CODEC_ID_H263P, the decoder
		 * is the regular h.263, so we handle this special case
		 * here.
		 */
		ff_dec_id = CODEC_ID_H263;
		name = "H.263+";
		e->avctx->flags |= CODEC_FLAG_AC_PRED;
		if (fragsize)
		{
			c->decode = decode_rtp_slice;
			e->avctx->rtp_payload_size = fragsize;
			e->avctx->flags |=
				CODEC_FLAG_TRUNCATED |
				CODEC_FLAG_H263P_SLICE_STRUCT |
				CODEC_FLAG2_STRICT_GOP |
				CODEC_FLAG2_LOCAL_HEADER;
			e->avctx->rtp_callback = encode_rtp_callback;
			d->avctx->flags |= CODEC_FLAG_TRUNCATED;
		}
		break;

	case IAXC_FORMAT_MPEG4:
		name = "MPEG4";
		c->decode = decode_rtp_slice;
		e->avctx->rtp_payload_size = fragsize;
		e->avctx->rtp_callback = encode_rtp_callback;
		e->avctx->flags |=
			CODEC_FLAG_TRUNCATED |
			CODEC_FLAG_H263P_SLICE_STRUCT |
			CODEC_FLAG2_STRICT_GOP |
			CODEC_FLAG2_LOCAL_HEADER;

		d->avctx->flags |= CODEC_FLAG_TRUNCATED;
		break;

	case IAXC_FORMAT_H264:
		name = "H.264";

		/*
		 * Encoder flags
		 */

		/* Headers are not repeated */
		/* e->avctx->flags |= CODEC_FLAG_GLOBAL_HEADER; */

		/* Slower, less blocky */
		/* e->avctx->flags |= CODEC_FLAG_LOOP_FILTER; */

		e->avctx->flags |= CODEC_FLAG_PASS1;
		/* e->avctx->flags |= CODEC_FLAG_PASS2; */

		/* Compute psnr values at encode-time (avctx->error[]) */
		/* e->avctx->flags |= CODEC_FLAG_PSNR; */

		/* e->avctx->flags2 |= CODEC_FLAG2_8X8DCT; */

		/* Access Unit Delimiters */
		e->avctx->flags2 |= CODEC_FLAG2_AUD;

		/* Allow b-frames to be used as reference */
		/* e->avctx->flags2 |= CODEC_FLAG2_BPYRAMID; */

		/* b-frame rate distortion optimization */
		/* e->avctx->flags2 |= CODEC_FLAG2_BRDO; */

		/* e->avctx->flags2 |= CODEC_FLAG2_FASTPSKIP; */

		/* Multiple references per partition */
		/* e->avctx->flags2 |= CODEC_FLAG2_MIXED_REFS; */

		/* Weighted biprediction for b-frames */
		/* e->avctx->flags2 |= CODEC_FLAG2_WPRED; */

		/*
		 * Decoder flags
		 */

		/* Do not draw edges */
		/* d->avctx->flags |= CODEC_FLAG_EMU_EDGE; */

		/* Decode grayscale only */
		/* d->avctx->flags |= CODEC_FLAG_GRAY; */

		/* d->avctx->flags |= CODEC_FLAG_LOW_DELAY; */

		/* Allow input bitstream to be randomly truncated */
		/* d->avctx->flags |= CODEC_FLAG_TRUNCATED; */

		/* Allow out-of-spec speed tricks */
		/* d->avctx->flags2 |= CODEC_FLAG2_FAST; */
		break;

	case IAXC_FORMAT_THEORA:
		/* TODO: ffmpeg only has a theora decoder. Until it has
		 * an encoder also, we cannot use ffmpeg for theora.
		 */
		name = "Theora";
		break;

	default:
		fprintf(stderr, "codec_ffmpeg: unsupported format (0x%08x)\n",
				format);
		goto bail;
	}

	strcpy(c->name, "ffmpeg-");
	strncat(c->name, name, sizeof(c->name));

	/* Get the codecs */
	codec = avcodec_find_encoder(ff_enc_id);
	if (!codec)
	{
		iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
			     "codec_ffmpeg: cannot find encoder %d\n",
			     ff_enc_id);
		goto bail;
	}

	if (avcodec_open(e->avctx, codec))
	{
		iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
			     "codec_ffmpeg: cannot open encoder %s\n", name);
		goto bail;
	}

	codec = avcodec_find_decoder(ff_dec_id);
	if (!codec)
	{
		iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
			     "codec_ffmpeg: cannot find decoder %d\n",
			     ff_dec_id);
		goto bail;
	}
	if (avcodec_open(d->avctx, codec))
	{
		iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
			     "codec_ffmpeg: cannot open decoder %s\n", name);
		goto bail;
	}

	{
		enum PixelFormat fmts[] = { PIX_FMT_YUV420P, -1 };
		if (d->avctx->get_format(d->avctx, fmts) != PIX_FMT_YUV420P)
		{
			iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
					"codec_ffmpeg: cannot set decode format to YUV420P\n");
			goto bail;
		}
	}

	return c;

bail:
	destroy(c);
	return 0;
}
Пример #19
0
EXPORT int iaxc_call_ex(const char *num, const char* callerid_name, const char* callerid_number, int video)
{
	int video_format_capability = 0;
	int video_format_preferred = 0;
	int callNo = -1;
	struct iax_session *newsession;
	char *ext = strstr(num, "/");

	get_iaxc_lock();

	// if no call is selected, get a new appearance
	if ( selected_call < 0 )
	{
		callNo = iaxc_first_free_call();
	} else
	{
		// use selected call if not active, otherwise, get a new appearance
		if ( calls[selected_call].state & IAXC_CALL_STATE_ACTIVE )
		{
			callNo = iaxc_first_free_call();
		} else
		{
			callNo = selected_call;
		}
	}

	if ( callNo < 0 )
	{
		iaxci_usermsg(IAXC_STATUS, "No free call appearances");
		goto iaxc_call_bail;
	}

	newsession = iax_session_new();
	if ( !newsession )
	{
		iaxci_usermsg(IAXC_ERROR, "Can't make new session");
		goto iaxc_call_bail;
	}

	calls[callNo].session = newsession;

	codec_destroy( callNo );

	/* When the ACCEPT comes back from the other-end, these formats
	 * are set. Whether the format is set or not determines whether
	 * we are in the Linked state (see the iax2 rfc).
	 * These will have already been cleared by iaxc_clear_call(),
	 * but we reset them anyway just to be pedantic.
	 */
	calls[callNo].format = 0;
	calls[callNo].vformat = 0;

	if ( ext )
	{
		strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ);
		strncpy(calls[callNo].remote,    ++ext, IAXC_EVENT_BUFSIZ);
	} else
	{
		strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ);
		strncpy(calls[callNo].remote,      "" , IAXC_EVENT_BUFSIZ);
	}

	if ( callerid_number != NULL )
		strncpy(calls[callNo].callerid_number, callerid_number, IAXC_EVENT_BUFSIZ);

	if ( callerid_name != NULL )
		strncpy(calls[callNo].callerid_name, callerid_name, IAXC_EVENT_BUFSIZ);

	strncpy(calls[callNo].local        , calls[callNo].callerid_name, IAXC_EVENT_BUFSIZ);
	strncpy(calls[callNo].local_context, "default", IAXC_EVENT_BUFSIZ);

	calls[callNo].state = IAXC_CALL_STATE_OUTGOING;

	/* reset activity and ping "timers" */
	iaxc_note_activity(callNo);
	calls[callNo].last_ping = calls[callNo].last_activity;

#ifdef USE_VIDEO
	if ( video )
		iaxc_video_format_get_cap(&video_format_preferred, &video_format_capability);
#endif

	iaxci_usermsg(IAXC_NOTICE, "Originating an %s call",
			video_format_preferred ? "audio+video" : "audio only");
	iax_call(calls[callNo].session, calls[callNo].callerid_number,
			calls[callNo].callerid_name, num, NULL, 0,
			audio_format_preferred | video_format_preferred,
			audio_format_capability | video_format_capability);

	// does state stuff also
	iaxc_select_call(callNo);

iaxc_call_bail:
	put_iaxc_lock();

	return callNo;
}