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; }
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; }
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; }
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; }
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; }
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; }
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) }