void StreamReplicator::getNextFrame(StreamReplica* replica) { if (fInputSourceHasClosed) { // handle closure instead FramedSource::handleClosure(replica); return; } if (replica->fFrameIndex == -1) { // This replica had stopped playing (or had just been created), but is now actively reading. Note this: replica->fFrameIndex = fFrameIndex; ++fNumActiveReplicas; } if (fMasterReplica == NULL) { // This is the first replica to request the next unread frame. Make it the 'master' replica - meaning that we read the frame // into its buffer, and then copy from this into the other replicas' buffers. fMasterReplica = replica; // Arrange to read the next frame into this replica's buffer: if (fInputSource != NULL) fInputSource->getNextFrame(fMasterReplica->fTo, fMasterReplica->fMaxSize, afterGettingFrame, this, onSourceClosure, this); } else if (replica->fFrameIndex != fFrameIndex) { // This replica is already asking for the next frame (because it has already received the current frame). Enqueue it: replica->fNext = fReplicasAwaitingNextFrame; fReplicasAwaitingNextFrame = replica; } else { // This replica is asking for the current frame. Enqueue it: replica->fNext = fReplicasAwaitingCurrentFrame; fReplicasAwaitingCurrentFrame = replica; if (fInputSource != NULL && !fInputSource->isCurrentlyAwaitingData()) { // The current frame has already arrived, so deliver it to this replica now: deliverReceivedFrame(); } } }
void StreamReplicator::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds) { // The frame was read into our master replica's buffer. Update the master replica's state, but don't complete delivery to it // just yet. We do that later, after we're sure that we've delivered it to all other replicas. fMasterReplica->fFrameSize = frameSize; fMasterReplica->fNumTruncatedBytes = numTruncatedBytes; fMasterReplica->fPresentationTime = presentationTime; fMasterReplica->fDurationInMicroseconds = durationInMicroseconds; deliverReceivedFrame(); }
void StreamReplicator::deactivateStreamReplica(StreamReplica* replicaBeingDeactivated) { if (replicaBeingDeactivated->fFrameIndex == -1) return; // this replica has already been deactivated (or was never activated at all) // Assert: fNumActiveReplicas > 0 if (fNumActiveReplicas == 0) fprintf(stderr, "StreamReplicator::deactivateStreamReplica() Internal Error!\n"); // should not happen --fNumActiveReplicas; replicaBeingDeactivated->fFrameIndex = -1; // Forget about any frame delivery that might have just been made to this replica: if (replicaBeingDeactivated->fFrameIndex != fFrameIndex && fNumDeliveriesMadeSoFar > 0) --fNumDeliveriesMadeSoFar; // Check whether the replica being deactivated is the 'master' replica, or is enqueued awaiting a frame: if (replicaBeingDeactivated == fMasterReplica) { // We need to replace the 'master replica', if we can: if (fReplicasAwaitingCurrentFrame == NULL) { // There's currently no replacement 'master replica' fMasterReplica = NULL; } else { // There's another replica that we can use as a replacement 'master replica': fMasterReplica = fReplicasAwaitingCurrentFrame; fReplicasAwaitingCurrentFrame = fReplicasAwaitingCurrentFrame->fNext; fMasterReplica->fNext = NULL; } // Check whether the read into the old master replica's buffer is still pending, or has completed: if (fInputSource != NULL) { if (fInputSource->isCurrentlyAwaitingData()) { // We have a pending read into the old master replica's buffer. // We need to stop it, and retry the read with a new master (if available) fInputSource->stopGettingFrames(); if (fMasterReplica != NULL) { fInputSource->getNextFrame(fMasterReplica->fTo, fMasterReplica->fMaxSize, afterGettingFrame, this, onSourceClosure, this); } } else { // The read into the old master replica's buffer has already completed. Copy the data to the new master replica (if any): if (fMasterReplica != NULL) { StreamReplica::copyReceivedFrame(fMasterReplica, replicaBeingDeactivated); } else { // We don't have a new master replica, so we can't copy the received frame to any new replica that might ask for it. // Fortunately this should be a very rare occurrence. } } } } else { // The replica that's being removed was not our 'master replica', but make sure it's not on either of our queues: if (fReplicasAwaitingCurrentFrame != NULL) { if (replicaBeingDeactivated == fReplicasAwaitingCurrentFrame) { fReplicasAwaitingCurrentFrame = replicaBeingDeactivated->fNext; replicaBeingDeactivated->fNext = NULL; } else { for (StreamReplica* r1 = fReplicasAwaitingCurrentFrame; r1->fNext != NULL; r1 = r1->fNext) { if (r1->fNext == replicaBeingDeactivated) { r1->fNext = replicaBeingDeactivated->fNext; replicaBeingDeactivated->fNext = NULL; break; } } } } if (fReplicasAwaitingNextFrame != NULL) { if (replicaBeingDeactivated == fReplicasAwaitingNextFrame) { fReplicasAwaitingNextFrame = replicaBeingDeactivated->fNext; replicaBeingDeactivated->fNext = NULL; } else { for (StreamReplica* r2 = fReplicasAwaitingNextFrame; r2->fNext != NULL; r2 = r2->fNext) { if (r2->fNext == replicaBeingDeactivated) { r2->fNext = replicaBeingDeactivated->fNext; replicaBeingDeactivated->fNext = NULL; break; } } } } // Check for the possibility that - now that a replica has been deactivated - all other // replicas have received the current frame, and so now we need to complete delivery to // the master replica: if (fMasterReplica != NULL && fInputSource != NULL && !fInputSource->isCurrentlyAwaitingData()) deliverReceivedFrame(); } if (fNumActiveReplicas == 0 && fInputSource != NULL) fInputSource->stopGettingFrames(); // tell our source to stop too }