Пример #1
0
int sys_mem_usage(SYS_USAGE_CTXT_T *pCtxt) {
  int rc = 0;
  TIME_VAL tmnow;

  if(!pCtxt || !pCtxt->pcurM) {
    return -1;
  }

  tmnow = timer_GetTime();

  //
  // Return if it has not yet been SYS_MEM_MIN_INTERVAL_MS since the last snapshot
  //
  if(pCtxt->memsnapshot.tvsnapshot != 0 && 
     ((tmnow - pCtxt->memsnapshot.tvsnapshot) / TIME_VAL_MS) < SYS_MEM_MIN_INTERVAL_MS) {
    LOG(X_DEBUGV("Memory snapshot not ready"));
    return 0;
  }
 
  //
  // Take a running snapshot of the cpu counters
  //
  if((rc = mem_snapshot(&pCtxt->memsnapshot, tmnow)) < 0)  {
    return rc;
  }

  memcpy(pCtxt->pcurM, &pCtxt->memsnapshot, sizeof(MEM_SNAPSHOT_T));

  return 1;
}
Пример #2
0
DIR_ENTRY_LIST_T *direntry_getentries(const MEDIADB_DESCR_T *pMediaDb, 
                                      const char *dir, 
                                      const char *fidxdir, 
                                      const char *searchstr,
                                      int includedirs,
                                      unsigned int startidx,
                                      unsigned int max,
                                      enum DIR_SORT sort) {
  DIR *pdir;
  int rc = 0;
  struct dirent *direntry;
  char path[VSX_MAX_PATH_LEN];
  struct stat st;
  int addEntry;
  FILE_LIST_T fileList;
  FILE_LIST_ENTRY_T *pFileEntry = NULL;
  META_FILE_T metaFile;
  DIR_ENTRY_LIST_T *pEntryList = NULL;
  DIR_ENTRY_T entry;
  DIR_ENTRY_T *pEntry;
  const char *pdispname;
  unsigned int idx = 0;
  unsigned int cnt = 0;
  unsigned int cntInDir = 0;
  COMPARE_DIR_ENTRY compareFunc = direntry_getcompfunc(sort);

  VSX_DEBUG_MGR( LOG(X_DEBUG("MGR - direntry_getentries dir: '%s', fidxdir: '%s', searchstr: '%s', "
                             "includedirs: %d, startidx: %d, max: %d"), 
                            dir, fidxdir, searchstr, includedirs, startidx, max));

  if(!(pdir = fileops_OpenDir(dir))) {
    return NULL;
  }

  memset(&fileList, 0, sizeof(fileList));
  if(fidxdir) { 
    file_list_read(fidxdir, &fileList);
  }

  //
  // Read the directory wide metafile to get a list of 'ignore' entries
  //
  memset(&metaFile, 0, sizeof(metaFile));
  mediadb_prepend_dir(dir, METAFILE_DEFAULT, path, sizeof(path));
  if(fileops_stat(path, &st) == 0) {
    metafile_open(path, &metaFile, 1, 1);
  }

  while((direntry = fileops_ReadDir(pdir))) {

    VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries d_name: '%s', isdir: %d"), 
           direntry->d_name, (direntry->d_type & DT_DIR)) );

    if(is_entry_ignored(metaFile.pignoreList, direntry->d_name)) {
      continue;
    }

    if(!(pdispname = find_entry_description(metaFile.pDescriptionList,
                                     direntry->d_name))) {
      pdispname = direntry->d_name;
    }

    if(searchstr && !is_match_search(pdispname, NULL, searchstr)) {
      continue;
    }

    memset(&entry, 0, sizeof(entry));
    strncpy(entry.d_name, direntry->d_name, sizeof(entry.d_name) - 1); 
    if(pdispname != direntry->d_name) {
      strncpy(entry.displayname, pdispname, sizeof(entry.displayname) - 1); 
    }
    entry.d_type = direntry->d_type;
    addEntry = 0;

    if(direntry->d_type & DT_DIR) {

      if(includedirs && mediadb_isvalidDirName(pMediaDb, direntry->d_name)) {
        addEntry = 1;
      }

    } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 1)) {

      mediadb_prepend_dir(dir, direntry->d_name, path, sizeof(path));
      if(fileops_stat(path, &st) == 0) {
        entry.size = st.st_size;
        //entry.tm = st.st_mtime;
        entry.tm = st.st_ctime;

        if(fidxdir && (pFileEntry = file_list_find(&fileList, direntry->d_name))) {
          entry.numTn = pFileEntry->numTn; 
          entry.duration = pFileEntry->duration;
        }
        addEntry = 1;
      }

    }

    if(addEntry) {
      VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries add d_name: '%s', isdir: %d"), 
           direntry->d_name, (direntry->d_type & DT_DIR)) );

      if(compareFunc || (idx >= startidx && (max == 0 || cnt < max))) {

        if(cnt >= DIR_ENTRY_LIST_BUFNUM) {
          LOG(X_WARNING("Not showing more than %d entries in %s"), cnt, dir);
          break;
        } else if(!(pEntry = direntry_addsorted(&pEntryList, &entry, compareFunc))) {
          LOG(X_ERROR("Failed to add directory entry '%s' to list"), direntry->d_name);
          rc = -1;
          break;
        }
        cnt++;
      }

      idx++;
      cntInDir++;
    }

  }

  //
  // Since when a sort is requested we have to sort every entry in the directory.  Now we can move the head pointer
  // to the first desired entry
  //
  if(pEntryList && compareFunc && startidx > 0) {
    pEntry = pEntryList->pHead;
    for(idx = 0; idx < startidx; idx++) {
      pEntry = pEntry->pnext;
      cnt--;
    }
    pEntryList->pHead = pEntry;
    if(cnt > max) {
      cnt = max;
    }
    //fprintf(stderr, "moved phead to %s, cnt:%d, cntInDir:%d\n", pEntryList->pHead ? pEntryList->pHead->d_name : NULL, cnt, cntInDir);
  }
  

  fileops_CloseDir(pdir);
  if(fidxdir) {
    file_list_close(&fileList);
  }
  metafile_close(&metaFile);

  if(rc == 0 && !pEntryList) {
    // If the user requested an index out of bounds, return an empty list with
    // a valid cntTotalInDir
    pEntryList = (DIR_ENTRY_LIST_T *) avc_calloc(1, sizeof(DIR_ENTRY_LIST_T));
  }

  if(pEntryList) {
    pEntryList->cntTotal = cnt; 
    pEntryList->cntTotalInDir = cntInDir; 
  }

  //if(pEntryList) fprintf(stderr, "DIR '%s' num:%d numAlloc:%d pnext:0x%x TOTAL:%d/%d\n", dir, pEntryList->num, pEntryList->numAlloc, pEntryList->pnext, pEntryList->cntTotal, pEntryList->cntTotalInDir);
 
  return pEntryList;
}
Пример #3
0
int sys_cpu_usage(SYS_USAGE_CTXT_T *pCtxt) {
  int rc = 0;
  CPU_SNAPSHOT_T *pSnapshots[2];
  CPU_SNAPSHOT_T diff;
  TIME_VAL tmnow;

  if(!pCtxt || !pCtxt->pcurC) {
    return -1;
  }

  if(pCtxt->cpusnapshots[0].tvsnapshot == 0) {
    pSnapshots[0] = &pCtxt->cpusnapshots[0];
    pSnapshots[1]  = &pCtxt->cpusnapshots[1];
  } else {
    pSnapshots[1] = &pCtxt->cpusnapshots[0];
    pSnapshots[0]  = &pCtxt->cpusnapshots[1];
  }

  tmnow = timer_GetTime();

  //
  // Return if it has not yet been SYS_CPU_MIN_INTERVAL_MS since the last snapshot
  //
  if(pSnapshots[1]->tvsnapshot != 0 && 
     ((tmnow - pSnapshots[1]->tvsnapshot) / TIME_VAL_MS) < SYS_CPU_MIN_INTERVAL_MS) {
    LOG(X_DEBUGV("CPU snapshots not ready"));
    return 0;
  }
 
  //
  // Take a running snapshot of the cpu counters
  //
  if((rc = cpu_snapshot(pSnapshots[0])) < 0) {
    return rc;
  } 

  pSnapshots[0]->tvsnapshot = tmnow;

  if(pSnapshots[1]->tvsnapshot == 0) {
    //
    // We've only been called once and don't have at least 2 snapshots
    //
    return 0;
  }

  //
  // Make sure the counters have been updated since the last snapshot
  //
  if((diff.tmtot = pSnapshots[0]->tmtot - pSnapshots[1]->tmtot) == 0) {
    LOG(X_ERROR("CPU tmtot 0 (%Lf - %Lf)"), pSnapshots[0]->tmtot, pSnapshots[1]->tmtot);
    return 0;
  }

  diff.tmuser = pSnapshots[0]->tmuser - pSnapshots[1]->tmuser;
  diff.tmnice = pSnapshots[0]->tmnice - pSnapshots[1]->tmnice;
  diff.tmsys = pSnapshots[0]->tmsys - pSnapshots[1]->tmsys;
  diff.tmidle = pSnapshots[0]->tmidle - pSnapshots[1]->tmidle;

  pCtxt->pcurC->percentuser = get_percentage(diff.tmuser, &diff);
  pCtxt->pcurC->percentnice = get_percentage(diff.tmnice, &diff);
  pCtxt->pcurC->percentsys = get_percentage(diff.tmsys, &diff);
  pCtxt->pcurC->percentidle = get_percentage(diff.tmidle, &diff);

  pSnapshots[1]->tvsnapshot = 0;

  return 1;
}
Пример #4
0
int streamxmit_onRTCPNACK(STREAM_RTP_DEST_T *pDest, const RTCP_PKT_RTPFB_NACK_T *pNack) {
  STREAMXMIT_PKT_HDR_T *pktHdr;
  TIME_VAL tvNow;
  uint16_t nackSeqNumStart;
  uint16_t nackBlp;
  unsigned int seqNumOffset;
  unsigned int idxWr;
  unsigned int count = 0;
  int doRetransmission = 0;
  STREAM_XMIT_QUEUE_T *pAsyncQ = NULL;

  if(!pDest || !pNack) {
    return -1;
  } else if(!(pAsyncQ = &pDest->asyncQ) || !pAsyncQ->doRtcpNack || !pAsyncQ->pQ) {
    return 0;
  }

//TODO: compute incoming NACK rate to outgoing RTP rate for ABR algorithm

  tvNow = timer_GetTime();
  nackSeqNumStart = htons(pNack->pid);
  nackBlp = htons(pNack->blp);

  pthread_mutex_lock(&pAsyncQ->mtx);

  //LOG(X_DEBUG("streamxmit_onRTCPNACK nackSeqNumStart:%d"), nackSeqNumStart);
  //fprintf(stderr, "treamxmit_onRTCPNACK nackSeqNumStart... nackSeqNumStart:%d\n", nackSeqNumStart); pktqueue_dump(pDest->asyncQ.pQ,  pktqueue_cb_streamxmit_dump_pkthdr);

  //
  // If the highest possible NACK sequence num came before the first packet of the keyframe of the current GOP,
  // then disregard it because we are assuming the keyframe is an IDR.
  //
  if(pAsyncQ->haveLastKeyframeSeqNumStart && nackSeqNumStart + 16 < pAsyncQ->lastKeyframeSeqNumStart) {
    pthread_mutex_unlock(&pAsyncQ->mtx);
    LOG(X_DEBUG("RTP NACK for sequence: %d ignored because it pertains to a prior GOP sequence:%d"), nackSeqNumStart, 
                pDest->asyncQ.lastKeyframeSeqNumStart);
    return 0;
  }

  //
  // Iterate the stored packet list backwards starting with the most recently 
  // transmitted packet
  //
  idxWr = pAsyncQ->pQ->idxWr;
  //LOG(X_DEBUG("streamxmit_onRTCPNACK starting at idxWr:%d / %d"), idxWr-1, pAsyncQ->pQ->cfg.maxPkts);
  while(count++ < pAsyncQ->pQ->cfg.maxPkts) {

    if(idxWr > 0) {
      idxWr--;
    } else {
      idxWr = pAsyncQ->pQ->cfg.maxPkts - 1;
    }

    if(!(pAsyncQ->pQ->pkts[idxWr].flags & PKTQUEUE_FLAG_HAVEPKTDATA)) {
      //
      // The write queue slot is empty
      //
      //LOG(X_DEBUG("streamxmit_onRTCPNACK idxWr:%d / %d is empty.. break"), idxWr, pAsyncQ->pQ->cfg.maxPkts);
      break;

    } else if((pktHdr = (STREAMXMIT_PKT_HDR_T *) pAsyncQ->pQ->pkts[idxWr].xtra.pQUserData) && !pktHdr->rtcp) {

      if(pktHdr->seqNum < nackSeqNumStart) {

        //
        // The queue slot RTP sequence number came before the NACK starting sequence number
        // so the current queue content is before the scope of the NACK
        //
        //LOG(X_DEBUG("streamxmit_onRTCPNACK idxWr:%d / %d is empty.. break.. seqNuM:%d came before nackSeqNumStart:%d"), idxWr, pAsyncQ->pQ->cfg.maxPkts, pktHdr->seqNum, nackSeqNumStart);
        break;

      } else if(pktHdr->tvXmit + (pAsyncQ->nackHistoryMs * TIME_VAL_MS) < tvNow) {

        //
        // The queue slot packet time is too old and beyond our threshold for RTP retransmission
        //
        //LOG(X_DEBUG("streamxmit_onRTCPNACK idxWr:%d / %d is empty.. seqNuM:%d nack too old to honor"), idxWr, pAsyncQ->pQ->cfg.maxPkts, pktHdr->seqNum);
        if(pktHdr->doRetransmit >= 0) {
          LOG(X_DEBUG("RTP NACK for sequence: %d ignored because it has age %d ms > %d ms"), nackSeqNumStart, pAsyncQ->nackHistoryMs,
               (tvNow - pktHdr->tvXmit) / TIME_VAL_MS);
        }
        pktHdr->doRetransmit = -1;
        break;

//TODO: handle seq roll... should not be a big problem here...
      } else if(pktHdr->doRetransmit >= 0 && pktHdr->seqNum <= nackSeqNumStart + 16) {

        //LOG(X_DEBUG("streamxmit_onRTCPNACK idxWr:%d / %d seqNum:%d, nackSeqNumStart:%d is within range. seqNumOffset:%d, nackBlp:0x%x"), idxWr, pAsyncQ->pQ->cfg.maxPkts, pktHdr->seqNum, nackSeqNumStart, (pktHdr->seqNum - nackSeqNumStart), nackBlp);

        if((seqNumOffset = pktHdr->seqNum - nackSeqNumStart) == 0 || (nackBlp & (1 << (seqNumOffset - 1)))) {

          //
          // The packet sequence number matches a packet which is being negatively-acknowledged so mark
          // it for retransmission
          //
          if(pktHdr->doRetransmit >= 0 && 
             (!pAsyncQ->haveLastKeyframeSeqNumStart || pktHdr->seqNum >= pAsyncQ->lastKeyframeSeqNumStart)) {

            LOG(X_DEBUGV("RTP NACK marked pt:%d sequence:%d for retransmission"), 
                pDest->pRtpMulti->init.pt, pktHdr->seqNum);

            if(pktHdr->doRetransmit == 0) {

              if(pDest->pstreamStats) {
                stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, 
                                         STREAM_ABR_UPDATE_REASON_NACK_REQ, .5f);
              }

            }

            pktHdr->doRetransmit++;

          } else {
            LOG(X_DEBUG("RTP NACK not marking pt:%d sequence:%d for retransmission"), pDest->pRtpMulti->init.pt, pktHdr->seqNum);
          }


       
          doRetransmission = 1;
        }

      }
    }

  }

  if(doRetransmission) {
    if(!pAsyncQ->haveRequestedRetransmission) {
      pAsyncQ->haveRequestedRetransmission = 1;
      //
      // Signal the output retransmission thread
      //
      vsxlib_cond_signal(&pDest->pRtpMulti->asyncRtpCond.cond, &pDest->pRtpMulti->asyncRtpCond.mtx);
    }
  }

  pthread_mutex_unlock(&pAsyncQ->mtx);

  return 0;
}
Пример #5
0
int addbuffered(MIXER_SOURCE_T *pSource, 
                       const int16_t *pSamples, 
                       unsigned int numSamples,
                       unsigned int channels, 
                       u_int64_t tsHz,
                       int vad,
                       int *pvad,
                       int lock) {
  int rc = 0;
  int rc_vad = 0;
  //int vadTot = 0, vadCnt = 0;
  unsigned int vadIdx;
  unsigned int idx = 0;
  unsigned int copy;
  AUDIO_PREPROC_T *pPreproc = &pSource->preproc;

  if(!pPreproc->active) {

    rc = addsamples(pSource, pSamples, numSamples, channels, tsHz, vad, NULL, lock);

    return rc;
  }

  LOG(X_DEBUGV("addbuffered sourceid:%d, active:%d %lluHz (lastWr:%lluHz), samples:%d, buffer starts at %lluHz, previously had %u samples"),pSource->id, pSource->active, tsHz, pSource->lastWrittenTsHz, numSamples, pSource->buf.tsHz, pSource->buf.numSamples);

  if(pSource->active && pSource->buf.haveTsHz && tsHz < pSource->buf.tsHz) {
    //
    // We likely previously skipped these input samples as they were late arriving and have already
    // been replaced with null noise
    //
    idx += (pSource->buf.tsHz - tsHz);
    LOG(X_WARNING("mixer_addbuffered samples sourceid:%d clipping first %d (max:%d) samples %lldHz < %lldHz, "
                "has %d samples"),
                pSource->id, idx, numSamples, tsHz, pSource->buf.tsHz, pSource->buf.numSamples);

#if defined(DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)
    mixer_dumpLog(S_DEBUG, pSource->pMixer, !lock, "addbuffered clipping");
#endif // (DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)

/*
    if(pSource->active && idx >= numSamples && tsHz < pSource->buf.tsHz && 
       (pSource->buf.tsHz - tsHz) > pSource->thresholdHz) {
      pSource->active = 0;
      pSource->needInputReset = 1;
      source_reset(pSource, !lock);
//#if defined(DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)
    fprintf(stderr, "addbuffered resetting source id:%d, haveTsHz:%d, tsHz:%lluHz, buf.numSamples:%d, tsHz:%lluHz, idx:%d, active:%d\n", pSource->id, pSource->buf.haveTsHz, pSource->buf.tsHz, pSource->buf.numSamples, tsHz - idx, idx, pSource->active);
    
//#endif // (DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)
      return 0;
    }
*/

    tsHz += idx;

  }

  if(!pSource->active && pPreproc->bufferIdx > 0) {
#if defined(DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)
    LOG(X_DEBUG("---mixer preproc setting bufferIdx=0 because source id:%d is not active"), pSource->id);
#endif // (DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)
    pPreproc->bufferIdx = 0;
  }

  //
  // Run the input samples through the preprocessor
  //
  while(idx < numSamples) {

#if defined(DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)
    if(pSource->id==1) 
      LOG(X_DEBUG("---mixer preproc source id:%d, %d/%d, pPreproc->tsHz:%lluHz, tsHz:%lluHz (discarded offset:%lldHz), pPreproc->bufferIdx:%d, source->active:%d"), pSource->id, idx, numSamples, pPreproc->tsHz, tsHz, pSource->discardedSamplesOffset, pPreproc->bufferIdx, pSource->active);
#endif // (DEBUG_MIXER_TIMING) && (DEBUG_MIXER_TIMING > 0)

    if(pPreproc->bufferIdx == 0) {
      pPreproc->tsHz = tsHz;
    }

    copy = MIN(pPreproc->chunkHz - pPreproc->bufferIdx, numSamples - idx);

//fprintf(stderr, "addbuffered sourceid:%dcopy:%d -> [%d]/%d, pPreproc->tsHz:%llu, tsHz:%llu\n", pSource->id, copy, pPreproc->bufferIdx, pPreproc->chunkHz, pPreproc->tsHz, tsHz);


    if(!pSamples) {
      //
      // Fill with blank samples
      //
      memset(&pPreproc->buffer[pPreproc->bufferIdx], 0x00, copy * sizeof(int16_t));
    } else if(pSamples != pSource->buf.buffer) {
      memcpy(&pPreproc->buffer[pPreproc->bufferIdx], &pSamples[idx], copy * sizeof(int16_t));
    }

    pPreproc->bufferIdx += copy;
    idx += copy; 
    tsHz += copy;

    if(pPreproc->bufferIdx >= pPreproc->chunkHz) {

      if(pPreproc->cfg_vad || pPreproc->cfg_denoise || pPreproc->cfg_agc) {

        //  
        // Run the audio preprocessor on the entire chunk of samples
        //
        if((rc_vad = audio_preproc_exec(pPreproc,  pPreproc->buffer, pPreproc->bufferIdx)) < 0) {
          rc_vad = 0;
        }
        //rc_vad = random()%2;

        if(pPreproc->cfg_vad_smooth) {
          //int rc_vad_orig = rc_vad;
#define VAD_SMOOTHING_RAISE_FACTOR 4.0f
#define VAD_SMOOTHING_LOWER_FACTOR 2.5f
#define VAD_SMOOTHING_THRESHOLD  0.65f
          pPreproc->vad_smooth_avg += ((float)rc_vad - pPreproc->vad_smooth_avg) / 
                         (rc_vad > 0 ? VAD_SMOOTHING_RAISE_FACTOR : VAD_SMOOTHING_LOWER_FACTOR);
          if(pPreproc->vad_smooth_avg >= VAD_SMOOTHING_THRESHOLD) {
            rc_vad = 1;
          } else {
            rc_vad = 0;
          }
        //if(((int) pthread_self()& 0xffff) != 0x5960) fprintf(stderr, "tid:0x%x rc_vad_orig:%d (smoothed:%d) vad_smooth_avg:%.3f\n", pthread_self(), rc_vad_orig, rc_vad, pPreproc->vad_smooth_avg);
        } 

      } 

      if(!pPreproc->cfg_vad) {
        //
        // The VAD value comes form the input, as it may have already been computed at
        // an up-stream source
        //
        rc_vad = vad ? 1 : 0;
      }

      //vadTot += pSamples ? rc_vad : 0;
      //vadCnt++;

      //
      // Store the returned VAD confidence value
      //
      if(pPreproc->vad_buffer) {


        //
        // Algorithm to persist VAD flag up to cfg_vad_persist samples after the last speex vad 
        // non-zero value was obtained
        //
        if(rc_vad > 0) {
          pPreproc->vad_persist = pPreproc->cfg_vad_persist;
        } else if(pPreproc->vad_persist > 0) {
          pPreproc->vad_persist--;
          rc_vad = 2;
        }

        vadIdx = pSource->buf.samplesWrIdx / pPreproc->chunkHz;
        pPreproc->vad_buffer[vadIdx] = rc_vad;
      }
      
      //fprintf(stderr, "audio_preproc_exec: vadIdx[%d], vad:%d (persist:%d/%d), tsHz:%llu\n", vadIdx, rc_vad, pPreproc->vad_persist, pPreproc->cfg_vad_persist, pPreproc->tsHz);

     //TOD: after reset pPreproc->tsHz corresponds to old buf.tsHz, should take effect of new input param tsHz

      rc = addsamples(pSource, pPreproc->buffer, pPreproc->bufferIdx, channels, pPreproc->tsHz, vad, NULL, lock);

      pPreproc->bufferIdx = 0;

      if(rc < 0 || !pSource->active) {
        break;
      }

    }

  }

  if(pvad) {
    //*pvad = vadCnt > 0 ? vadTot / vadCnt : 0;
    *pvad = rc_vad ? 1 : 0;
  }

  return rc;
}
Пример #6
0
SOCKET net_opensocket(int socktype, unsigned int rcvbufsz, int sndbufsz, const struct sockaddr *psa) {
  int val;
  int sockbufsz = 0;
  char tmp[128];
  sa_family_t sa_family = AF_INET;
  SOCKET sock = INVALID_SOCKET;

  if(socktype != SOCK_STREAM && socktype != SOCK_DGRAM) {
    return INVALID_SOCKET;
  }

  if(psa && psa->sa_family == AF_INET6) {
    sa_family = psa->sa_family;
  }

  if((sock = socket(sa_family, socktype, 0)) == INVALID_SOCKET) {
    LOG(X_ERROR("Unable to create socket type %d"), socktype);
    return INVALID_SOCKET;
  }

  if(psa) {
    //LOG(X_DEBUG("NET_OPENSOCKET... family: %d, is_multicast: %d"), psa->sa_family, (socktype == SOCK_DGRAM && INET_IS_MULTICAST(psa)));
    //
    // Handle IGMP multicast group subscription
    //
    if(socktype == SOCK_DGRAM && INET_IS_MULTICAST(psa)) {
      if(add_multicast_group(sock, psa)  < 0) {
        closesocket(sock);
        LOG(X_ERROR("Failed to create socket family: %d %s:%d"), sa_family, 
                    FORMAT_NETADDR(*psa, tmp, sizeof(tmp)), htons(PINET_PORT(psa)));
        LOGHEX_DEBUGV(psa, sizeof(struct sockaddr_storage));
        return INVALID_SOCKET;
      }
    }

    val = 1;
    if(setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *) &val, sizeof (val)) != 0) {
      LOG(X_WARNING("setsockopt SOL_SOCKET SO_REUSEADDR fail "ERRNO_FMT_STR), 
              ERRNO_FMT_ARGS);
    }

#if defined(__APPLE__)
    if(socktype == SOCK_DGRAM) {
      val = 1;
      if(setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
                      (char *) &val, sizeof (val)) != 0) {
        LOG(X_WARNING("setsockopt SOL_SOCKET SO_REUSEPORT fail "ERRNO_FMT_STR), 
                ERRNO_FMT_ARGS);
      }
    }
#endif // __APPLE__

    if(bind(sock, psa, INET_SIZE(*psa)) < 0) {
      LOG(X_ERROR("Unable to bind to local port %s:%d "ERRNO_FMT_STR),
                       FORMAT_NETADDR(*psa, tmp, sizeof(tmp)), ntohs(PINET_PORT(psa)), ERRNO_FMT_ARGS);
      closesocket(sock);
      return INVALID_SOCKET;
    }

     VSX_DEBUG_NET( LOG(X_DEBUG("NET - net_opensock: %s, family: %d (%d), fd: %d bound listener to %s:%d"), 
                socktype == SOCK_STREAM ? "stream" : "dgram", sa_family, psa->sa_family, sock, 
                FORMAT_NETADDR(*psa, tmp, sizeof(tmp)), ntohs(PINET_PORT(psa))) );

  } else {
     VSX_DEBUG_NET( LOG(X_DEBUG("NET - net_opensock: %s,family: %d, fd: %d"), 
                        socktype == SOCK_STREAM ? "stream" : "dgram", sa_family, sock) );
  }

  if(rcvbufsz > 0) {

    if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
                  (char*) &rcvbufsz, sizeof(rcvbufsz)) != 0) {
      LOG(X_WARNING("Unable to setsockopt SOL_SOCKET SO_RCVBUF %u"), rcvbufsz);
    }

    sockbufsz = 0;
    val = sizeof(sockbufsz);
    if(getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
                 (char*) &sockbufsz, (socklen_t *) &val) != 0) {
      LOG(X_ERROR("Unable to getsockopt SOL_SOCKET SO_RCVBUF %d"), val);
      closesocket(sock);
      return INVALID_SOCKET;
    }

    LOG(X_DEBUGV("socket receive buffer set to: %u"), sockbufsz);
  }

  if(sndbufsz > 0) {

    if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
                  (char*) &sndbufsz, sizeof(rcvbufsz)) != 0) {
      LOG(X_WARNING("Unable to setsockopt SOL_SOCKET SO_SNDBUF %u"), sndbufsz);
    }

    sockbufsz = 0;
    val = sizeof(sockbufsz);
    if(getsockopt(sock, SOL_SOCKET, SO_SNDBUF,
                 (char*) &sockbufsz, (socklen_t *) &val) != 0) {
      LOG(X_ERROR("Unable to getsockopt SOL_SOCKET SO_SNDBUF %d"), val);
      closesocket(sock);
      return INVALID_SOCKET;
    }

    LOG(X_DEBUGV("socket send buffer set to: %u"), sockbufsz);
  }

  return sock;
}
Пример #7
0
int streamer_run_tonet(STREAM_XMIT_NODE_T *pList, double durationSec) {
  STREAM_XMIT_NODE_T *pStream;
  int triedXmit;
  TIME_VAL tmstartOutput = 0;
  TIME_VAL tmstart, tmnow;
  int haveTmstartOutput = 0;
  int rc;

#if defined(VSX_HAVE_TURN)
  int pendingTurnRelays = 1;
  int pendingTurnRelays0;
  NET_PROGRESS_T progTurn;
  memset(&progTurn, 0, sizeof(progTurn));
#else // (VSX_HAVE_TURN)
  int pendingTurnRelays = 0;
#endif // (VSX_HAVE_TURN)

#if defined(VSX_HAVE_SSL_DTLS)
  TIME_VAL tmstartRtpHandshakeDone = 0;
  int giveupRtcpHandshakes = 0;
  int pendingDtlsRtpHandshakes = 1;
  NET_PROGRESS_T progRtp;
  NET_PROGRESS_T progRtcp;
  DTLS_TIMEOUT_CFG_T dtlsTimeouts;

  setDtlsTimeouts(&dtlsTimeouts, pList);
  memset(&progRtp, 0, sizeof(progRtp));
  memset(&progRtcp, 0, sizeof(progRtcp));
#else
  int pendingDtlsRtpHandshakes = 0;
#endif // (VSX_HAVE_SSL_DTLS)


#ifndef WIN32
  unsigned int countIterations = 0;
#endif // WIN32

  if(!pList 
#if defined(VSX_HAVE_LICENSE)
    || !pList->pLic
#endif // VSX_HAVE_LICENSE
    ) {
    return -1;
  }

  tmstart = tmnow = timer_GetTime();

  while(*pList->prunning == STREAMER_STATE_RUNNING && !g_proc_exit) {

    pStream = pList;
    triedXmit = 0;

    while(pStream) {

#if defined(VSX_HAVE_TURN)

      pendingTurnRelays0 = pendingTurnRelays;

      if(pendingTurnRelays > 0 && (pendingTurnRelays = do_turn_relays(pStream, &progTurn)) < 0) {
        LOG(X_ERROR("Giving up waiting for output transmission after TURN relay setup failure"));
        return -1; 
      }

      if(pendingTurnRelays == 0 && pendingTurnRelays0 != pendingTurnRelays && progTurn.numTotal > 0) {
        LOG(X_INFO("Starting output transmission after creating TURN relay(s)"));
      }

      //LOG(X_DEBUG("pendingTurnRelays:%d, %d/%d, numerror:%d"), pendingTurnRelays, progTurn.numCompleted, progTurn.numTotal, progTurn.numError); 
#endif // (VSX_HAVE_TURN)

#if defined(VSX_HAVE_SSL_DTLS)
      //if(pStream->pRtpMulti->pStreamerCfg->xcode.vid.pip.active) 
      //LOG(X_DEBUG("loop... pendingDtlsRtpHandshakes:%d, rtp:%d - %d, rtcp:%d - %d, giveupRtcpHandshakes:%d, tm:%lld ms"), pendingDtlsRtpHandshakes, progRtp.numTotal,  progRtp.numCompleted, progRtcp.numTotal,  progRtcp.numCompleted, giveupRtcpHandshakes, (timer_GetTime() - tmstart) / TIME_VAL_MS);

      //LOG(X_DEBUG("streamer2: pendingTurnRelays;%d, completed:%d/%d, pendingDtlsRtpHandshakes:%d"), pendingTurnRelays, progTurn.numCompleted, progTurn.numTotal, pendingDtlsRtpHandshakes);

      if(pendingTurnRelays == 0 && pendingDtlsRtpHandshakes > 0 && 
         (pendingDtlsRtpHandshakes = do_dtls_handshakes(pStream, tmstart, &tmstartRtpHandshakeDone, 
                                                     &progRtp, &progRtcp, &dtlsTimeouts)) < 0) {
        return -1;
      } else if(pendingDtlsRtpHandshakes == 0 && pendingTurnRelays == 0) {

        if(!haveTmstartOutput) {
          tmstartOutput = timer_GetTime();
          haveTmstartOutput = 1;
        }

        if(progRtcp.numTotal - progRtcp.numCompleted > 0 && !giveupRtcpHandshakes) {

          if(tmstartRtpHandshakeDone == 0) {
            tmstartRtpHandshakeDone = timer_GetTime();
          }

          if(((tmnow = timer_GetTime()) - tmstartRtpHandshakeDone) / TIME_VAL_MS > 
             dtlsTimeouts.handshakeRtcpAdditionalGiveupMs) {
            LOG(X_ERROR("Aborting DTLS RTCP handshaking after %lld ms"), (tmnow - tmstart) / TIME_VAL_MS);
            giveupRtcpHandshakes = 1;
          } else {
            do_dtls_handshakes(pStream, tmstart, &tmstartRtpHandshakeDone, NULL, &progRtcp, &dtlsTimeouts);
          }  

          //LOG(X_DEBUG("loop... calling do_dtls_handshakes Rtcp.numDtls:%d - Rtcp.numDtlsCompleted"), progRtcp.numTotal, progRtcp.numCompleted);
        }
#endif // (VSX_HAVE_SSL_DTLS)

        //if(pStream->pRtpMulti->pStreamerCfg->xcode.vid.pip.active) 
        //LOG(X_DEBUG("Calling cbCanSend"));
        if((rc = pStream->cbCanSend(pStream->pCbData)) > 0) {

          if((rc = pStream->cbPreparePkt(pStream->pCbData)) < 0) {
            return -1;
          } else if(rc > 0) {
            triedXmit = 1;
          }

        } else if(rc == -2) {
          // all programs have ended
          return 0;
        } else if(rc < 0) {
          return -1;
        } else {
          //fprintf(stderr, "streamer cansend rc:%d\n", rc);
        }   

#if defined(VSX_HAVE_SSL_DTLS)
      }
#endif // (VSX_HAVE_SSL_DTLS)

      pStream = pStream->pNext;
    } // while(pStream)

    if(triedXmit == 0) {

#ifdef WIN32

      //sl1 = timer_GetTime();

      //Sleep(1) may sleep past its short bedtime on win32, even from a thread w/ SCHED_RR
      //However, sleep(0) uses alot more cpu slices
      //TODO: make this a WaitForSingleObject for any registered pktqueue writers
      
      if(pList->pSleepQ) {
        //TODO: this does not return if a pkt has been queued and no subsequent pkt arrives
        pktqueue_waitforunreaddata(pList->pSleepQ);
      } else {
        Sleep(1);
      }

    } else {
      // On windows Sleep 0 relinquishes execution for any waiting threads
      Sleep(0);

#else // WIN32


      VSX_DEBUG2(tmnow = timer_GetTime());

      //fprintf(stderr, "usleep...\n");
      if(pendingDtlsRtpHandshakes > 0 || pendingTurnRelays > 0) {
        usleep(10000);
      } else {
        usleep(1000);
      }
      //fprintf(stderr, "usleep done...\n");

      countIterations = 0;

      VSX_DEBUG_STREAMAV( LOG(X_DEBUGV("stream_readframes slept for %lld ns"), timer_GetTime() - tmnow));

      //fprintf(stderr, "%lld --woke up from streamer2 zzz...\n", timer_GetTime() / TIME_VAL_MS);
    } else {
      //fprintf(stderr, "stream_readframes not sleeping count:%d tried:%d\n", countIterations, triedXmit);

      //fprintf(stderr, "no usleep...%d\n", countIterations);
      if(countIterations++ > 10000) {
        // During continuous xmit, sleep to prevent unresponsive system
        usleep(1);
        countIterations = 0;
      } 
#endif // WIN32

    } 

    tmnow = timer_GetTime();

#if defined(TEST_KILL)
//static int raiseSig=0; if(!raiseSig && haveTmstartOutput && tmnow > tmstartOutput + (4* TIME_VAL_US)) { raise(SIGINT); }
static int raiseSig=0; if(!raiseSig && haveTmstartOutput && tmnow > tmstartOutput + (19* TIME_VAL_US)) { g_proc_exit=1;if(g_proc_exit_cond){pthread_cond_broadcast(g_proc_exit_cond);} }
#endif // TEST_KILL

    if(haveTmstartOutput && durationSec > 0 && tmnow > tmstartOutput + (durationSec * TIME_VAL_US)) {
      LOG(X_DEBUG("Stream duration %.1f sec limit reached"), durationSec);
      //*pList->prunning = STREAMER_STATE_FINISHED;
      return 0;
    }

#if defined(VSX_HAVE_LICENSE)
    // Check if stream time is limited
    if(!(pList->pLic->capabilities & LIC_CAP_STREAM_TIME_UNLIMITED)) {

      if(haveTmstartOutput && tmnow > tmstartOutput + (STREAM_LIMIT_SEC * TIME_VAL_US)) {
        LOG(X_INFO("Stream time limited.  Stopping stream transmission after %d sec"), 
                 (int) (tmnow - tmstartOutput) / TIME_VAL_US);
        *pList->prunning = STREAMER_STATE_FINISHED;
        if(!(g_proc_exit_flags & PROC_EXIT_FLAG_NO_EXIT_ON_STREAM_TIME_LIMITED)) {
          g_proc_exit = 1;
        }
      }
    }
#endif // VSX_HAVE_LICENSE

/*
LOG(X_DEBUG("pList: 0x%x, pip.active:%d, overlay.havePip:%d"), pList, pList->pRtpMulti->pStreamerCfg->xcode.vid.pip.active,  pList->pRtpMulti->pStreamerCfg->xcode.vid.overlay.havePip);
if(pList->pRtpMulti->pStreamerCfg->xcode.vid.pip.active && haveTmstartOutput && tmnow > tmstartOutput + (5 * TIME_VAL_US)) {
  *pList->prunning = STREAMER_STATE_FINISHED;
  if(!(g_proc_exit_flags & PROC_EXIT_FLAG_NO_EXIT_ON_STREAM_TIME_LIMITED)) {
    g_proc_exit = 1;
  }
}
*/

#if defined(LITE_VERSION)
    if(haveTmstartOutput && tmnow > tmstartOutput + (STREAM_LIMIT_LITE_SEC * TIME_VAL_US)) {
      LOG(X_INFO("Stream time limited.  Stopping stream transmission after %d sec"),
               (int) (tmnow - tmstartOutput) / TIME_VAL_US);
      *pList->prunning = STREAMER_STATE_FINISHED;
      if(!(g_proc_exit_flags & PROC_EXIT_FLAG_NO_EXIT_ON_STREAM_TIME_LIMITED)) {
        g_proc_exit = 1;
      }
    }
#endif // (LITE_VERSION)

  }