示例#1
0
/*
 *  Thread for fax receiving
 *  We need to receive UDP (with UDPTL) packet and feed it to spandsp and also
 *  get UDPTL from spandsp and send them to remote IAF
 */
void *fax_worker_thread(void *data)
{
    fax_session_t *fax_session = (fax_session_t *)data;
    struct sockaddr_in local_addr;
    int ret_val = 0;
    int bytes_received = 0;
    const int poll_timeout = 20;
    struct pollfd fds;

    struct in_addr addr;
    addr.s_addr = htonl(fax_session->remote_ip);


    printf("fax: Starting T.38 FAX handling: local_port: %d remote_addr:%s:%d\n",
           fax_session->local_port, inet_ntoa(addr), fax_session->remote_port);

    fax_params_init(fax_session);

    ret_val = socket_init(&local_addr, fax_session);
    if (ret_val < 0) {
        printf("fax: Fax socket init failed\n");
        goto thread_finish;
    }

    fds.fd = ret_val;
    fds.events = POLLIN;

    fax_params_set_default(fax_session);
    if (spanfax_init(fax_session, FAX_TRANSPORT_T38_MOD) != 0) {
        printf("fax: spanfax_init() ERROR\n");
        goto thread_finish;
    }

    configure_t38(fax_session);

    if(!fax_session->pvt.caller)
    {
        printf("fax %s receiver: wait first frame\n", fax_session->call_id);
        bytes_received = receive_frame(fax_session, msg_buffer, MAX_MSG_SIZE);
        printf("fax %s receiver: first frame received\n", fax_session->call_id);
    }

    fcntl(fax_session->socket_fd, F_SETFL, O_NONBLOCK);

    while (!fax_session->pvt.done) {

        /*
         * All we need to do here is:
         *      1) Receive new UDPTL packet without blocking
         *      2) Feed it to spandsp (udptl_rx_packet)
         *      3) Invoke t38_terminal_send_timeout() function
         */
        ret_val = poll(&fds, 1, poll_timeout);
        if (ret_val == -1) {
            perror("poll");
            break;
        }

        if (fds.revents & POLLIN) {

            bytes_received = receive_frame(fax_session, msg_buffer, MAX_MSG_SIZE);
//            printf("fax: Packet RECEIVED (size: %d)\n", bytes_received);
            if (bytes_received == 0) continue;
            if (bytes_received == -1) {
                printf("fax: receive_frame() ERRROR: returned -1\n");
                break;
            }

            ret_val = udptl_rx_packet(fax_session->pvt.udptl_state,
                                      msg_buffer, bytes_received);
            if (ret_val) printf("fax %s: udptl_rx_packet() ERROR\n", fax_session->call_id);
        }

        t38_terminal_send_timeout(fax_session->pvt.t38_state, FRAMES_PER_CHUNK);
    }

thread_finish:
    spanfax_destroy(fax_session);
    fax_params_destroy(fax_session);

    close(fds.fd);

    pthread_exit(NULL);
}
static inline CopyRet receive_frame(AVCodecContext *avctx,
                                    void *data, int *data_size,
                                    uint8_t second_field)
{
	BC_STATUS ret;
	BC_DTS_PROC_OUT output =
	{
		.PicInfo.width  = avctx->width,
		.PicInfo.height = avctx->height,
	};
	CHDContext *priv = avctx->priv_data;
	HANDLE dev       = priv->dev;

	*data_size = 0;

	// Request decoded data from the driver
	ret = DtsProcOutputNoCopy(dev, OUTPUT_PROC_TIMEOUT, &output);
	if (ret == BC_STS_FMT_CHANGE)
	{
		av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Initial format change\n");
		avctx->width  = output.PicInfo.width;
		avctx->height = output.PicInfo.height;
		return RET_COPY_AGAIN;
	}
	else if (ret == BC_STS_SUCCESS)
	{
		int copy_ret = -1;
		if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID)
		{
			if (priv->last_picture == -1)
			{
				/*
				 * Init to one less, so that the incrementing code doesn't
				 * need to be special-cased.
				 */
				priv->last_picture = output.PicInfo.picture_number - 1;
			}

			if (avctx->codec->id == CODEC_ID_MPEG4 &&
			        output.PicInfo.timeStamp == 0)
			{
				av_log(avctx, AV_LOG_VERBOSE,
				       "CrystalHD: Not returning packed frame twice.\n");
				priv->last_picture++;
				DtsReleaseOutputBuffs(dev, NULL, FALSE);
				return RET_COPY_AGAIN;
			}

			print_frame_info(priv, &output);

			if (priv->last_picture + 1 < output.PicInfo.picture_number)
			{
				av_log(avctx, AV_LOG_WARNING,
				       "CrystalHD: Picture Number discontinuity\n");
				/*
				 * Have we lost frames? If so, we need to shrink the
				 * pipeline length appropriately.
				 *
				 * XXX: I have no idea what the semantics of this situation
				 * are so I don't even know if we've lost frames or which
				 * ones.
				 *
				 * In any case, only warn the first time.
				 */
				priv->last_picture = output.PicInfo.picture_number - 1;
			}

			copy_ret = copy_frame(avctx, &output, data, data_size, second_field);
			if (*data_size > 0)
			{
				avctx->has_b_frames--;
				priv->last_picture++;
				av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Pipeline length: %u\n",
				       avctx->has_b_frames);
			}
		}
		else
		{
			/*
			 * An invalid frame has been consumed.
			 */
			av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput succeeded with "
			       "invalid PIB\n");
			avctx->has_b_frames--;
			copy_ret = RET_OK;
		}
		DtsReleaseOutputBuffs(dev, NULL, FALSE);

		return copy_ret;
	}
	else if (ret == BC_STS_BUSY)
	{
		return RET_COPY_AGAIN;
	}
	else
	{
		av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput failed %d\n", ret);
		return RET_ERROR;
	}
}


static int decode(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt)
{
	BC_STATUS ret;
	BC_DTS_STATUS decoder_status;
	CopyRet rec_ret;
	CHDContext *priv   = avctx->priv_data;
	HANDLE dev         = priv->dev;
	int len            = avpkt->size;

	av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_frame\n");

	if (len)
	{
		int32_t tx_free = (int32_t)DtsTxFreeSize(dev);
		if (len < tx_free - 1024)
		{
			/*
			 * Despite being notionally opaque, either libcrystalhd or
			 * the hardware itself will mangle pts values that are too
			 * small or too large. The docs claim it should be in units
			 * of 100ns. Given that we're nominally dealing with a black
			 * box on both sides, any transform we do has no guarantee of
			 * avoiding mangling so we need to build a mapping to values
			 * we know will not be mangled.
			 */
			uint64_t pts = opaque_list_push(priv, avctx->pkt->pts);
			if (!pts)
			{
				return AVERROR(ENOMEM);
			}
			av_log(priv->avctx, AV_LOG_VERBOSE,
			       "input \"pts\": %"PRIu64"\n", pts);
			ret = DtsProcInput(dev, avpkt->data, len, pts, 0);
			if (ret == BC_STS_BUSY)
			{
				av_log(avctx, AV_LOG_WARNING,
				       "CrystalHD: ProcInput returned busy\n");
				usleep(BASE_WAIT);
				return AVERROR(EBUSY);
			}
			else if (ret != BC_STS_SUCCESS)
			{
				av_log(avctx, AV_LOG_ERROR,
				       "CrystalHD: ProcInput failed: %u\n", ret);
				return -1;
			}
			avctx->has_b_frames++;
		}
		else
		{
			av_log(avctx, AV_LOG_WARNING, "CrystalHD: Input buffer full\n");
			len = 0; // We didn't consume any bytes.
		}
	}
	else
	{
		av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
	}

	if (priv->skip_next_output)
	{
		av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Skipping next output.\n");
		priv->skip_next_output = 0;
		avctx->has_b_frames--;
		return len;
	}

	ret = DtsGetDriverStatus(dev, &decoder_status);
	if (ret != BC_STS_SUCCESS)
	{
		av_log(avctx, AV_LOG_ERROR, "CrystalHD: GetDriverStatus failed\n");
		return -1;
	}

	/*
	 * No frames ready. Don't try to extract.
	 *
	 * Empirical testing shows that ReadyListCount can be a damn lie,
	 * and ProcOut still fails when count > 0. The same testing showed
	 * that two more iterations were needed before ProcOutput would
	 * succeed.
	 */
	if (priv->output_ready < 2)
	{
		if (decoder_status.ReadyListCount != 0)
			priv->output_ready++;
		usleep(BASE_WAIT);
		av_log(avctx, AV_LOG_INFO, "CrystalHD: Filling pipeline.\n");
		return len;
	}
	else if (decoder_status.ReadyListCount == 0)
	{
		/*
		 * After the pipeline is established, if we encounter a lack of frames
		 * that probably means we're not giving the hardware enough time to
		 * decode them, so start increasing the wait time at the end of a
		 * decode call.
		 */
		usleep(BASE_WAIT);
		priv->decode_wait += WAIT_UNIT;
		av_log(avctx, AV_LOG_INFO, "CrystalHD: No frames ready. Returning\n");
		return len;
	}

	do
	{
		rec_ret = receive_frame(avctx, data, data_size, 0);
		if (rec_ret == 0 && *data_size == 0)
		{
			if (avctx->codec->id == CODEC_ID_H264)
			{
				/*
				 * This case is for when the encoded fields are stored
				 * separately and we get a separate avpkt for each one. To keep
				 * the pipeline stable, we should return nothing and wait for
				 * the next time round to grab the second field.
				 * H.264 PAFF is an example of this.
				 */
				av_log(avctx, AV_LOG_VERBOSE, "Returning after first field.\n");
				avctx->has_b_frames--;
			}
			else
			{
				/*
				 * This case is for when the encoded fields are stored in a
				 * single avpkt but the hardware returns then separately. Unless
				 * we grab the second field before returning, we'll slip another
				 * frame in the pipeline and if that happens a lot, we're sunk.
				 * So we have to get that second field now.
				 * Interlaced mpeg2 and vc1 are examples of this.
				 */
				av_log(avctx, AV_LOG_VERBOSE, "Trying to get second field.\n");
				while (1)
				{
					usleep(priv->decode_wait);
					ret = DtsGetDriverStatus(dev, &decoder_status);
					if (ret == BC_STS_SUCCESS &&
					        decoder_status.ReadyListCount > 0)
					{
						rec_ret = receive_frame(avctx, data, data_size, 1);
						if ((rec_ret == 0 && *data_size > 0) ||
						        rec_ret == RET_ERROR)
							break;
					}
				}
				av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Got second field.\n");
			}
		}
		else if (rec_ret == RET_SKIP_NEXT_COPY)
		{
			/*
			 * Two input packets got turned into a field pair. Gawd.
			 */
			av_log(avctx, AV_LOG_VERBOSE,
			       "Don't output on next decode call.\n");
			priv->skip_next_output = 1;
		}
		/*
		 * If rec_ret == RET_COPY_AGAIN, that means that either we just handled
		 * a FMT_CHANGE event and need to go around again for the actual frame,
		 * we got a busy status and need to try again, or we're dealing with
		 * packed b-frames, where the hardware strangely returns the packed
		 * p-frame twice. We choose to keep the second copy as it carries the
		 * valid pts.
		 */
	}
	while (rec_ret == RET_COPY_AGAIN);
	usleep(priv->decode_wait);
	return len;
}
示例#3
0
// Codigo para procesar los comandos recibidos a traves del canal USB
static portTASK_FUNCTION( CommandProcessingTask, pvParameters ){



	unsigned char frame[MAX_FRAME_SIZE];	//Ojo, esto hace que esta tarea necesite bastante pila
	int numdatos;
	unsigned int errors=0;
	unsigned char command;
	EventBits_t bits;



	/* The parameters are not used. */
	( void ) pvParameters;


	for(;;)
	{
		numdatos=receive_frame(frame,MAX_FRAME_SIZE);
		if (numdatos>0)
		{	//Si no hay error, proceso la trama que ha llegado.
			numdatos=destuff_and_check_checksum(frame,numdatos);
			if (numdatos<0)
			{
				//Error de checksum (PROT_ERROR_BAD_CHECKSUM), ignorar el paquete
				errors++;
				// Procesamiento del error (TODO)
			}
			else
			{
				//El paquete esta bien, luego procedo a tratarlo.
				command=decode_command_type(frame,0);
				bits=xEventGroupGetBits(xEventGroup);
				switch(command)
				{
				case COMANDO_PING :

					if(bits & TrazaBit == TrazaBit){
						UARTprintf("Comando PING\n ");
					}

					//A un comando de ping se responde con el propio comando
					numdatos=create_frame(frame,command,0,0,MAX_FRAME_SIZE);
					if (numdatos>=0)
					{
						send_frame(frame,numdatos);
					}else{
						//Error de creacion de trama: determinar el error y abortar operacion
						errors++;
						logError(numdatos);

					}
					break;
				case COMANDO_START:         // Comando de ejemplo: eliminar en la aplicacion final
				{

					if(bits & TrazaBit == TrazaBit){
						UARTprintf("Comando START\n ");
					}


					if(sensorTaskHandle == NULL){

						inicializarVariables();

						if((xTaskCreate(ConsumoTask, (signed portCHAR *)"Consumo", LED1TASKSTACKSIZE,NULL,tskIDLE_PRIORITY + 1, &consumoTaskHandle)!= pdTRUE))
						{
							while(1);
						}

						if((xTaskCreate(SensorTask, (signed portCHAR *)"Sensor", LED1TASKSTACKSIZE,NULL,tskIDLE_PRIORITY + 1, &sensorTaskHandle) != pdTRUE))
						{
							while(1);
						}
						if((xTaskCreate(HighTask, (signed portCHAR *)"Altitud", LED1TASKSTACKSIZE,NULL,tskIDLE_PRIORITY + 1, &altitudTaskHandle) != pdTRUE))
						{
							while(1);
						}

						if((xTaskCreate(turbulenciasTask, (signed portCHAR *)"Turbulencias", LED1TASKSTACKSIZE,NULL,tskIDLE_PRIORITY + 1, &turbulenciasTaskHandle) != pdTRUE))
						{
							while(1);
						}
					}

				}
				break;
				case COMANDO_STOP:
				{
					if(bits & TrazaBit == TrazaBit){
						UARTprintf("Comando STOP\n ");
					}
					if(combustible>0){ //Eliminamos las tareas en el STOP
						vTaskDelete(sensorTaskHandle);
						vTaskDelete( consumoTaskHandle );
						vTaskDelete(altitudTaskHandle);
						vTaskDelete( turbulenciasTaskHandle );

					}

				}
				break;
				case COMANDO_SPEED:
				{

					if(bits & TrazaBit == TrazaBit){
						UARTprintf("Comando SPEED\n ");
					}
					float  velocidad;

					//Recibimos y enviamos por la cola la velocidad
					extract_packet_command_param(frame,sizeof(velocidad),&velocidad);
					xQueueSend( velocidadQueue,&velocidad,portMAX_DELAY);

				}
				break;
				case COMANDO_TIME:
				{

					if(bits & TrazaBit == TrazaBit){
						UARTprintf("Comando TIME\n ");
					}

					uint32_t hora;
					extract_packet_command_param(frame,sizeof(hora),&hora);
					//recibimos y actualizamos el valor de Hora
					setHora(hora);
					//Creamos la tarea Time
					if(xTaskCreate(TimeTask, (portCHAR *)"Time",LED1TASKSTACKSIZE, NULL, tskIDLE_PRIORITY + 1, NULL) != pdTRUE)
					{
						while(1);
					}

				}
				break;
				default:
				{
					PARAM_COMANDO_NO_IMPLEMENTADO parametro;
					parametro.command=command;
					//El comando esta bien pero no esta implementado
					numdatos=create_frame(frame,COMANDO_NO_IMPLEMENTADO,&parametro,sizeof(parametro),MAX_FRAME_SIZE);
					if (numdatos>=0)
					{
						send_frame(frame,numdatos);
					}
					break;
				}
				}
			}
		}else{ // if (numdatos >0)
			//Error de recepcion de trama(PROT_ERROR_RX_FRAME_TOO_LONG), ignorar el paquete
			errors++;

		}
	}
}