示例#1
0
bool LocalRxBase::initialize(void)
{
  if (!Rx::initialize())
  {
    return false;
  }
  
  bool deemphasis = false;
  cfg.getValue(name(), "DEEMPHASIS", deemphasis);
  
  int delay_line_len = 0;
  bool  mute_1750 = false;
  if (cfg.getValue(name(), "1750_MUTING", mute_1750))
  {
    delay_line_len = max(delay_line_len, TONE_1750_MUTING_PRE);
  }

  cfg.getValue(name(), "SQL_TAIL_ELIM", sql_tail_elim);
  if (sql_tail_elim > 0)
  {
    delay_line_len = max(delay_line_len, sql_tail_elim);
  }
  
  cfg.getValue(name(), "PREAMP", preamp_gain);
  
  bool peak_meter = false;
  cfg.getValue(name(), "PEAK_METER", peak_meter);
  
    // Get the audio source object
  AudioSource *prev_src = audioSource();
  assert(prev_src != 0);
  
    // Create a fifo buffer to handle large audio blocks
  input_fifo = new AudioFifo(1024);
//  input_fifo->setOverwrite(true);
  prev_src->registerSink(input_fifo);
  prev_src = input_fifo;

  SvxLink::SepPair<string, uint16_t> raw_audio_fwd_dest;
  if (cfg.getValue(name(), "RAW_AUDIO_UDP_DEST", raw_audio_fwd_dest))
  {
    AudioSplitter *raw_audio_splitter = new AudioSplitter;
    prev_src->registerSink(raw_audio_splitter, true);
    AudioPassthrough *pass = new AudioPassthrough;
    raw_audio_splitter->addSink(pass, true);
    prev_src = pass;
    AudioUdpSink *udp = new AudioUdpSink(IpAddress(raw_audio_fwd_dest.first),
                                         raw_audio_fwd_dest.second);
    if (!udp->initOk())
    {
      cerr << "*** ERROR: Could not open UDP socket for raw audio output\n";
      return false;

    }
    raw_audio_splitter->addSink(udp, true);
  }
  
    // If a preamp was configured, create it
  if (preamp_gain != 0)
  {
    AudioAmp *preamp = new AudioAmp;
    preamp->setGain(preamp_gain);
    prev_src->registerSink(preamp, true);
    prev_src = preamp;
  }
  
    // If a peak meter was configured, create it
  if (peak_meter)
  {
    PeakMeter *peak_meter = new PeakMeter(name());
    prev_src->registerSink(peak_meter, true);
    prev_src = peak_meter;
  }
  
    // If the sound card sample rate is higher than 16kHz (48kHz assumed),
    // decimate it down to 16kHz
  if (audioSampleRate() > 16000)
  {
    AudioDecimator *d1 = new AudioDecimator(3, coeff_48_16_wide,
					    coeff_48_16_wide_taps);
    prev_src->registerSink(d1, true);
    prev_src = d1;
  }

  AudioSplitter *siglevdet_splitter = 0;
  siglevdet_splitter = new AudioSplitter;
  prev_src->registerSink(siglevdet_splitter, true);

    // Create the signal level detector
  siglevdet = SigLevDetFactoryBase::createNamedSigLevDet(cfg, name());
  if ((siglevdet == 0) ||
      (!siglevdet->initialize(cfg, name(), INTERNAL_SAMPLE_RATE)))
  {
    cout << "*** ERROR: Could not initialize the signal level detector for "
         << "receiver " << name() << endl;
    delete siglevdet;
    siglevdet = 0;
    return false;
  }
  siglevdet->setIntegrationTime(0);
  siglevdet->signalLevelUpdated.connect(
      mem_fun(*this, &LocalRxBase::onSignalLevelUpdated));
  siglevdet_splitter->addSink(siglevdet, true);
  
    // Create a mute valve
  mute_valve = new AudioValve;
  mute_valve->setOpen(true);
  siglevdet_splitter->addSink(mute_valve, true);
  prev_src = mute_valve;
  
#if (INTERNAL_SAMPLE_RATE != 16000)
    // If the sound card sample rate is higher than 8kHz (16 or 48kHz assumed)
    // decimate it down to 8kHz.
    // 16kHz audio to other consumers.
  if (audioSampleRate() > 8000)
  {
    AudioDecimator *d2 = new AudioDecimator(2, coeff_16_8, coeff_16_8_taps);
    prev_src->registerSink(d2, true);
    prev_src = d2;
  }
#endif

    // If a deemphasis filter was configured, create it
  if (deemphasis)
  {
    //AudioFilter *deemph_filt = new AudioFilter("LpBu1/300");
    //AudioFilter *deemph_filt = new AudioFilter("HsBq1/0.01/-18/3500");
    //AudioFilter *deemph_filt = new AudioFilter("HsBq1/0.05/-36/3500");
    //deemph_filt->setOutputGain(9.0f);
    //AudioFilter *deemph_filt = new AudioFilter("HpBu1/50 x LpBu1/150");
    //deemph_filt->setOutputGain(7.0f);

    DeemphasisFilter *deemph_filt = new DeemphasisFilter;
    prev_src->registerSink(deemph_filt, true);
    prev_src = deemph_filt;
  }
  
    // Create a splitter to distribute full bandwidth audio to all consumers
  AudioSplitter *fullband_splitter = new AudioSplitter;
  prev_src->registerSink(fullband_splitter, true);
  prev_src = fullband_splitter;

    // Create the configured squelch detector and initialize it
  string sql_det_str;
  if (!cfg.getValue(name(), "SQL_DET", sql_det_str))
  {
    cerr << "*** ERROR: Config variable " << name() << "/SQL_DET not set\n";
    return false;
  }

  if (sql_det_str == "OPEN")
  {
    squelch_det = new SquelchOpen;
  }
  else if (sql_det_str == "VOX")
  {
    squelch_det = new SquelchVox;
  }
  else if (sql_det_str == "CTCSS")
  {
    SquelchCtcss *squelch_ctcss = new SquelchCtcss;
    squelch_ctcss->snrUpdated.connect(ctcssSnrUpdated.make_slot());
    squelch_det = squelch_ctcss;
  }
  else if (sql_det_str == "SERIAL")
  {
    squelch_det = new SquelchSerial;
  }
  else if (sql_det_str == "SIGLEV")
  {
    squelch_det = new SquelchSigLev(siglevdet);
  }
  else if (sql_det_str == "EVDEV")
  {
    squelch_det = new SquelchEvDev;
  }
  else if (sql_det_str == "GPIO")
  {
    squelch_det = new SquelchGpio;
  }
  else if (sql_det_str == "PTY")
  {
    squelch_det = new SquelchPty;
  }
#ifdef HAS_HIDRAW_SUPPORT
  else if (sql_det_str == "HIDRAW")
  {
    squelch_det = new SquelchHidraw;
  }
#endif
  else
  {
    cerr << "*** ERROR: Unknown squelch type specified in config variable "
      	 << name() << "/SQL_DET. Legal values are: OPEN, VOX, CTCSS, SIGLEV, "
	 << "EVDEV, GPIO, PTY and SERIAL\n";
    // FIXME: Cleanup
    return false;
  }
  
  if (!squelch_det->initialize(cfg, name()))
  {
    cerr << "*** ERROR: Squelch detector initialization failed for RX \""
      	 << name() << "\"\n";
    delete squelch_det;
    squelch_det = 0;
    // FIXME: Cleanup
    return false;
  }

  readyStateChanged.connect(mem_fun(*this, &LocalRxBase::rxReadyStateChanged));

  if (cfg.getValue(name(), "SQL_HANGTIME", sql_hangtime))
  {
    squelch_det->setHangtime(sql_hangtime);
  }
  cfg.getValue(name(), "SQL_EXTENDED_HANGTIME", sql_extended_hangtime);
  cfg.getValue(name(), "SQL_EXTENDED_HANGTIME_THRESH",
      sql_extended_hangtime_thresh);
  
  squelch_det->squelchOpen.connect(mem_fun(*this, &LocalRxBase::onSquelchOpen));
  fullband_splitter->addSink(squelch_det, true);

    // Create a new audio splitter to handle tone detectors
  tone_dets = new AudioSplitter;
  prev_src->registerSink(tone_dets, true);
  prev_src = tone_dets;

    // Filter out the voice band, removing high- and subaudible frequencies,
    // for example CTCSS.
#if (INTERNAL_SAMPLE_RATE == 16000)
  AudioFilter *voiceband_filter = new AudioFilter("BpCh10/-0.1/300-5000");
#else
  AudioFilter *voiceband_filter = new AudioFilter("BpCh10/-0.1/300-3500");
#endif
  prev_src->registerSink(voiceband_filter, true);
  prev_src = voiceband_filter;

    // Create an audio splitter to distribute the voiceband audio to all
    // other consumers
  AudioSplitter *voiceband_splitter = new AudioSplitter;
  prev_src->registerSink(voiceband_splitter, true);
  prev_src = voiceband_splitter;

    // Create the configured type of DTMF decoder and add it to the splitter
  string dtmf_dec_type("NONE");
  cfg.getValue(name(), "DTMF_DEC_TYPE", dtmf_dec_type);
  if (dtmf_dec_type != "NONE")
  {
    DtmfDecoder *dtmf_dec = DtmfDecoder::create(cfg, name());
    if ((dtmf_dec == 0) || !dtmf_dec->initialize())
    {
      // FIXME: Cleanup?
      delete dtmf_dec;
      return false;
    }
    dtmf_dec->digitActivated.connect(
        mem_fun(*this, &LocalRxBase::dtmfDigitActivated));
    dtmf_dec->digitDeactivated.connect(
        mem_fun(*this, &LocalRxBase::dtmfDigitDeactivated));
    voiceband_splitter->addSink(dtmf_dec, true);

    bool dtmf_muting = false;
    cfg.getValue(name(), "DTMF_MUTING", dtmf_muting);
    if (dtmf_muting)
    {
      dtmf_muting_pre = dtmf_dec->detectionTime();
      delay_line_len = max(delay_line_len, dtmf_muting_pre);
    }
  }
  
    // Create a selective multiple tone detector object
  string sel5_dec_type("NONE");
  cfg.getValue(name(), "SEL5_DEC_TYPE", sel5_dec_type);
  if (sel5_dec_type != "NONE")
  {
    Sel5Decoder *sel5_dec = Sel5Decoder::create(cfg, name());
    if (sel5_dec == 0 || !sel5_dec->initialize())
    {
      cerr << "*** ERROR: Sel5 decoder initialization failed for RX \""
          << name() << "\"\n";
      return false;
    }
    sel5_dec->sequenceDetected.connect(
        mem_fun(*this, &LocalRxBase::sel5Detected));
    voiceband_splitter->addSink(sel5_dec, true);
  }

    // Create an audio valve to use as squelch and connect it to the splitter
  sql_valve = new AudioValve;
  sql_valve->setOpen(false);
  prev_src->registerSink(sql_valve, true);
  prev_src = sql_valve;

    // Create the state detector
  AudioStreamStateDetector *state_det = new AudioStreamStateDetector;
  state_det->sigStreamStateChanged.connect(
            mem_fun(*this, &LocalRxBase::audioStreamStateChange));
  prev_src->registerSink(state_det, true);
  prev_src = state_det;

    // If we need a delay line (e.g. for DTMF muting and/or squelch tail
    // elimination), create it
  if (delay_line_len > 0)
  {
    delay = new AudioDelayLine(delay_line_len);
    prev_src->registerSink(delay, true);
    prev_src = delay;
  }

    // Add a limiter to smoothly limiting the audio before hard clipping it
  AudioCompressor *limit = new AudioCompressor;
  limit->setThreshold(-1);
  limit->setRatio(0.1);
  limit->setAttack(2);
  limit->setDecay(20);
  limit->setOutputGain(1);
  prev_src->registerSink(limit, true);
  prev_src = limit;

    // Clip audio to limit its amplitude
  AudioClipper *clipper = new AudioClipper;
  clipper->setClipLevel(0.98);
  prev_src->registerSink(clipper, true);
  prev_src = clipper;

    // Remove high frequencies generated by the previous clipping
#if (INTERNAL_SAMPLE_RATE == 16000)
  AudioFilter *splatter_filter = new AudioFilter("LpCh9/-0.05/5000");
#else
  AudioFilter *splatter_filter = new AudioFilter("LpCh9/-0.05/3500");
#endif
  prev_src->registerSink(splatter_filter, true);
  prev_src = splatter_filter;
  
    // Set the previous audio pipe object to handle audio distribution for
    // the LocalRxBase class
  setHandler(prev_src);
  
    // Open the audio device for reading
  if (!audioOpen())
  {
    // FIXME: Cleanup?
    return false;
  }
  
  if (mute_1750)
  {
    ToneDetector *calldet = new ToneDetector(1750, 50, 100);
    assert(calldet != 0);
    calldet->setPeakThresh(13);
    calldet->activated.connect(mem_fun(*this, &LocalRxBase::tone1750detected));
    voiceband_splitter->addSink(calldet, true);
    //cout << "### Enabling 1750Hz muting\n";
  }

  return true;
  
} /* LocalRxBase:initialize */
示例#2
0
bool LocalRx::initialize(void)
{
  if (!Rx::initialize())
  {
    return false;
  }
  
  string value;

  string audio_dev;
  if (!cfg.getValue(name(), "AUDIO_DEV", audio_dev))
  {
    cerr << "*** ERROR: Config variable " << name() << "/AUDIO_DEV not set\n";
    return false;
  }
  
  if (!cfg.getValue(name(), "AUDIO_CHANNEL", value))
  {
    cerr << "*** ERROR: Config variable " << name()
         << "/AUDIO_CHANNEL not set\n";
    return false;
  }
  int audio_channel = atoi(value.c_str());
  
  bool deemphasis = false;
  if (cfg.getValue(name(), "DEEMPHASIS", value))
  {
    deemphasis = (atoi(value.c_str()) != 0);
  }
  
  int delay_line_len = 0;
  if (cfg.getValue(name(), "MUTE_DTMF", value))
  {
    cerr << "*** ERROR: The MUTE_DTMF configuration variable has been\n"
      	 << "           renamed to DTMF_MUTING. Change this in configuration\n"
	 << "           section \"" << name() << "\".\n";
    return false;
  }
  
  if (cfg.getValue(name(), "DTMF_MUTING", value))
  {
    mute_dtmf = (atoi(value.c_str()) != 0);
    delay_line_len = DTMF_MUTING_PRE;
  }
  
  if (cfg.getValue(name(), "SQL_TAIL_ELIM", value))
  {
    sql_tail_elim = atoi(value.c_str());
    delay_line_len = max(delay_line_len, sql_tail_elim);
  }
  
  if (cfg.getValue(name(), "PREAMP", value))
  {
    preamp_gain = atoi(value.c_str());
  }
  
  bool peak_meter = false;
  if (cfg.getValue(name(), "PEAK_METER", value))
  {
    peak_meter = (atoi(value.c_str()) != 0);
  }
  
  int dtmf_hangtime = 100;
  if (cfg.getValue(name(), "DTMF_HANGTIME", value))
  {
    dtmf_hangtime = atoi(value.c_str());
  }
  
    // Create the audio IO object
  audio_io = new AudioIO(audio_dev, audio_channel);
  //FIXME: Check that the audio device is correctly initialized
  //       before continuing.
  AudioSource *prev_src = audio_io;
  
    // Create a fifo buffer to handle large audio blocks
  AudioFifo *input_fifo = new AudioFifo(1024);
//  input_fifo->setOverwrite(true);
  prev_src->registerSink(input_fifo, true);
  prev_src = input_fifo;
  
    // If a preamp was configured, create it
  if (preamp_gain != 0)
  {
    AudioAmp *preamp = new AudioAmp;
    preamp->setGain(preamp_gain);
    prev_src->registerSink(preamp, true);
    prev_src = preamp;
  }
  
    // If a peak meter was configured, create it
  if (peak_meter)
  {
    PeakMeter *peak_meter = new PeakMeter(name());
    prev_src->registerSink(peak_meter, true);
    prev_src = peak_meter;
  }
  
    // If the sound card sample rate is higher than 16kHz (48kHz assumed),
    // decimate it down to 16kHz
  if (audio_io->sampleRate() > 16000)
  {
    AudioDecimator *d1 = new AudioDecimator(3, coeff_48_16_wide,
					    coeff_48_16_wide_taps);
    prev_src->registerSink(d1, true);
    prev_src = d1;
  }
  
    // If the sound card sample rate is higher than 8kHz (16 or 48kHz assumed)
    // decimate it down to 8kHz. Also create a splitter to distribute the
    // 16kHz audio to other consumers.
#if (INTERNAL_SAMPLE_RATE != 16000)
  AudioSplitter *rate_16k_splitter = 0;
  if (audio_io->sampleRate() > 8000)
  {
    rate_16k_splitter = new AudioSplitter;
    prev_src->registerSink(rate_16k_splitter, true);

    AudioDecimator *d2 = new AudioDecimator(2, coeff_16_8, coeff_16_8_taps);
    //prev_src->registerSink(d2, true);
    rate_16k_splitter->addSink(d2, true);
    prev_src = d2;
  }
#endif

    // If a deemphasis filter was configured, create it
  if (deemphasis)
  {
    //AudioFilter *deemph_filt = new AudioFilter("LpBu1/300");
    //AudioFilter *deemph_filt = new AudioFilter("HsBq1/0.01/-18/3500");
    AudioFilter *deemph_filt = new AudioFilter("HsBq1/0.05/-36/3500");
    deemph_filt->setOutputGain(2.88);
    prev_src->registerSink(deemph_filt, true);
    prev_src = deemph_filt;
  }
  
    // Create an audio splitter to distribute the 8kHz audio to all consumers
  AudioSplitter *splitter = new AudioSplitter;
  prev_src->registerSink(splitter, true);
  prev_src = 0;
  
    // Create the signal level detector. Connect it to the 16 or 8kHz splitter
    // depending on how the sound card sample rate is setup.
#if (INTERNAL_SAMPLE_RATE != 16000)
  if (rate_16k_splitter != 0)
  {
    siglevdet = createSigLevDet(name(), 16000);
    if (siglevdet == 0)
    {
      return false;
    }
    rate_16k_splitter->addSink(siglevdet, true);
  }
  else
  {
    siglevdet = createSigLevDet(name(), 8000);
    if (siglevdet == 0)
    {
      return false;
    }
    splitter->addSink(siglevdet, true);
  }
#else
  siglevdet = createSigLevDet(name(), 16000);
  if (siglevdet == 0)
  {
    return false;
  }
  splitter->addSink(siglevdet, true);
#endif
  
    // Create the configured squech detector and initialize it. Then connect
    // it to the 8kHz audio splitter
  string sql_det_str;
  if (!cfg.getValue(name(), "SQL_DET", sql_det_str))
  {
    cerr << "*** ERROR: Config variable " << name() << "/SQL_DET not set\n";
    return false;
  }

  if (sql_det_str == "VOX")
  {
    squelch_det = new SquelchVox;
  }
  else if (sql_det_str == "CTCSS")
  {
    squelch_det = new SquelchCtcss;
  }
  else if (sql_det_str == "SERIAL")
  {
    squelch_det = new SquelchSerial;
  }
  else if (sql_det_str == "SIGLEV")
  {
    squelch_det = new SquelchSigLev(siglevdet);
  }
  else if (sql_det_str == "EVDEV")
  {
    squelch_det = new SquelchEvDev;
  }
  else
  {
    cerr << "*** ERROR: Unknown squelch type specified in config variable "
      	 << name() << "/SQL_DET. Legal values are: VOX, CTCSS, SIGLEV, "
	 << "EVDEV and SERIAL\n";
    // FIXME: Cleanup
    return false;
  }
  
  if (!squelch_det->initialize(cfg, name()))
  {
    cerr << "*** ERROR: Squelch detector initialization failed for RX \""
      	 << name() << "\"\n";
    delete squelch_det;
    squelch_det = 0;
    // FIXME: Cleanup
    return false;
  }
  
  squelch_det->squelchOpen.connect(slot(*this, &LocalRx::onSquelchOpen));
  splitter->addSink(squelch_det, true);

    // Create the configured type of DTMF decoder and add it to the splitter
  DtmfDecoder *dtmf_dec = DtmfDecoder::create(cfg, name());
  if ((dtmf_dec == 0) || !dtmf_dec->initialize())
  {
    // FIXME: Cleanup?
    return false;
  }

  dtmf_dec->digitActivated.connect(slot(*this, &LocalRx::dtmfDigitActivated));
  dtmf_dec->digitDeactivated.connect(
      slot(*this, &LocalRx::dtmfDigitDeactivated));
  splitter->addSink(dtmf_dec, true);
  
   // creates a selective multiple tone detector object
  string sel5_det_str;
  if (cfg.getValue(name(), "SEL5_DEC_TYPE", sel5_det_str))
  {
    Sel5Decoder *sel5_dec = Sel5Decoder::create(cfg, name());
    if (sel5_dec == 0 || !sel5_dec->initialize())
    {
      cerr << "*** ERROR: Sel5 decoder initialization failed for RX \""
          << name() << "\"\n";
      return false;
    }
    sel5_dec->sequenceDetected.connect(slot(*this, &LocalRx::sel5Detected));
    splitter->addSink(sel5_dec, true);
  }

    // Create a new audio splitter to handle tone detectors then add it to
    // the splitter
  tone_dets = new AudioSplitter;
  splitter->addSink(tone_dets, true);
  
    // Create an audio valve to use as squelch and connect it to the splitter
  sql_valve = new AudioValve;
  sql_valve->setOpen(false);
  splitter->addSink(sql_valve, true);
  prev_src = sql_valve;

    // Create the state detector
  AudioStreamStateDetector *state_det = new AudioStreamStateDetector;
  state_det->sigStreamStateChanged.connect(
            slot(*this, &LocalRx::audioStreamStateChange));
  prev_src->registerSink(state_det, true);
  prev_src = state_det;

    // Create the highpass CTCSS filter that cuts off audio below 300Hz
  AudioFilter *ctcss_filt = new AudioFilter("HpBu20/300");
  prev_src->registerSink(ctcss_filt, true);
  prev_src = ctcss_filt;
  
    // If we need a delay line (e.g. for DTMF muting and/or squelch tail
    // elimination), create it
  if (delay_line_len > 0)
  {
    delay = new AudioDelayLine(delay_line_len);
    prev_src->registerSink(delay, true);
    prev_src = delay;
  }
  
    // Add a limiter to smoothly limiting the audio before hard clipping it
  AudioCompressor *limit = new AudioCompressor;
  limit->setThreshold(-1);
  limit->setRatio(0.1);
  limit->setAttack(2);
  limit->setDecay(20);
  limit->setOutputGain(1);
  prev_src->registerSink(limit, true);
  prev_src = limit;

    // Clip audio to limit its amplitude
  AudioClipper *clipper = new AudioClipper;
  clipper->setClipLevel(0.98);
  prev_src->registerSink(clipper, true);
  prev_src = clipper;

    // Remove high frequencies generated by the previous clipping
#if (INTERNAL_SAMPLE_RATE == 16000)
  AudioFilter *splatter_filter = new AudioFilter("LpBu20/5500");
#else
  AudioFilter *splatter_filter = new AudioFilter("LpBu20/3500");
#endif
  prev_src->registerSink(splatter_filter, true);
  prev_src = splatter_filter;
  
    // Set the previous audio pipe object to handle audio distribution for
    // the LocalRx class
  setHandler(prev_src);
  
  return true;
  
} /* LocalRx:initialize */