int MpTopologyGraph::addVirtualOutputs(MpResourceTopology& resourceTopology, UtlHashBag& newResources, UtlBoolean replaceNumInName, int resourceNum) { int portsAdded = 0; MpResourceTopology::VirtualPortIterator portIter; UtlString realResourceName; int realPortIdx; UtlString virtualResourceName; int virtualPortIdx; resourceTopology.initVirtualOutputIterator(portIter); while (resourceTopology.getNextVirtualOutput(portIter, realResourceName, realPortIdx, virtualResourceName, virtualPortIdx) == OS_SUCCESS) { if(replaceNumInName) { MpResourceTopology::replaceNumInName(realResourceName, resourceNum); MpResourceTopology::replaceNumInName(virtualResourceName, resourceNum); } // Lookup real resource. MpResource *pResource = (MpResource*)newResources.find(&realResourceName); assert(pResource); if (!pResource) { continue; } // Check port index correctness. Note, that this check gracefully // handles case with realPortIdx equal -1. if (realPortIdx >= pResource->maxOutputs()) { assert(!"Trying to map virtual port to non existing real port!"); continue; } // Add entry to virtual ports map. // We need to create UtlVoidPtr wrapper for pResource, or it will be // destroyed on pair deletion. UtlContainablePair *pRealPort = new UtlContainablePair(new UtlVoidPtr(pResource), new UtlInt(realPortIdx)); UtlContainablePair *pVirtPort = new UtlContainablePair(new UtlString(virtualResourceName), new UtlInt(virtualPortIdx)); mVirtualOutputs.insertKeyAndValue(pVirtPort, pRealPort); portsAdded++; } resourceTopology.freeVirtualOutputIterator(portIter); return portsAdded; }
// (static) Displays information on the console about the specified flow // graph. void MpFlowGraphBase::flowGraphInfo(MpFlowGraphBase* pFlowGraph) { int i; MpResource* pResource; if (NULL == pFlowGraph) { MpMediaTask* pMediaTask = MpMediaTask::getMediaTask(0); pFlowGraph = pMediaTask->getFocus(); if (NULL == pFlowGraph) { pMediaTask->getManagedFlowGraphs(&pFlowGraph, 1, i); if (0 == i) pFlowGraph = NULL; } } if (NULL == pFlowGraph) { printf("No flowGraph to display!\n"); return; } printf("\nFlow graph information for %p\n", pFlowGraph); printf(" State: %s\n", pFlowGraph->isStarted() ? "STARTED" : "STOPPED"); printf(" Processed Frame Count: %d\n", pFlowGraph->numFramesProcessed()); printf(" Samples Per Frame: %d\n", pFlowGraph->getSamplesPerFrame()); printf(" Samples Per Second: %d\n", pFlowGraph->getSamplesPerSec()); pResource = pFlowGraph->mpResourceInProcess; if (pResource == NULL) printf(" Resource Being Processed: NULL\n"); else printf(" Resource Being Processed: %p\n", pResource); printf("\n Resource Information\n"); printf(" Resources: %d\n", pFlowGraph->numResources()); printf(" Links: %d\n", pFlowGraph->numLinks()); for (i=0; i < pFlowGraph->mResourceCnt; i++) { pResource = pFlowGraph->mUnsorted[i]; pResource->resourceInfo(pResource, i); } }
// Makes pBuf available to resource connected to the outPortIdx output // port of this resource. // Returns TRUE if there is a resource connected to the specified output // port, FALSE otherwise. UtlBoolean MpResource::pushBufferDownsream(int outPortIdx, const MpBufPtr& pBuf) { MpResource* pDownstreamInput; int downstreamPortIdx; // Not locking mpOutConns here as we only lock for setting/accessing // reservation state (the only thing set in mpOutConns outside media task) if (outPortIdx < 0 || outPortIdx >= mMaxOutputs) // port out of range return FALSE; pDownstreamInput = mpOutConns[outPortIdx].pResource; downstreamPortIdx = mpOutConns[outPortIdx].portIndex; if (pDownstreamInput == NULL) // no connected resource return FALSE; pDownstreamInput->setInputBuffer(downstreamPortIdx, pBuf); return TRUE; }
//:Inserts "rResource" into the flow graph upstream of the //:designated "rDownstreamResource" resource. // The new resource will be inserted on the "inPortIdx" input // link of "rDownstreamResource". // If the flow graph is not "started", this call takes effect // immediately. Otherwise, the call takes effect at the start of the // next frame processing interval. // Returns OS_SUCCESS if the resource was successfully inserted. Returns // OS_INVALID_ARGUMENT if the caller specified an invalid port index. OsStatus MpFlowGraphBase::insertResourceBefore(MpResource& rResource, MpResource& rDownstreamResource, int inPortIdx) { MpResource *pUpstreamResource; int upstreamOutPortIdx; OsStatus res; // Get information about the downstream end of the link rDownstreamResource.getInputInfo(inPortIdx, pUpstreamResource, upstreamOutPortIdx); // Add the new resource to the flow graph res = addResource(rResource); if (res != OS_SUCCESS) return res; if (pUpstreamResource != NULL) { // Remove the link between the upstream and downstream resources res = removeLink(*pUpstreamResource, upstreamOutPortIdx); if (res != OS_SUCCESS) { // recover from remove link failure removeResource(rResource); return res; } // Add the link between output port 0 the new resource and the // downstream resource res = addLink(rResource, 0, rDownstreamResource, inPortIdx); if (res != OS_SUCCESS) { // recover from add link failure removeResource(rResource); addLink(*pUpstreamResource, upstreamOutPortIdx, rDownstreamResource, inPortIdx); return res; } } // Add the link between the upstream resource and input port 0 of // the new resource res = addLink(*pUpstreamResource, upstreamOutPortIdx, rResource, 0); if (res != OS_SUCCESS) { // recover from add link failure removeResource(rResource); if (pUpstreamResource != NULL) { addLink(*pUpstreamResource, upstreamOutPortIdx, rDownstreamResource, inPortIdx); } } return res; }
// Handle the FLOWGRAPH_REMOVE_LINK message. // Returns TRUE if the message was handled, otherwise FALSE. UtlBoolean MpFlowGraphBase::handleRemoveLink(MpResource* pFrom, int outPortIdx) { int connectedPort; MpResource* pConnectedResource; // make sure the resource is part of this flow graph if (pFrom->getFlowGraph() != this) { Zprintf("handleRemoveLink: pFrom->getFlowGraph() != this: 0x%p != 0x%p\n", (pFrom->getFlowGraph()), this, 0,0,0,0); assert(FALSE); return FALSE; } // get information about the downstream end of the link pFrom->getOutputInfo(outPortIdx, pConnectedResource, connectedPort); // disconnect the upstream end of the link if (pFrom->disconnectOutput(outPortIdx) == FALSE) { Zprintf("handleRemoveLink: disconnectOutput(0x%p, %d) failed\n", pFrom, outPortIdx, 0,0,0,0); assert(FALSE); // couldn't disconnect return FALSE; } // disconnect the downstream end of the link if (pConnectedResource->disconnectInput(connectedPort) == FALSE) { Zprintf("handleRemoveLink: disconnectInput(0x%p, %d) failed\n", pConnectedResource, connectedPort, 0,0,0,0); assert(FALSE); // couldn't disconnect return FALSE; } mLinkCnt--; mRecomputeOrder = TRUE; return TRUE; }
// Creates a link between the "outPortIdx" port of the "rFrom" resource // to the "inPortIdx" port of the "rTo" resource. // If the flow graph is not "started", this call takes effect immediately. // Otherwise, the call takes effect at the start of the next frame processing // interval. // Returns OS_SUCCESS if the link was successfully added. Returns // OS_INVALID_ARGUMENT if the caller specified an invalid port index. // Returns OS_UNSPECIFIED if the addLink attempt failed for some other // reason. OsStatus MpFlowGraphBase::addLink(MpResource& rFrom, int outPortIdx, MpResource& rTo, int inPortIdx) { OsWriteLock lock(mRWMutex); UtlBoolean handled; MpFlowGraphMsg msg(MpFlowGraphMsg::FLOWGRAPH_ADD_LINK, NULL, &rFrom, &rTo, outPortIdx, inPortIdx); if (outPortIdx < 0 || outPortIdx >= rFrom.maxOutputs() || inPortIdx < 0 || inPortIdx >= rTo.maxInputs()) return OS_INVALID_ARGUMENT; if (mCurState == STARTED) return postMessage(msg); handled = handleMessage(msg); if (handled) return OS_SUCCESS; else return OS_UNSPECIFIED; }
UtlBoolean MpRtpInputConnection::connectOutput(MpResource& rTo, int toPortIdx, int fromPortIdx) { UtlBoolean res = MpResource::connectOutput(rTo, toPortIdx, fromPortIdx); if (res) { assert(rTo.getContainableType() == MprDecode::TYPE); MprDecode *pDecode = (MprDecode*)&rTo; res = mpRtpDispatcher->connectOutput(fromPortIdx, pDecode); } return res; }
// Handle the FLOWGRAPH_ENABLE message. // Returns TRUE if the message was handled, otherwise FALSE. UtlBoolean MpFlowGraphBase::handleEnable(void) { int i; MpFlowGraphMsg msg(MpFlowGraphMsg::RESOURCE_ENABLE); MpResource* pResource; // iterate over all resources // invoke the enable() method for each resource in the flow graph for (i=0; i < mResourceCnt; i++) { // iterate through the resources pResource = mUnsorted[i]; // make each resource handle a RESOURCE_ENABLE message msg.setMsgDest(pResource); if (!pResource->handleMessage(msg)) { assert(FALSE); return FALSE; } } return TRUE; }
// Handle the FLOWGRAPH_SET_SAMPLES_PER_SEC message. // Returns TRUE if the message was handled, otherwise FALSE. UtlBoolean MpFlowGraphBase::handleSetSamplesPerSec(int samplesPerSec) { int i; MpFlowGraphMsg msg(MpFlowGraphMsg::RESOURCE_SET_SAMPLES_PER_SEC, NULL, NULL, NULL, samplesPerSec); MpResource* pResource; // iterate over all resources for (i=0; i < mResourceCnt; i++) { pResource = mUnsorted[i]; // make each resource handle a SET_SAMPLES_PER_SEC message msg.setMsgDest(pResource); if (!pResource->handleMessage(msg)) { assert(FALSE); return FALSE; } } mSamplesPerSec = samplesPerSec; return TRUE; }
// Notification that this flow graph has just lost the focus. // Disable our microphone and speaker resources OsStatus MpTopologyGraph::loseFocus(void) { UtlBoolean boolRes; OsStatus result; OsStatus retval = OS_FAILED; // disable the FromInputDevice and ToOutputDevice -- we no longer have the focus. { MpResource* pResource = NULL; result = lookupResource("FromMic1", pResource); if (result == OS_SUCCESS) { // This flowgraph have local input part. Disable it. assert(pResource); boolRes = pResource->disable(); assert(boolRes); retval = OS_SUCCESS; } } { MpResource* pResource = NULL; result = lookupResource("ToSpeaker1", pResource); if (result == OS_SUCCESS) { // This flowgraph have local input part. Disable it. assert(pResource); boolRes = pResource->disable(); assert(boolRes); retval = OS_SUCCESS; } } return retval; }
// Processes all of the messages currently queued for this flow graph. // For now, this method always returns OS_SUCCESS. OsStatus MpFlowGraphBase::processMessages(void) { OsWriteLock lock(mRWMutex); UtlBoolean done; UtlBoolean handled; static MpFlowGraphMsg* pStopMsg = NULL; MpResource* pMsgDest; OsStatus res; // First, we send ourselves a FLOWGRAPH_PROCESS_FRAME message. // This message serves as a "stopper" in the message queue. When we // handle that message, we know that we have processed all of the messages // for the flowgraph (and its resources) that had arrived prior to the // start of this frame processing interval. if (NULL == pStopMsg) { pStopMsg = new MpFlowGraphMsg(MpFlowGraphMsg::FLOWGRAPH_PROCESS_FRAME); pStopMsg->setReusable(TRUE); } res = postMessage(*pStopMsg); assert(res == OS_SUCCESS); done = FALSE; while (!done) { // get the next message OsMsg* pMsg ; res = mMessages.receive(pMsg, OsTime::NO_WAIT); assert(res == OS_SUCCESS); if (pMsg->getMsgType() == OsMsg::MP_FLOWGRAPH_MSG) { MpFlowGraphMsg* pRcvdMsg = (MpFlowGraphMsg*) pMsg ; // determine if this message is intended for a resource in the // flow graph (as opposed to a message for the flow graph itself) pMsgDest = pRcvdMsg->getMsgDest(); if (pMsgDest != NULL) { // deliver the message if the resource is still part of this graph if (pMsgDest->getFlowGraph() == this) { handled = pMsgDest->handleMessage(*pRcvdMsg); assert(handled); } } else { // since pMsgDest is NULL, this msg is intended for the flow graph switch (pRcvdMsg->getMsg()) { case MpFlowGraphMsg::FLOWGRAPH_PROCESS_FRAME: done = TRUE; // "stopper" message encountered -- we are done break; // processing messages for this frame interval default: handled = handleMessage(*pRcvdMsg); assert(handled); break; } } pRcvdMsg->releaseMsg(); // free the msg } else { handled = handleMessage(*pMsg); assert(handled); pMsg->releaseMsg() ; } } return OS_SUCCESS; }
SIPXTAPI_API SIPX_RESULT sipxQOSDebug(SIPX_INST phInst, CStdString& txt) { CStdString buff; #ifdef INCLUDE_RTCP IRTCPControl* ic = CRTCManager::getRTCPControl(); IRTCPSession* sess = ic->GetFirstSession(); while (sess) { buff.Format("Sess: %d ", sess->GetSessionID()); txt += buff; IRTCPConnection* conn = sess->GetFirstConnection(); while (conn) { txt += "Conn\n"; CRTCPRender* render = (CRTCPRender*)((CRTCPConnection*)conn)->GetRenderInterface(); IGetSrcDescription* statDesc; IGetSenderStatistics* statSender; IGetReceiverStatistics* statRcvr; IGetByeInfo* statBye; render->GetStatistics(&statDesc, &statSender, &statRcvr, &statBye); char appName [255]; statDesc->GetAppName((unsigned char*)appName); unsigned long packetCount, octetCount; statSender->GetSenderStatistics(&packetCount, &octetCount); unsigned long fractionalLoss, cumulativeLoss, highestSeq, interarrivalJitter, SRtimestamp, packetDelay; statRcvr->GetReceiverStatistics(&fractionalLoss, &cumulativeLoss, &highestSeq, &interarrivalJitter, &SRtimestamp, &packetDelay); buff.Format("app=%s, packet=%d, octet=%d, loss=%d, cLoss=%d, seq=%d, jitt=%d, SR=%d, delay=%d", appName, packetCount, octetCount, fractionalLoss, cumulativeLoss, highestSeq, interarrivalJitter, SRtimestamp, packetDelay); txt += buff + "\n"; conn = sess->GetNextConnection(); } sess = ic->GetNextSession(); } #endif MpMediaTask* mtask = MpMediaTask::getMediaTask(32); MpFlowGraphBase* flowGraph = mtask->getFocus(); if (flowGraph) { for (int i=0; i < flowGraph->mResourceCnt; i++) { MpResource* r = flowGraph->mExecOrder[i]; if (strstr(r->getName(), "Dejitter")) { /* MprDejitter* dejj = (MprDejitter*) r; buff.Format("<u>%s</u>:: ave=%d, buff=%d, pull=%d, push=%d, " //"lmax=%d, lmin=%d, " "disc=%d, packs=%d ", dejj->getName().data(), dejj->getAveBufferLength(), dejj->mBufferLength, dejj->mLastPulled, dejj->mLastPushed //, dejj->mLatencyMax, dejj->mLatencyMin , dejj->mNumDiscarded, dejj->mNumPackets); txt += buff + "<br/>"; */ } else if (strstr(r->getName(), "Decode")) { /* MprDecode* decode = (MprDecode*) r; for (int c=0; c < decode->mNumCurrentCodecs; c++) { MpDecoderBase* mpd = decode->mpCurrentCodecs[c]; if (mpd->getInfo()->getCodecType() == SdpCodec::SDP_CODEC_PCMU || mpd->getInfo()->getCodecType() == SdpCodec::SDP_CODEC_PCMA) { MpdSipxPcma* pcma = (MpdSipxPcma*)mpd; MpJitterBuffer* jb = (MpJitterBuffer*)pcma->pJBState; buff.Format("Codec::%d tci=%d, pull=%d, wait=%d, under=%d, seq=%d, few=%d, many=%d, last=%d", pcma->getInfo()->getCodecType(), pcma->mTimerCountIncrement, pcma->mNextPullTimerCount, pcma->mWaitTimeInFrames, pcma->mUnderflowCount, pcma->mLastSeqNo, pcma->mTooFewPacketsInBuffer, pcma->mTooManyPacketsInBuffer, pcma->mLastReportSize); txt += buff + ", JB:"; buff.Format("avail=%d, qc=%d, qi=%d, qo=%d", jb->JbPacketsAvail, jb->JbQCount, jb->JbQIn, jb->JbQOut); txt += buff + "<br/>"; } } */ }/* else if (stristr(r->getName(), "FromNet")) { MprFromNet* fromNet = (MprFromNet*) r; }*/ } } int rating = 0; sipxQOSRating(phInst, rating); buff.Format("Rating: <b>%d</b>", rating); txt += buff; /* MprDejitter::getAveBufferLength -> MprDejitter -> MprDecode::getMyDejitter / MprFromNet::getMyDejitter() MpdSipxPcmu -> MpConnection::mapPayloadType MpCodecFactory::createDecoder MpdSipxPcma (MpDecoderBase) MpJitterBuffer -> MpConnection::getJBinst MpCallFlowGraph::getConnectionPtr */ return SIPX_RESULT_SUCCESS; }
int MpTopologyGraph::linkTopologyResources(MpResourceTopology& resourceTopology, UtlHashBag& newResources, UtlBoolean replaceNumInName, int resourceNum) { // Link the resources int connectionIndex = 0; UtlString outputResourceName; UtlString inputResourceName; int outputResourcePortIndex; int inputResourcePortIndex; MpResource* outputResource = NULL; MpResource* inputResource = NULL; OsStatus result; UtlHashMap newConnectionIds; #ifdef TEST_PRINT osPrintf("%d new resources in the list\n", newResources.entries()); UtlHashBagIterator iterator(newResources); MpResource* containerResource = NULL; while(containerResource = (MpResource*) iterator()) { osPrintf("found list resource: \"%s\" value: \"%s\"\n", containerResource->getName().data(), containerResource->data()); } #endif while(resourceTopology.getConnection(connectionIndex, outputResourceName, outputResourcePortIndex, inputResourceName, inputResourcePortIndex) == OS_SUCCESS) { if(replaceNumInName) { resourceTopology.replaceNumInName(outputResourceName, resourceNum); resourceTopology.replaceNumInName(inputResourceName, resourceNum); } // Look in the container of new resources first as this is more // efficient and new resources are not added immediately to a running // flowgraph outputResource = (MpResource*) newResources.find(&outputResourceName); if(outputResource == NULL) { result = lookupResource(outputResourceName, outputResource); if(result != OS_SUCCESS) { int virtPortIdx = outputResourcePortIndex>=0?outputResourcePortIndex:-1; int realPortIdx; result = lookupVirtualOutput(outputResourceName, virtPortIdx, outputResource, realPortIdx); if (result == OS_SUCCESS && outputResourcePortIndex>=0) { outputResourcePortIndex = realPortIdx; } } assert(result == OS_SUCCESS); } inputResource = (MpResource*) newResources.find(&inputResourceName); if(inputResource == NULL) { result = lookupResource(inputResourceName, inputResource); if(result != OS_SUCCESS) { int virtPortIdx = inputResourcePortIndex>=0?inputResourcePortIndex:-1; int realPortIdx; result = lookupVirtualInput(inputResourceName, virtPortIdx, inputResource, realPortIdx); if (result == OS_SUCCESS && inputResourcePortIndex>=0) { inputResourcePortIndex = realPortIdx; } } assert(result == OS_SUCCESS); } assert(outputResource); assert(inputResource); if(outputResource && inputResource) { if(outputResourcePortIndex == MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { outputResourcePortIndex = outputResource->reserveFirstUnconnectedOutput(); assert(outputResourcePortIndex >= 0); } else if(outputResourcePortIndex < MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { // First see if a real port is already in the dictionary UtlInt searchKey(outputResourcePortIndex); UtlInt* foundValue = NULL; if((foundValue = (UtlInt*) newConnectionIds.findValue(&searchKey))) { // Use the mapped index outputResourcePortIndex = foundValue->getValue(); } else { // Find an available port and add it to the map int realPortNum = outputResource->reserveFirstUnconnectedOutput(); assert(realPortNum >= 0); UtlInt* portKey = new UtlInt(outputResourcePortIndex); UtlInt* portValue = new UtlInt(realPortNum); newConnectionIds.insertKeyAndValue(portKey, portValue); outputResourcePortIndex = realPortNum; } } if(inputResourcePortIndex == MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { inputResourcePortIndex = inputResource->reserveFirstUnconnectedInput(); assert(inputResourcePortIndex >= 0); } else if(inputResourcePortIndex < MpResourceTopology::MP_TOPOLOGY_NEXT_AVAILABLE_PORT) { // First see if a real port is already in the dictionary UtlInt searchKey(inputResourcePortIndex); UtlInt* foundValue = NULL; if((foundValue = (UtlInt*) newConnectionIds.findValue(&searchKey))) { // Use the mapped index inputResourcePortIndex = foundValue->getValue(); } else { // Find an available port and add it to the map int realPortNum = inputResource->reserveFirstUnconnectedInput(); assert(realPortNum >= 0); UtlInt* portKey = new UtlInt(inputResourcePortIndex); UtlInt* portValue = new UtlInt(realPortNum); newConnectionIds.insertKeyAndValue(portKey, portValue); inputResourcePortIndex = realPortNum; } } result = addLink(*outputResource, outputResourcePortIndex, *inputResource, inputResourcePortIndex); assert(result == OS_SUCCESS); } connectionIndex++; } newConnectionIds.destroyAll(); return(connectionIndex); }
int MpTopologyGraph::addTopologyResources(MpResourceTopology& resourceTopology, MpResourceFactory& resourceFactory, UtlHashBag& newResources, UtlBoolean replaceNumInName, int resourceNum) { // Add the resources int resourceIndex = 0; MpResource* resourcePtr = NULL; MpResource* resourceArray[MAX_CONSTRUCTED_RESOURCES]; UtlString resourceType; UtlString resourceName; MpConnectionID resourceConnId; int resourceStreamId; OsStatus result; while(resourceTopology.getResource(resourceIndex, resourceType, resourceName, resourceConnId, resourceStreamId) == OS_SUCCESS) { if(replaceNumInName) { MpResourceTopology::replaceNumInName(resourceName, resourceNum); } int numConstructorResources; OsStatus status; status = resourceFactory.newResource(resourceType, resourceName, MAX_CONSTRUCTED_RESOURCES, numConstructorResources, resourceArray); if(status == OS_SUCCESS) { assert(numConstructorResources > 0); int arrayIndex; // We now can potentially get more than one resource back from the // constructor for(arrayIndex = 0; arrayIndex < numConstructorResources; arrayIndex++) { resourcePtr = resourceArray[arrayIndex]; assert(resourcePtr); if(resourcePtr) { #ifdef TEST_PRINT printf("constructed and adding resource name: %s type: %s\n", resourcePtr->getName().data(), resourceType.data()); #endif if(replaceNumInName && resourceConnId == MP_INVALID_CONNECTION_ID) { resourcePtr->setConnectionId(resourceNum); } else { resourcePtr->setConnectionId(resourceConnId); } resourcePtr->setStreamId(resourceStreamId); newResources.insert(resourcePtr); result = addResource(*resourcePtr, FALSE); assert(result == OS_SUCCESS); } } } else { OsSysLog::add(FAC_MP, PRI_ERR, "Failed to create resource type: %s name: %s status: %d", resourceType.data(), resourceName.data(), status); } resourceIndex++; } return(resourceIndex); }