blob: ab144ad797e7f0f9cdbb5f7440ef69d981fd0e07 [file] [log] [blame]
/**********
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 <http://www.gnu.org/copyleft/lesser.html>.)
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 <string.h>
////////// 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;
}