/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. // Media Sinks // Implementation #include "MediaSink.hh" #include "GroupsockHelper.hh" #include ////////// MediaSink ////////// MediaSink::MediaSink(UsageEnvironment& env) : Medium(env), fSource(NULL) { } MediaSink::~MediaSink() { stopPlaying(); } Boolean MediaSink::isSink() const { return True; } Boolean MediaSink::lookupByName(UsageEnvironment& env, char const* sinkName, MediaSink*& resultSink) { resultSink = NULL; // unless we succeed Medium* medium; if (!Medium::lookupByName(env, sinkName, medium)) return False; if (!medium->isSink()) { env.setResultMsg(sinkName, " is not a media sink"); return False; } resultSink = (MediaSink*)medium; return True; } Boolean MediaSink::sourceIsCompatibleWithUs(MediaSource& source) { // We currently support only framed sources. return source.isFramedSource(); } Boolean MediaSink::startPlaying(MediaSource& source, afterPlayingFunc* afterFunc, void* afterClientData) { // Make sure we're not already being played: if (fSource != NULL) { envir().setResultMsg("This sink is already being played"); return False; } // Make sure our source is compatible: if (!sourceIsCompatibleWithUs(source)) { envir().setResultMsg("MediaSink::startPlaying(): source is not compatible!"); return False; } fSource = (FramedSource*)&source; fAfterFunc = afterFunc; fAfterClientData = afterClientData; return continuePlaying(); } void MediaSink::stopPlaying() { // First, tell the source that we're no longer interested: if (fSource != NULL) fSource->stopGettingFrames(); // Cancel any pending tasks: envir().taskScheduler().unscheduleDelayedTask(nextTask()); fSource = NULL; // indicates that we can be played again fAfterFunc = NULL; } void MediaSink::onSourceClosure(void* clientData) { MediaSink* sink = (MediaSink*)clientData; sink->onSourceClosure(); } void MediaSink::onSourceClosure() { // Cancel any pending tasks: envir().taskScheduler().unscheduleDelayedTask(nextTask()); fSource = NULL; // indicates that we can be played again if (fAfterFunc != NULL) { (*fAfterFunc)(fAfterClientData); } } Boolean MediaSink::isRTPSink() const { return False; // default implementation } ////////// OutPacketBuffer ////////// unsigned OutPacketBuffer::maxSize = 60000; // by default OutPacketBuffer ::OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize, unsigned maxBufferSize) : fPreferred(preferredPacketSize), fMax(maxPacketSize), fOverflowDataSize(0) { if (maxBufferSize == 0) maxBufferSize = maxSize; unsigned maxNumPackets = (maxBufferSize + (maxPacketSize-1))/maxPacketSize; fLimit = maxNumPackets*maxPacketSize; fBuf = new unsigned char[fLimit]; resetPacketStart(); resetOffset(); resetOverflowData(); } OutPacketBuffer::~OutPacketBuffer() { delete[] fBuf; } void OutPacketBuffer::enqueue(unsigned char const* from, unsigned numBytes) { if (numBytes > totalBytesAvailable()) { #ifdef DEBUG fprintf(stderr, "OutPacketBuffer::enqueue() warning: %d > %d\n", numBytes, totalBytesAvailable()); #endif numBytes = totalBytesAvailable(); } if (curPtr() != from) memmove(curPtr(), from, numBytes); increment(numBytes); } void OutPacketBuffer::enqueueWord(u_int32_t word) { u_int32_t nWord = htonl(word); enqueue((unsigned char*)&nWord, 4); } void OutPacketBuffer::insert(unsigned char const* from, unsigned numBytes, unsigned toPosition) { unsigned realToPosition = fPacketStart + toPosition; if (realToPosition + numBytes > fLimit) { if (realToPosition > fLimit) return; // we can't do this numBytes = fLimit - realToPosition; } memmove(&fBuf[realToPosition], from, numBytes); if (toPosition + numBytes > fCurOffset) { fCurOffset = toPosition + numBytes; } } void OutPacketBuffer::insertWord(u_int32_t word, unsigned toPosition) { u_int32_t nWord = htonl(word); insert((unsigned char*)&nWord, 4, toPosition); } void OutPacketBuffer::extract(unsigned char* to, unsigned numBytes, unsigned fromPosition) { unsigned realFromPosition = fPacketStart + fromPosition; if (realFromPosition + numBytes > fLimit) { // sanity check if (realFromPosition > fLimit) return; // we can't do this numBytes = fLimit - realFromPosition; } memmove(to, &fBuf[realFromPosition], numBytes); } u_int32_t OutPacketBuffer::extractWord(unsigned fromPosition) { u_int32_t nWord; extract((unsigned char*)&nWord, 4, fromPosition); return ntohl(nWord); } void OutPacketBuffer::skipBytes(unsigned numBytes) { if (numBytes > totalBytesAvailable()) { numBytes = totalBytesAvailable(); } increment(numBytes); } void OutPacketBuffer ::setOverflowData(unsigned overflowDataOffset, unsigned overflowDataSize, struct timeval const& presentationTime, unsigned durationInMicroseconds) { fOverflowDataOffset = overflowDataOffset; fOverflowDataSize = overflowDataSize; fOverflowPresentationTime = presentationTime; fOverflowDurationInMicroseconds = durationInMicroseconds; } void OutPacketBuffer::useOverflowData() { enqueue(&fBuf[fPacketStart + fOverflowDataOffset], fOverflowDataSize); fCurOffset -= fOverflowDataSize; // undoes increment performed by "enqueue" resetOverflowData(); } void OutPacketBuffer::adjustPacketStart(unsigned numBytes) { fPacketStart += numBytes; if (fOverflowDataOffset >= numBytes) { fOverflowDataOffset -= numBytes; } else { fOverflowDataOffset = 0; fOverflowDataSize = 0; // an error otherwise } } void OutPacketBuffer::resetPacketStart() { if (fOverflowDataSize > 0) { fOverflowDataOffset += fPacketStart; } fPacketStart = 0; }