DVB tuning in JNI does not work

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm trying to write a DVB recording application in Java. I chose JNI and
a small native C/C++ function for tuning. However, I can't get tuning to
work - I get no tuning lock and nothing on dvr either.

As a test, I also copied the szap code verbatim into my file and just
called zap_to() instead of my code, and it did not work either. Plain
szap on commandline works.
This suggests JVM/JNI as culprit, but dvbcentral also uses JNI and it
seems to work (at least for its author, haven't tried myself).

Does anybody have an idea what's going on? I suspect I'm just doing
*something* wrong, but I have no idea what, and no targetted way (like
error messages) to find out.

Source attached. Hints appreciated. Thanks!

Ben
/**
 * DVB card access on the OS level (system function ioctl()), to tune.
 *
 * This needs to happen in C/C++, because ioctl() is not accessible from Java. 
 * This implements the JNI library libzeipisdvbtune.so, a native C++ library
 * accessible from Java. It implements the |native| methods from the
 * org.bucksch.zeipis.recorder.DVBTunerNativeJNILinux Java class.
 * We do as little as possible in C++.
 */

#include "DVBTunerNativeJNILinux.h"
#include <sys/ioctl.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <fcntl.h>
#include <iostream>

void throwEx(JNIEnv* env, const char* message)
{
  jclass eClass = env->FindClass("org/bucksch/zeipis/recorder/CantUseTVCard");
  if (eClass == 0) // can't find exception class; unexpected
    return;
  env->ThrowNew(eClass, message);
}

#define CHECK_RV(message) \
  if (rv < 0) \
  { \
    throwEx(env, message); \
    close(frontendFD); \
    return -1; \
  }

/**
 * Called with e.g. "/dev/dvb/adapter0/frontend0", false, 12187000, false, 27500000 (=VOX in Germany)
 */
JNIEXPORT jint JNICALL Java_org_bucksch_zeipis_recorder_DVBTunerNativeJNILinux_tuneToNative
  (JNIEnv* env, jobject self, jstring frontendFilename, jboolean dvbs2, jint frequency, jboolean polv, jint symbolrate)
{
  // Open frontend device
  const char* frontendFilenameC = env->GetStringUTFChars(frontendFilename, 0);
  int frontendFD = open(frontendFilenameC, O_RDWR | O_NONBLOCK);
  env->ReleaseStringUTFChars(frontendFilename, frontendFilenameC);
  if (frontendFD < 0)
  {
    throwEx(env, "Can't get info from device");
    return -1;
  }

  /* from szap
  // Remove stale events
  struct dvb_frontend_event ev;
  while (ioctl(frontendFD, FE_GET_EVENT, &ev) >= 0)
	;
  */

  // Get info from device
  int rv;
  dvb_frontend_info info;
  rv = ioctl(frontendFD, FE_GET_INFO, &info);
  CHECK_RV("Can't get info from device");
#ifdef FE_GET_EXTENDED_INFO
  dvb_fe_caps_extended info2;
  if (dvbs2 && info.caps & FE_HAS_EXTENDED_INFO) // TODO
  {
    rv = ioctl(frontendFD, FE_GET_EXTENDED_INFO, &info2);
    CHECK_RV("Can't get extended info from device");
    if (info2.modulations & MOD_8PSK)
    {
      // set card to DVB-S2 mode
      rv = ioctl(frontendFD, FE_SET_STANDARD, FE_DVB_S2)
      CHECK_RV("Failed to set card to DVB-S2 mode");
      // get new info
      rv = ioctl(frontendFD, FE_GET_INFO, &info);
      CHECK_RV("Can't get info from device after setting to DVB-S2 mode");
    }
  }
#endif
  
  // Disecq
  int sat_no = 0;
  bool hiband = false;
  // LNB config from szap
  // Universal LNB
  const int lnb_low_val = 9750;
  const int lnb_high_val = 10600;
  const int lnb_switch_val = 11700;
  if (lnb_switch_val && lnb_high_val &&
    frequency >= lnb_switch_val)
    hiband = true;
  if (hiband)
    frequency = frequency - lnb_high_val;
  else
  {
    if (frequency < lnb_low_val)
      frequency = lnb_low_val - frequency;
    else
      frequency = frequency - lnb_low_val;
  }
  rv = ioctl(frontendFD, FE_SET_TONE, SEC_TONE_OFF);
  CHECK_RV("Cound not turn disecq tone");
  rv = ioctl(frontendFD, FE_SET_VOLTAGE, polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
  CHECK_RV("Could not set disecq voltage for polarity");
  usleep(15 * 1000);
  rv = ioctl(frontendFD, FE_SET_TONE, SEC_TONE_OFF);
  CHECK_RV("Cound not turn off disecq tone");
  usleep(15 * 1000);
  struct dvb_diseqc_master_cmd disecq_cmd = {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
  disecq_cmd.msg[3] = 0xf0 | (((sat_no * 4) & 0x0f) | (hiband ? 1 : 0) | (polv ? 0 : 2));
  rv = ioctl(frontendFD, FE_DISEQC_SEND_MASTER_CMD, &disecq_cmd);
  CHECK_RV("Cound send disecq master command");
  usleep(15 * 1000);
  rv = ioctl(frontendFD, FE_DISEQC_SEND_BURST, (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A);
  CHECK_RV("Cound set satellite on disecq");
  usleep(15 * 1000);
  rv = ioctl(frontendFD, FE_SET_TONE, hiband ? SEC_TONE_ON : SEC_TONE_OFF);
  CHECK_RV("Cound set disecq tone");
  // TODO diseqc power on?
  // TODO more diseqc?

  // CAM start
  // TODO

  // Put tuning data into struct
  #ifdef FE_GET_EXTENDED_INFO
    #define dvb_fe_params dvb_frontend_parameters_new
  #else
    #define dvb_fe_params dvb_frontend_parameters
  #endif
  dvb_fe_params p;
  // DVB-S
  p.frequency = frequency;
  p.u.qpsk.symbol_rate = symbolrate / 1000;
  // TODO inversion
  p.inversion = INVERSION_AUTO;
  if (info.caps & FE_CAN_FEC_AUTO)
    p.u.qpsk.fec_inner = FEC_AUTO;
  else
  {
    rv = -1;
    CHECK_RV("Card needs to support FEC INNER AUTO (TODO support setting it)");
  }
  // TODO DVB-T
  // TODO DVB-C

  // Tuning
#ifdef FE_GET_EXTENDED_INFO
  if (dvbs2)
    rv = ioctl(frontendFD, FE_SET_FRONTEND2, &p);
  else
#endif
    rv = ioctl(frontendFD, FE_SET_FRONTEND, &p);
  CHECK_RV("Setting tuning params failed");

  // Wait for lock
  bool haveLock = false;
  int loops = 0;
  while (!haveLock && loops++ < 50) // 5s
  {
  	fe_status_t status;
	rv = ioctl(frontendFD, FE_READ_STATUS, &status);
	CHECK_RV("Reading status failed after setting tuning param");
	haveLock = status & FE_HAS_LOCK;
	usleep(100000); // 0.1s
  }
  if (!haveLock)
  {
  	uint16_t snr, sig;
	rv = ioctl(frontendFD, FE_READ_SIGNAL_STRENGTH, &sig);
	rv = ioctl(frontendFD, FE_READ_SNR, &snr);
	std::cout << "Tuning failed. Signal strength " << sig << ", Signal/noise ratio " << snr << "%" << std::endl; // TODO
	rv = -1;
  	CHECK_RV("Tuning failed");
  }

  return frontendFD;
}

JNIEXPORT jint JNICALL Java_org_bucksch_zeipis_recorder_DVBTunerNativeJNILinux_openDemuxNative
  (JNIEnv* env, jobject self, jstring demuxFilename, jint pid)
{
  // Open demux device
  const char* demuxFilenameC = env->GetStringUTFChars(demuxFilename, 0);
  int demuxFD = open(demuxFilenameC, O_RDWR);
  env->ReleaseStringUTFChars(demuxFilename, demuxFilenameC);
  if (demuxFD < 0)
  {
    throwEx(env, "Could not open de-multiplexer device");
    return -1;
  }
 
  // Buffer size From szap TODO needed?
  int rv = ioctl(demuxFD, DMX_SET_BUFFER_SIZE, 64 * 1024);
  if (rv < 0)
  {
    throwEx(env, "Setting buffer size for PID filter failed");
    close(demuxFD);
    return -1;
  }

  // Set PID
  struct dmx_pes_filter_params pesfilter;
  pesfilter.pid = pid;
  pesfilter.input = DMX_IN_FRONTEND;
  pesfilter.output = DMX_OUT_TS_TAP;
  pesfilter.pes_type = DMX_PES_OTHER; // TODO DMX_PES_VIDEO, DMX_PES_AUDIO?
  pesfilter.flags = DMX_IMMEDIATE_START;
  rv = ioctl(demuxFD, DMX_SET_PES_FILTER, &pesfilter);
  if (rv < 0)
  {
    throwEx(env, "Could not set PID");
    close(demuxFD);
    return -1;
  }

  return demuxFD;
}

JNIEXPORT void JNICALL Java_org_bucksch_zeipis_recorder_DVBTunerNativeJNILinux_closeNative
  (JNIEnv* env, jobject self, jint fd)
{
  close(fd);
}
/**
 * DVB card access on the OS level (system function ioctl()), to tune.
 *
 * This needs to happen in C/C++, because ioctl() is not accessible from Java. 
 * This implements the JNI library libzeipisdvbtune.so, a native C++ library
 * accessible from Java. It implements the |native| methods from the
 * org.bucksch.zeipis.recorder.DVBTunerNativeJNILinux Java class.
 * We do as little as possible in C++.
 */

#include "DVBTunerNativeJNILinux.h"
#include <sys/ioctl.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <fcntl.h>
#include <iostream>

void throwEx(JNIEnv* env, const char* message)
{
  jclass eClass = env->FindClass("org/bucksch/zeipis/recorder/CantUseTVCard");
  if (eClass == 0) // can't find exception class; unexpected
    return;
  env->ThrowNew(eClass, message);
}

#define CHECK_RV(message) \
  if (rv < 0) \
  { \
    throwEx(env, message); \
    close(frontendFD); \
    return -1; \
  }

static int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
      unsigned int sat_no, unsigned int freq, unsigned int pol,
      unsigned int sr, unsigned int vpid, unsigned int apid, int sid,
      int dvr, int rec_psi, int bypass);

/**
 * Called with e.g. "/dev/dvb/adapter0/frontend0", false, 12187000, false, 27500000 (=VOX in Germany)
 */
JNIEXPORT jint JNICALL Java_org_bucksch_zeipis_recorder_DVBTunerNativeJNILinux_tuneToNative
  (JNIEnv* env, jobject self, jstring frontendFilename, jboolean dvbs2, jint frequency, jboolean polv, jint symbolrate)
{
	 printf("sat %u, frequency = %u MHz %c, symbolrate %u, "
		"vpid = 0x%04x, apid = 0x%04x sid = 0x%04x\n",
		0, frequency / 1000, polv ? 'V' : 'H', symbolrate, 0x00a7, 0x0088, 0x2f1c);
  zap_to(0, 0, 0,
	   0, frequency, polv ? 1 : 0, symbolrate, 0x00a7, 0x0088, 0x2f1c,
	   1, 0, 0);
  return -1;
}

JNIEXPORT jint JNICALL Java_org_bucksch_zeipis_recorder_DVBTunerNativeJNILinux_openDemuxNative
  (JNIEnv* env, jobject self, jstring demuxFilename, jint pid)
{
  return -1;
}

JNIEXPORT void JNICALL Java_org_bucksch_zeipis_recorder_DVBTunerNativeJNILinux_closeNative
  (JNIEnv* env, jobject self, jint fd)
{
  if (fd < 0)
  	return;
  close(fd);
}


/* szap -- simple zapping tool for the Linux DVB API
 *
 * szap operates on VDR (http://www.cadsoft.de/people/kls/vdr/index.htm)
 * satellite channel lists (e.g. from http://www.dxandy.de/cgi-bin/dvbchan.pl).
 * szap assumes you have a "Universal LNB" (i.e. with LOFs 9750/10600 MHz).
 *
 * Compilation: `gcc -Wall -I../../ost/include -O2 szap.c -o szap`
 *  or, if your DVB driver is in the kernel source tree:
 *              `gcc -Wall -DDVB_IN_KERNEL -O2 szap.c -o szap`
 *
 * Copyright (C) 2001 Johannes Stezenbach (js@xxxxxxxxxxxxxx)
 * for convergence integrated media
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

struct lnb_types_st {
	char	*name;
	char	**desc;
	unsigned long	low_val;
	unsigned long	high_val;	/* zero indicates no hiband */
	unsigned long	switch_val;	/* zero indicates no hiband */
};

/* Enumerate through standard types of LNB's until NULL returned.
 * Increment curno each time
 */

struct lnb_types_st *
lnb_enum(int curno);

/* Decode an lnb type, for example given on a command line
 * If alpha and standard type, e.g. "Universal" then match that
 * otherwise low[,high[,switch]]
 */

int
lnb_decode(char *str, struct lnb_types_st *lnbp);


#include <stdlib.h>
#include <string.h>
#include <ctype.h>

static char *univ_desc[] = {
		"Europe",
		"10800 to 11800 MHz and 11600 to 12700 Mhz",
		"Dual LO, loband 9750, hiband 10600 MHz",
		(char *)NULL };

static char *dbs_desc[] = {
		"Expressvu, North America",
		"12200 to 12700 MHz",
		"Single LO, 11250 MHz",
		(char *)NULL };

static char *standard_desc[] = {
		"10945 to 11450 Mhz",
		"Single LO, 10000 Mhz",
		(char *)NULL };

static char *enhan_desc[] = {
		"Astra",
		"10700 to 11700 MHz",
		"Single LO, 9750 MHz",
		(char *)NULL };

static char *cband_desc[] = {
		"Big Dish",
		"3700 to 4200 MHz",
		"Single LO, 5150 Mhz",
		(char *)NULL };

static struct lnb_types_st lnbs[] = {
	{"UNIVERSAL",	univ_desc,		9750, 10600, 11700 },
 	{"DBS",		dbs_desc, 		11250, 0, 0 },
	{"STANDARD",	standard_desc,		10000, 0, 0 },
	{"ENHANCED",	enhan_desc,		9750, 0, 0 },
	{"C-BAND",	cband_desc,		5150, 0, 0 }
};

/* Enumerate through standard types of LNB's until NULL returned.
 * Increment curno each time
 */

struct lnb_types_st *
lnb_enum(int curno)
{
	if (curno >= (int) (sizeof(lnbs) / sizeof(lnbs[0])))
		return (struct lnb_types_st *)NULL;
	return &lnbs[curno];
}

/* Decode an lnb type, for example given on a command line
 * If alpha and standard type, e.g. "Universal" then match that
 * otherwise low[,high[,switch]]
 */

int
lnb_decode(char *str, struct lnb_types_st *lnbp)
{
int i;
char *cp, *np;

	memset(lnbp, 0, sizeof(*lnbp));
	cp = str;
	while(*cp && isspace(*cp))
		cp++;
	if (isalpha(*cp)) {
		for (i = 0; i < (int)(sizeof(lnbs) / sizeof(lnbs[0])); i++) {
			if (!strcasecmp(lnbs[i].name, cp)) {
				*lnbp = lnbs[i];
				return 1;
			}
		}
		return -1;
	}
	if (*cp == '\0' || !isdigit(*cp))
		return -1;
	lnbp->low_val = strtoul(cp, &np, 0);
	if (lnbp->low_val == 0)
		return -1;
	cp = np;
	while(*cp && (isspace(*cp) || *cp == ','))
		cp++;
	if (*cp == '\0')
		return 1;
	if (!isdigit(*cp))
		return -1;
	lnbp->high_val = strtoul(cp, &np, 0);
	cp = np;
	while(*cp && (isspace(*cp) || *cp == ','))
		cp++;
	if (*cp == '\0')
		return 1;
	if (!isdigit(*cp))
		return -1;
	lnbp->switch_val = strtoul(cp, NULL, 0);
	return 1;
}

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>

#include <stdint.h>
#include <sys/time.h>

#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/audio.h>

#ifndef TRUE
#define TRUE (1==1)
#endif
#ifndef FALSE
#define FALSE (1==0)
#endif

/* location of channel list file */
#define CHANNEL_FILE "channels.conf"

/* one line of the VDR channel file has the following format:
 * ^name:frequency_MHz:polarization:sat_no:symbolrate:vpid:apid:?:service_id$
 */


#define FRONTENDDEVICE "/dev/dvb/adapter%d/frontend%d"
#define DEMUXDEVICE "/dev/dvb/adapter%d/demux%d"
#define AUDIODEVICE "/dev/dvb/adapter%d/audio%d"

static struct lnb_types_st lnb_type;

static int exit_after_tuning;
static int interactive;

static int set_demux(int dmxfd, int pid, dmx_pes_type_t pes_type, int dvr)
{
   struct dmx_pes_filter_params pesfilter;

   if (pid < 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
	   return TRUE;

   if (dvr) {
      int buffersize = 64 * 1024;
      if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
        perror("DMX_SET_BUFFER_SIZE failed");
   }

   pesfilter.pid = pid;
   pesfilter.input = DMX_IN_FRONTEND;
   pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
   pesfilter.pes_type = pes_type;
   pesfilter.flags = DMX_IMMEDIATE_START;

   if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
      fprintf(stderr, "DMX_SET_PES_FILTER failed "
	      "(PID = 0x%04x): %d %m\n", pid, errno);
      return FALSE;
   }

   return TRUE;
}

int get_pmt_pid(char *dmxdev, int sid)
{
   int patfd, count;
   int pmt_pid = 0;
   int patread = 0;
   int section_length;
   unsigned char buft[4096];
   unsigned char *buf = buft;
   struct dmx_sct_filter_params f;

   memset(&f, 0, sizeof(f));
   f.pid = 0;
   f.filter.filter[0] = 0x00;
   f.filter.mask[0] = 0xff;
   f.timeout = 0;
   f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;

   if ((patfd = open(dmxdev, O_RDWR)) < 0) {
      perror("openening pat demux failed");
      return -1;
   }

   if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
      perror("ioctl DMX_SET_FILTER failed");
      close(patfd);
      return -1;
   }

   while (!patread){
      if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
         count = read(patfd, buf, sizeof(buft));
      if (count < 0) {
         perror("read_sections: read error");
         close(patfd);
         return -1;
      }

      section_length = ((buf[1] & 0x0f) << 8) | buf[2];
      if (count != section_length + 3)
         continue;

      buf += 8;
      section_length -= 8;

      patread = 1; /* assumes one section contains the whole pat */
      while (section_length > 0) {
         int service_id = (buf[0] << 8) | buf[1];
         if (service_id == sid) {
            pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
            section_length = 0;
         }
         buf += 4;
         section_length -= 4;
     }
   }

   close(patfd);
   return pmt_pid;
}

struct diseqc_cmd {
   struct dvb_diseqc_master_cmd cmd;
   uint32_t wait;
};

void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
		     fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
{
   if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1)
      perror("FE_SET_TONE failed");
   if (ioctl(fd, FE_SET_VOLTAGE, v) == -1)
      perror("FE_SET_VOLTAGE failed");
   usleep(15 * 1000);
   if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1)
      perror("FE_DISEQC_SEND_MASTER_CMD failed");
   usleep(cmd->wait * 1000);
   usleep(15 * 1000);
   if (ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1)
      perror("FE_DISEQC_SEND_BURST failed");
   usleep(15 * 1000);
   if (ioctl(fd, FE_SET_TONE, t) == -1)
      perror("FE_SET_TONE failed");
}




/* digital satellite equipment control,
 * specification is available from http://www.eutelsat.com/
 */
static int diseqc(int secfd, int sat_no, int pol_vert, int hi_band)
{
   struct diseqc_cmd cmd =
       { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };

   /* param: high nibble: reset bits, low nibble set bits,
    * bits are: option, position, polarizaion, band
    */
   cmd.cmd.msg[3] =
       0xf0 | (((sat_no * 4) & 0x0f) | (hi_band ? 1 : 0) | (pol_vert ? 0 : 2));

   diseqc_send_msg(secfd, pol_vert ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18,
		   &cmd, hi_band ? SEC_TONE_ON : SEC_TONE_OFF,
		   (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A);

   return TRUE;
}

static int do_tune(int fefd, unsigned int ifreq, unsigned int sr)
{
   struct dvb_frontend_parameters tuneto;
   struct dvb_frontend_event ev;

   /* discard stale QPSK events */
   while (1) {
      if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
	 break;
   }

   tuneto.frequency = ifreq;
   tuneto.inversion = INVERSION_AUTO;
   tuneto.u.qpsk.symbol_rate = sr;
   tuneto.u.qpsk.fec_inner = FEC_AUTO;

   if (ioctl(fefd, FE_SET_FRONTEND, &tuneto) == -1) {
      perror("FE_SET_FRONTEND failed");
      return FALSE;
   }

   return TRUE;
}


static
int check_frontend (int fe_fd, int dvr)
{
   (void)dvr;
   fe_status_t status;
   uint16_t snr, signal;
   uint32_t ber, uncorrected_blocks;
   int timeout = 0;

   do {
      if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
         perror("FE_READ_STATUS failed");
      /* some frontends might not support all these ioctls, thus we
       * avoid printing errors */
      if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
         signal = -2;
      if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
         snr = -2;
      if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
         ber = -2;
      if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
         uncorrected_blocks = -2;

      printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
	      status, signal, snr, ber, uncorrected_blocks);

      if (status & FE_HAS_LOCK)
	 printf("FE_HAS_LOCK");
      printf("\n");

      if (exit_after_tuning && ((status & FE_HAS_LOCK) || (++timeout >= 10)))
         break;

      usleep(1000000);
   } while (1);

   return 0;
}


static
int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
      unsigned int sat_no, unsigned int freq, unsigned int pol,
      unsigned int sr, unsigned int vpid, unsigned int apid, int sid,
      int dvr, int rec_psi, int bypass)
{
   char fedev[128], dmxdev[128], auddev[128];
   static int fefd, dmxfda, dmxfdv, audiofd = -1, patfd, pmtfd;
   int pmtpid;
   uint32_t ifreq;
   int hiband, result;
   static struct dvb_frontend_info fe_info;

   if (!fefd) {
      snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
      snprintf(dmxdev, sizeof(dmxdev), DEMUXDEVICE, adapter, demux);
      snprintf(auddev, sizeof(auddev), AUDIODEVICE, adapter, demux);
      printf("using '%s' and '%s'\n", fedev, dmxdev);

      if ((fefd = open(fedev, O_RDWR | O_NONBLOCK)) < 0) {
	 perror("opening frontend failed");
	 return FALSE;
      }

      result = ioctl(fefd, FE_GET_INFO, &fe_info);

      if (result < 0) {
	 perror("ioctl FE_GET_INFO failed");
	 close(fefd);
	 return FALSE;
      }

      if (fe_info.type != FE_QPSK) {
	 fprintf(stderr, "frontend device is not a QPSK (DVB-S) device!\n");
	 close(fefd);
	 return FALSE;
      }

      if ((dmxfdv = open(dmxdev, O_RDWR)) < 0) {
	 perror("opening video demux failed");
	 close(fefd);
	 return FALSE;
      }

      if ((dmxfda = open(dmxdev, O_RDWR)) < 0) {
	 perror("opening audio demux failed");
	 close(fefd);
	 return FALSE;
      }

      if (dvr == 0)	/* DMX_OUT_DECODER */
	 audiofd = open(auddev, O_RDWR);

      if (rec_psi){
         if ((patfd = open(dmxdev, O_RDWR)) < 0) {
	    perror("opening pat demux failed");
	    close(audiofd);
	    close(dmxfda);
	    close(dmxfdv);
	    close(fefd);
	    return FALSE;
         }

         if ((pmtfd = open(dmxdev, O_RDWR)) < 0) {
	    perror("opening pmt demux failed");
	    close(patfd);
	    close(audiofd);
	    close(dmxfda);
	    close(dmxfdv);
	    close(fefd);
	    return FALSE;
         }
      }
   }

   hiband = 0;
   if (lnb_type.switch_val && lnb_type.high_val &&
	freq >= lnb_type.switch_val)
	hiband = 1;

   if (hiband)
      ifreq = freq - lnb_type.high_val;
   else {
      if (freq < lnb_type.low_val)
          ifreq = lnb_type.low_val - freq;
      else
          ifreq = freq - lnb_type.low_val;
   }
   result = FALSE;

   if (diseqc(fefd, sat_no, pol, hiband))
      if (do_tune(fefd, ifreq, sr))
	 if (set_demux(dmxfdv, vpid, DMX_PES_VIDEO, dvr))
	    if (audiofd >= 0)
	       (void)ioctl(audiofd, AUDIO_SET_BYPASS_MODE, bypass);
	    if (set_demux(dmxfda, apid, DMX_PES_AUDIO, dvr)) {
	       if (rec_psi) {
	          pmtpid = get_pmt_pid(dmxdev, sid);
		  if (pmtpid < 0) {
		     result = FALSE;
		  }
		  if (pmtpid == 0) {
		     fprintf(stderr,"couldn't find pmt-pid for sid %04x\n",sid);
		     result = FALSE;
		  }
		  if (set_demux(patfd, 0, DMX_PES_OTHER, dvr))
	             if (set_demux(pmtfd, pmtpid, DMX_PES_OTHER, dvr))
	                result = TRUE;
	          } else {
		    result = TRUE;
		  }
	       }

   check_frontend (fefd, dvr);

   if (!interactive) {
      close(patfd);
      close(pmtfd);
      if (audiofd >= 0)
	 close(audiofd);
      close(dmxfda);
      close(dmxfdv);
      close(fefd);
   }

   return result;
}
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux