Exemplo n.º 1
0
static switch_status_t do_write_video(switch_file_handle_t *handle, switch_frame_t *frame)
{
	uint32_t datalen = frame->datalen;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int is_iframe = 0;
	uint8_t *hdr = NULL;
	uint8_t start_bit;
	uint32_t used;
	bool is_key = false;
	webm_file_context_t *context = (webm_file_context_t *)handle->private_info;

	hdr = (uint8_t *)frame->data;

	switch_assert(frame->img);

	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x | len:%d m:%d st:%d i:%d\n", hdr[0], hdr[1], hdr[2], datalen, frame->m, start_bit, is_iframe);

	

	if (!context->video) {
		context->video_track_id = context->segment->AddVideoTrack(frame->img->d_w, frame->img->d_h, 0);
		if (!context->video_track_id) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add video track!\n");
			switch_goto_status(SWITCH_STATUS_FALSE, end);
		}
		context->video = static_cast<mkvmuxer::VideoTrack*>(context->segment->GetTrackByNumber(context->video_track_id));
		context->video->SetStereoMode(0);
		context->video->set_codec_id("V_VP8");
		context->video->set_uid(0xDEADBEEF); // debug ?
	}

	buffer_vp8_packets(context, frame, &is_key);

	if (frame->m && (used = switch_buffer_inuse(context->buf))) {
		const void *data;
		int duration = 0;

		
		switch_buffer_peek_zerocopy(context->buf, &data);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VID samplecount: %u\n", context->timer.samplecount);

		switch_mutex_lock(context->mutex);
		switch_core_timer_sync(&context->timer);
		bool ret = false;
		ret = context->segment->AddFrame((const uint8_t *)data, used, context->video_track_id, context->timer.samplecount * 1000LL, is_key);
		switch_mutex_unlock(context->mutex);

		if (!ret) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add frame %d bytes, timecode: %llu\n", used, context->timer.samplecount * 1000LL);
			switch_goto_status(SWITCH_STATUS_FALSE, end);
		}

		switch_buffer_zero(context->buf);
	}

end:
	

	return status;
}
static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t *frame)
{
	uint8_t *data = (uint8_t *)frame->data;
	uint8_t *vp9  = (uint8_t *)frame->data;
	int len = 0;

	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x %02x %d %d\n", *data, *(data+1), *(data+2), *(data+3), frame->m, frame->datalen);

	if (switch_buffer_inuse(context->vpx_packet_buffer)) { // middle packet
		if (IS_VP9_START_PKT(*vp9)) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "got invalid vp9 packet, packet loss? resetting buffer\n");
			switch_buffer_zero(context->vpx_packet_buffer);
		}
	} else { // start packet
		if (!IS_VP9_START_PKT(*vp9)) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "got invalid vp9 packet, packet loss? waiting for a start packet\n");
			goto end;
		}
	}

	vp9 = data + 1;

	len = frame->datalen - (vp9 - data);
	switch_buffer_write(context->vpx_packet_buffer, vp9, len);

end:
	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffered %d bytes, buffer size: %" SWITCH_SIZE_T_FMT "\n", len, switch_buffer_inuse(context->vpx_packet_buffer));

	return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void) switch_core_media_bug_inuse(switch_media_bug_t *bug, switch_size_t *readp, switch_size_t *writep)
{
	if (switch_test_flag(bug, SMBF_READ_STREAM)) {
		switch_mutex_lock(bug->read_mutex);
		*readp = bug->raw_read_buffer ? switch_buffer_inuse(bug->raw_read_buffer) : 0;
		switch_mutex_unlock(bug->read_mutex);
	} else {
		*readp = 0;
	}

	if (switch_test_flag(bug, SMBF_WRITE_STREAM)) {
		switch_mutex_lock(bug->write_mutex);
		*writep = bug->raw_write_buffer ? switch_buffer_inuse(bug->raw_write_buffer) : 0;
		switch_mutex_unlock(bug->write_mutex);
	} else {
		*writep = 0;
	}
}
Exemplo n.º 4
0
static switch_status_t rtmp_tcp_write(rtmp_session_t *rsession, const unsigned char *buf, switch_size_t *len)
{
	//rtmp_io_tcp_t *io = (rtmp_io_tcp_t*)rsession->profile->io;
	rtmp_tcp_io_private_t *io_pvt = rsession->io_private;
	switch_status_t status;
	switch_size_t orig_len = *len;	
	
#ifdef RTMP_DEBUG_IO
	{
		int i;
		fprintf(rsession->io_debug_out,
			"SEND %"SWITCH_SIZE_T_FMT" bytes\n> ", *len);

		for (i = 0; i < *len; i++) {
			fprintf(rsession->io_debug_out, "%02X ", (uint8_t)buf[i]);
				
			if (i != 0 && i % 32 == 0) {
				fprintf(rsession->io_debug_out, "\n> ");
			}
		}
		fprintf(rsession->io_debug_out, "\n\n ");
		
		fflush(rsession->io_debug_out);
	}
#endif
	
	if (io_pvt->sendq && switch_buffer_inuse(io_pvt->sendq) > 0) {
		/* We already have queued data, append it to the sendq */
		switch_buffer_write(io_pvt->sendq, buf, *len);
		return SWITCH_STATUS_SUCCESS;
	}
	
	status = switch_socket_send_nonblock(io_pvt->socket, (char*)buf, len);
	
	if (*len > 0 && *len < orig_len) {
		
		if (rsession->state >= RS_DESTROY) {
			return SWITCH_STATUS_FALSE;
		}
		
		/* We didnt send it all... add it to the sendq*/		
		switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG, "%"SWITCH_SIZE_T_FMT" bytes added to sendq.\n", (orig_len - *len));
		
		switch_buffer_write(io_pvt->sendq, (buf + *len), orig_len - *len);

		/* Make sure we poll-write */
		rtmp_tcp_alter_pollfd(rsession, SWITCH_TRUE);
	}
	
	return status;
}
Exemplo n.º 5
0
static switch_status_t shout_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
{
	shout_context_t *context = handle->private_info;

	if (handle->handler || switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
		return SWITCH_STATUS_FALSE;
	} else {
		if (whence == SWITCH_SEEK_CUR) {
			samples -= switch_buffer_inuse(context->audio_buffer) / sizeof(int16_t);
		}

		switch_buffer_zero(context->audio_buffer);
		*cur_sample = mpg123_seek(context->mh, (off_t) samples, whence);

		return *cur_sample >= 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
	}
}
Exemplo n.º 6
0
static switch_status_t vlc_file_close(switch_file_handle_t *handle)
{
	vlc_file_context_t *context = handle->private_info;
	int sanity = 0;	
	
	context->playing = 0;
	
	/* The clients need to empty the last of the audio buffer */
	while ( switch_buffer_inuse(context->audio_buffer) > 0 ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC waiting to close the files: %d \n", (int) switch_buffer_inuse(context->audio_buffer));
		switch_yield(500000);
		if (++sanity > 10) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Giving up waiting for client to empty the audio buffer\n");
			break;
		}
	}

	/* Let the clients get the last of the audio stream */
	sanity = 0;
	while ( 3 == libvlc_media_get_state(context->m) ) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC waiting for clients: %d \n", libvlc_media_get_state(context->m));
		switch_yield(500000); 
                if (++sanity > 10) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Giving up waiting for client to get the last of the audio stream\n");
                        break;
		}
	}

	if( context->mp ) 
		libvlc_media_player_stop(context->mp);
	
	if( context->m ) 
		libvlc_media_release(context->m);
	
	if ( context->inst_out != NULL )
		libvlc_release(context->inst_out);

	return SWITCH_STATUS_SUCCESS;
}
Exemplo n.º 7
0
static void decode_fd(shout_context_t *context, void *data, size_t bytes)
{
	int decode_status = 0;
	size_t usedlen;

	while (!context->err && !context->eof && switch_buffer_inuse(context->audio_buffer) < bytes) {
		usedlen = 0;

		decode_status = mpg123_read(context->mh, context->decode_buf, sizeof(context->decode_buf), &usedlen);

		if (decode_status == MPG123_NEW_FORMAT) {
			continue;
		} else if (decode_status == MPG123_OK) {
			;
		} else if (decode_status == MPG123_DONE || decode_status == MPG123_NEED_MORE) {
			context->eof++;
		} else if (decode_status == MPG123_ERR || decode_status > 0) {
			if (++context->mp3err >= 5) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error!\n");
				context->eof++;
				goto error;
			}
			continue;
		}

		context->mp3err = 0;

		switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
	}

	return;

  error:
	switch_mutex_lock(context->audio_mutex);
	context->err++;
	switch_mutex_unlock(context->audio_mutex);
}
Exemplo n.º 8
0
SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags,
															   int stream_id)
{
	switch_io_event_hook_read_frame_t *ptr;
	switch_status_t status = SWITCH_STATUS_FALSE;
	int need_codec, perfect, do_bugs = 0, do_resample = 0, is_cng = 0;
	switch_codec_implementation_t codec_impl;
	unsigned int flag = 0;

	switch_assert(session != NULL);


	if (switch_mutex_trylock(session->codec_read_mutex) == SWITCH_STATUS_SUCCESS) {
		switch_mutex_unlock(session->codec_read_mutex);
	} else {
		switch_cond_next();
		*frame = &runtime.dummy_cng_frame;
		return SWITCH_STATUS_SUCCESS;
	}

	if (!(session->read_codec && session->read_codec->implementation && switch_core_codec_ready(session->read_codec))) {
		if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_get_state(session->channel) == CS_HIBERNATE) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s reading on a session with no media!\n",
							  switch_channel_get_name(session->channel));
			switch_cond_next();
			*frame = &runtime.dummy_cng_frame;
			return SWITCH_STATUS_SUCCESS;
		}
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no read codec.\n", switch_channel_get_name(session->channel));
		switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
		return SWITCH_STATUS_FALSE;
	}

	switch_mutex_lock(session->codec_read_mutex);

	if (!switch_core_codec_ready(session->read_codec)) {
		switch_mutex_unlock(session->codec_read_mutex);
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no read codec.\n", switch_channel_get_name(session->channel));
		switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
		*frame = &runtime.dummy_cng_frame;
        return SWITCH_STATUS_FALSE;
	}

	switch_mutex_lock(session->read_codec->mutex);

  top:
	
	if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) {
		switch_ivr_dmachine_ping(session->dmachine, NULL);
	}
	
	if (switch_channel_down(session->channel) || !switch_core_codec_ready(session->read_codec)) {
		*frame = NULL;
		status = SWITCH_STATUS_FALSE;
		goto even_more_done;
	}


	status = SWITCH_STATUS_FALSE;
	need_codec = perfect = 0;

	*frame = NULL;

	if (session->read_codec && !session->track_id && session->track_duration) {
		if (session->read_frame_count == 0) {
			switch_event_t *event;
			session->read_frame_count = (session->read_impl.actual_samples_per_second / session->read_impl.samples_per_packet) * session->track_duration;

			switch_event_create(&event, SWITCH_EVENT_SESSION_HEARTBEAT);
			switch_channel_event_set_data(session->channel, event);
			switch_event_fire(&event);
		} else {
			session->read_frame_count--;
		}
	}


	if (switch_channel_test_flag(session->channel, CF_HOLD)) {
		switch_yield(session->read_impl.microseconds_per_packet);
		status = SWITCH_STATUS_BREAK;
		goto even_more_done;
	}

	if (session->endpoint_interface->io_routines->read_frame) {
		switch_mutex_unlock(session->read_codec->mutex);
		switch_mutex_unlock(session->codec_read_mutex);
		if ((status = session->endpoint_interface->io_routines->read_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
			for (ptr = session->event_hooks.read_frame; ptr; ptr = ptr->next) {
				if ((status = ptr->read_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
					break;
				}
			}
		}

		if (!SWITCH_READ_ACCEPTABLE(status) || !session->read_codec || !switch_core_codec_ready(session->read_codec)) {
			*frame = NULL;
			return SWITCH_STATUS_FALSE;
		}

		switch_mutex_lock(session->codec_read_mutex);

		if (!switch_core_codec_ready(session->read_codec)) {
			switch_mutex_unlock(session->codec_read_mutex);
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no read codec.\n", switch_channel_get_name(session->channel));
			switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
			*frame = &runtime.dummy_cng_frame;
			return SWITCH_STATUS_FALSE;
		}

		switch_mutex_lock(session->read_codec->mutex);
		if (!switch_core_codec_ready(session->read_codec)) {
			*frame = NULL;
			status = SWITCH_STATUS_FALSE;
			goto even_more_done;			
		}

	}

	if (status != SWITCH_STATUS_SUCCESS) {
		goto done;
	}

	if (!(*frame)) {
		goto done;
	}

	switch_assert(*frame != NULL);

	if (switch_test_flag(*frame, SFF_PROXY_PACKET)) {
		/* Fast PASS! */
		status = SWITCH_STATUS_SUCCESS;
		goto done;
	}

	if (switch_test_flag(*frame, SFF_CNG)) {
		status = SWITCH_STATUS_SUCCESS;
		if (!session->bugs && !session->plc) {
			goto done;
		}
		is_cng = 1;
	}

	switch_assert((*frame)->codec != NULL);

	if (!(session->read_codec && (*frame)->codec && (*frame)->codec->implementation) && switch_core_codec_ready((*frame)->codec)) {
		status = SWITCH_STATUS_FALSE;
		goto done;
	}

	codec_impl = *(*frame)->codec->implementation;

	if (session->read_codec->implementation->impl_id != codec_impl.impl_id) {
		need_codec = TRUE;
	} 
	
	if (codec_impl.actual_samples_per_second != session->read_impl.actual_samples_per_second) {
		do_resample = 1;
	}

	if (session->bugs && !need_codec) {
		do_bugs = 1;
		need_codec = 1;
	}

	if (switch_test_flag(session, SSF_READ_TRANSCODE) && !need_codec && switch_core_codec_ready(session->read_codec)) {
		switch_core_session_t *other_session;
		const char *uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_SIGNAL_BOND_VARIABLE);
		switch_clear_flag(session, SSF_READ_TRANSCODE);
		
		if (uuid && (other_session = switch_core_session_locate(uuid))) {
			switch_set_flag(other_session, SSF_READ_CODEC_RESET);
			switch_set_flag(other_session, SSF_READ_CODEC_RESET);
			switch_set_flag(other_session, SSF_WRITE_CODEC_RESET);
			switch_core_session_rwunlock(other_session);
		}
	}

	if (switch_test_flag(session, SSF_READ_CODEC_RESET)) {
		switch_core_codec_reset(session->read_codec);
		switch_clear_flag(session, SSF_READ_CODEC_RESET);
	}

	




	if (status == SWITCH_STATUS_SUCCESS && need_codec) {
		switch_frame_t *enc_frame, *read_frame = *frame;

		switch_set_flag(session, SSF_READ_TRANSCODE);

		if (!switch_test_flag(session, SSF_WARN_TRANSCODE)) {
			switch_core_session_message_t msg = { 0 };

			msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY;
			switch_core_session_receive_message(session, &msg);
			switch_set_flag(session, SSF_WARN_TRANSCODE);
		}

		if (read_frame->codec || is_cng) {
			session->raw_read_frame.datalen = session->raw_read_frame.buflen;

			if (is_cng) {
				if (session->plc) {
					plc_fillin(session->plc, session->raw_read_frame.data, read_frame->codec->implementation->decoded_bytes_per_packet / 2);
					is_cng = 0;
					flag &= !SFF_CNG;
				} else {
					memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet);
				}

				session->raw_read_frame.timestamp = 0;
				session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
				session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
				read_frame = &session->raw_read_frame;
				status = SWITCH_STATUS_SUCCESS;
			} else {
				switch_codec_t *use_codec = read_frame->codec;
				if (do_bugs) {
					switch_thread_rwlock_wrlock(session->bug_rwlock);
					if (!session->bugs) {
						do_bugs = 0;
						switch_thread_rwlock_unlock(session->bug_rwlock);
						goto done;
					}

					if (!switch_core_codec_ready(&session->bug_codec)) {
						switch_core_codec_copy(read_frame->codec, &session->bug_codec, NULL);
					}
					use_codec = &session->bug_codec;
					switch_thread_rwlock_unlock(session->bug_rwlock);

					switch_thread_rwlock_wrlock(session->bug_rwlock);
					if (!session->bugs) {
						do_bugs = 0;
					}
					switch_thread_rwlock_unlock(session->bug_rwlock);
					if (!do_bugs) goto done;
				}

				if (switch_test_flag(read_frame, SFF_PLC)) {
					session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
					session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
					memset(session->raw_read_frame.data, 255, session->raw_read_frame.datalen);
					status = SWITCH_STATUS_SUCCESS;
				} else {
					status = switch_core_codec_decode(use_codec,
													  session->read_codec,
													  read_frame->data,
													  read_frame->datalen,
													  session->read_impl.actual_samples_per_second,
													  session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate, 
													  &read_frame->flags);
				}
				
				if (status == SWITCH_STATUS_SUCCESS) {
					if ((switch_channel_test_flag(session->channel, CF_JITTERBUFFER) || switch_channel_test_flag(session->channel, CF_CNG_PLC)) 
						&& !session->plc) {
						session->plc = plc_init(NULL);
					}
				
					if (session->plc) {
						if (switch_test_flag(read_frame, SFF_PLC)) {
							plc_fillin(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2);
							switch_clear_flag(read_frame, SFF_PLC);
						} else {
							plc_rx(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2);
						}
					}
				}


			}

			if (do_resample && ((status == SWITCH_STATUS_SUCCESS) || is_cng)) {
				status = SWITCH_STATUS_RESAMPLE;
			}

			switch (status) {
			case SWITCH_STATUS_RESAMPLE:
				if (!session->read_resampler) {
					switch_mutex_lock(session->resample_mutex);
					status = switch_resample_create(&session->read_resampler,
													read_frame->codec->implementation->actual_samples_per_second,
													session->read_impl.actual_samples_per_second,
													session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1);

					switch_mutex_unlock(session->resample_mutex);

					if (status != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Unable to allocate resampler\n");
						status = SWITCH_STATUS_FALSE;
						goto done;
					}
				}
			case SWITCH_STATUS_SUCCESS:
				session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
				session->raw_read_frame.rate = read_frame->rate;
				if (read_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) {
					session->raw_read_frame.timestamp = 0;
				} else {
					session->raw_read_frame.timestamp = read_frame->timestamp;
				}
				session->raw_read_frame.ssrc = read_frame->ssrc;
				session->raw_read_frame.seq = read_frame->seq;
				session->raw_read_frame.m = read_frame->m;
				session->raw_read_frame.payload = read_frame->payload;
				session->raw_read_frame.flags = 0;
				if (switch_test_flag(read_frame, SFF_PLC)) {
					session->raw_read_frame.flags |= SFF_PLC;
				}
				read_frame = &session->raw_read_frame;
				break;
			case SWITCH_STATUS_NOOP:
				if (session->read_resampler) {
					switch_mutex_lock(session->resample_mutex);
					switch_resample_destroy(&session->read_resampler);
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating read resampler\n");
					switch_mutex_unlock(session->resample_mutex);
				}

				status = SWITCH_STATUS_SUCCESS;
				break;
			case SWITCH_STATUS_BREAK:
				memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet);
				session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
				session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
				session->raw_read_frame.timestamp = read_frame->timestamp;
				session->raw_read_frame.rate = read_frame->rate;
				session->raw_read_frame.ssrc = read_frame->ssrc;
				session->raw_read_frame.seq = read_frame->seq;
				session->raw_read_frame.m = read_frame->m;
				session->raw_read_frame.payload = read_frame->payload;
				session->raw_read_frame.flags = 0;
				if (switch_test_flag(read_frame, SFF_PLC)) {
					session->raw_read_frame.flags |= SFF_PLC;
				}

				read_frame = &session->raw_read_frame;
				status = SWITCH_STATUS_SUCCESS;
				break;
			case SWITCH_STATUS_NOT_INITALIZED:
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n");
				goto done;
			default:
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error!\n",
								  session->read_codec->codec_interface->interface_name);
				goto done;
			}
		}

		if (session->bugs) {
			switch_media_bug_t *bp;
			switch_bool_t ok = SWITCH_TRUE;
			int prune = 0;
			switch_thread_rwlock_rdlock(session->bug_rwlock);

			for (bp = session->bugs; bp; bp = bp->next) {
				if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
					continue;
				}

				if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
					continue;
				}
				if (switch_test_flag(bp, SMBF_PRUNE)) {
					prune++;
					continue;
				}

				if (bp->ready && switch_test_flag(bp, SMBF_READ_STREAM)) {
					switch_mutex_lock(bp->read_mutex);
					switch_buffer_write(bp->raw_read_buffer, read_frame->data, read_frame->datalen);
					if (bp->callback) {
						ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ);
					}
					switch_mutex_unlock(bp->read_mutex);
				}

				if (ok && switch_test_flag(bp, SMBF_READ_REPLACE)) {
					do_bugs = 0;
					if (bp->callback) {
						bp->read_replace_frame_in = read_frame;
						bp->read_replace_frame_out = read_frame;
						if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_REPLACE)) == SWITCH_TRUE) {
							read_frame = bp->read_replace_frame_out;
						}
					}
				}

				if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) {
					switch_set_flag(bp, SMBF_PRUNE);
					prune++;
				}


			}
			switch_thread_rwlock_unlock(session->bug_rwlock);
			if (prune) {
				switch_core_media_bug_prune(session);
			}
		}

		if (do_bugs) {
			goto done;
		}

		if (session->read_codec) {
			if (session->read_resampler) {
				short *data = read_frame->data;
				switch_mutex_lock(session->resample_mutex);
				switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2);
				memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2);
				read_frame->samples = session->read_resampler->to_len;
				read_frame->datalen = session->read_resampler->to_len * 2;
				read_frame->rate = session->read_resampler->to_rate;
				switch_mutex_unlock(session->resample_mutex);
			}

			if (read_frame->datalen == session->read_impl.decoded_bytes_per_packet) {
				perfect = TRUE;
			} else {
				if (!session->raw_read_buffer) {
					switch_size_t bytes = session->read_impl.decoded_bytes_per_packet;
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Engaging Read Buffer at %u bytes vs %u\n",
									  (uint32_t) bytes, (uint32_t) (*frame)->datalen);
					switch_buffer_create_dynamic(&session->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES, bytes * SWITCH_BUFFER_START_FRAMES, 0);
				}

				if (!switch_buffer_write(session->raw_read_buffer, read_frame->data, read_frame->datalen)) {
					status = SWITCH_STATUS_MEMERR;
					goto done;
				}
			}

			if (perfect || switch_buffer_inuse(session->raw_read_buffer) >= session->read_impl.decoded_bytes_per_packet) {
				if (perfect) {
					enc_frame = read_frame;
					session->raw_read_frame.rate = read_frame->rate;
				} else {
					session->raw_read_frame.datalen = (uint32_t) switch_buffer_read(session->raw_read_buffer,
																					session->raw_read_frame.data,
																					session->read_impl.decoded_bytes_per_packet);

					session->raw_read_frame.rate = session->read_impl.actual_samples_per_second;
					enc_frame = &session->raw_read_frame;
				}
				session->enc_read_frame.datalen = session->enc_read_frame.buflen;

				switch_assert(session->read_codec != NULL);
				switch_assert(enc_frame != NULL);
				switch_assert(enc_frame->data != NULL);

				status = switch_core_codec_encode(session->read_codec,
												  enc_frame->codec,
												  enc_frame->data,
												  enc_frame->datalen,
												  session->read_impl.actual_samples_per_second,
												  session->enc_read_frame.data, &session->enc_read_frame.datalen, &session->enc_read_frame.rate, &flag);

				switch (status) {
				case SWITCH_STATUS_RESAMPLE:
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 1\n");
				case SWITCH_STATUS_SUCCESS:
					session->enc_read_frame.samples = session->read_impl.decoded_bytes_per_packet / sizeof(int16_t);
					if (perfect) {
						if (enc_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) {
							session->enc_read_frame.timestamp = 0;
						} else {
							session->enc_read_frame.timestamp = read_frame->timestamp;
						}
						session->enc_read_frame.rate = read_frame->rate;
						session->enc_read_frame.ssrc = read_frame->ssrc;
						session->enc_read_frame.seq = read_frame->seq;
						session->enc_read_frame.m = read_frame->m;
						session->enc_read_frame.payload = session->read_impl.ianacode;
					}
					*frame = &session->enc_read_frame;
					break;
				case SWITCH_STATUS_NOOP:
					session->raw_read_frame.samples = enc_frame->codec->implementation->samples_per_packet;
					session->raw_read_frame.timestamp = read_frame->timestamp;
					session->raw_read_frame.payload = enc_frame->codec->implementation->ianacode;
					session->raw_read_frame.m = read_frame->m;
					session->raw_read_frame.ssrc = read_frame->ssrc;
					session->raw_read_frame.seq = read_frame->seq;
					*frame = enc_frame;
					status = SWITCH_STATUS_SUCCESS;
					break;
				case SWITCH_STATUS_NOT_INITALIZED:
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n");
					*frame = NULL;
					status = SWITCH_STATUS_GENERR;
					break;
				default:
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error!\n",
									  session->read_codec->codec_interface->interface_name);
					*frame = NULL;
					status = SWITCH_STATUS_GENERR;
					break;
				}
			} else {
				goto top;
			}
		}
	}

  done:
	if (!(*frame)) {
		status = SWITCH_STATUS_FALSE;
	} else {
		if (flag & SFF_CNG) {
			switch_set_flag((*frame), SFF_CNG);
		}
		if (session->bugs) {
			switch_media_bug_t *bp;
			switch_bool_t ok = SWITCH_TRUE;
			int prune = 0;
			switch_thread_rwlock_rdlock(session->bug_rwlock);
			for (bp = session->bugs; bp; bp = bp->next) {
				if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
					continue;
				}

				if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
					continue;
				}

				if (switch_test_flag(bp, SMBF_PRUNE)) {
					prune++;
					continue;
				}

				if (bp->ready && switch_test_flag(bp, SMBF_READ_PING)) {
					switch_mutex_lock(bp->read_mutex);
					if (bp->callback) {
						if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_PING) == SWITCH_FALSE
							|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
							ok = SWITCH_FALSE;
						}
					}
					switch_mutex_unlock(bp->read_mutex);
				}

				if (ok == SWITCH_FALSE) {
					switch_set_flag(bp, SMBF_PRUNE);
					prune++;
				}
			}
			switch_thread_rwlock_unlock(session->bug_rwlock);
			if (prune) {
				switch_core_media_bug_prune(session);
			}
		}
	}

  even_more_done:

	if (!*frame || !(*frame)->codec || !(*frame)->codec->implementation || !switch_core_codec_ready((*frame)->codec)) {
		*frame = &runtime.dummy_cng_frame;
	}

	switch_mutex_unlock(session->read_codec->mutex);
	switch_mutex_unlock(session->codec_read_mutex);

	return status;
}
Exemplo n.º 9
0
void *SWITCH_THREAD_FUNC rtmp_io_tcp_thread(switch_thread_t *thread, void *obj)
{
	rtmp_io_tcp_t *io = (rtmp_io_tcp_t*)obj;
	io->base.running = 1;
	
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: I/O Thread starting\n", io->base.profile->name);
	
	
	while(io->base.running) {
		const switch_pollfd_t *fds;
		int32_t numfds;
		int32_t i;
		switch_status_t status;
		
		switch_mutex_lock(io->mutex);
		status = switch_pollset_poll(io->pollset, 500000, &numfds, &fds);
		switch_mutex_unlock(io->mutex);
		
		if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_TIMEOUT) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "pollset_poll failed\n");
			continue;
		} else if (status == SWITCH_STATUS_TIMEOUT) {
			switch_cond_next();
		}
		
		for (i = 0; i < numfds; i++) {
			if (!fds[i].client_data) { 
				switch_socket_t *newsocket;
				if (switch_socket_accept(&newsocket, io->listen_socket, io->base.pool) != SWITCH_STATUS_SUCCESS) {
					if (io->base.running) {
						/* Don't spam the logs if we are shutting down */
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error [%s]\n", strerror(errno));	
					} else {
						return NULL;
					}
				} else {
					rtmp_session_t *rsession;
					
					if (switch_socket_opt_set(newsocket, SWITCH_SO_NONBLOCK, TRUE)) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't set socket as non-blocking\n");
					}

					if (switch_socket_opt_set(newsocket, SWITCH_SO_TCP_NODELAY, 1)) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't disable Nagle.\n");
					}
					
					if (rtmp_session_request(io->base.profile, &rsession) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTMP session request failed\n");
						switch_socket_close(newsocket);
					} else {
						switch_sockaddr_t *addr = NULL;
						char ipbuf[200];
						
						/* Create out private data and attach it to the rtmp session structure */
						rtmp_tcp_io_private_t *pvt = switch_core_alloc(rsession->pool, sizeof(*pvt));
						rsession->io_private = pvt;
						pvt->socket = newsocket;
						switch_socket_create_pollfd(&pvt->pollfd, newsocket, SWITCH_POLLIN | SWITCH_POLLERR, rsession, rsession->pool);
						switch_pollset_add(io->pollset, pvt->pollfd);
						switch_buffer_create_dynamic(&pvt->sendq, 512, 1024, 0);
						
						/* Get the remote address/port info */
						switch_socket_addr_get(&addr, SWITCH_TRUE, newsocket);
						switch_get_addr(ipbuf, sizeof(ipbuf), addr);
						rsession->remote_address = switch_core_strdup(rsession->pool, ipbuf);
						rsession->remote_port = switch_sockaddr_get_port(addr);
						switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Rtmp connection from %s:%i\n",
										  rsession->remote_address, rsession->remote_port);
					}
				}
			} else {
				rtmp_session_t *rsession = (rtmp_session_t*)fds[i].client_data;
				rtmp_tcp_io_private_t *io_pvt = (rtmp_tcp_io_private_t*)rsession->io_private;
				
				if (fds[i].rtnevents & SWITCH_POLLOUT && switch_buffer_inuse(io_pvt->sendq) > 0) {
					/* Send as much remaining data as possible */
					switch_size_t sendlen;
					const void *ptr;
					sendlen = switch_buffer_peek_zerocopy(io_pvt->sendq, &ptr);
					switch_socket_send_nonblock(io_pvt->socket, ptr, &sendlen);
					switch_buffer_toss(io_pvt->sendq, sendlen);
					if (switch_buffer_inuse(io_pvt->sendq) == 0) {
						/* Remove our fd from OUT polling */
						rtmp_tcp_alter_pollfd(rsession, SWITCH_FALSE);
					}
				} else 	if (fds[i].rtnevents & SWITCH_POLLIN && rtmp_handle_data(rsession) != SWITCH_STATUS_SUCCESS) {
					switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG, "Closing socket\n");
					
					switch_mutex_lock(io->mutex);
					switch_pollset_remove(io->pollset, io_pvt->pollfd);
					switch_mutex_unlock(io->mutex);
					
					switch_socket_close(io_pvt->socket);
					io_pvt->socket = NULL;
					
					rtmp_session_destroy(&rsession);
				}
			}
		}
	}
	
	io->base.running = -1;
	switch_socket_close(io->listen_socket);
	
	return NULL;
}
Exemplo n.º 10
0
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
{
	local_stream_source_t *source = obj;
	switch_file_handle_t fh = { 0 };
	local_stream_context_t *cp;
	char file_buf[128] = "", path_buf[512] = "";
	switch_timer_t timer = { 0 };
	int fd = -1;
	switch_buffer_t *audio_buffer;
	switch_byte_t *dist_buf;
	switch_size_t used;
	int skip = 0;
	switch_memory_pool_t *temp_pool = NULL;

	switch_mutex_lock(globals.mutex);
	THREADS++;
	switch_mutex_unlock(globals.mutex);

	if (!source->prebuf) {
		source->prebuf = DEFAULT_PREBUFFER_SIZE;
	}

	switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0);
	dist_buf = switch_core_alloc(source->pool, source->prebuf + 10);

	if (source->shuffle) {
		skip = do_rand();
	}

	switch_thread_rwlock_create(&source->rwlock, source->pool);

	if (RUNNING) {
		switch_mutex_lock(globals.mutex);
		switch_core_hash_insert(globals.source_hash, source->name, source);
		switch_mutex_unlock(globals.mutex);
		source->ready = 1;
	}

	while (RUNNING && !source->stopped) {
		const char *fname;

		if (temp_pool) {
			switch_core_destroy_memory_pool(&temp_pool);
		}

		if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool");
			goto done;
		}

		if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location);
			goto done;
		}

		switch_yield(1000000);

		while (RUNNING) {
			switch_size_t olen;
			uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };

			if (fd > -1) {
				char *p;
				if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
					if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) {
						*p = '\0';
					}
				} else {
					close(fd);
					fd = -1;
					continue;
				}
			} else {
				if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) {
					break;
				}

				switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname);

				if (switch_stristr(".loc", path_buf)) {
					if ((fd = open(path_buf, O_RDONLY)) < 0) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
						switch_yield(1000000);
					}
					continue;
				}
			}

			if (skip > 0) {
				skip--;
				continue;
			}

			fname = path_buf;
			fh.prebuf = source->prebuf;
			fh.pre_buffer_datalen = source->prebuf;

			if (switch_core_file_open(&fh,
									  (char *) fname,
									  source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
				switch_yield(1000000);
				continue;
			}

			if (switch_core_timer_init(&timer, source->timer_name, source->interval, source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n");
				switch_dir_close(source->dir_handle);
				source->dir_handle = NULL;
				goto done;
			}

			while (RUNNING) {
				int is_open;
				switch_file_handle_t *use_fh = &fh;

				switch_core_timer_next(&timer);
				olen = source->samples;

				if (source->chime_total) {

					if (source->chime_counter > 0) {
						source->chime_counter -= source->samples;
					}

					if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) {
						char *val;

						val = source->chime_list[source->chime_cur++];

						if (source->chime_cur >= source->chime_total) {
							source->chime_cur = 0;
						}

						if (switch_core_file_open(&source->chime_fh,
												  (char *) val,
												  source->channels,
												  source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val);
						}
					}

					if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
						use_fh = &source->chime_fh;
					}
				}

			  retry:

				is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN);

				if (is_open) {
					if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
						switch_core_file_close(use_fh);
						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
						}
						is_open = 0;
					} else {
						if (use_fh == &source->chime_fh && source->chime_max) {
							source->chime_max_counter += source->samples;
							if (source->chime_max_counter >= source->chime_max) {
								source->chime_max_counter = 0;
								switch_core_file_close(use_fh);
								source->chime_counter = source->rate * source->chime_freq;
								use_fh = &fh;
								goto retry;
							}
						}

						switch_buffer_write(audio_buffer, abuf, olen * 2);
					}
				}

				used = switch_buffer_inuse(audio_buffer);

				if (!used && !is_open) {
					break;
				}

				if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) {
					used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2);
					if (source->total) {

						switch_mutex_lock(source->mutex);
						for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
							if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
								continue;
							}
							switch_mutex_lock(cp->audio_mutex);
							if (switch_buffer_inuse(cp->audio_buffer) > source->samples * 768) {
								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d]\n", cp->func, cp->file,
												  cp->line);
								switch_buffer_zero(cp->audio_buffer);
							} else {
								switch_buffer_write(cp->audio_buffer, dist_buf, used);
							}
							switch_mutex_unlock(cp->audio_mutex);
						}
						switch_mutex_unlock(source->mutex);
					}
				}
			}

			switch_core_timer_destroy(&timer);
			if (RUNNING && source->shuffle) {
				skip = do_rand();
			}
		}

		switch_dir_close(source->dir_handle);
		source->dir_handle = NULL;
	}

  done:

	if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&fh);
	}

	if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&source->chime_fh);
	}

	source->ready = 0;
	switch_mutex_lock(globals.mutex);
	switch_core_hash_delete(globals.source_hash, source->name);
	switch_mutex_unlock(globals.mutex);

	switch_thread_rwlock_wrlock(source->rwlock);
	switch_thread_rwlock_unlock(source->rwlock);

	switch_buffer_destroy(&audio_buffer);

	if (fd > -1) {
		close(fd);
	}

	if (temp_pool) {
		switch_core_destroy_memory_pool(&temp_pool);
	}

	switch_core_destroy_memory_pool(&source->pool);

	switch_mutex_lock(globals.mutex);
	THREADS--;
	switch_mutex_unlock(globals.mutex);

	return NULL;
}
Exemplo n.º 11
0
/* NB. this starts the input thread after some initial setup for the call leg */
void conference_loop_output(conference_member_t *member)
{
	switch_channel_t *channel;
	switch_frame_t write_frame = { 0 };
	uint8_t *data = NULL;
	switch_timer_t timer = { 0 };
	uint32_t interval;
	uint32_t samples;
	//uint32_t csamples;
	uint32_t tsamples;
	uint32_t flush_len;
	uint32_t low_count, bytes;
	call_list_t *call_list, *cp;
	switch_codec_implementation_t read_impl = { 0 };
	int sanity;
	switch_status_t st;

	switch_core_session_get_read_impl(member->session, &read_impl);


	channel = switch_core_session_get_channel(member->session);
	interval = read_impl.microseconds_per_packet / 1000;
	samples = switch_samples_per_packet(member->conference->rate, interval);
	//csamples = samples;
	tsamples = member->orig_read_impl.samples_per_packet;
	low_count = 0;
	bytes = samples * 2 * member->conference->channels;
	call_list = NULL;
	cp = NULL;

	member->loop_loop = 0;

	switch_assert(member->conference != NULL);

	flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval);

	if (switch_core_timer_init(&timer, member->conference->timer_name, interval, tsamples, NULL) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Timer Setup Failed.  Conference Cannot Start\n");
		return;
	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Setup timer %s success interval: %u  samples: %u\n",
					  member->conference->timer_name, interval, tsamples);


	write_frame.data = data = switch_core_session_alloc(member->session, SWITCH_RECOMMENDED_BUFFER_SIZE);
	write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;


	write_frame.codec = &member->write_codec;

	/* Start the input thread */
	conference_loop_launch_input(member, switch_core_session_get_pool(member->session));

	if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) {
		const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name");
		const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number");
		const char *toval = switch_channel_get_variable(channel, "conference_auto_outcall_timeout");
		const char *flags = switch_channel_get_variable(channel, "conference_utils_auto_outcall_flags");
		const char *profile = switch_channel_get_variable(channel, "conference_auto_outcall_profile");
		const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce");
		const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix");
		const char *maxwait = switch_channel_get_variable(channel, "conference_auto_outcall_maxwait");
		const char *delimiter_val = switch_channel_get_variable(channel, "conference_auto_outcall_delimiter");
		int to = 60;
		int wait_sec = 2;
		int loops = 0;

		if (ann && !switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_REQ)) {
			member->conference->special_announce = switch_core_strdup(member->conference->pool, ann);
		}

		switch_channel_set_private(channel, "_conference_autocall_list_", NULL);

		conference_utils_set_flag(member->conference, CFLAG_OUTCALL);

		if (toval) {
			to = atoi(toval);
			if (to < 10 || to > 500) {
				to = 60;
			}
		}

		for (cp = call_list; cp; cp = cp->next) {
			int argc;
			char *argv[512] = { 0 };
			char *cpstr = strdup(cp->string);
			int x = 0;

			switch_assert(cpstr);
			if (!zstr(delimiter_val) && strlen(delimiter_val) == 1) {
				char delimiter = *delimiter_val;
				argc = switch_separate_string(cpstr, delimiter, argv, (sizeof(argv) / sizeof(argv[0])));
			} else {
				argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
			}
			for (x = 0; x < argc; x++) {
				char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
				switch_assert(dial_str);
				conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL,
									  profile, &member->conference->cancel_cause, NULL);
				switch_safe_free(dial_str);
			}
			switch_safe_free(cpstr);
		}

		if (maxwait) {
			int tmp = atoi(maxwait);
			if (tmp > 0) {
				wait_sec = tmp;
			}
		}


		loops = wait_sec * 10;

		switch_channel_set_app_flag(channel, CF_APP_TAGGED);
		do {
			switch_ivr_sleep(member->session, 100, SWITCH_TRUE, NULL);
		} while(switch_channel_up(channel) && (member->conference->originating && --loops));
		switch_channel_clear_app_flag(channel, CF_APP_TAGGED);

		if (!switch_channel_ready(channel)) {
			member->conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
			goto end;
		}

		conference_member_play_file(member, "tone_stream://%(500,0,640)", 0, SWITCH_TRUE);
	}

	if (!conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) {
		switch_channel_answer(channel);
	}


	sanity = 2000;
	while(!conference_utils_member_test_flag(member, MFLAG_ITHREAD) && sanity > 0) {
		switch_cond_next();
		sanity--;
	}

	/* Fair WARNING, If you expect the caller to hear anything or for digit handling to be processed,      */
	/* you better not block this thread loop for more than the duration of member->conference->timer_name!  */
	while (!member->loop_loop && conference_utils_member_test_flag(member, MFLAG_RUNNING) && conference_utils_member_test_flag(member, MFLAG_ITHREAD)
		   && switch_channel_ready(channel)) {
		switch_event_t *event;
		int use_timer = 0;
		switch_buffer_t *use_buffer = NULL;
		uint32_t mux_used = 0;


		//if (member->reset_media || switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) {
		//	switch_cond_next();
		//	continue;
		//}

		switch_mutex_lock(member->write_mutex);


		if (switch_channel_test_flag(member->channel, CF_CONFERENCE_ADV)) {
			if (member->conference->la) {
				conference_event_adv_la(member->conference, member, SWITCH_TRUE);
			}
			switch_channel_clear_flag(member->channel, CF_CONFERENCE_ADV);
		}


		if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
			if (event->event_id == SWITCH_EVENT_MESSAGE) {
				char *from = switch_event_get_header(event, "from");
				char *to = switch_event_get_header(event, "to");
				char *body = switch_event_get_body(event);

				if (to && from && body) {
					if (strchr(to, '+') && strncmp(to, CONF_CHAT_PROTO, strlen(CONF_CHAT_PROTO))) {
						switch_event_del_header(event, "to");
						switch_event_add_header(event, SWITCH_STACK_BOTTOM,
												"to", "%s+%s@%s", CONF_CHAT_PROTO, member->conference->name, member->conference->domain);
					} else {
						switch_event_del_header(event, "to");
						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", member->conference->name);
					}
					chat_send(event);
				}
			}
			switch_event_destroy(&event);
		}

		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
			/* test to see if outbound channel has answered */
			if (switch_channel_test_flag(channel, CF_ANSWERED) && !conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG,
								  "Outbound conference channel answered, setting CFLAG_ANSWERED\n");
				conference_utils_set_flag(member->conference, CFLAG_ANSWERED);
			}
		} else {
			if (conference_utils_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "CLFAG_ANSWERED set, answering inbound channel\n");
				switch_channel_answer(channel);
			}
		}

		use_buffer = NULL;
		mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);

		use_timer = 1;

		if (mux_used) {
			if (mux_used < bytes) {
				if (++low_count >= 5) {
					/* partial frame sitting around this long is useless and builds delay */
					conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
				}
			} else if (mux_used > flush_len) {
				/* getting behind, clear the buffer */
				conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
			}
		}

		if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
			conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
		} else if (mux_used >= bytes) {
			/* Flush the output buffer and write all the data (presumably muxed) back to the channel */
			switch_mutex_lock(member->audio_out_mutex);
			write_frame.data = data;
			use_buffer = member->mux_buffer;
			low_count = 0;

			if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) {
				if (write_frame.datalen) {
					write_frame.samples = write_frame.datalen / 2 / member->conference->channels;

					if( !conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
						memset(write_frame.data, 255, write_frame.datalen);
					} else if (member->volume_out_level) { /* Check for output volume adjustments */
						switch_change_sln_volume(write_frame.data, write_frame.samples * member->conference->channels, member->volume_out_level);
					}

					write_frame.timestamp = timer.samplecount;

					if (member->fnode) {
						conference_member_add_file_data(member, write_frame.data, write_frame.datalen);
					}

					conference_member_check_channels(&write_frame, member, SWITCH_FALSE);

					if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
						switch_mutex_unlock(member->audio_out_mutex);
						break;
					}
				}
			}

			switch_mutex_unlock(member->audio_out_mutex);
		}

		if (conference_utils_member_test_flag(member, MFLAG_FLUSH_BUFFER)) {
			if (switch_buffer_inuse(member->mux_buffer)) {
				switch_mutex_lock(member->audio_out_mutex);
				switch_buffer_zero(member->mux_buffer);
				switch_mutex_unlock(member->audio_out_mutex);
			}
			conference_utils_member_clear_flag_locked(member, MFLAG_FLUSH_BUFFER);
		}

		switch_mutex_unlock(member->write_mutex);


		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE)) {
			if (!zstr(member->conference->muted_sound)) {
				conference_member_play_file(member, member->conference->muted_sound, 0, SWITCH_TRUE);
			} else {
				char msg[512];

				switch_snprintf(msg, sizeof(msg), "Muted");
				conference_member_say(member, msg, 0);
			}
			conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE);
		}

		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE_DETECT)) {
			if (!zstr(member->conference->mute_detect_sound)) {
				conference_member_play_file(member, member->conference->mute_detect_sound, 0, SWITCH_TRUE);
			} else {
				char msg[512];

				switch_snprintf(msg, sizeof(msg), "Currently Muted");
				conference_member_say(member, msg, 0);
			}
			conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE_DETECT);
		}

		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_UNMUTE)) {
			if (!zstr(member->conference->unmuted_sound)) {
				conference_member_play_file(member, member->conference->unmuted_sound, 0, SWITCH_TRUE);
			} else {
				char msg[512];

				switch_snprintf(msg, sizeof(msg), "Un-Muted");
				conference_member_say(member, msg, 0);
			}
			conference_utils_member_clear_flag(member, MFLAG_INDICATE_UNMUTE);
		}

		if (switch_core_session_private_event_count(member->session)) {
			switch_channel_set_app_flag(channel, CF_APP_TAGGED);
			switch_ivr_parse_all_events(member->session);
			switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
			conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
			switch_core_session_set_read_codec(member->session, &member->read_codec);
		} else {
			switch_ivr_parse_all_messages(member->session);
		}

		if (use_timer) {
			switch_core_timer_next(&timer);
		} else {
			switch_cond_next();
		}

	} /* Rinse ... Repeat */

 end:

	if (!member->loop_loop) {
		conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);

		/* Wait for the input thread to end */
		if (member->input_thread) {
			switch_thread_join(&st, member->input_thread);
			member->input_thread = NULL;
		}
	}

	switch_core_timer_destroy(&timer);

	if (member->loop_loop) {
		return;
	}

	switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_INFO, "Channel leaving conference, cause: %s\n",
					  switch_channel_cause2str(switch_channel_get_cause(channel)));

	/* if it's an outbound channel, store the release cause in the conference struct, we might need it */
	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
		member->conference->bridge_hangup_cause = switch_channel_get_cause(channel);
	}
}
Exemplo n.º 12
0
static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *data)
{
	register unsigned int realsize = (unsigned int) (size * nmemb);
	shout_context_t *context = data;
	int decode_status = 0;
	size_t usedlen;
	uint32_t used, buf_size = 1024 * 128;	/* do not make this 64 or less, stutter will ensue after 
											   first 64k buffer is dry */

	if (context->prebuf) {
		buf_size = context->prebuf;
	}

	/* make sure we aren't over zealous by slowing down the stream when the buffer is too full */
	while (!context->err) {
		switch_mutex_lock(context->audio_mutex);
		used = switch_buffer_inuse(context->audio_buffer);
		switch_mutex_unlock(context->audio_mutex);

		if (used < buf_size) {
			/* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Buffered %u/%u!\n", used, buf_size); */
			break;
		}

		switch_yield(500000);
	}

	if (mpg123_feed(context->mh, ptr, realsize) != MPG123_OK) {
		goto error;
	}

	do {
		usedlen = 0;

		decode_status = mpg123_read(context->mh, context->decode_buf, sizeof(context->decode_buf), &usedlen);

		if (decode_status == MPG123_NEW_FORMAT) {
			continue;
		} else if (decode_status == MPG123_OK || decode_status == MPG123_NEED_MORE) {
			;
		} else if (decode_status == MPG123_DONE) {
			context->eof++;
		} else if (decode_status == MPG123_ERR || decode_status > 0) {
			if (++context->mp3err >= 5) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error! %s\n", context->stream_url);
				context->eof++;
				goto error;
			}
			continue;
		}

		context->mp3err = 0;

		switch_mutex_lock(context->audio_mutex);
		switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
		switch_mutex_unlock(context->audio_mutex);
	} while (!context->err && !context->eof && decode_status != MPG123_NEED_MORE);

	if (context->err) {
		goto error;
	}

	return realsize;

  error:
	switch_mutex_lock(context->audio_mutex);
	context->err++;
	switch_mutex_unlock(context->audio_mutex);
	return 0;
}
Exemplo n.º 13
0
void do_telecast(switch_stream_handle_t *stream)
{
	char *path_info = switch_event_get_header(stream->param_event, "http-path-info");
	char *uuid = strdup(path_info + 4);
	switch_core_session_t *tsession;
	char *fname = "stream.mp3";

	if ((fname = strchr(uuid, '/'))) {
		*fname++ = '\0';
	}

	if (!(tsession = switch_core_session_locate(uuid))) {
		char *ref = switch_event_get_header(stream->param_event, "http-referer");
		stream->write_function(stream, "Content-type: text/html\r\n\r\n<h2>Not Found!</h2>\n" "<META http-equiv=\"refresh\" content=\"1;URL=%s\">", ref);
	} else {
		switch_media_bug_t *bug = NULL;
		switch_buffer_t *buffer = NULL;
		switch_mutex_t *mutex;
		switch_channel_t *channel = switch_core_session_get_channel(tsession);
		lame_global_flags *gfp = NULL;
		switch_codec_implementation_t read_impl = { 0 };
		switch_core_session_get_read_impl(tsession, &read_impl);

		if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stepping into media path so this will work!\n");
			switch_ivr_media(uuid, SMF_REBRIDGE);
		}

		if (!(gfp = lame_init())) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n");
			goto end;
		}
		lame_set_num_channels(gfp, read_impl.number_of_channels);
		lame_set_in_samplerate(gfp, read_impl.actual_samples_per_second);
		lame_set_brate(gfp, 16 * (read_impl.actual_samples_per_second / 8000) * read_impl.number_of_channels);
		lame_set_mode(gfp, 3);
		lame_set_quality(gfp, 2);
		lame_set_errorf(gfp, log_error);
		lame_set_debugf(gfp, log_debug);
		lame_set_msgf(gfp, log_msg);
		lame_set_bWriteVbrTag(gfp, 0);
		lame_mp3_tags_fid(gfp, NULL);
		lame_init_params(gfp);
		lame_print_config(gfp);

		switch_mutex_init(&mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession));
		switch_buffer_create_dynamic(&buffer, 1024, 2048, 0);
		switch_buffer_add_mutex(buffer, mutex);

		if (switch_core_media_bug_add(tsession, "telecast", NULL,
									  telecast_callback, buffer, 0,
									  SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING, &bug) != SWITCH_STATUS_SUCCESS) {
			goto end;
		}

		stream->write_function(stream, "Content-type: audio/mpeg\r\n" "Content-Disposition: inline; filename=\"%s\"\r\n\r\n", fname);

		while (switch_channel_ready(channel)) {
			unsigned char mp3buf[TC_BUFFER_SIZE] = "";
			int rlen;
			uint8_t buf[1024];
			switch_size_t bytes = 0;

			if (switch_buffer_inuse(buffer) >= 1024) {
				switch_buffer_lock(buffer);
				bytes = switch_buffer_read(buffer, buf, sizeof(buf));
				switch_buffer_unlock(buffer);
			} else {
				if (!bytes) {
					switch_cond_next();
					continue;
				}
				memset(buf, 0, bytes);
			}

			if ((rlen = lame_encode_buffer(gfp, (void *) buf, NULL, bytes / 2, mp3buf, sizeof(mp3buf))) < 0) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen);
				goto end;
			}

			if (rlen) {
				if (stream->raw_write_function(stream, mp3buf, rlen)) {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected\n");
					goto end;
				}
			}
		}

	  end:

		switch_safe_free(uuid);

		if (gfp) {
			lame_close(gfp);
			gfp = NULL;
		}

		if (bug) {
			switch_core_media_bug_remove(tsession, &bug);
		}

		if (buffer) {
			switch_buffer_destroy(&buffer);
		}

		switch_core_session_rwunlock(tsession);
	}
}
Exemplo n.º 14
0
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame, switch_bool_t fill)
{
	switch_size_t bytes = 0, datalen = 0;
	int16_t *dp, *fp;
	uint32_t x;
	size_t rlen = 0;
	size_t wlen = 0;
	uint32_t blen;
	switch_codec_implementation_t read_impl = { 0 };
	int16_t *tp;
	switch_size_t do_read = 0, do_write = 0;
	int fill_read = 0, fill_write = 0;


	switch_core_session_get_read_impl(bug->session, &read_impl);

	bytes = read_impl.decoded_bytes_per_packet;

	if (frame->buflen < bytes) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s frame buffer too small!\n",
						  switch_channel_get_name(bug->session->channel));
		return SWITCH_STATUS_FALSE;
	}

	if ((!bug->raw_read_buffer && (!bug->raw_write_buffer || !switch_test_flag(bug, SMBF_WRITE_STREAM)))) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, 
				"%s Buffer Error (raw_read_buffer=%p, raw_write_buffer=%p, read=%s, write=%s)\n",
			        switch_channel_get_name(bug->session->channel),
				(void *)bug->raw_read_buffer, (void *)bug->raw_write_buffer, 
				switch_test_flag(bug, SMBF_READ_STREAM) ? "yes" : "no",
				switch_test_flag(bug, SMBF_WRITE_STREAM) ? "yes" : "no");
		return SWITCH_STATUS_FALSE;
	}

	frame->flags = 0;
	frame->datalen = 0;

	if (switch_test_flag(bug, SMBF_READ_STREAM)) {
		switch_mutex_lock(bug->read_mutex);
		do_read = switch_buffer_inuse(bug->raw_read_buffer);
		switch_mutex_unlock(bug->read_mutex);
	}

	if (switch_test_flag(bug, SMBF_WRITE_STREAM)) {
		switch_mutex_lock(bug->write_mutex);
		do_write = switch_buffer_inuse(bug->raw_write_buffer);
		switch_mutex_unlock(bug->write_mutex);
	}

	if (bug->record_frame_size && bug->record_pre_buffer_max && (do_read || do_write) && bug->record_pre_buffer_count < bug->record_pre_buffer_max) {
		bug->record_pre_buffer_count++;
		return SWITCH_STATUS_FALSE;
	}

	if (!bug->record_frame_size) {
		switch_size_t frame_size;
		switch_codec_implementation_t read_impl = { 0 };
		//switch_codec_implementation_t other_read_impl = { 0 };
		//switch_core_session_t *other_session;
			
		switch_core_session_get_read_impl(bug->session, &read_impl);
		frame_size = read_impl.decoded_bytes_per_packet;
		bug->record_frame_size = frame_size;
#if 0
		if (do_read && do_write) {			
			if (switch_core_session_get_partner(bug->session, &other_session) == SWITCH_STATUS_SUCCESS) {
				switch_core_session_get_read_impl(other_session, &other_read_impl);
				switch_core_session_rwunlock(other_session);

				if (read_impl.actual_samples_per_second == other_read_impl.actual_samples_per_second) {
					if (read_impl.decoded_bytes_per_packet < other_read_impl.decoded_bytes_per_packet) {
						frame_size = read_impl.decoded_bytes_per_packet;
					}					
				} else {
					if (read_impl.decoded_bytes_per_packet > other_read_impl.decoded_bytes_per_packet) {
						frame_size = read_impl.decoded_bytes_per_packet;
					}
				}
			}

			bug->record_frame_size = frame_size;
		}
#endif
	}


	if (bug->record_frame_size) {
		if ((do_read && do_read < bug->record_frame_size) || (do_write && do_write < bug->record_frame_size)) {
			return SWITCH_STATUS_FALSE;
		}

		if (do_read && do_read > bug->record_frame_size) {
			do_read = bug->record_frame_size;
		}

		if (do_write && do_write > bug->record_frame_size) {
			do_write = bug->record_frame_size;
		}
	}

	fill_read = !do_read;
	fill_write = !do_write;

	if (fill_read && fill_write) {
		return SWITCH_STATUS_FALSE;
	}

	if (do_read && do_read > SWITCH_RECOMMENDED_BUFFER_SIZE) {
		do_read = 1280;
	}

	if (do_write && do_write > SWITCH_RECOMMENDED_BUFFER_SIZE) {
		do_write = 1280;
	}
	
	if (do_read) {
		switch_mutex_lock(bug->read_mutex);
		frame->datalen = (uint32_t) switch_buffer_read(bug->raw_read_buffer, frame->data, do_read);
		if (frame->datalen != do_read) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "Framing Error Reading!\n");
			switch_core_media_bug_flush(bug);
			switch_mutex_unlock(bug->read_mutex);
			return SWITCH_STATUS_FALSE;
		}
		switch_mutex_unlock(bug->read_mutex);
	} else if (fill_read) {
		frame->datalen = bytes;
		memset(frame->data, 255, frame->datalen);
	}

	if (do_write) {
		switch_assert(bug->raw_write_buffer);
		switch_mutex_lock(bug->write_mutex);
		datalen = (uint32_t) switch_buffer_read(bug->raw_write_buffer, bug->data, do_write);
		if (datalen != do_write) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "Framing Error Writing!\n");
			switch_core_media_bug_flush(bug);
			switch_mutex_unlock(bug->write_mutex);
			return SWITCH_STATUS_FALSE;
		}
		switch_mutex_unlock(bug->write_mutex);
	} else if (fill_write) {
		datalen = bytes;
		memset(bug->data, 255, datalen);
	}

	tp = bug->tmp;
	dp = (int16_t *) bug->data;
	fp = (int16_t *) frame->data;
	rlen = frame->datalen / 2;
	wlen = datalen / 2;
	blen = bytes / 2;

	if (switch_test_flag(bug, SMBF_STEREO)) {
		int16_t *left, *right;
		size_t left_len, right_len;
		if (switch_test_flag(bug, SMBF_STEREO_SWAP)) {
			left = dp; /* write stream */
			left_len = wlen;
			right = fp; /* read stream */
			right_len = rlen;
		} else {
			left = fp; /* read stream */
			left_len = rlen;
			right = dp; /* write stream */
			right_len = wlen;
		}
		for (x = 0; x < blen; x++) {
			if (x < left_len) {
				*(tp++) = *(left + x);
			} else {
				*(tp++) = 0;
			}
			if (x < right_len) {
				*(tp++) = *(right + x);
			} else {
				*(tp++) = 0;
			}
		}
		memcpy(frame->data, bug->tmp, bytes * 2);
	} else {
		for (x = 0; x < blen; x++) {
			int32_t w = 0, r = 0, z = 0;
			
			if (x < rlen) {
				r = (int32_t) * (fp + x);
			}

			if (x < wlen) {
				w = (int32_t) * (dp + x);
			}
			
			z = w + r;

			if (z > SWITCH_SMAX || z < SWITCH_SMIN) {
				if (r) z += (r/2);
				if (w) z += (w/2);
			}

			switch_normalize_to_16bit(z);

			*(fp + x) = (int16_t) z;
		}
	}

	frame->datalen = bytes;
	frame->samples = bytes / sizeof(int16_t);
	frame->rate = read_impl.actual_samples_per_second;
	frame->codec = NULL;

	if (fill_read && fill_write) {
		return SWITCH_STATUS_BREAK;
	}

	if (fill_read || fill_write) {
		return SWITCH_STATUS_BREAK;
	}

	memcpy(bug->session->recur_buffer, frame->data, frame->datalen);
	bug->session->recur_buffer_len = frame->datalen;
	
	return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *bug, switch_frame_t *frame, switch_bool_t fill)
{
	switch_size_t bytes = 0, datalen = 0, ttl = 0;
	int16_t *dp, *fp;
	uint32_t x;
	size_t rlen = 0;
	size_t wlen = 0;
	uint32_t blen;
	switch_codec_implementation_t read_impl = { 0 };
	int16_t *tp;

	switch_core_session_get_read_impl(bug->session, &read_impl);

	bytes = read_impl.decoded_bytes_per_packet;

	if (frame->buflen < bytes) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s frame buffer too small!\n",
						  switch_channel_get_name(bug->session->channel));
		return SWITCH_STATUS_FALSE;
	}

	if (!(bug->raw_read_buffer && (bug->raw_write_buffer || !switch_test_flag(bug, SMBF_WRITE_STREAM)))) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s Buffer Error\n",
						  switch_channel_get_name(bug->session->channel));
		return SWITCH_STATUS_FALSE;
	}

	frame->flags = 0;
	frame->datalen = 0;

	if (!switch_buffer_inuse(bug->raw_read_buffer)) {
		return SWITCH_STATUS_FALSE;
	}

	switch_mutex_lock(bug->read_mutex);
	frame->datalen = (uint32_t) switch_buffer_read(bug->raw_read_buffer, frame->data, bytes);
	ttl += frame->datalen;
	switch_mutex_unlock(bug->read_mutex);

	if (switch_test_flag(bug, SMBF_WRITE_STREAM)) {
		switch_assert(bug->raw_write_buffer);
		switch_mutex_lock(bug->write_mutex);
		datalen = (uint32_t) switch_buffer_read(bug->raw_write_buffer, bug->data, bytes);
		ttl += datalen;
		if (fill && datalen < bytes) {
			memset(((unsigned char *) bug->data) + datalen, 0, bytes - datalen);
			datalen = bytes;
		}
		switch_mutex_unlock(bug->write_mutex);
	}

	tp = bug->tmp;
	dp = (int16_t *) bug->data;
	fp = (int16_t *) frame->data;
	rlen = frame->datalen / 2;
	wlen = datalen / 2;
	blen = bytes / 2;

	if (!fill && rlen == 0 && wlen == 0) {
		frame->datalen = 0;
		frame->samples = 0;
		frame->rate = read_impl.actual_samples_per_second;
		frame->codec = NULL;
		return SWITCH_STATUS_FALSE;
	}

	if (switch_test_flag(bug, SMBF_STEREO)) {
		for (x = 0; x < blen; x++) {
			if (x < rlen) {
				*(tp++) = *(fp + x);
			} else {
				*(tp++) = 0;
			}
			if (x < wlen) {
				*(tp++) = *(dp + x);
			} else {
				*(tp++) = 0;
			}
		}
		memcpy(frame->data, bug->tmp, bytes * 2);
	} else {
		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 / 2;
		}
	}

	if (!ttl) {
		switch_set_flag(frame, SFF_CNG);
	}

	frame->datalen = bytes;
	frame->samples = bytes / sizeof(int16_t);
	frame->rate = read_impl.actual_samples_per_second;
	frame->codec = NULL;

	return SWITCH_STATUS_SUCCESS;
}
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
{
	portaudio_stream_source_t *source = obj;
	portaudio_stream_context_t *cp;
	int samples = 0;
	int bused, bytesToWrite;


	switch_mutex_lock(globals.mutex);
	globals.threads++;
	switch_mutex_unlock(globals.mutex);

	if (!source->prebuf) {
		source->prebuf = DEFAULT_PREBUFFER_SIZE;
	}



	switch_mutex_lock(globals.mutex);
	switch_core_hash_insert(globals.source_hash, source->sourcename, source);
	switch_mutex_unlock(globals.mutex);


	switch_thread_rwlock_create(&source->rwlock, source->pool);

	if (engage_device(source, 0) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Dev %d cant be engaged !\n", (int) source->sourcedev);
	} else {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Dev %d engaged at %d rate!\n", (int) source->sourcedev, (int) source->rate);
		if (globals.running && !source->stopped) {
			source->ready = 1;

			if (!source->audio_stream) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Audio Stream wops!\n");
				source->stopped = 0;
				source->ready = 0;
			} else {
				while (globals.running && !source->stopped) {
					samples = 0;
					switch_mutex_lock(source->device_lock);
					samples = ReadAudioStream(source->audio_stream, source->databuf,
								  source->read_codec.implementation->samples_per_packet, 0, &source->timer);
					switch_mutex_unlock(source->device_lock);


					if (samples) {
						bytesToWrite = source->samples;
						if (samples < bytesToWrite) {
							bytesToWrite = samples;
						}
						bytesToWrite *= source->audio_stream->bytesPerFrame;

						if (source->total) {

							switch_mutex_lock(source->mutex);
							for (cp = source->context_list; cp; cp = cp->next) {

								switch_mutex_lock(cp->audio_mutex);

								bused = switch_buffer_inuse(cp->audio_buffer);
								if (bused > source->samples * 768) {
									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d] %d used %d max\n",
													  cp->func, cp->file, cp->line, (int) bused, (int) (source->samples * 768));
									switch_buffer_zero(cp->audio_buffer);
								} else {
									switch_buffer_write(cp->audio_buffer, source->databuf, bytesToWrite);
								}

								switch_mutex_unlock(cp->audio_mutex);
							}
							switch_mutex_unlock(source->mutex);
						}

					}

				}
			}

		}
	}


	source->ready = 0;

	switch_mutex_lock(globals.mutex);
	switch_core_hash_delete(globals.source_hash, source->sourcename);
	switch_mutex_unlock(globals.mutex);

	switch_thread_rwlock_wrlock(source->rwlock);
	switch_thread_rwlock_unlock(source->rwlock);


	switch_mutex_lock(source->device_lock);
	CloseAudioStream(source->audio_stream);
	if (switch_core_codec_ready(&source->read_codec)) {
		switch_core_codec_destroy(&source->read_codec);
		switch_core_codec_destroy(&source->write_codec);
	}
	if (switch_core_codec_ready(&source->write_codec)) {
		switch_core_codec_destroy(&source->write_codec);
	}
	switch_mutex_unlock(source->device_lock);


	switch_core_destroy_memory_pool(&source->pool);

	switch_mutex_lock(globals.mutex);
	globals.threads--;
	switch_mutex_unlock(globals.mutex);

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " thread ending succesfully !\n");
	switch_thread_exit(thread, SWITCH_STATUS_SUCCESS);

	return NULL;
}
Exemplo n.º 17
0
SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh)
{
	switch_status_t status;

	switch_assert(fh != NULL);
	switch_assert(fh->file_interface != NULL);

	if (!switch_test_flag(fh, SWITCH_FILE_OPEN)) {
		return SWITCH_STATUS_FALSE;
	}

	if (fh->params) {
		switch_event_destroy(&fh->params);
	}

	fh->samples_in = 0;
	fh->max_samples = 0;

	if (fh->buffer) {
		switch_buffer_destroy(&fh->buffer);
	}

	if (fh->pre_buffer) {
		if (switch_test_flag(fh, SWITCH_FILE_FLAG_WRITE)) {
			switch_size_t rlen, blen;
			int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);

			while ((rlen = switch_buffer_inuse(fh->pre_buffer))) {
				if ((blen = switch_buffer_read(fh->pre_buffer, fh->pre_buffer_data, fh->pre_buffer_datalen))) {
					if (!asis)
						blen /= 2;
					if (fh->channels > 1)
						blen /= fh->channels;

					if (fh->file_interface->file_write(fh, fh->pre_buffer_data, &blen) != SWITCH_STATUS_SUCCESS) {
						break;
					}
				}
			}
		}

		switch_buffer_destroy(&fh->pre_buffer);
	}

	switch_clear_flag(fh, SWITCH_FILE_OPEN);
	status = fh->file_interface->file_close(fh);

	switch_resample_destroy(&fh->resampler);


	if (fh->spool_path) {
		char *command;

#ifdef _MSC_VER
		command = switch_mprintf("move %s %s", fh->spool_path, fh->file_path);
#else
		command = switch_mprintf("/bin/mv %s %s", fh->spool_path, fh->file_path);
#endif
		if (system(command) == -1) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to copy spooled file [%s] to [%s] because of a command error : %s\n", fh->spool_path, fh->file_path, command);
		} else {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Copy spooled file [%s] to [%s]\n", fh->spool_path, fh->file_path);
		}
		free(command);
	}


	UNPROTECT_INTERFACE(fh->file_interface);

	if (switch_test_flag(fh, SWITCH_FILE_FLAG_FREE_POOL)) {
		switch_core_destroy_memory_pool(&fh->memory_pool);
	}

	switch_safe_free(fh->dbuf);


	return status;
}
Exemplo n.º 18
0
SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, void *data, switch_size_t *len)
{
	switch_size_t orig_len = *len;

	switch_assert(fh != NULL);
	switch_assert(fh->file_interface != NULL);

	if (!switch_test_flag(fh, SWITCH_FILE_OPEN)) {
		return SWITCH_STATUS_FALSE;
	}

	if (!fh->file_interface->file_write) {
		return SWITCH_STATUS_FALSE;
	}

	if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) {
		if (!fh->resampler) {
			if (switch_resample_create(&fh->resampler,
									   fh->native_rate,
									   fh->samplerate,
									   (uint32_t) orig_len * 2 * fh->channels, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
				return SWITCH_STATUS_GENERR;
			}
		}

		switch_resample_process(fh->resampler, data, (uint32_t) * len);

		if (fh->resampler->to_len > orig_len) {
			if (!fh->dbuf || (fh->dbuflen < fh->resampler->to_len * 2 * fh->channels)) {
				void *mem;
				fh->dbuflen = fh->resampler->to_len * 2 * fh->channels;
				mem = realloc(fh->dbuf, fh->dbuflen);
				switch_assert(mem);
				fh->dbuf = mem;
			}
			switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen);
			memcpy(fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
			data = fh->dbuf;
		} else {
			memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
		}

		*len = fh->resampler->to_len;
	}

	if (!*len) {
		return SWITCH_STATUS_SUCCESS;
	}

	if (fh->pre_buffer) {
		switch_size_t rlen, blen;
		switch_status_t status = SWITCH_STATUS_SUCCESS;
		int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);

		switch_buffer_write(fh->pre_buffer, data, (asis ? *len : *len * 2) * fh->channels);

		rlen = switch_buffer_inuse(fh->pre_buffer);

		if (rlen >= fh->pre_buffer_datalen) {
			if ((blen = switch_buffer_read(fh->pre_buffer, fh->pre_buffer_data, fh->pre_buffer_datalen))) {
				if (!asis)
					blen /= 2;
				if (fh->channels > 1)
					blen /= fh->channels;
				if ((status = fh->file_interface->file_write(fh, fh->pre_buffer_data, &blen)) != SWITCH_STATUS_SUCCESS) {
					*len = 0;
				}
			}
		}
		fh->samples_out += orig_len;
		return status;
	} else {
		switch_status_t status;
		if ((status = fh->file_interface->file_write(fh, data, len)) == SWITCH_STATUS_SUCCESS) {
			fh->samples_out += orig_len;
		}
		return status;
	}
}
Exemplo n.º 19
0
SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, void *data, switch_size_t *len)
{
	switch_status_t status = SWITCH_STATUS_FALSE;
	switch_size_t want, orig_len = *len;

	switch_assert(fh != NULL);
	switch_assert(fh->file_interface != NULL);

	if (!switch_test_flag(fh, SWITCH_FILE_OPEN)) {
		return SWITCH_STATUS_FALSE;
	}

  top:

	if (fh->max_samples > 0 && fh->samples_in >= (switch_size_t)fh->max_samples) {
		*len = 0;
		return SWITCH_STATUS_FALSE;
	}

	if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2 * fh->channels) {
		*len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels;
		return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS;
	}

	if (switch_test_flag(fh, SWITCH_FILE_DONE)) {
		switch_clear_flag(fh, SWITCH_FILE_DONE);
		*len = 0;
		return SWITCH_STATUS_FALSE;
	}

	want = *len;

  more:

	if (fh->pre_buffer) {
		switch_size_t rlen;
		int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);

		if (!switch_test_flag(fh, SWITCH_FILE_BUFFER_DONE)) {
			rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2 / fh->real_channels;

			if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2 * fh->channels) {
				if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) == SWITCH_STATUS_BREAK) {
					return SWITCH_STATUS_BREAK;
				}
				

				if (status != SWITCH_STATUS_SUCCESS || !rlen) {
					switch_set_flag(fh, SWITCH_FILE_BUFFER_DONE);
				} else {
					fh->samples_in += rlen;
					if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
						switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->real_channels, fh->channels);
					}
					switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2 * fh->channels);
				}
			}
		}

		rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2 * fh->channels);
		*len = asis ? rlen : rlen / 2 / fh->channels;

		if (*len == 0) {
			switch_set_flag(fh, SWITCH_FILE_DONE);
			goto top;
		} else {
			status = SWITCH_STATUS_SUCCESS;
		}

	} else {

		if ((status = fh->file_interface->file_read(fh, data, len)) == SWITCH_STATUS_BREAK) {
			return SWITCH_STATUS_BREAK;
		}

		if (status != SWITCH_STATUS_SUCCESS || !*len) {
			switch_set_flag(fh, SWITCH_FILE_DONE);
			goto top;
		}

		fh->samples_in += *len;

		if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
			switch_mux_channels((int16_t *) data, *len, fh->real_channels, fh->channels);
		}
	}

	if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) {
		if (!fh->resampler) {
			if (switch_resample_create(&fh->resampler,
									   fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
				return SWITCH_STATUS_GENERR;
			}
		}

		switch_resample_process(fh->resampler, data, (uint32_t) *len);

		if (fh->resampler->to_len < want || fh->resampler->to_len > orig_len) {
			if (!fh->buffer) {
				int factor = fh->resampler->to_len * fh->samplerate / 1000;
				switch_buffer_create_dynamic(&fh->buffer, factor, factor, 0);
				switch_assert(fh->buffer);
			}
			if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2 * fh->channels) {
				void *mem;
				fh->dbuflen = fh->resampler->to_len * 2 * fh->channels;
				mem = realloc(fh->dbuf, fh->dbuflen);
				switch_assert(mem);
				fh->dbuf = mem;
			}
			switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen);
			memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
			switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2 * fh->channels);

			if (switch_buffer_inuse(fh->buffer) < want * 2 * fh->channels) {
				*len = want;
				goto more;
			}
			*len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels;
		} else {
			memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
			*len = fh->resampler->to_len;
		}


	}

	return status;
}
Exemplo n.º 20
0
SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle_t *sh, void *data, switch_size_t *datalen, switch_speech_flag_t *flags)
{
    switch_status_t status;
    switch_size_t want, orig_len = *datalen;

    switch_assert(sh != NULL);

    want = *datalen;

top:

    if (sh->buffer && (switch_buffer_inuse(sh->buffer) >= orig_len || switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE))) {
        if ((*datalen = switch_buffer_read(sh->buffer, data, orig_len))) {
            return SWITCH_STATUS_SUCCESS;
        }
    }

    if (switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE)) {
        switch_clear_flag(sh, SWITCH_SPEECH_FLAG_DONE);
        *datalen = 0;
        return SWITCH_STATUS_BREAK;
    }

more:

    if ((status = sh->speech_interface->speech_read_tts(sh, data, datalen, flags)) != SWITCH_STATUS_SUCCESS) {
        switch_set_flag(sh, SWITCH_SPEECH_FLAG_DONE);
        goto top;
    }


    if (sh->native_rate && sh->samplerate && sh->native_rate != sh->samplerate) {
        if (!sh->resampler) {
            if (switch_resample_create(&sh->resampler,
                                       sh->native_rate, sh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
                return SWITCH_STATUS_GENERR;
            }
        }

        switch_resample_process(sh->resampler, data, (uint32_t)(*datalen / 2));
        if (sh->resampler->to_len < want / 2 || sh->resampler->to_len > orig_len / 2) {
            if (!sh->buffer) {
                int factor = sh->resampler->to_len * sh->samplerate / 1000;
                switch_buffer_create_dynamic(&sh->buffer, factor, factor, 0);
                switch_assert(sh->buffer);
            }
            if (!sh->dbuf || sh->dbuflen < sh->resampler->to_len * 2) {
                sh->dbuflen = sh->resampler->to_len * 2;
                sh->dbuf = switch_core_alloc(sh->memory_pool, sh->dbuflen);
            }
            switch_assert(sh->resampler->to_len <= sh->dbuflen);

            memcpy((int16_t *) sh->dbuf, sh->resampler->to, sh->resampler->to_len * 2);
            switch_buffer_write(sh->buffer, sh->dbuf, sh->resampler->to_len * 2);

            if (switch_buffer_inuse(sh->buffer) < want) {
                *datalen = want;
                goto more;
            }
            *datalen = switch_buffer_read(sh->buffer, data, orig_len);
            status = SWITCH_STATUS_SUCCESS;
        } else {
            memcpy(data, sh->resampler->to, sh->resampler->to_len * 2);
            *datalen = sh->resampler->to_len * 2;
            status = SWITCH_STATUS_SUCCESS;
        }
    }

    return status;

}
Exemplo n.º 21
0
/* marshall frames from the call leg to the conference thread for muxing to other call legs */
void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *obj)
{
	switch_event_t *event;
	conference_member_t *member = obj;
	switch_channel_t *channel;
	switch_status_t status;
	switch_frame_t *read_frame = NULL;
	uint32_t hangover = 40, hangunder = 5, hangover_hits = 0, hangunder_hits = 0, diff_level = 400;
	switch_core_session_t *session = member->session;
	uint32_t flush_len;
	switch_frame_t tmp_frame = { 0 };

	if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
		goto end;
	}

	switch_assert(member != NULL);

	conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);

	channel = switch_core_session_get_channel(session);

	switch_core_session_get_read_impl(session, &member->read_impl);

	switch_channel_audio_sync(channel);

	flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval);

	/* As long as we have a valid read, feed that data into an input buffer where the conference thread will take it
	   and mux it with any audio from other channels. */

	while (conference_utils_member_test_flag(member, MFLAG_RUNNING) && switch_channel_ready(channel)) {

		if (switch_channel_ready(channel) && switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
			switch_yield(100000);
			continue;
		}

		/* Read a frame. */
		status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);

		switch_mutex_lock(member->read_mutex);

		/* end the loop, if appropriate */
		if (!SWITCH_READ_ACCEPTABLE(status) || !conference_utils_member_test_flag(member, MFLAG_RUNNING)) {
			switch_mutex_unlock(member->read_mutex);
			break;
		}

		if (switch_channel_test_flag(channel, CF_VIDEO) && !conference_utils_member_test_flag(member, MFLAG_ACK_VIDEO)) {
			conference_utils_member_set_flag_locked(member, MFLAG_ACK_VIDEO);
			conference_video_check_avatar(member, SWITCH_FALSE);
			switch_core_session_video_reinit(member->session);
			conference_video_set_floor_holder(member->conference, member, SWITCH_FALSE);
		} else if (conference_utils_member_test_flag(member, MFLAG_ACK_VIDEO) && !switch_channel_test_flag(channel, CF_VIDEO)) {
			conference_video_check_avatar(member, SWITCH_FALSE);
		}

		/* if we have caller digits, feed them to the parser to find an action */
		if (switch_channel_has_dtmf(channel)) {
			char dtmf[128] = "";

			switch_channel_dequeue_dtmf_string(channel, dtmf, sizeof(dtmf));

			if (conference_utils_member_test_flag(member, MFLAG_DIST_DTMF)) {
				conference_member_send_all_dtmf(member, member->conference, dtmf);
			} else if (member->dmachine) {
				char *p;
				char str[2] = "";
				for (p = dtmf; p && *p; p++) {
					str[0] = *p;
					switch_ivr_dmachine_feed(member->dmachine, str, NULL);
				}
			}
		} else if (member->dmachine) {
			switch_ivr_dmachine_ping(member->dmachine, NULL);
		}

		if (switch_queue_size(member->dtmf_queue)) {
			switch_dtmf_t *dt;
			void *pop;

			if (switch_queue_trypop(member->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
				dt = (switch_dtmf_t *) pop;
				switch_core_session_send_dtmf(member->session, dt);
				free(dt);
			}
		}

		if (switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) {
			member->reset_media = 10;
			switch_channel_audio_sync(member->channel);
			switch_channel_clear_flag(member->channel, CF_CONFERENCE_RESET_MEDIA);
		}

		if (member->reset_media) {
			if (--member->reset_media > 0) {
				goto do_continue;
			}

			if (conference_member_setup_media(member, member->conference)) {
				switch_mutex_unlock(member->read_mutex);
				break;
			}

			member->loop_loop = 1;
			
			goto do_continue;			
		}

		if (switch_test_flag(read_frame, SFF_CNG)) {
			if (member->conference->agc_level) {
				member->nt_tally++;
			}

			if (hangunder_hits) {
				hangunder_hits--;
			}
			if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
				if (++hangover_hits >= hangover) {
					hangover_hits = hangunder_hits = 0;
					conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
					conference_member_update_status_field(member);
					conference_member_check_agc_levels(member);
					conference_member_clear_avg(member);
					member->score_iir = 0;
					member->floor_packets = 0;

					if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
						switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
						conference_member_add_event_data(member, event);
						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking");
						switch_event_fire(&event);
					}
				}
			}

			goto do_continue;
		}

		if (member->nt_tally > (int32_t)(member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) * 3) {
			member->agc_volume_in_level = 0;
			conference_member_clear_avg(member);
		}

		/* Check for input volume adjustments */
		if (!member->conference->agc_level) {
			member->conference->agc_level = 0;
			conference_member_clear_avg(member);
		}


		/* if the member can speak, compute the audio energy level and */
		/* generate events when the level crosses the threshold        */
		if ((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) || conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT))) {
			uint32_t energy = 0, i = 0, samples = 0, j = 0;
			int16_t *data;
			int agc_period = (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) / 4;


			data = read_frame->data;
			member->score = 0;

			if (member->volume_in_level) {
				switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->volume_in_level);
			}

			if (member->agc_volume_in_level) {
				switch_change_sln_volume_granular(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->agc_volume_in_level);
			}

			if ((samples = read_frame->datalen / sizeof(*data) / member->read_impl.number_of_channels)) {
				for (i = 0; i < samples; i++) {
					energy += abs(data[j]);
					j += member->read_impl.number_of_channels;
				}

				member->score = energy / samples;
			}

			if (member->vol_period) {
				member->vol_period--;
			}

			if (member->conference->agc_level && member->score &&
				conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&
				conference_member_noise_gate_check(member)
				) {
				int last_shift = abs((int)(member->last_score - member->score));

				if (member->score && member->last_score && last_shift > 900) {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7,
									  "AGC %s:%d drop anomalous shift of %d\n",
									  member->conference->name,
									  member->id, last_shift);

				} else {
					member->avg_tally += member->score;
					member->avg_itt++;
					if (!member->avg_itt) member->avg_itt++;
					member->avg_score = member->avg_tally / member->avg_itt;
				}

				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7,
								  "AGC %s:%d diff:%d level:%d cur:%d avg:%d vol:%d\n",
								  member->conference->name,
								  member->id, member->conference->agc_level - member->avg_score, member->conference->agc_level,
								  member->score, member->avg_score, member->agc_volume_in_level);

				if (++member->agc_concur >= agc_period) {
					if (!member->vol_period) {
						conference_member_check_agc_levels(member);
					}
					member->agc_concur = 0;
				}
			} else {
				member->nt_tally++;
			}

			member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir));

			if (member->score_iir > SCORE_MAX_IIR) {
				member->score_iir = SCORE_MAX_IIR;
			}

			if (conference_member_noise_gate_check(member)) {
				uint32_t diff = member->score - member->energy_level;
				if (hangover_hits) {
					hangover_hits--;
				}

				if (member->conference->agc_level) {
					member->nt_tally = 0;
				}

				if (member == member->conference->floor_holder) {
					member->floor_packets++;
				}

				if (diff >= diff_level || ++hangunder_hits >= hangunder) {

					hangover_hits = hangunder_hits = 0;
					member->last_talking = switch_epoch_time_now(NULL);

					if (!conference_utils_member_test_flag(member, MFLAG_TALKING)) {
						conference_utils_member_set_flag_locked(member, MFLAG_TALKING);
						conference_member_update_status_field(member);
						member->floor_packets = 0;

						if (test_eflag(member->conference, EFLAG_START_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&
							switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
							conference_member_add_event_data(member, event);
							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "start-talking");
							switch_event_fire(&event);
						}

						if (conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT) && !conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {

							if (!zstr(member->conference->mute_detect_sound)) {
								conference_utils_member_set_flag(member, MFLAG_INDICATE_MUTE_DETECT);
							}

							if (test_eflag(member->conference, EFLAG_MUTE_DETECT) &&
								switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
								conference_member_add_event_data(member, event);
								switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "mute-detect");
								switch_event_fire(&event);
							}
						}
					}
				}
			} else {
				if (hangunder_hits) {
					hangunder_hits--;
				}

				if (member->conference->agc_level) {
					member->nt_tally++;
				}

				if (conference_utils_member_test_flag(member, MFLAG_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
					switch_event_t *event;
					if (++hangover_hits >= hangover) {
						hangover_hits = hangunder_hits = 0;
						conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
						conference_member_update_status_field(member);
						conference_member_check_agc_levels(member);
						conference_member_clear_avg(member);

						if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
							switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
							conference_member_add_event_data(member, event);
							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking");
							switch_event_fire(&event);
						}
					}
				}
			}


			member->last_score = member->score;

			if (member == member->conference->floor_holder) {
				if (member->id != member->conference->video_floor_holder &&
					(member->floor_packets > member->conference->video_floor_packets || member->energy_level == 0)) {
					conference_video_set_floor_holder(member->conference, member, SWITCH_FALSE);
				}
			}
		}
		
		/* skip frames that are not actual media or when we are muted or silent */
		if ((conference_utils_member_test_flag(member, MFLAG_TALKING) || member->energy_level == 0 || conference_utils_test_flag(member->conference, CFLAG_AUDIO_ALWAYS))
			&& conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&	!conference_utils_test_flag(member->conference, CFLAG_WAIT_MOD)
			&& (member->conference->count > 1 || (member->conference->record_count && member->conference->count >= member->conference->min_recording_participants))) {
			switch_audio_resampler_t *read_resampler = member->read_resampler;
			void *data;
			uint32_t datalen;

			if (read_resampler) {
				int16_t *bptr = (int16_t *) read_frame->data;
				int len = (int) read_frame->datalen;

				switch_resample_process(read_resampler, bptr, len / 2 / member->read_impl.number_of_channels);
				memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2 * member->read_impl.number_of_channels);
				len = read_resampler->to_len * 2 * member->read_impl.number_of_channels;
				datalen = len;
				data = member->resample_out;
			} else {
				data = read_frame->data;
				datalen = read_frame->datalen;
			}

			tmp_frame.data = data;
			tmp_frame.datalen = datalen;
			tmp_frame.rate = member->conference->rate;
			conference_member_check_channels(&tmp_frame, member, SWITCH_TRUE);


			if (datalen) {
				switch_size_t ok = 1;

				/* Write the audio into the input buffer */
				switch_mutex_lock(member->audio_in_mutex);
				if (switch_buffer_inuse(member->audio_buffer) > flush_len) {
					switch_buffer_toss(member->audio_buffer, tmp_frame.datalen);
				}
				ok = switch_buffer_write(member->audio_buffer, tmp_frame.data, tmp_frame.datalen);
				switch_mutex_unlock(member->audio_in_mutex);
				if (!ok) {
					switch_mutex_unlock(member->read_mutex);
					break;
				}
			}
		}

	do_continue:

		switch_mutex_unlock(member->read_mutex);

	}

	if (switch_queue_size(member->dtmf_queue)) {
		switch_dtmf_t *dt;
		void *pop;

		while (switch_queue_trypop(member->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
			dt = (switch_dtmf_t *) pop;
			free(dt);
		}
	}


	switch_resample_destroy(&member->read_resampler);
	switch_core_session_rwunlock(session);

 end:

	conference_utils_member_clear_flag_locked(member, MFLAG_ITHREAD);

	return NULL;
}
Exemplo n.º 22
0
SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags,
																int stream_id)
{

	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, do_bugs = 0, do_write = 0, do_resample = 0, ptime_mismatch = 0, pass_cng = 0, resample = 0;
	int did_write_resample = 0;

	switch_assert(session != NULL);
	switch_assert(frame != NULL);

	if (!switch_channel_ready(session->channel)) {
		return SWITCH_STATUS_FALSE;
	}

	if (switch_mutex_trylock(session->codec_write_mutex) == SWITCH_STATUS_SUCCESS) {
		switch_mutex_unlock(session->codec_write_mutex);
	} else {
		return SWITCH_STATUS_SUCCESS;
	}

	if (switch_test_flag(frame, SFF_CNG)) {
		if (switch_channel_test_flag(session->channel, CF_ACCEPT_CNG)) {
			pass_cng = 1;
		} else {
			return SWITCH_STATUS_SUCCESS;
		}
	}

	if (!(session->write_codec && switch_core_codec_ready(session->write_codec)) && !pass_cng) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no write codec.\n", switch_channel_get_name(session->channel));
		switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
		return SWITCH_STATUS_FALSE;
	}

	if (switch_channel_test_flag(session->channel, CF_HOLD)) {
		return SWITCH_STATUS_SUCCESS;
	}

	if (switch_test_flag(frame, SFF_PROXY_PACKET) || pass_cng) {
		/* Fast PASS! */
		switch_mutex_lock(session->codec_write_mutex);
		status = perform_write(session, frame, flag, stream_id);
		switch_mutex_unlock(session->codec_write_mutex);
		return status;
	}

	switch_mutex_lock(session->codec_write_mutex);

	if (!(frame->codec && frame->codec->implementation)) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has received a bad frame with no codec!\n", 
						  switch_channel_get_name(session->channel));
		switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
		switch_mutex_unlock(session->codec_write_mutex);
		return SWITCH_STATUS_FALSE;
	}

	switch_assert(frame->codec != NULL);
	switch_assert(frame->codec->implementation != NULL);

	if (!(switch_core_codec_ready(session->write_codec) && frame->codec) ||
		!switch_channel_ready(session->channel) || !switch_channel_media_ready(session->channel)) {
		switch_mutex_unlock(session->codec_write_mutex);
		return SWITCH_STATUS_FALSE;
	}

	switch_mutex_lock(session->write_codec->mutex);
	switch_mutex_lock(frame->codec->mutex);

	if (!(switch_core_codec_ready(session->write_codec) && switch_core_codec_ready(frame->codec))) goto error;
	
	if ((session->write_codec && frame->codec && session->write_codec->implementation != frame->codec->implementation)) {
		if (session->write_impl.codec_id == frame->codec->implementation->codec_id ||
			session->write_impl.microseconds_per_packet != frame->codec->implementation->microseconds_per_packet) {
			ptime_mismatch = TRUE;
			if ((switch_test_flag(frame->codec, SWITCH_CODEC_FLAG_PASSTHROUGH) || switch_test_flag(session->read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH)) ||
				switch_channel_test_flag(session->channel, CF_PASSTHRU_PTIME_MISMATCH)) {
				status = perform_write(session, frame, flags, stream_id);
				goto error;
			}
		}
		need_codec = TRUE;
	}

	if (session->write_codec && !frame->codec) {
		need_codec = TRUE;
	}

	if (session->bugs && !need_codec) {
		do_bugs = TRUE;
		need_codec = TRUE;
	}

	if (frame->codec->implementation->actual_samples_per_second != session->write_impl.actual_samples_per_second) {
		need_codec = TRUE;
		do_resample = TRUE;
	}

	if (switch_test_flag(session, SSF_WRITE_TRANSCODE) && !need_codec && switch_core_codec_ready(session->write_codec)) {
		switch_core_session_t *other_session;
		const char *uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_SIGNAL_BOND_VARIABLE);

		if (uuid && (other_session = switch_core_session_locate(uuid))) {
			switch_set_flag(other_session, SSF_READ_CODEC_RESET);
			switch_set_flag(other_session, SSF_READ_CODEC_RESET);
			switch_set_flag(other_session, SSF_WRITE_CODEC_RESET);
			switch_core_session_rwunlock(other_session);
		}
		
		switch_clear_flag(session, SSF_WRITE_TRANSCODE);
	}


	if (switch_test_flag(session, SSF_WRITE_CODEC_RESET)) {
		switch_core_codec_reset(session->write_codec);
		switch_clear_flag(session, SSF_WRITE_CODEC_RESET);
	}

	if (!need_codec) {
		do_write = TRUE;
		write_frame = frame;
		goto done;
	}

	if (!switch_test_flag(session, SSF_WARN_TRANSCODE)) {
		switch_core_session_message_t msg = { 0 };

		msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY;
		switch_core_session_receive_message(session, &msg);
		switch_set_flag(session, SSF_WARN_TRANSCODE);
	}

	if (frame->codec) {
		session->raw_write_frame.datalen = session->raw_write_frame.buflen;
		status = switch_core_codec_decode(frame->codec,
										  session->write_codec,
										  frame->data,
										  frame->datalen,
										  session->write_impl.actual_samples_per_second,
										  session->raw_write_frame.data, &session->raw_write_frame.datalen, &session->raw_write_frame.rate, &frame->flags);




		if (do_resample && status == SWITCH_STATUS_SUCCESS) {
			status = SWITCH_STATUS_RESAMPLE;
		}

		switch (status) {
		case SWITCH_STATUS_RESAMPLE:
			resample++;
			write_frame = &session->raw_write_frame;
			write_frame->rate = frame->codec->implementation->actual_samples_per_second;
			if (!session->write_resampler) {
				switch_mutex_lock(session->resample_mutex);
				status = switch_resample_create(&session->write_resampler,
												frame->codec->implementation->actual_samples_per_second,
												session->write_impl.actual_samples_per_second,
												session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1);


				switch_mutex_unlock(session->resample_mutex);
				if (status != SWITCH_STATUS_SUCCESS) {
					goto done;
				}
			}
			break;
		case SWITCH_STATUS_SUCCESS:
			session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t);
			session->raw_write_frame.timestamp = frame->timestamp;
			session->raw_write_frame.rate = frame->rate;
			session->raw_write_frame.m = frame->m;
			session->raw_write_frame.ssrc = frame->ssrc;
			session->raw_write_frame.seq = frame->seq;
			session->raw_write_frame.payload = frame->payload;
			session->raw_write_frame.flags = 0;
			if (switch_test_flag(frame, SFF_PLC)) {
				session->raw_write_frame.flags |= SFF_PLC;
			}

			write_frame = &session->raw_write_frame;
			break;
		case SWITCH_STATUS_BREAK:
			status = SWITCH_STATUS_SUCCESS;
			goto error;
		case SWITCH_STATUS_NOOP:
			if (session->write_resampler) {
				switch_mutex_lock(session->resample_mutex);
				switch_resample_destroy(&session->write_resampler);
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n");
				switch_mutex_unlock(session->resample_mutex);
			}
			write_frame = frame;
			status = SWITCH_STATUS_SUCCESS;
			break;
		default:
			if (status == SWITCH_STATUS_NOT_INITALIZED) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n");
				goto error;
			}
			if (ptime_mismatch) {
				status = perform_write(session, frame, flags, stream_id);
				status = SWITCH_STATUS_SUCCESS;
				goto error;
			}

			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error!\n",
							  frame->codec->codec_interface->interface_name);
			goto error;
		}
	}



	if (session->write_resampler) {
		short *data = write_frame->data;

		switch_mutex_lock(session->resample_mutex);
		if (session->write_resampler) {

			switch_resample_process(session->write_resampler, data, write_frame->datalen / 2);

			memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2);

			write_frame->samples = session->write_resampler->to_len;

			write_frame->datalen = write_frame->samples * 2;

			write_frame->rate = session->write_resampler->to_rate;

			did_write_resample = 1;
		}
		switch_mutex_unlock(session->resample_mutex);
	}



	if (session->bugs) {
		switch_media_bug_t *bp;
		int prune = 0;

		switch_thread_rwlock_rdlock(session->bug_rwlock);
		for (bp = session->bugs; bp; bp = bp->next) {
			switch_bool_t ok = SWITCH_TRUE;
			if (!bp->ready) {
				continue;
			}

			if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
				continue;
			}

			if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
				continue;
			}

			if (switch_test_flag(bp, SMBF_PRUNE)) {
				prune++;
				continue;
			}

			if (switch_test_flag(bp, SMBF_WRITE_STREAM)) {

				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) {
					ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE);
				}
			}

			if (switch_test_flag(bp, SMBF_WRITE_REPLACE)) {
				do_bugs = 0;
				if (bp->callback) {
					bp->write_replace_frame_in = write_frame;
					bp->write_replace_frame_out = write_frame;
					if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_REPLACE)) == SWITCH_TRUE) {
						write_frame = bp->write_replace_frame_out;
					}
				}
			}

			if (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) {
				ok = SWITCH_FALSE;
			}


			if (ok == SWITCH_FALSE) {
				switch_set_flag(bp, SMBF_PRUNE);
				prune++;
			}
		}
		switch_thread_rwlock_unlock(session->bug_rwlock);
		if (prune) {
			switch_core_media_bug_prune(session);
		}
	}

	if (do_bugs) {
		do_write = TRUE;
		write_frame = frame;
		goto done;
	}

	if (session->write_codec) {
		if (!ptime_mismatch && write_frame->codec && write_frame->codec->implementation &&
			write_frame->codec->implementation->decoded_bytes_per_packet == session->write_impl.decoded_bytes_per_packet) {
			perfect = TRUE;
		}



		if (perfect) {

			if (write_frame->datalen < session->write_impl.decoded_bytes_per_packet) {
				memset(write_frame->data, 255, session->write_impl.decoded_bytes_per_packet - write_frame->datalen);
				write_frame->datalen = session->write_impl.decoded_bytes_per_packet;
			}

			enc_frame = write_frame;
			session->enc_write_frame.datalen = session->enc_write_frame.buflen;

			status = switch_core_codec_encode(session->write_codec,
											  frame->codec,
											  enc_frame->data,
											  enc_frame->datalen,
											  session->write_impl.actual_samples_per_second,
											  session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag);




			switch (status) {
			case SWITCH_STATUS_RESAMPLE:
				resample++;
				/* switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 2\n"); */
			case SWITCH_STATUS_SUCCESS:
				session->enc_write_frame.codec = session->write_codec;
				session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
				if (frame->codec->implementation->samples_per_packet != session->write_impl.samples_per_packet) {
					session->enc_write_frame.timestamp = 0;
				} else {
					session->enc_write_frame.timestamp = frame->timestamp;
				}
				session->enc_write_frame.payload = session->write_impl.ianacode;
				session->enc_write_frame.m = frame->m;
				session->enc_write_frame.ssrc = frame->ssrc;
				session->enc_write_frame.seq = frame->seq;
				write_frame = &session->enc_write_frame;
				break;
			case SWITCH_STATUS_NOOP:
				enc_frame->codec = session->write_codec;
				enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
				enc_frame->timestamp = frame->timestamp;
				enc_frame->m = frame->m;
				enc_frame->seq = frame->seq;
				enc_frame->ssrc = frame->ssrc;
				enc_frame->payload = enc_frame->codec->implementation->ianacode;
				write_frame = enc_frame;
				status = SWITCH_STATUS_SUCCESS;
				break;
			case SWITCH_STATUS_NOT_INITALIZED:
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n");
				write_frame = NULL;
				goto error;
			default:
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error!\n",
								  session->read_codec->codec_interface->interface_name);
				write_frame = NULL;
				goto error;
			}
			if (flag & SFF_CNG) {
				switch_set_flag(write_frame, SFF_CNG);
			}

			status = perform_write(session, write_frame, flags, stream_id);
			goto error;
		} else {
			if (!session->raw_write_buffer) {
				switch_size_t bytes_per_packet = session->write_impl.decoded_bytes_per_packet;
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
								  "Engaging Write Buffer at %u bytes to accommodate %u->%u\n",
								  (uint32_t) bytes_per_packet, write_frame->datalen, session->write_impl.decoded_bytes_per_packet);
				if ((status = switch_buffer_create_dynamic(&session->raw_write_buffer,
														   bytes_per_packet * SWITCH_BUFFER_BLOCK_FRAMES,
														   bytes_per_packet * SWITCH_BUFFER_START_FRAMES, 0)) != SWITCH_STATUS_SUCCESS) {
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Write Buffer Failed!\n");
					goto error;
				}
			}

			if (!(switch_buffer_write(session->raw_write_buffer, write_frame->data, write_frame->datalen))) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Write Buffer %u bytes Failed!\n", write_frame->datalen);
				status = SWITCH_STATUS_MEMERR;
				goto error;
			}

			status = SWITCH_STATUS_SUCCESS;

			while (switch_buffer_inuse(session->raw_write_buffer) >= session->write_impl.decoded_bytes_per_packet) {
				int rate;

				if (switch_channel_down(session->channel) || !session->raw_write_buffer) {
					goto error;
				}
				if ((session->raw_write_frame.datalen = (uint32_t)
					 switch_buffer_read(session->raw_write_buffer, session->raw_write_frame.data, session->write_impl.decoded_bytes_per_packet)) == 0) {
					goto error;
				}

				enc_frame = &session->raw_write_frame;
				session->raw_write_frame.rate = session->write_impl.actual_samples_per_second;
				session->enc_write_frame.datalen = session->enc_write_frame.buflen;
				session->enc_write_frame.timestamp = 0;


				if (frame->codec && frame->codec->implementation && switch_core_codec_ready(frame->codec)) {
					rate = frame->codec->implementation->actual_samples_per_second;
				} else {
					rate = session->write_impl.actual_samples_per_second;
				}

				status = switch_core_codec_encode(session->write_codec,
												  frame->codec,
												  enc_frame->data,
												  enc_frame->datalen,
												  rate,
												  session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag);


				switch (status) {
				case SWITCH_STATUS_RESAMPLE:
					resample++;
					session->enc_write_frame.codec = session->write_codec;
					session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
					session->enc_write_frame.m = frame->m;
					session->enc_write_frame.ssrc = frame->ssrc;
					session->enc_write_frame.payload = session->write_impl.ianacode;
					write_frame = &session->enc_write_frame;
					if (!session->write_resampler) {
						switch_mutex_lock(session->resample_mutex);
						if (!session->write_resampler) {
							status = switch_resample_create(&session->write_resampler,
															frame->codec->implementation->actual_samples_per_second,
															session->write_impl.actual_samples_per_second,
															session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1);
						}
						switch_mutex_unlock(session->resample_mutex);



						if (status != SWITCH_STATUS_SUCCESS) {
							goto done;
						}
					}
					break;
				case SWITCH_STATUS_SUCCESS:
					session->enc_write_frame.codec = session->write_codec;
					session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
					session->enc_write_frame.m = frame->m;
					session->enc_write_frame.ssrc = frame->ssrc;
					session->enc_write_frame.payload = session->write_impl.ianacode;
					write_frame = &session->enc_write_frame;
					break;
				case SWITCH_STATUS_NOOP:
					if (session->write_resampler) {
						switch_mutex_lock(session->resample_mutex);
						if (session->write_resampler) {
							switch_resample_destroy(&session->write_resampler);
							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n");
						}
						switch_mutex_unlock(session->resample_mutex);
					}
					enc_frame->codec = session->write_codec;
					enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
					enc_frame->m = frame->m;
					enc_frame->ssrc = frame->ssrc;
					enc_frame->payload = enc_frame->codec->implementation->ianacode;
					write_frame = enc_frame;
					status = SWITCH_STATUS_SUCCESS;
					break;
				case SWITCH_STATUS_NOT_INITALIZED:
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n");
					write_frame = NULL;
					goto error;
				default:
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error %d!\n",
									  session->read_codec->codec_interface->interface_name, status);
					write_frame = NULL;
					goto error;
				}

				if (!did_write_resample && session->read_resampler) {
					short *data = write_frame->data;
					switch_mutex_lock(session->resample_mutex);
					if (session->read_resampler) {
						switch_resample_process(session->read_resampler, data, write_frame->datalen / 2);
						memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2);
						write_frame->samples = session->read_resampler->to_len;
						write_frame->datalen = session->read_resampler->to_len * 2;
						write_frame->rate = session->read_resampler->to_rate;
					}
					switch_mutex_unlock(session->resample_mutex);

				}

				if (flag & SFF_CNG) {
					switch_set_flag(write_frame, SFF_CNG);
				}

				if (ptime_mismatch || resample) {
					write_frame->timestamp = 0;
				}

				if ((status = perform_write(session, write_frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
					break;
				}

			}

			goto error;
		}
	}





  done:

	if (ptime_mismatch || resample) {
		write_frame->timestamp = 0;
	}

	if (do_write) {
		status = perform_write(session, write_frame, flags, stream_id);
	}

  error:

	switch_mutex_unlock(session->write_codec->mutex);
	switch_mutex_unlock(frame->codec->mutex);
	switch_mutex_unlock(session->codec_write_mutex);

	return status;
}
Exemplo n.º 23
0
static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *frame)
{
	vpx_context_t *context = (vpx_context_t *)codec->private_info;
	switch_size_t len;
	vpx_codec_ctx_t *decoder = NULL;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int is_start = 0, is_keyframe = 0, get_refresh = 0;

	if (context->is_vp9) {
		is_start = is_keyframe = IS_VP9_KEY_FRAME(*(unsigned char *)frame->data);
	} else { // vp8
		is_start = (*(unsigned char *)frame->data & 0x10);
		is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data);
	}

	// if (is_keyframe) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got key %d\n", is_keyframe);

	if (context->need_decoder_reset != 0) {
		vpx_codec_destroy(&context->decoder);
		context->decoder_init = 0;
		init_decoder(codec);
		context->need_decoder_reset = 0;
	}
	
	if (!context->decoder_init) {
		init_decoder(codec);
	}

	if (!context->decoder_init) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX decoder is not initialized!\n");
		return SWITCH_STATUS_FALSE;
	}

	decoder = &context->decoder;
	
	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "len: %d ts: %u mark:%d\n", frame->datalen, frame->timestamp, frame->m);

	// context->last_received_timestamp = frame->timestamp;
	context->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE;

	if (is_start) {
		context->got_start_frame = 1;
	}
	
	if (is_keyframe) {
		if (context->got_key_frame <= 0) {
			context->got_key_frame = 1;
			if (!is_keyframe) {
				get_refresh = 1;
			}
		} else {
			context->got_key_frame++;
		}
	} else if (context->got_key_frame <= 0) {
		if ((--context->got_key_frame % 200) == 0) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Waiting for key frame %d\n", context->got_key_frame);
		}
		if (!context->got_start_frame) {
			switch_goto_status(SWITCH_STATUS_MORE_DATA, end);
		}
	}


	status = context->is_vp9 ? buffer_vp9_packets(context, frame) : buffer_vp8_packets(context, frame);


	if (context->dec_iter && (frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter))) {
		switch_goto_status(SWITCH_STATUS_SUCCESS, end);
	}

	//printf("READ buf:%ld got_key:%d st:%d m:%d\n", switch_buffer_inuse(context->vpx_packet_buffer), context->got_key_frame, status, frame->m);

	len = switch_buffer_inuse(context->vpx_packet_buffer);

	//if (frame->m && (status != SWITCH_STATUS_SUCCESS || !len)) {
		//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "WTF????? %d %ld\n", status, len);
	//}


	if (status == SWITCH_STATUS_SUCCESS && frame->m && len) {
		uint8_t *data;
		int corrupted = 0;
		int err;

		switch_buffer_peek_zerocopy(context->vpx_packet_buffer, (void *)&data);

		context->dec_iter = NULL;
		err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0);

		if (err != VPX_CODEC_OK) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%s:%s]\n",
							  len, err, vpx_codec_error(decoder), vpx_codec_error_detail(decoder));
			switch_goto_status(SWITCH_STATUS_RESTART, end);
		}

		if (vpx_codec_control(decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX control error!\n");
			switch_goto_status(SWITCH_STATUS_RESTART, end);
		}
		
		if (corrupted) {
			frame->img = NULL;
		} else {
			frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter);
		}
		
		switch_buffer_zero(context->vpx_packet_buffer);
		
		if (!frame->img) {
			//context->need_decoder_reset = 1;
			context->got_key_frame = 0;
			context->got_start_frame = 0;
			status = SWITCH_STATUS_RESTART;
		}
	}

end:

	if (status == SWITCH_STATUS_RESTART) {
		switch_buffer_zero(context->vpx_packet_buffer);
		//context->need_decoder_reset = 1;
		context->got_key_frame = 0;
		context->got_start_frame = 0;
		//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "RESET VPX\n");
	}

	if (!frame->img || status == SWITCH_STATUS_RESTART) {
		status = SWITCH_STATUS_MORE_DATA;
	}

	if (context->got_key_frame <= 0 || get_refresh) {
		switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
	}

	return status;
}
Exemplo n.º 24
0
static switch_status_t buffer_vp8_packets(vpx_context_t *context, switch_frame_t *frame)
{
	uint8_t *data = frame->data;
	uint8_t S;
	uint8_t DES;
	//	uint8_t PID;
	int len;
#if 0
	int key = 0;

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, 
					  "VIDEO VPX: seq: %d ts: %u len: %ld %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d\n",
					  frame->seq, frame->timestamp, frame->datalen,
					  *((uint8_t *)data), *((uint8_t *)data + 1),
					  *((uint8_t *)data + 2), *((uint8_t *)data + 3),
					  *((uint8_t *)data + 4), *((uint8_t *)data + 5),
					  *((uint8_t *)data + 6), *((uint8_t *)data + 7),
					  *((uint8_t *)data + 8), *((uint8_t *)data + 9),
					  *((uint8_t *)data + 10), frame->m);
#endif

	
	DES = *data;
	data++;
	S = (DES & 0x10);
	//	PID = DES & 0x07;

	//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DATA LEN %d S BIT %d PID: %d\n", frame->datalen, S, PID);
			
	if (DES & 0x80) { // X
		uint8_t X = *data;
		//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "X BIT SET\n");
		data++;
		if (X & 0x80) { // I
			uint8_t M = (*data) & 0x80;
			//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "I BIT SET\n");
			data++;
			if (M) {
				//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "M BIT SET\n");
				data++;
			}
		}
		if (X & 0x40) {
			//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "L BIT SET\n");
			data++; // L
		}
		if (X & 0x30) {
			//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "T/K BIT SET\n");
			data++; // T/K
		}
	}

	if (!switch_buffer_inuse(context->vpx_packet_buffer) && !S) {
		if (context->got_key_frame > 0) {
			context->got_key_frame = 0;
			context->got_start_frame = 0;
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "packet loss?\n");
		}
		return SWITCH_STATUS_MORE_DATA;
	}

	if (S) {
		switch_buffer_zero(context->vpx_packet_buffer);
		context->last_received_timestamp = frame->timestamp;
#if 0
		if (PID == 0) {
			key = __IS_VP8_KEY_FRAME(*data);
		}
#endif
	}

	len = frame->datalen - (data - (uint8_t *)frame->data);
	//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POST PARSE: DATA LEN %d KEY %d KEYBYTE = %0x\n", len, key, *data);
	
	if (len <= 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid packet %d\n", len);
		return SWITCH_STATUS_RESTART;
	}

	if (context->last_received_timestamp != frame->timestamp) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "wrong timestamp %u, expect %u, packet loss?\n", frame->timestamp, context->last_received_timestamp);
		switch_buffer_zero(context->vpx_packet_buffer);
		return SWITCH_STATUS_RESTART;
	}

	switch_buffer_write(context->vpx_packet_buffer, data, len);
	return SWITCH_STATUS_SUCCESS;
}
Exemplo n.º 25
0
/**
 * Read from file
 * @param handle
 * @param data
 * @param len
 * @return
 */
static switch_status_t fileman_file_read(switch_file_handle_t *handle, void *data, size_t *len)
{
	struct fileman_file_context *context = (struct fileman_file_context *)handle->private_info;
	switch_file_handle_t *fh = &context->fh;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_size_t o_len = 0;

	/* anything called "_len" is measured in 2-byte samples */

	if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
		return switch_core_file_read(fh, data, len);
	}

	//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "len = %"SWITCH_SIZE_T_FMT"\n", *len);
	if (*len > context->max_frame_len) {
		*len = context->max_frame_len;
	}

	for (;;) {
		int do_speed = 1;
		size_t read_bytes = 0;

		if (switch_test_flag(handle, SWITCH_FILE_PAUSE)) {
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read pause frame\n");
			memset(context->abuf, 255, *len * 2);
			do_speed = 0;
			o_len = *len;
		} else if (fh->sp_audio_buffer && (context->eof || (switch_buffer_inuse(fh->sp_audio_buffer) > (switch_size_t) (*len * 2)))) {
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read speed frame\n");
			/* get next speed frame */
			if (!(read_bytes = switch_buffer_read(fh->sp_audio_buffer, context->abuf, *len * 2))) {
				/* This is the reverse of what happens in switch_ivr_play_file... i think that implementation is wrong */
				if (context->eof) {
					/* done with file */
					status = SWITCH_STATUS_FALSE;
					goto done;
				} else {
					/* try again to fetch frame */
					continue;
				}
			}

			/* pad short frame with silence */
			if (read_bytes < *len * 2) {
				//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Padding speed frame %"SWITCH_SIZE_T_FMT" bytes\n", (context->frame_len * 2) - read_bytes);
				memset(context->abuf + read_bytes, 255, (*len * 2) - read_bytes);
			}
			o_len = *len;
			do_speed = 0;
		} else if (fh->audio_buffer && (context->eof || (switch_buffer_inuse(fh->audio_buffer) > (switch_size_t) (*len * 2)))) {
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "(2) Read audio frame\n");
			/* get next file frame */
			if (!(read_bytes = switch_buffer_read(fh->audio_buffer, context->abuf, *len * 2))) {
				if (context->eof) {
					/* done with file */
					status = SWITCH_STATUS_FALSE;
					goto done;
				} else {
					/* try again to fetch frame */
					continue;
				}
			}
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "(2) Read audio frame %"SWITCH_SIZE_T_FMT" bytes\n", read_bytes);
			fh->offset_pos += read_bytes / 2;
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "(2) file pos = %i\n", fh->offset_pos);

			/* pad short frame with silence */
			if (read_bytes < (*len * 2)) {
				//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Padding audio frame %"SWITCH_SIZE_T_FMT" bytes\n", (context->frame_len * 2) - read_bytes);
				memset(context->abuf + read_bytes, 255, (*len * 2) - read_bytes);
			}

			o_len = *len;
		} else {
			if (context->eof) {
				/* done with file */
				status = SWITCH_STATUS_FALSE;
				goto done;
			}
			o_len = FILE_STARTBYTES / 2;
			if (switch_core_file_read(fh, context->abuf, &o_len) != SWITCH_STATUS_SUCCESS) {
				context->eof++;
				/* at end of file... need to clear buffers before giving up */
				continue;
			}
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read file %"SWITCH_SIZE_T_FMT" bytes\n", o_len * 2);

			/* add file data to audio bufer */
			read_bytes = switch_buffer_write(fh->audio_buffer, context->abuf, o_len * 2);
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Write audio frame %"SWITCH_SIZE_T_FMT" bytes\n", read_bytes);

			read_bytes = switch_buffer_read(fh->audio_buffer, context->abuf, *len * 2);
			o_len = read_bytes / 2;
			fh->offset_pos += o_len;
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read audio frame %"SWITCH_SIZE_T_FMT" bytes\n", read_bytes);
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "file pos = %i\n", fh->offset_pos);
		}

		if (o_len <= 0) {
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "o_len <= 0 (%"SWITCH_SIZE_T_FMT")\n", o_len);
			status = SWITCH_STATUS_FALSE;
			goto done;
		}

		/* limit speed... there is a .25 factor change in packet size relative to original packet size for each increment.
		   Too many increments and we cause badness when (factor * speed * o_len) > o_len */
		if (handle->speed > 2) {
			handle->speed = 2;
		} else if (handle->speed < -2) {
			handle->speed = -2;
		}

		if (switch_test_flag(fh, SWITCH_FILE_SEEK)) {
			/* file position has changed flush the buffer */
			switch_buffer_zero(fh->audio_buffer);
			switch_clear_flag(fh, SWITCH_FILE_SEEK);
		}

		/* generate speed frames */
		if (handle->speed && do_speed) {
			float factor = 0.25f * abs(handle->speed);
			switch_size_t new_len, supplement_len, step_len;
			short *bp = context->abuf;
			switch_size_t wrote_len = 0;
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Generate speed frame (%i)\n", handle->speed);

			supplement_len = (int) (factor * o_len);
			if (!supplement_len) {
				supplement_len = 1;
			}
			new_len = (handle->speed > 0) ? o_len - supplement_len : o_len + supplement_len;

			step_len = (handle->speed > 0) ? (new_len / supplement_len) : (o_len / supplement_len);

			if (!fh->sp_audio_buffer) {
				switch_buffer_create_dynamic(&fh->sp_audio_buffer, 1024, 1024, 0);
			}

			while ((wrote_len + step_len) < new_len) {
				switch_buffer_write(fh->sp_audio_buffer, bp, step_len * 2);
				wrote_len += step_len;
				bp += step_len;
				if (handle->speed > 0) {
					bp++;
				} else {
					float f;
					short s;
					f = (float) (*bp + *(bp + 1) + *(bp - 1));
					f /= 3;
					s = (short) f;
					switch_buffer_write(fh->sp_audio_buffer, &s, 2);
					wrote_len++;
				}
			}
			if (wrote_len < new_len) {
				switch_size_t r_len = new_len - wrote_len;
				switch_buffer_write(fh->sp_audio_buffer, bp, r_len * 2);
				wrote_len += r_len;
			}
			continue;
		}

		/* adjust volume on frame */
		if (handle->vol) {
			//switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Adjust volume to = %i\n", handle->vol);
			switch_change_sln_volume(context->abuf, *len, handle->vol);
		}
		break;
	}

done:

	/* copy frame over to return to caller */
	memcpy(data, context->abuf, *len * 2);
	handle->offset_pos = context->fh.offset_pos;

	return status;
}
Exemplo n.º 26
0
static switch_status_t cepstral_speech_read_tts(switch_speech_handle_t *sh, void *data, size_t *datalen, switch_speech_flag_t *flags)
{
	cepstral_t *cepstral;
	size_t desired = *datalen;
	switch_status_t status = SWITCH_STATUS_FALSE;
	size_t used, padding = 0;

	assert(sh != NULL);
	cepstral = sh->private_info;
	assert(cepstral != NULL);

	while (!cepstral->done) {
		if (!cepstral->done_gen) {
			int check = swift_port_status(cepstral->port, cepstral->tts_stream);

			if (!check == SWIFT_STATUS_RUNNING) {
				cepstral->done_gen = 1;
			}
		}

		switch_mutex_lock(cepstral->audio_lock);
		used = switch_buffer_inuse(cepstral->audio_buffer);
		switch_mutex_unlock(cepstral->audio_lock);


		if (!used && cepstral->done_gen) {

			status = SWITCH_STATUS_BREAK;
			break;
		}

		/* wait for the right amount of data (unless there is no blocking flag) */
		if (used < desired) {
			if (cepstral->done_gen) {
				padding = desired - used;
				desired = used;
			}
			if (!(*flags & SWITCH_SPEECH_FLAG_BLOCKING)) {
				*datalen = 0;
				status = SWITCH_STATUS_SUCCESS;
				break;
			}
			switch_cond_next();
			continue;
		}

		/* There is enough, read it and return */
		switch_mutex_lock(cepstral->audio_lock);
		*datalen = switch_buffer_read(cepstral->audio_buffer, data, desired);
		if (padding) {
			size_t x = 0;
			unsigned char *p = data;

			for (x = 0; x < padding; x++) {
				*(p + x) = 0;
				(*datalen)++;
			}
		}

		switch_mutex_unlock(cepstral->audio_lock);
		status = SWITCH_STATUS_SUCCESS;

		break;
	}

	return status;
}
Exemplo n.º 27
0
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
{
	local_stream_source_t *source = obj;
	switch_file_handle_t fh = { 0 };
	local_stream_context_t *cp;
	char file_buf[128] = "", path_buf[512] = "";
	switch_timer_t timer = { 0 };
	int fd = -1;
	switch_buffer_t *audio_buffer;
	switch_byte_t *dist_buf;
	switch_size_t used;
	int skip = 0;
	switch_memory_pool_t *temp_pool = NULL;

	switch_mutex_lock(globals.mutex);
	THREADS++;
	switch_mutex_unlock(globals.mutex);

	if (!source->prebuf) {
		source->prebuf = DEFAULT_PREBUFFER_SIZE;
	}

	switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0);
	dist_buf = switch_core_alloc(source->pool, source->prebuf + 10);

	if (source->shuffle) {
		skip = do_rand();
	}

	switch_thread_rwlock_create(&source->rwlock, source->pool);

	if (RUNNING) {
		switch_mutex_lock(globals.mutex);
		switch_core_hash_insert(globals.source_hash, source->name, source);
		switch_mutex_unlock(globals.mutex);
		source->ready = 1;
	}

	while (RUNNING && !source->stopped) {
		const char *fname;

		if (temp_pool) {
			switch_core_destroy_memory_pool(&temp_pool);
		}

		if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool");
			goto done;
		}

		if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location);
			goto done;
		}

		switch_yield(1000000);

		while (RUNNING && !source->stopped) {
			switch_size_t olen;
			uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };

			if (fd > -1) {
				char *p;
				if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
					if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) {
						*p = '\0';
					}
				} else {
					close(fd);
					fd = -1;
					continue;
				}
			} else {
				if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) {
					break;
				}

				switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname);

				if (switch_stristr(".loc", path_buf)) {
					if ((fd = open(path_buf, O_RDONLY)) < 0) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
						switch_yield(1000000);
					}
					continue;
				}
			}

			if (skip > 0) {
				skip--;
				continue;
			}

			fname = path_buf;
			fh.prebuf = source->prebuf;
			fh.pre_buffer_datalen = source->prebuf;

			if (switch_core_file_open(&fh,
									  (char *) fname,
									  source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
				switch_yield(1000000);
				continue;
			}

			if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n");
				switch_dir_close(source->dir_handle);
				source->dir_handle = NULL;
				goto done;
			}

			while (RUNNING && !source->stopped) {
				int is_open;
				switch_file_handle_t *use_fh = &fh;

				switch_core_timer_next(&timer);
				olen = source->samples;

				if (source->chime_total) {

					if (source->chime_counter > 0) {
						source->chime_counter -= (int32_t)source->samples;
					}

					if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) {
						char *val;

						val = source->chime_list[source->chime_cur++];

						if (source->chime_cur >= source->chime_total) {
							source->chime_cur = 0;
						}

						if (switch_core_file_open(&source->chime_fh,
												  (char *) val,
												  source->channels,
												  source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val);
						}
					}

					if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
						use_fh = &source->chime_fh;
					}
				}

			  retry:

				is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN);

				if (source->hup) {
					source->hup = 0;
					if (is_open) {
						is_open = 0;

						switch_core_file_close(use_fh);
						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
							use_fh = &fh;
							goto retry;
							//switch_core_file_close(&fh);
						}
					}
				}



				if (is_open) {
					if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
						switch_core_file_close(use_fh);
						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
						}
						is_open = 0;
					} else {
						if (use_fh == &source->chime_fh && source->chime_max) {
							source->chime_max_counter += (int32_t)source->samples;
							if (source->chime_max_counter >= source->chime_max) {
								source->chime_max_counter = 0;
								switch_core_file_close(use_fh);
								source->chime_counter = source->rate * source->chime_freq;
								use_fh = &fh;
								goto retry;
							}
						}

						switch_buffer_write(audio_buffer, abuf, olen * 2);
					}
				}

				used = switch_buffer_inuse(audio_buffer);

				if (!used && !is_open) {
					break;
				}

				if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) {
					used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2);
					if (source->total) {
						uint32_t bused = 0;
						switch_mutex_lock(source->mutex);
						for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
							if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
								continue;
							}
							switch_mutex_lock(cp->audio_mutex);
							bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer);
							if (bused > source->samples * 768) {
								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", 
												  cp->func, cp->file, cp->line, bused, (long)source->samples);
								switch_buffer_zero(cp->audio_buffer);
							} else {
								switch_buffer_write(cp->audio_buffer, dist_buf, used);
							}
							switch_mutex_unlock(cp->audio_mutex);
						}
						switch_mutex_unlock(source->mutex);
					}
				}
			}

			switch_core_timer_destroy(&timer);
			if (RUNNING && source->shuffle) {
				skip = do_rand();
			}
		}

		switch_dir_close(source->dir_handle);
		source->dir_handle = NULL;

		if (source->full_reload) {
			if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name);
				if (source->part_reload) {
					switch_xml_t cfg, xml, directory, param;
					if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
					}
					if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) {
						for (param = switch_xml_child(directory, "param"); param; param = param->next) {
							char *var = (char *) switch_xml_attr_soft(param, "name");
							char *val = (char *) switch_xml_attr_soft(param, "value");
							if (!strcasecmp(var, "shuffle")) {
								source->shuffle = switch_true(val);
							} else if (!strcasecmp(var, "chime-freq")) {
								int tmp = atoi(val);
								if (tmp > 1) {
									source->chime_freq = tmp;
								}
							} else if (!strcasecmp(var, "chime-max")) {
								int tmp = atoi(val);
								if (tmp > 1) {
									source->chime_max = tmp;
								}
							} else if (!strcasecmp(var, "chime-list")) {
								char *list_dup = switch_core_strdup(source->pool, val);
								source->chime_total =
									switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
							} else if (!strcasecmp(var, "interval")) {
								int tmp = atoi(val);
								if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
									source->interval = tmp;
								} else {
									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
													  "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
								}
							}
							if (source->chime_max) {
								source->chime_max *= source->rate;
							}
							if (source->chime_total) {
								source->chime_counter = source->rate * source->chime_freq;
							}
						}
					}
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name);
					source->part_reload = 0;
				}
			} else {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name);
				launch_streams(source->name);
				goto done;
			}
		}
	}

  done:

	if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&fh);
	}

	if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&source->chime_fh);
	}

	source->ready = 0;
	switch_mutex_lock(globals.mutex);
	switch_core_hash_delete(globals.source_hash, source->name);
	switch_mutex_unlock(globals.mutex);

	switch_thread_rwlock_wrlock(source->rwlock);
	switch_thread_rwlock_unlock(source->rwlock);

	switch_buffer_destroy(&audio_buffer);

	if (fd > -1) {
		close(fd);
	}

	if (temp_pool) {
		switch_core_destroy_memory_pool(&temp_pool);
	}

	switch_core_destroy_memory_pool(&source->pool);

	switch_mutex_lock(globals.mutex);
	THREADS--;
	switch_mutex_unlock(globals.mutex);

	return NULL;
}
Exemplo n.º 28
0
static switch_status_t do_write_video(switch_file_handle_t *handle, switch_frame_t *frame)
{
	uint32_t datalen = frame->datalen;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int is_iframe = 0;
	uint32_t size;
	uint8_t *hdr = NULL;
	uint8_t fragment_type;
	uint8_t nal_type;
	uint8_t start_bit;
	mp4_file_context_t *context = handle->private_info;

	hdr = (uint8_t *)frame->data;
	fragment_type = hdr[0] & 0x1f;
	nal_type = hdr[1] & 0x1f;
	start_bit = hdr[1] & 0x80;
	is_iframe = (((fragment_type == 28 || fragment_type == 29) && nal_type == 5 && start_bit == 128) || fragment_type == 5 || fragment_type ==7 || fragment_type ==8) ? 1 : 0;

	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x | len:%d m:%d st:%d i:%d\n", hdr[0], hdr[1], hdr[2], datalen, frame->m, start_bit, is_iframe);

	size = htonl(datalen);
	switch_buffer_write(context->buf, &size, 4);
	switch_buffer_write(context->buf, hdr, datalen);

	switch_mutex_lock(context->mutex);

	if (fragment_type == 7 && !context->sps_set) { //sps
		context->sps_set = 1;

		init_video_track(context->fd, &context->video, frame);
		if (context->video == MP4_INVALID_TRACK_ID) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add video track!\n");
			switch_goto_status(SWITCH_STATUS_FALSE, end);
		}
	} else if (fragment_type == 8 && context->sps_set && !context->pps_set) { //pps
		MP4AddH264PictureParameterSet(context->fd, context->video, hdr, datalen);
		context->pps_set = 1;
	}

	if (nal_type == 7 || nal_type == 8 || frame->m == 0) {
	} else if (context->sps_set && context->pps_set) {
		uint32_t used = switch_buffer_inuse(context->buf);
		const void *data;
		int duration = 0;

		if (!context->timer.interval) {
			switch_core_timer_init(&context->timer, "soft", 1, 1, context->pool);
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "init timer\n");
		} else {
			switch_core_timer_sync(&context->timer);
		}

		duration = context->timer.samplecount - context->last_pts;

		// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "samplecount: %u, duration: %u\n", context->timer.samplecount, duration);
		switch_buffer_peek_zerocopy(context->buf, &data);

		if (context->last_pts == 0) { // first img, write at the very beginning so we don't see blank screen
			duration /= 2;
			MP4WriteSample(context->fd, context->video, data, used, duration, 0, is_iframe);

			if (duration > context->offset) {
				duration -= context->offset;
			} else {
				duration = 0;
			}
		}

		context->last_pts = context->timer.samplecount;

		// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "samplecount: %u, duration: %u\n", context->timer.samplecount, duration);

		if (duration) {
			MP4WriteSample(context->fd, context->video, data, used, duration, 0, is_iframe);
		}
		switch_buffer_zero(context->buf);
	}

end:
	switch_mutex_unlock(context->mutex);

	return status;
}
Exemplo n.º 29
0
static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t *frame)
{
	vpx_payload_descriptor_t *payload_descriptor;
	uint8_t *body;
	uint32_t hdrlen = 0, payload_size = 0, packet_size = 0, start = 0, key = 0;
	switch_size_t remaining_bytes = 0;

	if (!context->pkt) {
		if ((context->pkt = vpx_codec_get_cx_data(&context->encoder, &context->enc_iter))) {
			start = 1;
			if (!context->pbuffer) {
				switch_buffer_create_partition(context->pool, &context->pbuffer, context->pkt->data.frame.buf, context->pkt->data.frame.sz);
			} else {
				switch_buffer_set_partition_data(context->pbuffer, context->pkt->data.frame.buf, context->pkt->data.frame.sz);
			}
		}
	}

	if (context->pbuffer) {
		remaining_bytes = switch_buffer_inuse(context->pbuffer);
	}

	if (!context->pkt || context->pkt->kind != VPX_CODEC_CX_FRAME_PKT || !remaining_bytes) {
		frame->datalen = 0;
		frame->m = 1;
		context->pkt = NULL;
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "writing 0 bytes\n");
		return SWITCH_STATUS_SUCCESS;
	}

	key = (context->pkt->data.frame.flags & VPX_FRAME_IS_KEY);

#if 0
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "flags: %x pts: %lld duration:%lu partition_id: %d\n",
		context->pkt->data.frame.flags, context->pkt->data.frame.pts, context->pkt->data.frame.duration, context->pkt->data.frame.partition_id);
#endif

	/* reset header */
	*(uint8_t *)frame->data = 0;
	payload_descriptor = (vpx_payload_descriptor_t *) frame->data;

	// if !extended
	hdrlen = 1;
	body = ((uint8_t *)frame->data) + hdrlen;
	packet_size = SLICE_SIZE;
	payload_size = packet_size - hdrlen;
	// else add extended TBD

	frame->datalen = hdrlen;

	if (context->is_vp9) {
		payload_descriptor->vp9.start = start;
		payload_descriptor->vp9.key = key;
	} else {
		payload_descriptor->vp8.start = start;
	}

	if (remaining_bytes <= payload_size) {
		switch_buffer_read(context->pbuffer, body, remaining_bytes);
		context->pkt = NULL;
		frame->datalen += remaining_bytes;
		frame->m = 1;
		return SWITCH_STATUS_SUCCESS;
	} else {
		switch_buffer_read(context->pbuffer, body, payload_size);
		frame->datalen += payload_size;
		frame->m = 0;
		return SWITCH_STATUS_MORE_DATA;
	}
}
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
{
	local_stream_source_t *source = obj;
	switch_file_handle_t fh = { 0 };
	local_stream_context_t *cp;
	char file_buf[128] = "", path_buf[512] = "", last_path[512], png_buf[512] = "", tmp_buf[512] = "";
	switch_timer_t timer = { 0 };
	int fd = -1;
	switch_buffer_t *audio_buffer;
	switch_byte_t *dist_buf;
	switch_size_t used;
	int skip = 0;
	switch_memory_pool_t *temp_pool = NULL;
	uint32_t dir_count = 0, do_shuffle = 0;
	char *p;

	switch_mutex_lock(globals.mutex);
	THREADS++;
	switch_mutex_unlock(globals.mutex);

	if (!source->prebuf) {
		source->prebuf = DEFAULT_PREBUFFER_SIZE;
	}

	if (source->shuffle) {
		do_shuffle = 1;
	}

	switch_queue_create(&source->video_q, 500, source->pool);
	switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0);
	dist_buf = switch_core_alloc(source->pool, source->prebuf + 10);

	switch_thread_rwlock_create(&source->rwlock, source->pool);

	if (RUNNING) {
		switch_mutex_lock(globals.mutex);
		switch_core_hash_insert(globals.source_hash, source->name, source);
		switch_mutex_unlock(globals.mutex);
		source->ready = 1;
	}

	while (RUNNING && !source->stopped) {
		const char *fname;

		if (temp_pool) {
			switch_core_destroy_memory_pool(&temp_pool);
		}

		if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool");
			goto done;
		}

		if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location);
			goto done;
		}

		if (fd > -1) {
			dir_count = 0;
			while (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
				dir_count++;
			}
			lseek(fd, 0, SEEK_SET);
		} else {
			dir_count = switch_dir_count(source->dir_handle);
		}

		if (do_shuffle) {
			skip = do_rand(dir_count);
			do_shuffle = 0;
		}

		switch_yield(1000000);

		while (RUNNING && !source->stopped) {
			switch_size_t olen;
			uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
			const char *artist = NULL, *title = NULL;

			if (fd > -1) {
				char *pb;
				if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
					if ((pb = strchr(path_buf, '\r')) || (pb = strchr(path_buf, '\n'))) {
						*pb = '\0';
					}
				} else {
					close(fd);
					fd = -1;
					continue;
				}
			} else {
				if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) {
					break;
				}

				switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname);

				if (switch_stristr(".loc", path_buf)) {
					if ((fd = open(path_buf, O_RDONLY)) < 0) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
						switch_yield(1000000);
					}
					continue;
				}
			}

			if (dir_count > 1 && !strcmp(last_path, path_buf)) {
				continue;
			}

			if (skip > 0) {
				skip--;
				continue;
			}

			switch_set_string(last_path, path_buf);

			fname = path_buf;
			fh.prebuf = source->prebuf;
			fh.pre_buffer_datalen = source->prebuf;

			if (switch_core_file_open(&fh,
									  (char *) fname,
									  source->channels, source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
				switch_yield(1000000);
				continue;
			}

			if (switch_core_file_has_video(&fh)) {
				flush_video_queue(source->video_q);
			}

			if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n");
				switch_dir_close(source->dir_handle);
				source->dir_handle = NULL;
				goto done;
			}

			switch_img_free(&source->cover_art);
			switch_set_string(tmp_buf, path_buf);
			if ((p = strrchr(tmp_buf, '/'))) {
				*p++ = '\0';
				switch_snprintf(png_buf, sizeof(png_buf), "%s/art/%s.png", tmp_buf, p);				
				if (switch_file_exists(png_buf, source->pool) == SWITCH_STATUS_SUCCESS) {
					source->cover_art = switch_img_read_png(png_buf, SWITCH_IMG_FMT_I420);
				}
			}

			source->serno++;
			switch_safe_free(source->banner_txt);
			title = artist = NULL;
			
			switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_ARTIST, &artist);
			switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_TITLE, &title);
			
			if (title && (source->cover_art || switch_core_file_has_video(&fh))) {
				const char *format = "#cccccc:#333333:FreeSans.ttf:3%:";

				if (artist) {
					source->banner_txt = switch_mprintf("%s%s (%s)", format, title, artist);
				} else {
					source->banner_txt = switch_mprintf("%s%s", format, title);
				}
			}

			while (RUNNING && !source->stopped) {
				int is_open;
				switch_file_handle_t *use_fh = &fh;

				switch_core_timer_next(&timer);
				olen = source->samples;
				
				if (source->chime_total) {

					if (source->chime_counter > 0) {
						source->chime_counter -= (int32_t)source->samples;
					}

					if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) {
						char *val;

						val = source->chime_list[source->chime_cur++];

						if (source->chime_cur >= source->chime_total) {
							source->chime_cur = 0;
						}

						if (switch_core_file_open(&source->chime_fh,
												  (char *) val,
												  source->channels,
												  source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val);
						}


						if (switch_core_file_has_video(&source->chime_fh)) {
							flush_video_queue(source->video_q);
						}

					}

					if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
						use_fh = &source->chime_fh;
					}
				}

			retry:

				source->has_video = switch_core_file_has_video(use_fh) || source->cover_art || source->banner_txt;

				is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN);

				if (source->hup) {
					source->hup = 0;
					if (is_open) {
						is_open = 0;

						switch_core_file_close(use_fh);
						flush_video_queue(source->video_q);
						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
							switch_core_file_close(&fh);
							use_fh = &fh;							
						}
						goto retry;
					}
				}
				
				if (is_open) {
					if (switch_core_has_video() && switch_core_file_has_video(use_fh)) {
						switch_frame_t vid_frame = { 0 };

						if (use_fh == &source->chime_fh && switch_core_file_has_video(&fh)) {
							if (switch_core_file_read_video(&fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
								switch_img_free(&vid_frame.img);
							}
						}

						if (switch_core_file_read_video(use_fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
							if (vid_frame.img) {
								int flush = 1;

								source->has_video = 1;
								
								if (source->total) {
									if (switch_queue_trypush(source->video_q, vid_frame.img) == SWITCH_STATUS_SUCCESS) {
										flush = 0;
									}
								}

								if (flush) {
									switch_img_free(&vid_frame.img);
									flush_video_queue(source->video_q);
								}
							}
						}
					} else {
						source->has_video = 0;
					}

					if (use_fh == &source->chime_fh) {
						olen = source->samples;
						switch_core_file_read(&fh, abuf, &olen);
						olen = source->samples;
					}

					if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
						switch_core_file_close(use_fh);
						flush_video_queue(source->video_q);

						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
							use_fh = &fh;
						} else {
							is_open = 0;
						}
					} else {
						if (use_fh == &source->chime_fh && source->chime_max) {
							source->chime_max_counter += (int32_t)source->samples;
							if (source->chime_max_counter >= source->chime_max) {
								source->chime_max_counter = 0;
								switch_core_file_close(use_fh);
								flush_video_queue(source->video_q);
								source->chime_counter = source->rate * source->chime_freq;
								use_fh = &fh;
								goto retry;
							}
						}
						
						if (source->total) {
							switch_buffer_write(audio_buffer, abuf, olen * 2 * source->channels);
						} else {
							switch_buffer_zero(audio_buffer);
						}
					}
				}

				used = switch_buffer_inuse(audio_buffer);

				if (!used && !is_open) {
					break;
				}

				if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) {
					void *pop;

					used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels);

					if (!source->total) {
						flush_video_queue(source->video_q);
					} else {
						uint32_t bused = 0;

						switch_mutex_lock(source->mutex);
						for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
							
							if (source->has_video) {
								switch_set_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
							} else {
								switch_clear_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
							}
							
							if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
								continue;
							}
							
							switch_mutex_lock(cp->audio_mutex);
							bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer);
							if (bused > source->samples * 768) {
								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", 
												  cp->func, cp->file, cp->line, bused, (long)source->samples);
								switch_buffer_zero(cp->audio_buffer);
							} else {
								switch_buffer_write(cp->audio_buffer, dist_buf, used);
							}
							switch_mutex_unlock(cp->audio_mutex);
						}
						switch_mutex_unlock(source->mutex);

						
						while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
							switch_image_t *img = (switch_image_t *) pop;
							switch_image_t *imgcp = NULL;

							if (source->total == 1) {
								switch_queue_push(source->context_list->video_q, img);
							} else {
								if (source->context_list) {
									switch_mutex_lock(source->mutex);
									for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
										if (cp->video_q) {
											imgcp = NULL;
											switch_img_copy(img, &imgcp);
											if (imgcp) {
												if (switch_queue_trypush(cp->video_q, imgcp) != SWITCH_STATUS_SUCCESS) {
													flush_video_queue(cp->video_q);
												}
											}
										}
									}
									switch_mutex_unlock(source->mutex);
								}
								switch_img_free(&img);
							}
						}
					}
				}
			}

			switch_core_timer_destroy(&timer);
			if (RUNNING && source->shuffle) {
				skip = do_rand(dir_count);
			}
		}

		switch_dir_close(source->dir_handle);
		source->dir_handle = NULL;

		if (source->full_reload) {
			if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name);
				if (source->part_reload) {
					switch_xml_t cfg, xml, directory, param;
					if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
					}
					if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) {
						for (param = switch_xml_child(directory, "param"); param; param = param->next) {
							char *var = (char *) switch_xml_attr_soft(param, "name");
							char *val = (char *) switch_xml_attr_soft(param, "value");
							if (!strcasecmp(var, "shuffle")) {
								source->shuffle = switch_true(val);
							} else if (!strcasecmp(var, "chime-freq")) {
								int tmp = atoi(val);
								if (tmp > 1) {
									source->chime_freq = tmp;
								}
							} else if (!strcasecmp(var, "chime-max")) {
								int tmp = atoi(val);
								if (tmp > 1) {
									source->chime_max = tmp;
								}
							} else if (!strcasecmp(var, "chime-list")) {
								char *list_dup = switch_core_strdup(source->pool, val);
								source->chime_total =
									switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
							} else if (!strcasecmp(var, "interval")) {
								int tmp = atoi(val);
								if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
									source->interval = tmp;
								} else {
									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
													  "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
								}
							}
							if (source->chime_max) {
								source->chime_max *= source->rate;
							}
							if (source->chime_total) {
								source->chime_counter = source->rate * source->chime_freq;
							}
						}
					}
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name);
					source->part_reload = 0;
				}
			} else {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name);
				launch_streams(source->name);
				goto done;
			}
		}
	}

  done:

	switch_safe_free(source->banner_txt);
	
	if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&fh);
	}

	if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&source->chime_fh);
	}

	source->ready = 0;
	switch_mutex_lock(globals.mutex);
	switch_core_hash_delete(globals.source_hash, source->name);
	switch_mutex_unlock(globals.mutex);

	switch_thread_rwlock_wrlock(source->rwlock);
	switch_thread_rwlock_unlock(source->rwlock);

	switch_buffer_destroy(&audio_buffer);

	flush_video_queue(source->video_q);

	if (fd > -1) {
		close(fd);
	}

	if (temp_pool) {
		switch_core_destroy_memory_pool(&temp_pool);
	}

	switch_core_destroy_memory_pool(&source->pool);

	switch_mutex_lock(globals.mutex);
	THREADS--;
	switch_mutex_unlock(globals.mutex);

	return NULL;
}