bool RTMFPWriter::flush(bool full) { if(_messagesSent.size()>100) TRACE("_messagesSent.size()=",_messagesSent.size()); if(state()==OPENING) { ERROR("Violation policy, impossible to flush data on a opening writer"); return false; } bool hasSent(false); // flush bool header = !_band.canWriteFollowing(*this); while(!_messages.empty()) { hasSent = true; RTMFPMessage& message(*_messages.front()); if(message.repeatable) { ++_repeatable; _trigger.start(); } UInt32 fragments= 0; UInt32 available = message.size(); do { ++_stage; // Actual sending packet is enough large? UInt32 contentSize = _band.availableToWrite(); UInt32 headerSize = (header && contentSize<62) ? this->headerSize(_stage) : 0; // calculate only if need! if(contentSize<(headerSize+12)) { // 12 to have a size minimum of fragmentation _band.flush(); // send packet (and without time echo) header=true; } contentSize = available; UInt32 size = contentSize+4; if(header) size+= headerSize>0 ? headerSize : this->headerSize(_stage); // Compute flags UInt8 flags = 0; if(fragments>0) flags |= MESSAGE_WITH_BEFOREPART; bool head = header; UInt32 availableToWrite(_band.availableToWrite()); if(size>availableToWrite) { // the packet will change! The message will be fragmented. flags |= MESSAGE_WITH_AFTERPART; contentSize = availableToWrite-(size-contentSize); size=availableToWrite; header=true; } else header=false; // the packet stays the same! // Write packet size-=3; // type + timestamp removed, before the "writeMessage" flush(_band.writeMessage(head ? 0x10 : 0x11,(UInt16)size,this),_stage,flags,head,message,fragments,contentSize); message.fragments[fragments] = _stage; available -= contentSize; fragments += contentSize; } while(available>0); _qos.add(message.size(),_band.ping()); _messagesSent.emplace_back(&message); _messages.pop_front(); } if (full) _band.flush(); return hasSent; }
void RTMFPWriter::acknowledgment(PacketReader& packet) { UInt64 bufferSize = packet.read7BitLongValue(); // TODO use this value in reliability mechanism? if(bufferSize==0) { // In fact here, we should send a 0x18 message (with id flow), // but it can create a loop... We prefer the following behavior fail("Negative acknowledgment"); return; } UInt64 stageAckPrec = _stageAck; UInt64 stageReaden = packet.read7BitLongValue(); UInt64 stage = _stageAck+1; if(stageReaden>_stage) { ERROR("Acknowledgment received ",stageReaden," superior than the current sending stage ",_stage," on writer ",id); _stageAck = _stage; } else if(stageReaden<=_stageAck) { // already acked if(packet.available()==0) DEBUG("Acknowledgment ",stageReaden," obsolete on writer ",id); } else _stageAck = stageReaden; UInt64 maxStageRecv = stageReaden; UInt32 pos=packet.position(); while(packet.available()>0) maxStageRecv += packet.read7BitLongValue()+packet.read7BitLongValue()+2; if(pos != packet.position()) { // TRACE(stageReaden,"..x"Util::FormatHex(reader.current(),reader.available())); packet.reset(pos); } UInt64 lostCount = 0; UInt64 lostStage = 0; bool repeated = false; bool header = true; bool stop=false; auto it=_messagesSent.begin(); while(!stop && it!=_messagesSent.end()) { RTMFPMessage& message(**it); if(message.fragments.empty()) { CRITIC("RTMFPMessage ",(stage+1)," is bad formatted on fowWriter ",id); ++it; continue; } map<UInt32,UInt64>::iterator itFrag=message.fragments.begin(); while(message.fragments.end()!=itFrag) { // ACK if(_stageAck>=stage) { message.fragments.erase(message.fragments.begin()); itFrag=message.fragments.begin(); ++_ackCount; ++stage; continue; } // Read lost informations while(!stop) { if(lostCount==0) { if(packet.available()>0) { lostCount = packet.read7BitLongValue()+1; lostStage = stageReaden+1; stageReaden = lostStage+lostCount+packet.read7BitLongValue(); } else { stop=true; break; } } // check the range if(lostStage>_stage) { // Not yet sent ERROR("Lost information received ",lostStage," have not been yet sent on writer ",id); stop=true; } else if(lostStage<=_stageAck) { // already acked --lostCount; ++lostStage; continue; } break; } if(stop) break; // lostStage > 0 and lostCount > 0 if(lostStage!=stage) { if(repeated) { ++stage; ++itFrag; header=true; } else // No repeated, it means that past lost packet was not repeatable, we can ack this intermediate received sequence _stageAck = stage; continue; } /// Repeat message asked! if(!message.repeatable) { if(repeated) { ++itFrag; ++stage; header=true; } else { INFO("RTMFPWriter ",id," : message ",stage," lost"); --_ackCount; ++_lostCount; _stageAck = stage; } --lostCount; ++lostStage; continue; } repeated = true; // Don't repeate before that the receiver receives the itFrag->second sending stage if(itFrag->second >= maxStageRecv) { ++stage; header=true; --lostCount; ++lostStage; ++itFrag; continue; } // Repeat message DEBUG("RTMFPWriter ",id," : stage ",stage," repeated"); UInt32 fragment(itFrag->first); itFrag->second = _stage; // Save actual stage sending to wait that the receiver gets it before to retry UInt32 contentSize = message.size() - fragment; // available ++itFrag; // Compute flags UInt8 flags = 0; if(fragment>0) flags |= MESSAGE_WITH_BEFOREPART; // fragmented if(itFrag!=message.fragments.end()) { flags |= MESSAGE_WITH_AFTERPART; contentSize = itFrag->first - fragment; } UInt32 size = contentSize+4; UInt32 availableToWrite(_band.availableToWrite()); if(!header && size>availableToWrite) { _band.flush(); header=true; } if(header) size+=headerSize(stage); if(size>availableToWrite) _band.flush(); // Write packet size-=3; // type + timestamp removed, before the "writeMessage" flush(_band.writeMessage(header ? 0x10 : 0x11,(UInt16)size) ,stage,flags,header,message,fragment,contentSize); header=false; --lostCount; ++lostStage; ++stage; } if(message.fragments.empty()) { if(message.repeatable) --_repeatable; if(_ackCount || _lostCount) { _qos.add(_lostCount / (_lostCount + _ackCount)); _ackCount=_lostCount=0; } delete *it; it=_messagesSent.erase(it); } else ++it; } if(lostCount>0 && packet.available()>0) ERROR("Some lost information received have not been yet sent on writer ",id); // rest messages repeatable? if(_repeatable==0) _trigger.stop(); else if(_stageAck>stageAckPrec || repeated) _trigger.reset(); }
ssize_t MonoPipe::write(const void *buffer, size_t count) { if (CC_UNLIKELY(!mNegotiated)) { return NEGOTIATE; } size_t totalFramesWritten = 0; while (count > 0) { // can't return a negative value, as we already checked for !mNegotiated size_t avail = availableToWrite(); size_t written = avail; if (CC_LIKELY(written > count)) { written = count; } size_t rear = mRear & (mMaxFrames - 1); size_t part1 = mMaxFrames - rear; if (part1 > written) { part1 = written; } if (CC_LIKELY(part1 > 0)) { memcpy((char *) mBuffer + (rear << mBitShift), buffer, part1 << mBitShift); if (CC_UNLIKELY(rear + part1 == mMaxFrames)) { size_t part2 = written - part1; if (CC_LIKELY(part2 > 0)) { memcpy(mBuffer, (char *) buffer + (part1 << mBitShift), part2 << mBitShift); } } android_atomic_release_store(written + mRear, &mRear); totalFramesWritten += written; } if (!mWriteCanBlock || mIsShutdown) { break; } count -= written; buffer = (char *) buffer + (written << mBitShift); // Simulate blocking I/O by sleeping at different rates, depending on a throttle. // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter. uint32_t ns; if (written > 0) { size_t filled = (mMaxFrames - avail) + written; // FIXME cache these values to avoid re-computation if (filled <= mSetpoint / 2) { // pipe is (nearly) empty, fill quickly ns = written * ( 500000000 / Format_sampleRate(mFormat)); } else if (filled <= (mSetpoint * 3) / 4) { // pipe is below setpoint, fill at slightly faster rate ns = written * ( 750000000 / Format_sampleRate(mFormat)); } else if (filled <= (mSetpoint * 5) / 4) { // pipe is at setpoint, fill at nominal rate ns = written * (1000000000 / Format_sampleRate(mFormat)); } else if (filled <= (mSetpoint * 3) / 2) { // pipe is above setpoint, fill at slightly slower rate ns = written * (1150000000 / Format_sampleRate(mFormat)); } else if (filled <= (mSetpoint * 7) / 4) { // pipe is overflowing, fill slowly ns = written * (1350000000 / Format_sampleRate(mFormat)); } else { // pipe is severely overflowing ns = written * (1750000000 / Format_sampleRate(mFormat)); } } else { ns = count * (1350000000 / Format_sampleRate(mFormat)); } if (ns > 999999999) { ns = 999999999; } struct timespec nowTs; bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs); // deduct the elapsed time since previous write() completed if (nowTsValid && mWriteTsValid) { time_t sec = nowTs.tv_sec - mWriteTs.tv_sec; long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec; ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0), "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld", mWriteTs.tv_sec, mWriteTs.tv_nsec, nowTs.tv_sec, nowTs.tv_nsec); if (nsec < 0) { --sec; nsec += 1000000000; } if (sec == 0) { if ((long) ns > nsec) { ns -= nsec; } else { ns = 0; } } } if (ns > 0) { const struct timespec req = {0, ns}; nanosleep(&req, NULL); } // record the time that this write() completed if (nowTsValid) { mWriteTs = nowTs; if ((mWriteTs.tv_nsec += ns) >= 1000000000) { mWriteTs.tv_nsec -= 1000000000; ++mWriteTs.tv_sec; } } mWriteTsValid = nowTsValid; } mFramesWritten += totalFramesWritten; return totalFramesWritten; }