Exemple #1
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 );
}
Exemple #2
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;
}
Exemple #3
0
int audio_send_encoded_audio(struct iaxc_call *call, int callNo, void *data,
		int format, int samples)
{
	unsigned char outbuf[1024];
	int outsize = 1024;
	int silent;
	int insize = samples;

	/* update last input timestamp */
	timeLastInput = iax_tvnow();

	silent = input_postprocess(data, insize, 8000);

	if(silent)
	{
		if(!call->tx_silent)
		{  /* send a Comfort Noise Frame */
			call->tx_silent = 1;
			if ( iaxci_filters & IAXC_FILTER_CN )
				iax_send_cng(call->session, 10, NULL, 0);
		}
		return 0;  /* poof! no encoding! */
	}

	/* we're going to send voice now */
	call->tx_silent = 0;

	/* destroy encoder if it is incorrect type */
	if(call->encoder && call->encoder->format != format)
	{
		call->encoder->destroy(call->encoder);
		call->encoder = NULL;
	}

	/* just break early if there's no format defined: this happens for the
	 * first couple of frames of new calls */
	if(format == 0) return 0;

	/* create encoder if necessary */
	if(!call->encoder)
	{
		call->encoder = create_codec(format);
	}

	if(!call->encoder)
	{
		/* ERROR: no codec */
		fprintf(stderr, "ERROR: Codec could not be created: %d\n", format);
		return 0;
	}

	if(call->encoder->encode(call->encoder, &insize, (short *)data,
				&outsize, outbuf))
	{
		/* ERROR: codec error */
		fprintf(stderr, "ERROR: encode error: %d\n", format);
		return 0;
	}

	if(samples-insize == 0)
	{
		fprintf(stderr, "ERROR encoding (no samples output (samples=%d)\n", samples);
		return -1;
	}

	// Send the encoded audio data back to the app if required
	// TODO: fix the stupid way in which the encoded audio size is returned
	if ( iaxc_get_audio_prefs() & IAXC_AUDIO_PREF_RECV_LOCAL_ENCODED )
		iaxci_do_audio_callback(callNo, 0, IAXC_SOURCE_LOCAL, 1,
				call->encoder->format & IAXC_AUDIO_FORMAT_MASK,
				sizeof(outbuf) - outsize, outbuf);

	if(iax_send_voice(call->session,format, outbuf,
				sizeof(outbuf) - outsize, samples-insize) == -1)
	{
		fprintf(stderr, "Failed to send voice! %s\n", iax_errstr);
		return -1;
	}

	return 0;
}