int flvsrv_record_start(FLVSRV_CTXT_T *pFlvCtxt, STREAMER_OUTFMT_T *pLiveFmt) { int rc = 0; unsigned int numQFull = 0; if(!pFlvCtxt || !pLiveFmt) { return -1; } // // Add a livefmt cb // pFlvCtxt->pRecordOutFmt = outfmt_setCb(pLiveFmt, flvsrv_addFrame, pFlvCtxt, &pLiveFmt->qCfg, NULL, 0, 0, &numQFull); if(pFlvCtxt->pRecordOutFmt) { if(flvsrv_init(pFlvCtxt, pLiveFmt->qCfg.growMaxPktLen) < 0) { return rc; } pFlvCtxt->cbWrite = flvsrv_cbWriteDataFile; LOG(X_INFO("Starting flvlive recording[%d] %d/%d to %s"), pFlvCtxt->pRecordOutFmt->cbCtxt.idx, numQFull + 1, pLiveFmt->max, pFlvCtxt->recordFile.filename); } else { LOG(X_ERROR("No flvlive recording resource available (max:%d)"), (pLiveFmt ? pLiveFmt->max : 0)); } return rc; }
int flvsrv_cbWriteDataFile(void *pArg, const unsigned char *pData, unsigned int len) { int rc = 0; FLVSRV_CTXT_T *pFlvCtxt = (FLVSRV_CTXT_T *) pArg; //fprintf(stderr, "CB FLV RECORD len:%d\n", len); if(pFlvCtxt->recordFile.fp == FILEOPS_INVALID_FP) { if(capture_openOutputFile(&pFlvCtxt->recordFile, pFlvCtxt->overwriteFile, NULL) < 0) { // Do not call outfmt_removeCb since we're invoked from the cb thread //outfmt_removeCb(pFlvCtxt->pRecordOutFmt); pFlvCtxt->pRecordOutFmt->do_outfmt = 0; pFlvCtxt->pRecordOutFmt = NULL; return -1; } LOG(X_INFO("Created flv recording output file %s"), pFlvCtxt->recordFile.filename); } if((rc = WriteFileStream(&pFlvCtxt->recordFile, pData, len)) < 0) { LOG(X_ERROR("Failed to write flv %s %u bytes, total: %llu)"), (pFlvCtxt->writeErrDescr ? pFlvCtxt->writeErrDescr : ""), len, pFlvCtxt->totXmit); } else { pFlvCtxt->totXmit += len; } return rc; }
static void srvlisten_rtmplive_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; NETIO_SOCK_T netsocksrv; struct sockaddr_in sa; int rc = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); memset(&sa, 0, sizeof(sa)); memset(&netsocksrv, 0, sizeof(netsocksrv)); sa.sin_family = PF_INET; sa.sin_addr = pListenCfg->sain.sin_addr; sa.sin_port = pListenCfg->sain.sin_port; netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_INFO("rtmp %sserver available at rtmp://%s:%d max:%d"), ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL) " : ""), net_inet_ntoa(sa.sin_addr, buf), ntohs(sa.sin_port), pListenCfg->max); // // Service any client connections on the live listening port // rc = srvlisten_loop(pListenCfg, srv_rtmp_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_WARNING("rtmp listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return; }
T operator()(RawArray<const T,2> x) const { // Temporary arrays and views GEODE_ASSERT(x.sizes()==vec(n+3,d)); // Collect quadrature points Array<T,2> tq(n,quads,uninit); Array<T,3> xq(n,quads,d,uninit); Array<T,3> vq(n,quads,d,uninit); for (int i=0;i<n;i++) { T_INFO(i) for (int q=0;q<quads;q++) { const T s = samples[q]; tq(i,q) = t1+dt*s; SPLINE_INFO(s) for (int a=0;a<d;a++) { X_INFO(i,a) xq(i,q,a) = a0*x0+a1*x1+a2*x2+a3*x3; vq(i,q,a) = b0*x0+b1*x1+b2*x2+b3*x3; } } } // Compute energy const auto Uq_ = U(tq.reshape_own(n*quads),NdArray<const T>(qshape,xq.flat),NdArray<const T>(qshape,vq.flat)); GEODE_ASSERT(Uq_.size()==n*quads); const auto Uq = Uq_.reshape(n,quads); // Accumulate T sum = 0; for (int i=0;i<n;i++) { const T dt = t[i+2]-t[i+1]; for (int q=0;q<quads;q++) sum += weights[q]*dt*Uq(i,q); } return sum; }
int mp4_extractRaw(const MP4_CONTAINER_T *pMp4, const char *outPrfx, float fStart, float fDuration, int overwrite, int extractVid, int extractAud) { BOX_HDLR_T *pBoxHdlr; BOX_T *pBoxTrak; BOX_T *pBox; MP4_TRAK_T mp4Trak; char *outPath = NULL; size_t szPath; FILE_HANDLE fp; int rc = 0; if(!pMp4|| !pMp4->pStream || !pMp4->pStream->cbCheckFd(pMp4->pStream) || !outPrfx) { return -1; } else if(!extractVid && !extractAud) { return -1; } if(!(pBoxTrak = mp4_findBoxInTree(pMp4->proot, *((uint32_t *) "moov"))) || !(pBoxTrak = pBoxTrak->child)) { LOG(X_ERROR("No tracks found in mp4")); return -1; } while(pBoxTrak) { if(pBoxTrak->type != *((uint32_t *) "trak") || !(pBoxHdlr = (BOX_HDLR_T *) mp4_findBoxInTree(pBoxTrak, *((uint32_t *) "hdlr")))) { pBoxTrak = pBoxTrak->pnext; continue; } memset(&mp4Trak, 0, sizeof(MP4_TRAK_T)); mp4Trak.pTrak = pBoxTrak; pBox = fillTrack(&mp4Trak, 0); if(!pBox) { pBoxTrak = pBoxTrak->pnext; continue; } szPath = strlen(outPrfx); outPath = (char *) avc_calloc(1, szPath + 8); memcpy(outPath, outPrfx, szPath); rc = 0; if(pBoxHdlr->handlertype == *((uint32_t *) "soun") || pBoxHdlr->handlertype == *((uint32_t *) "sdsm")) { if(extractAud) { if(mp4_findBoxInTree(pBoxTrak, *((uint32_t *) "mp4a"))) { strncpy(&outPath[szPath], ".aac", 7); } else { LOG(X_WARNING("Unknown audio track %c%c%c%c written as raw output"), ((unsigned char *)&pBox->type)[0], ((unsigned char *)&pBox->type)[1], ((unsigned char *)&pBox->type)[2], ((unsigned char *)&pBox->type)[3]); strncpy(&outPath[szPath], ".araw", 7); } } else { pBox = NULL; } } else if(pBoxHdlr->handlertype == *((uint32_t *) "vide")) { if(extractVid) { if(mp4_findBoxInTree(pBoxTrak, *((uint32_t *) "avc1"))) { strncpy(&outPath[szPath], ".h264", 7); } else if(mp4_findBoxInTree(pBoxTrak, *((uint32_t *) "mp4v"))) { strncpy(&outPath[szPath], ".mpg4", 7); } else { LOG(X_WARNING("Unknown video track %c%c%c%c written as raw output"), ((unsigned char *)&pBox->type)[0], ((unsigned char *)&pBox->type)[1], ((unsigned char *)&pBox->type)[2], ((unsigned char *)&pBox->type)[3]); strncpy(&outPath[szPath], ".vraw", 7); } } else { pBox = NULL; } } else { pBox = NULL; } if(pBox) { if(!overwrite && (fp = fileops_Open(outPath, O_RDONLY)) != FILEOPS_INVALID_FP) { fileops_Close(fp); LOG(X_ERROR("File %s already exists. Will not overwrite."), outPath); free(outPath); pBoxTrak = pBoxTrak->pnext; continue; } if(pBox->type == *((uint32_t *) "avc1")) { rc = mp4_extractAvcVid(pMp4, outPath, fStart, fDuration); } else if(pBox->type == *((uint32_t *) "mp4v")) { rc = mp4_extractMp4Vid(pMp4, outPath, fStart, fDuration); } else if(pBox->type == *((uint32_t *) "mp4a")) { rc = mp4_extractAacAud(pMp4, outPath, fStart, fDuration); } else { rc = extractGenericTrak(pMp4, &mp4Trak, outPath, fStart, fDuration); } if(rc == 0) { LOG(X_INFO("Created %s"), outPath); } free(outPath); } pBoxTrak = pBoxTrak->pnext; } return rc; }
int stream_udp(STREAM_XMIT_NODE_T *pList, double durationSec) { STREAM_XMIT_NODE_T *pStream; COLLECT_STREAM_PKTDATA_T collectPkt; int triedXmit; unsigned int idxDest; TIME_VAL tmstart, tm1, tmnow; TIME_VAL tmprevbwdescr; int rc; int sz; int szPkt; unsigned int szData; const unsigned char *pData; unsigned int szDataPayload; const unsigned char *pDataPayload; uint64_t totBytes = 0; unsigned int totPkts = 0; unsigned int bytes = 0; unsigned int pkts = 0; unsigned int bytes2 = 0; unsigned int pkts2 = 0; //char dstStr[64]; #ifndef WIN32 unsigned int countIterations = 0; #endif // WIN32 if(!pList #if defined(VSX_HAVE_LICENSE) || !pList->pLic #endif // VSX_HAVE_LICENSE ) { return -1; } //snprintf(dstStr, sizeof(dstStr), "%s:%d", inet_ntoa(pList->pRtpMulti->pdests[0].saDsts.sin_addr), // ntohs(pList->pRtpMulti->pdests[0].saDsts.sin_port)); tmstart = tmnow = timer_GetTime(); tm1 = tmstart; tmprevbwdescr = tmstart; while(*pList->prunning == STREAMER_STATE_RUNNING && !g_proc_exit) { pStream = pList; triedXmit = 0; while(pStream) { if((rc = pStream->cbCanSend(pStream->pCbData)) > 0) { pData = stream_rtp_data(pStream->pRtpMulti); szData = stream_rtp_datalen(pStream->pRtpMulti); if(szData >= RTP_HEADER_LEN) { pDataPayload = pData + RTP_HEADER_LEN; szDataPayload = szData - RTP_HEADER_LEN; } else { pDataPayload = NULL; szDataPayload = 0; } if(pStream->pXmitAction->do_stream) { triedXmit = 1; totPkts++; pkts++; pkts2++; if(pStream->pXmitAction->do_output) { szPkt = 0; for(idxDest = 0; idxDest < pStream->pRtpMulti->numDests; idxDest++) { if(pStream->pXmitDestRc[idxDest] != 0) { continue; } if(pStream->rawSend) { if(pktgen_Queue(pData, szData) != 0) { pStream->pXmitDestRc[idxDest] = -1; sz = -1; } else { sz = szData; } } else { // // Check and send an rtcp sender report // if(*pStream->pfrtcp_sr_intervalsec > 0 && (tmnow - pStream->pRtpMulti->pdests[idxDest].tmLastRtcpSr) / TIME_VAL_MS > *pStream->pfrtcp_sr_intervalsec * 1000) { sendRtcpSr(pStream, idxDest); pStream->pRtpMulti->pdests[idxDest].tmLastRtcpSr = tmnow; } if((sz = sendPktUdpRtp(pStream, idxDest, pData, szData)) < 0) { pStream->pXmitDestRc[idxDest] = sz; } } if(szPkt == 0 && sz > 0) { szPkt = sz; } } // end of for // Exit if there are no good transmitters in the list if(pStream->pXmitAction->do_output && szPkt == 0) { return -1; } } else { // if do_output szPkt = szData; } if(!pStream->pXmitAction->do_output_rtphdr && szPkt > RTP_HEADER_LEN) { szPkt -= RTP_HEADER_LEN; } totBytes += szPkt; bytes += szPkt; // // Add the packet data to any outbound avclive subscribers // // TODO: do not hardcode szData > RTP_HEADER_LEN rtp hdr len if(pStream->pLiveQ && pStream->pLiveQ->numActive > 0 && szDataPayload > 0) { pthread_mutex_lock(&pStream->pLiveQ->mtx); for(sz = 0; (unsigned int) sz < pStream->pLiveQ->max; sz++) { if(pStream->pLiveQ->pQs[sz]) { pktqueue_addpkt(pStream->pLiveQ->pQs[sz], pDataPayload, szDataPayload, NULL, 0); } } pthread_mutex_unlock(&pStream->pLiveQ->mtx); } bytes2 += szPkt; } else { // preserve rtp sequence number during 'live pause' //pStream->pRtp->m_pRtp->sequence_num = // htons(htons(pStream->pRtp->m_pRtp->sequence_num) - 1); //During 'live pause', update the last seq # //if(pStream->pXmitAction->prior_do_stream && pStream->prtp_sequence_at_end) { // *pStream->prtp_sequence_at_end = pStream->pRtp->m_pRtp->sequence_num; //} //fprintf(stderr, "not streaming\n"); } // // Record output stream // if(pStream->pXmitAction->do_record_post && pStream->pXmitCbs->cbRecord && pStream->pXmitCbs->pCbRecordData) { memset(&collectPkt, 0, sizeof(collectPkt)); collectPkt.payload.pData = (unsigned char *) pDataPayload; PKTCAPLEN(collectPkt.payload) = szDataPayload; if((sz = pStream->pXmitCbs->cbRecord(pStream->pXmitCbs->pCbRecordData, &collectPkt)) < 0) { return -1; } if(triedXmit == 0) { triedXmit = 1; } } // // Call post processing function, such as http live streaming // callback to segment and package output ts files // if(pStream->pXmitAction->do_httplive && pStream->pXmitCbs->cbPostProc && pStream->pXmitCbs->pCbPostProcData && pStream->pXmitAction->do_stream) { if((sz = pStream->pXmitCbs->cbPostProc(pStream->pXmitCbs->pCbPostProcData, pDataPayload, szDataPayload)) < 0) { return -1; } if(triedXmit == 0) { triedXmit = 1; } } //if(pStream->pXmitAction->do_stream != pStream->pXmitAction->prior_do_stream) { // pStream->pXmitAction->prior_do_stream = pStream->pXmitAction->do_stream; //} pStream->pRtpMulti->payloadLen = 0; if((rc = pStream->cbPreparePkt(pStream->pCbData)) < 0) { return -1; } //fprintf(stderr, "streamer prepare pkt returned %d\n", rc); } else if(rc < 0) { LOG(X_DEBUG("Stream ending, sent: %"LL64"u bytes %u pkts"), totBytes, totPkts); return -1; } else { //fprintf(stderr, "streamer cansend rc:%d\n", rc); } pStream = pStream->pNext; } // while(pStream) pktgen_SendQueued(); 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); //pthread_cond_wait(pList->pCond, pList->pMtxCond); } else { Sleep(1); } } else { // On windows Sleep 0 relinquishes execution for any waiting threads Sleep(0); #else // WIN32 VSX_DEBUG2(tmnow = timer_GetTime()) usleep(1000); countIterations = 0; VSX_DEBUGLOG3("stream_udp slept for %lld ns\n", timer_GetTime() - tmnow); } else { if(countIterations++ > 10000) { // During continuous xmit, sleep to prevent unresponsive system usleep(1); countIterations = 0; } #endif // WIN32 } tmnow = timer_GetTime(); if(pList->pBwDescr && (tmnow / TIME_VAL_US) > (tmprevbwdescr / TIME_VAL_US) + 1) { pList->pBwDescr->intervalMs = (float)(tmnow - tmprevbwdescr)/ TIME_VAL_MS; pList->pBwDescr->pkts = pkts2; pList->pBwDescr->bytes = bytes2; TV_FROM_TIMEVAL(pList->pBwDescr->updateTv, tmnow); //pList->pBwDescr->updateTv.tv_sec = tmnow / TIME_VAL_US; //pList->pBwDescr->updateTv.tv_usec = tmnow % TIME_VAL_US; bytes2 = 0; pkts2 = 0; tmprevbwdescr = tmnow; } if(durationSec > 0 && tmnow > tmstart + (durationSec * TIME_VAL_US)) { LOG(X_DEBUG("Stream duration %.1f sec limit reached"), durationSec); *pList->prunning = STREAMER_STATE_FINISHED; } #if defined (VSX_HAVE_LICENSE) // Check if stream time is limited if(!(pList->pLic->capabilities & LIC_CAP_STREAM_TIME_UNLIMITED)) { if(tmnow > tmstart + (STREAM_LIMIT_SEC * TIME_VAL_US)) { LOG(X_INFO("Stream time limited. Stopping stream transmission after %d sec"), (int) (tmnow - tmstart) / 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 #if defined(LITE_VERSION) if(tmnow > tmstart + (STREAM_LIMIT_LITE_SEC * TIME_VAL_US)) { LOG(X_INFO("Stream time limited. Stopping stream transmission after %d sec"), (int) (tmnow - tmstart) / 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) /* if(0 && pList->verbosity > 1 && tv2.tv_sec > tv1.tv_sec+3) { elapsedMs0 = ((tv2.tv_sec - tv0.tv_sec) * 1000) + ((tv2.tv_usec - tv0.tv_usec) /1000); elapsedMs1 = ((tv2.tv_sec - tv1.tv_sec) * 1000) + ((tv2.tv_usec - tv1.tv_usec) /1000); fprintf(stdout, "%u", elapsedMs0/1000); if(durationSec != 0) { fprintf(stdout, "/%.1f", durationSec); } fprintf(stdout, " sec, %s %.1fKb/s %.1fpkts/s (total: %u pkts, %.1fKB, %.1fKb/s)", dstStr, (double)(bytes / 128.0f / ((double)elapsedMs1/1000.0f)), (double)(pkts/ ((double)elapsedMs1/1000.0f)), totPkts, (double)totBytes/1024.0f, (double)(totBytes / 128.0f / ((double)elapsedMs0/1000.0f))); fprintf(stdout, "\n"); bytes = 0; pkts = 0; tv1.tv_sec = tv2.tv_sec; tv1.tv_usec = tv2.tv_usec; } */ }
static void srvlisten_media_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; NETIO_SOCK_T netsocksrv; struct sockaddr_storage sa; CLIENT_CONN_T *pConnTmp; char tmp[128]; char bufses[32]; const int backlog = NET_BACKLOG_DEFAULT; unsigned int tsMax = 0; unsigned int flvMax = 0; unsigned int mkvMax = 0; unsigned int rtmpMax = 0; unsigned int rtspMax = 0; int haveAuth = 0; int haveRtmpAuth = 0; int haveRtspAuth = 0; int haveToken = 0; int rc = 0; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); if((pListenCfg->urlCapabilities & (URL_CAP_TSLIVE | URL_CAP_TSHTTPLIVE | URL_CAP_FLVLIVE | URL_CAP_MKVLIVE | URL_CAP_LIVE | URL_CAP_STATUS | URL_CAP_MOOFLIVE | URL_CAP_PIP | URL_CAP_CONFIG | URL_CAP_BROADCAST | URL_CAP_RTMPLIVE | URL_CAP_RTMPTLIVE | URL_CAP_RTSPLIVE)) == 0) { LOG(X_WARNING("Server listener exiting because no capabilities enabled on %s:%d"), FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa))); logutil_tid_remove(pthread_self()); return; } else if(!(pConnTmp = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements)) { return; } memset(&netsocksrv, 0, sizeof(netsocksrv)); memcpy(&sa, &pListenCfg->sa, sizeof(pListenCfg->sa)); netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen((const struct sockaddr *) &sa, backlog)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); if(pListenCfg->pAuthStore && IS_AUTH_CREDENTIALS_SET(pListenCfg->pAuthStore)) { haveAuth = 1; } if(pListenCfg->pAuthTokenId && pListenCfg->pAuthTokenId[0] != '\0') { haveToken = 1; } tsMax = pConnTmp->pStreamerCfg0->liveQs[0].max; flvMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_FLV].max; mkvMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_MKV].max; rtmpMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].max; rtspMax = pConnTmp->pStreamerCfg0->pRtspSessions->max; if(HAVE_URL_CAP_RTMP(pListenCfg->urlCapabilities)) { if(IS_AUTH_CREDENTIALS_SET(&pConnTmp->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTMP].stores[pListenCfg->idxCfg])) { // // RTMP server streaming credentials not implemented // //haveRtmpAuth = 1; } LOG(X_INFO("rtmp %s%s available at "URL_RTMP_FMT_STR"%s max:%d"), ((pListenCfg->netflags & NETIO_FLAG_PLAINTEXT) && (pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ) ? "(SSL) " : ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL only) " : ""), ((pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE) && !(pListenCfg->urlCapabilities & URL_CAP_RTMPLIVE) ? "(tunneled only) " : ((pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE) ? "(tunneled) " : "")), URL_PROTO_FMT2_ARGS( (pListenCfg->netflags & NETIO_FLAG_SSL_TLS), FORMAT_NETADDR(sa, tmp, sizeof(tmp))), ntohs(INET_PORT(sa)), (haveRtmpAuth ? " (Using auth)" : ""), rtmpMax); } if(pListenCfg->urlCapabilities & URL_CAP_RTSPLIVE) { if(IS_AUTH_CREDENTIALS_SET(&pConnTmp->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTSP].stores[pListenCfg->idxCfg])) { haveRtspAuth = 1; } if(pListenCfg->pCfg->prtspsessiontimeout && *pListenCfg->pCfg->prtspsessiontimeout != 0) { snprintf(bufses, sizeof(bufses), ", timeout:%u sec", *pListenCfg->pCfg->prtspsessiontimeout); } else { bufses[0] = '\0'; } LOG(X_INFO("rtsp %s available at "URL_RTSP_FMT_STR"%s max:%d%s"), ((pListenCfg->netflags & NETIO_FLAG_PLAINTEXT) && (pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ) ? "(SSL) " : ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL only) " : ""), URL_PROTO_FMT2_ARGS( (pListenCfg->netflags & NETIO_FLAG_SSL_TLS), FORMAT_NETADDR(sa, tmp, sizeof(tmp))), ntohs(INET_PORT(sa)), (haveRtspAuth ? " (Using auth)" : ""), rtspMax, bufses); } if((pListenCfg->urlCapabilities & URL_CAP_ROOTHTML)) { LOG(X_INFO("broadcast interface available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_ROOT_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_LIVE)) { LOG(X_INFO("live available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_LIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_TSLIVE)) { LOG(X_INFO("tslive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_TSLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), tsMax); } if((pListenCfg->urlCapabilities & URL_CAP_TSHTTPLIVE)) { LOG(X_INFO("httplive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_HTTPLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_FLVLIVE)) { LOG(X_INFO("flvlive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_FLVLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), flvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MKVLIVE)) { LOG(X_INFO("mkvlive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_MKVLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), mkvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MOOFLIVE)) { LOG(X_INFO("dash available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_DASH_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_STATUS)) { LOG(X_INFO("status available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_STATUS_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_PIP)) { LOG(X_INFO("pip available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_PIP_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_CONFIG)) { LOG(X_INFO("config available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_CONFIG_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } //fprintf(stderr, "LISTENER THREAD %s %s:%d active:%d cap: 0x%x\n", pListenCfg->netflags & NETIO_FLAG_SSL_TLS ? "SSL" : "", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), pListenCfg->active, pListenCfg->urlCapabilities); // // Service any client connections on the live listening port // rc = srvlisten_loop(pListenCfg, srv_cmd_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_WARNING("HTTP listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return; }
int srv_rtmp_proc(CLIENT_CONN_T *pConn, const unsigned char *prebuf, unsigned int prebufsz, int istunneled) { int rc = 0; STREAMER_CFG_T *pStreamerCfg = NULL; STREAMER_OUTFMT_T *pLiveFmt = NULL; STREAM_STATS_T *pstats = NULL; RTMP_CTXT_T rtmpCtxt; unsigned int numQFull = 0; char tmps[2][128]; OUTFMT_CFG_T *pOutFmt = NULL; if(!pConn) { return -1; } if(!HAVE_URL_CAP_RTMP(pConn->pListenCfg->urlCapabilities)) { LOG(X_ERROR("Listener %s:%d not enabled for rtmp%s%s stream to %s:%d"), FORMAT_NETADDR(pConn->pListenCfg->sa, tmps[1], sizeof(tmps[1])), ntohs(INET_PORT(pConn->pListenCfg->sa)), istunneled > 0 ? "t" : "", (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); return -1; } pStreamerCfg = GET_STREAMER_FROM_CONN(pConn); if(pStreamerCfg && pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].do_outfmt) { pLiveFmt = &pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP]; if(pStreamerCfg->pMonitor && pStreamerCfg->pMonitor->active) { if(!(pstats = stream_monitor_createattach(pStreamerCfg->pMonitor, (const struct sockaddr *) &pConn->sd.sa, STREAM_METHOD_RTMP, STREAM_MONITOR_ABR_NONE))) { } } // // Add a livefmt cb // pOutFmt = outfmt_setCb(pLiveFmt, rtmp_addFrame, &rtmpCtxt, &pLiveFmt->qCfg, pstats, 1, pStreamerCfg->frameThin, &numQFull); } if(pOutFmt) { memset(&rtmpCtxt, 0, sizeof(rtmpCtxt)); rtmp_init(&rtmpCtxt, MAX(pLiveFmt->qCfg.maxPktLen, pLiveFmt->qCfg.growMaxPktLen)); rtmpCtxt.pSd = &pConn->sd; rtmpCtxt.novid = pStreamerCfg->novid; rtmpCtxt.noaud = pStreamerCfg->noaud; rtmpCtxt.av.vid.pStreamerCfg = pStreamerCfg; rtmpCtxt.av.aud.pStreamerCfg = pStreamerCfg; rtmpCtxt.pAuthTokenId = pConn->pListenCfg->pAuthTokenId; if(pstats) { rtmpCtxt.pStreamMethod = &pstats->method; } rtmpCtxt.pOutFmt = pOutFmt; rtmpCtxt.prebufdata = (unsigned char *) prebuf; rtmpCtxt.prebufsz = prebufsz; if(!(pConn->pListenCfg->urlCapabilities & URL_CAP_RTMPLIVE)) { rtmpCtxt.donotunnel = 1; } if((pConn->pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE)) { rtmpCtxt.dohttptunnel = 1; } // // Unpause the outfmt callback mechanism now that rtmp_init was called // outfmt_pause(pOutFmt, 0); LOG(X_INFO("Starting rtmp%s%s stream[%d] %d/%d to %s:%d"), istunneled > 0 ? "t" : "", (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", pOutFmt->cbCtxt.idx, numQFull + 1, pLiveFmt->max, FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); rtmp_handle_conn(&rtmpCtxt); LOG(X_INFO("Ending rtmp%s%s stream[%d] to %s:%d"), istunneled > 0 ? "t" : "", (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", pOutFmt->cbCtxt.idx, FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); // // Remove the livefmt cb // outfmt_removeCb(pOutFmt); rtmp_close(&rtmpCtxt); } else { if(pstats) { // // Destroy automatically detaches the stats from the monitor linked list // stream_stats_destroy(&pstats, NULL); } LOG(X_WARNING("No rtmp resource available (max:%d) for %s:%d"), (pLiveFmt ? pLiveFmt->max : 0), FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); rc = -1; } netio_closesocket(&pConn->sd.netsocket); LOG(X_DEBUG("RTMP connection thread ended %s:%d"), FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); return rc; }
static void srvlisten_rtsplive_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; CLIENT_CONN_T *pConn = NULL; NETIO_SOCK_T netsocksrv; struct sockaddr_in sa; int haveRtspAuth = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; char bufses[32]; int rc = 0; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); memset(&sa, 0, sizeof(sa)); memset(&netsocksrv, 0, sizeof(netsocksrv)); sa.sin_family = PF_INET; sa.sin_addr = pListenCfg->sain.sin_addr; sa.sin_port = pListenCfg->sain.sin_port; netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pConn = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements; if(pConn) { if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTSP].stores[pListenCfg->idxCfg])) { haveRtspAuth = 1; } } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); if(pListenCfg->pCfg->prtspsessiontimeout && *pListenCfg->pCfg->prtspsessiontimeout != 0) { snprintf(bufses, sizeof(bufses), ", timeout:%u sec", *pListenCfg->pCfg->prtspsessiontimeout); } else { bufses[0] = '\0'; } LOG(X_INFO("rtsp %sserver available at "URL_RTSP_FMT_STR"%s max:%d%s"), ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL) " : ""), URL_RTSP_FMT2_ARGS( (pListenCfg->netflags & NETIO_FLAG_SSL_TLS), net_inet_ntoa(sa.sin_addr, buf)), ntohs(sa.sin_port), (haveRtspAuth ? " (Using auth)" : ""), pListenCfg->max, bufses); // // Service any client connections on the rtsp listening port // rc = srvlisten_loop(pListenCfg, srv_rtsp_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_DEBUG("rtsp listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return ; }
static void srvlisten_http_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; NETIO_SOCK_T netsocksrv; struct sockaddr_in sa; CLIENT_CONN_T *pConn; unsigned int tsMax = 0; unsigned int flvMax = 0; unsigned int mkvMax = 0; /* int haveMkvAuth = 0; int haveFlvAuth = 0; int haveTsliveAuth = 0; int haveHttpliveAuth = 0; int haveMoofAuth = 0; int haveConfigAuth = 0; int havePipAuth = 0; int haveStatusAuth = 0; int haveRootAuth = 0; */ int haveAuth = 0; int rc = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); if((pListenCfg->urlCapabilities & (URL_CAP_TSLIVE | URL_CAP_TSHTTPLIVE | URL_CAP_FLVLIVE | URL_CAP_MKVLIVE | URL_CAP_LIVE | URL_CAP_STATUS | URL_CAP_MOOFLIVE | URL_CAP_PIP | URL_CAP_CONFIG | URL_CAP_BROADCAST)) == 0) { LOG(X_WARNING("http listener exiting because no capabilities enabled on %s:%d"), inet_ntoa(pListenCfg->sain.sin_addr), ntohs(pListenCfg->sain.sin_port)); logutil_tid_remove(pthread_self()); return; } memset(&sa, 0, sizeof(sa)); memset(&netsocksrv, 0, sizeof(netsocksrv)); sa.sin_family = PF_INET; sa.sin_addr = pListenCfg->sain.sin_addr; sa.sin_port = pListenCfg->sain.sin_port; netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); if(pListenCfg->pAuthStore && IS_AUTH_CREDENTIALS_SET(pListenCfg->pAuthStore)) { haveAuth = 1; } pConn = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements; if(pConn) { tsMax = pConn->pStreamerCfg0->liveQs[0].max; flvMax = pConn->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_FLV].max; mkvMax = pConn->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_MKV].max; /* if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_FLV].stores[pListenCfg->idxCfg])) { haveFlvAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_MKV].stores[pListenCfg->idxCfg])) { haveMkvAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_TSLIVE].stores[pListenCfg->idxCfg])) { haveTsliveAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_HTTPLIVE].stores[pListenCfg->idxCfg])) { haveHttpliveAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_MOOFLIVE].stores[pListenCfg->idxCfg])) { haveMoofAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_CONFIG].stores[pListenCfg->idxCfg])) { haveConfigAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_PIP].stores[pListenCfg->idxCfg])) { havePipAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_STATUS].stores[pListenCfg->idxCfg])) { haveStatusAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_ROOT].stores[pListenCfg->idxCfg])) { haveRootAuth = 1; } */ //if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds.auths[STREAMER_AUTH_IDX_ROOT])) { // LOG(X_DEBUG("LIVE/ROOT AUTH ON")); //} } if((pListenCfg->urlCapabilities & URL_CAP_ROOTHTML)) { LOG(X_INFO("broadcast interface available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_ROOT_URL, //(haveRootAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_LIVE)) { LOG(X_INFO("live available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_LIVE_URL, //(haveRootAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_TSLIVE)) { LOG(X_INFO("tslive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_TSLIVE_URL, //(haveTsliveAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), tsMax); } if((pListenCfg->urlCapabilities & URL_CAP_TSHTTPLIVE)) { LOG(X_INFO("httplive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_HTTPLIVE_URL, //(haveHttpliveAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_FLVLIVE)) { LOG(X_INFO("flvlive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_FLVLIVE_URL, //(haveFlvAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), flvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MKVLIVE)) { LOG(X_INFO("mkvlive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_MKVLIVE_URL, //(haveMkvAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), mkvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MOOFLIVE)) { LOG(X_INFO("dash available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_DASH_URL, // (haveMoofAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_STATUS)) { LOG(X_INFO("status available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_STATUS_URL, //(haveStatusAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_PIP)) { LOG(X_INFO("pip available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_PIP_URL, //(havePipAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_CONFIG)) { LOG(X_INFO("config available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_CONFIG_URL, //(haveConfigAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } //fprintf(stderr, "LISTENER THREAD %s %s:%d active:%d cap: 0x%x\n", pListenCfg->netflags & NETIO_FLAG_SSL_TLS ? "SSL" : "", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), pListenCfg->active, pListenCfg->urlCapabilities); // // Service any client connections on the live listening port // rc = srvlisten_loop(pListenCfg, srv_cmd_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_WARNING("HTTP listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return; }
static void srv_rtmp_proc(void *pfuncarg) { CLIENT_CONN_T *pConn = (CLIENT_CONN_T *) pfuncarg; STREAMER_CFG_T *pStreamerCfg = NULL; STREAMER_OUTFMT_T *pLiveFmt = NULL; STREAM_STATS_T *pstats = NULL; RTMP_CTXT_T rtmpCtxt; unsigned int numQFull = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; OUTFMT_CFG_T *pOutFmt = NULL; pStreamerCfg = GET_STREAMER_FROM_CONN(pConn); if(pStreamerCfg && pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].do_outfmt) { pLiveFmt = &pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP]; if(pStreamerCfg->pMonitor && pStreamerCfg->pMonitor->active) { if(!(pstats = stream_monitor_createattach(pStreamerCfg->pMonitor, &pConn->sd.sain, STREAM_METHOD_RTMP, STREAM_MONITOR_ABR_NONE))) { } } // // Add a livefmt cb // pOutFmt = outfmt_setCb(pLiveFmt, rtmp_addFrame, &rtmpCtxt, &pLiveFmt->qCfg, pstats, 1, pStreamerCfg->frameThin, &numQFull); } if(pOutFmt) { memset(&rtmpCtxt, 0, sizeof(rtmpCtxt)); rtmp_init(&rtmpCtxt, MAX(pLiveFmt->qCfg.maxPktLen, pLiveFmt->qCfg.growMaxPktLen)); rtmpCtxt.pSd = &pConn->sd; rtmpCtxt.novid = pStreamerCfg->novid; rtmpCtxt.noaud = pStreamerCfg->noaud; rtmpCtxt.av.vid.pStreamerCfg = pStreamerCfg; rtmpCtxt.av.aud.pStreamerCfg = pStreamerCfg; // // Unpause the outfmt callback mechanism now that rtmp_init was called // outfmt_pause(pOutFmt, 0); LOG(X_INFO("Starting rtmp stream[%d] %d/%d to %s:%d"), pOutFmt->cbCtxt.idx, numQFull + 1, pLiveFmt->max, net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); rtmp_handle_conn(&rtmpCtxt); LOG(X_INFO("Ending rtmp stream[%d] to %s:%d"), pOutFmt->cbCtxt.idx, net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); // // Remove the livefmt cb // outfmt_removeCb(pOutFmt); rtmp_close(&rtmpCtxt); } else { if(pstats) { // // Destroy automatically detaches the stats from the monitor linked list // stream_stats_destroy(&pstats, NULL); } LOG(X_WARNING("No rtmp resource available (max:%d) for %s:%d"), (pLiveFmt ? pLiveFmt->max : 0), net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); } netio_closesocket(&pConn->sd.netsocket); LOG(X_DEBUG("RTMP connection thread ended %s:%d"), net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); }
static int xcode_ipc_dispatch(XCODE_IPC_DESCR_T *pXcodeIpc) { int errcnt = 0; IXCODE_OUTBUF_T outbuf; #ifdef WIN32 int rc; #endif // WIN32 while(errcnt < SEM_MAX_ERRORS) { #if defined(WIN32) if((rc = WaitForSingleObject(pXcodeIpc->hSemSrv, INFINITE)) == WAIT_FAILED) { LOG(X_ERROR("WaitForSingleObject failed (error: %d)"), GetLastError()); #else // WIN32 if(sem_wait(pXcodeIpc->sem_srv) != 0) { LOG(X_ERROR("sem_wait failed with error: %d"), errno); #endif // WIN32 errcnt++; continue; } else if(errcnt > 0) { errcnt = 0; } //fprintf(stderr, "ipc exec cmd: %d ...\n", pXcodeIpc->pmem->hdr.cmd); switch(pXcodeIpc->pmem->hdr.cmd) { case XCODE_IPC_CMD_INIT_VID: pXcodeIpc->pmem->hdr.cmdrc = ixcode_init_vid(&pXcodeIpc->pmem->hdr.ctxt.vid); break; case XCODE_IPC_CMD_INIT_AUD: pXcodeIpc->pmem->hdr.cmdrc = ixcode_init_aud(&pXcodeIpc->pmem->hdr.ctxt.aud); break; case XCODE_IPC_CMD_CLOSE_VID: ixcode_close_vid(&pXcodeIpc->pmem->hdr.ctxt.vid); pXcodeIpc->pmem->hdr.cmdrc = 0; break; case XCODE_IPC_CMD_CLOSE_AUD: ixcode_close_aud(&pXcodeIpc->pmem->hdr.ctxt.aud); pXcodeIpc->pmem->hdr.cmdrc = 0; break; case XCODE_IPC_CMD_ENCODE_VID: memset(&outbuf, 0, sizeof(outbuf)); outbuf.buf = XCODE_IPC_MEM_DATA(pXcodeIpc->pmem); outbuf.lenbuf = XCODE_IPC_MEM_DATASZ(pXcodeIpc->pmem); pXcodeIpc->pmem->hdr.cmdrc = ixcode_frame_vid(&pXcodeIpc->pmem->hdr.ctxt.vid, XCODE_IPC_MEM_DATA(pXcodeIpc->pmem), (unsigned int) pXcodeIpc->pmem->hdr.cmdrc, &outbuf); break; case XCODE_IPC_CMD_ENCODE_AUD: if(pXcodeIpc->pmem->hdr.offsetOut > XCODE_IPC_MEM_DATASZ(pXcodeIpc->pmem)) { pXcodeIpc->pmem->hdr.cmdrc = IXCODE_RC_ERROR; } else { pXcodeIpc->pmem->hdr.cmdrc = ixcode_frame_aud(&pXcodeIpc->pmem->hdr.ctxt.aud, XCODE_IPC_MEM_DATA(pXcodeIpc->pmem), (unsigned int) pXcodeIpc->pmem->hdr.cmdrc, XCODE_IPC_MEM_DATA(pXcodeIpc->pmem) + pXcodeIpc->pmem->hdr.offsetOut, XCODE_IPC_MEM_DATASZ(pXcodeIpc->pmem) - pXcodeIpc->pmem->hdr.offsetOut); } break; default: LOG(X_ERROR("Invalid ipc command: %d"), pXcodeIpc->pmem->hdr.cmd); pXcodeIpc->pmem->hdr.cmdrc = IXCODE_RC_ERROR; } if(pXcodeIpc->pmem->hdr.cmdrc < IXCODE_RC_OK) { LOG(X_ERROR("ipc exec cmd: %d rc: %d"), pXcodeIpc->pmem->hdr.cmd, pXcodeIpc->pmem->hdr.cmdrc); } pXcodeIpc->pmem->hdr.cmd = XCODE_IPC_CMD_NONE; #if defined(WIN32) if(ReleaseSemaphore(pXcodeIpc->hSemCli, 1, NULL) == 0) { LOG(X_ERROR("sem_post failed with error: %d"), GetLastError()); #else if(sem_post(pXcodeIpc->sem_cli) != 0) { LOG(X_ERROR("sem_post failed with error: %d"), errno); #endif // WIN32 } } return 0; } static void usage(int argc, char *argv[]) { fprintf(stdout, "usage: %s \n", argv[0]); fprintf(stdout, "Used in conjunction with OpenVSX to transcode video\n\n"); } int main(int argc, char *argv[]) { XCODE_IPC_DESCR_T xcodeIpc; int rc; fprintf(stdout, "\n"XCODE_BANNER" "ARCH"\n\n", BUILD_INFO_NUM); if(argc > 1) { usage(argc, argv); return 0; } logger_Init(NULL, NULL, 0, 0, LOG_FLAG_USESTDERR | LOG_FLAG_FLUSHOUTPUT); logger_SetFile("log", "vsx-xcode", LOGGER_MAX_FILES, LOGGER_MAX_FILE_SZ, LOG_OUTPUT_DEFAULT | LOG_FLAG_USELOCKING); logger_SetLevel(S_DEBUG); logger_AddStderr(S_DEBUG, LOG_OUTPUT_DEFAULT_STDERR); LOG(X_INFO("vsx-xcode starting")); memset(&xcodeIpc, 0, sizeof(xcodeIpc)); g_pXcodeIpc = &xcodeIpc; xcodeIpc.sz = XCODE_IPC_MEM_SZ; #if !defined(WIN32) xcodeIpc.key = XCODE_IPC_SHMKEY; signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGKILL, sig_handler); #endif // WIN32 rc = xcode_ipc_init(&xcodeIpc); if(rc == 0) { xcode_ipc_dispatch(&xcodeIpc); } xcode_ipc_close(&xcodeIpc); return 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) }
static void stream_monitor_proc(void *pArg) { MONITOR_START_WRAP_T startWrap; STREAM_STATS_MONITOR_T *pMonitor = NULL; FILE *fp = NULL; unsigned int intervalMs; TIME_VAL tvNext, tv; memcpy(&startWrap, pArg, sizeof(startWrap)); pMonitor = startWrap.pMonitor; logutil_tid_add(pthread_self(), startWrap.tid_tag); pMonitor->runMonitor = 1; if((intervalMs = pMonitor->dumpIntervalMs) <= 0) { intervalMs = STREAM_STATS_DUMP_MS; } // // Set the output file path // if(pMonitor->statfilepath) { if(!strcasecmp(pMonitor->statfilepath, "stdout")) { fp = stdout; } else if(!strcasecmp(pMonitor->statfilepath, "stderr")) { fp = stderr; } else if(!(fp = fopen(pMonitor->statfilepath, "w"))) { LOG(X_ERROR("Failed top open stats file %s for writing"), pMonitor->statfilepath); pMonitor->runMonitor = -1; } } else { //fp = stdout; } if(pMonitor->runMonitor == 1) { tvNext = timer_GetTime() + (intervalMs * TIME_VAL_MS); LOG(X_INFO("Started %sstream output monitor %s%s"), pMonitor->pAbr ? "ABR " : "", pMonitor->statfilepath ? "to " : "", pMonitor->statfilepath ? pMonitor->statfilepath : ""); } while(pMonitor->runMonitor == 1 && !g_proc_exit) { if((tv = timer_GetTime()) >= tvNext) { stream_monitor_dump(fp, pMonitor); tvNext += (intervalMs * TIME_VAL_MS); } usleep(100000); } if(fp) { fclose(fp); } pMonitor->runMonitor = -1; pthread_mutex_destroy(&pMonitor->mtx); pMonitor->active = -1; logutil_tid_remove(pthread_self()); }