blob: cd4ca42164538de49b31cf826957aa7101a12170 [file]
/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <RtpEncoderNode.h>
#include <ImsMediaTimer.h>
#include <ImsMediaTrace.h>
#include <ImsMediaVideoUtil.h>
#include <AudioConfig.h>
#include <VideoConfig.h>
#include <TextConfig.h>
#include <string.h>
RtpEncoderNode::RtpEncoderNode(BaseSessionCallback* callback) :
BaseNode(callback)
{
mRtpSession = nullptr;
mDTMFMode = false;
mMark = false;
mPrevTimestamp = 0;
mSamplingRate = 0;
mRtpPayloadTx = 0;
mRtpPayloadRx = 0;
mRtpTxDtmfPayload = 0;
mRtpRxDtmfPayload = 0;
mDtmfSamplingRate = 0;
mDtmfTimestamp = 0;
mCvoValue = CVO_DEFINE_NONE;
mRedundantLevel = 0;
mRedundantPayload = 0;
}
RtpEncoderNode::~RtpEncoderNode()
{
// remove IRtpSession here to avoid shared instance in other node from unable to use
if (mRtpSession)
{
mRtpSession->StopRtp();
mRtpSession->SetRtpEncoderListener(nullptr);
IRtpSession::ReleaseInstance(mRtpSession);
mRtpSession = nullptr;
}
}
kBaseNodeId RtpEncoderNode::GetNodeId()
{
return kNodeIdRtpEncoder;
}
ImsMediaResult RtpEncoderNode::Start()
{
IMLOGD1("[Start] type[%d]", mMediaType);
if (mRtpPayloadTx == 0 || mRtpPayloadRx == 0)
{
IMLOGE0("[Start] invalid payload number");
return RESULT_INVALID_PARAM;
}
if (mRtpSession == nullptr)
{
mRtpSession = IRtpSession::GetInstance(mMediaType, mLocalAddress, mPeerAddress);
if (mRtpSession == nullptr)
{
IMLOGE0("[Start] Can't create rtp session");
return RESULT_NOT_READY;
}
}
mRtpSession->SetRtpEncoderListener(this);
if (mMediaType == IMS_MEDIA_AUDIO)
{
mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000,
mRtpTxDtmfPayload, mRtpRxDtmfPayload, mDtmfSamplingRate * 1000);
}
else if (mMediaType == IMS_MEDIA_VIDEO)
{
mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000);
}
else if (mMediaType == IMS_MEDIA_TEXT)
{
if (mRedundantPayload > 0)
{
mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000,
mRedundantPayload, mSamplingRate * 1000);
}
else
{
mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000);
}
}
mRtpSession->StartRtp();
mDTMFMode = false;
mMark = true;
mPrevTimestamp = 0;
#ifdef DEBUG_JITTER_GEN_SIMULATION_DELAY
mNextTime = 0;
#endif
#ifdef DEBUG_JITTER_GEN_SIMULATION_REORDER
jitterData.Clear();
mReorderDataCount = 0;
#endif
mNodeState = kNodeStateRunning;
return RESULT_SUCCESS;
}
void RtpEncoderNode::Stop()
{
IMLOGD1("[Stop] type[%d]", mMediaType);
std::lock_guard<std::mutex> guard(mMutex);
if (mRtpSession)
{
mRtpSession->StopRtp();
}
ClearDataQueue();
mNodeState = kNodeStateStopped;
}
void RtpEncoderNode::ProcessData()
{
std::lock_guard<std::mutex> guard(mMutex);
if (mNodeState != kNodeStateRunning)
{
return;
}
ImsMediaSubType subtype;
uint8_t* data = nullptr;
uint32_t size = 0;
uint32_t timestamp = 0;
bool mark = false;
uint32_t seq = 0;
ImsMediaSubType datatype;
uint32_t arrivalTime = 0;
if (GetData(&subtype, &data, &size, &timestamp, &mark, &seq, &datatype, &arrivalTime))
{
if (mMediaType == IMS_MEDIA_AUDIO)
{
if (!ProcessAudioData(subtype, data, size))
{
return;
}
}
else if (mMediaType == IMS_MEDIA_VIDEO)
{
ProcessVideoData(subtype, data, size, timestamp, mark);
}
else if (mMediaType == IMS_MEDIA_TEXT)
{
ProcessTextData(subtype, data, size, timestamp, mark);
}
DeleteData();
}
}
bool RtpEncoderNode::IsRunTime()
{
return false;
}
bool RtpEncoderNode::IsSourceNode()
{
return false;
}
void RtpEncoderNode::SetConfig(void* config)
{
IMLOGD1("[SetConfig] media[%d]", mMediaType);
if (config == nullptr)
{
return;
}
if (mMediaType == IMS_MEDIA_AUDIO)
{
AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
mSamplingRate = pConfig->getSamplingRateKHz();
mRtpPayloadTx = pConfig->getTxPayloadTypeNumber();
mRtpPayloadRx = pConfig->getRxPayloadTypeNumber();
mRtpTxDtmfPayload = pConfig->getTxDtmfPayloadTypeNumber();
mRtpRxDtmfPayload = pConfig->getRxDtmfPayloadTypeNumber();
mDtmfSamplingRate = pConfig->getDtmfsamplingRateKHz();
}
else if (mMediaType == IMS_MEDIA_VIDEO)
{
VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config);
mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
mSamplingRate = pConfig->getSamplingRateKHz();
mRtpPayloadTx = pConfig->getTxPayloadTypeNumber();
mRtpPayloadRx = pConfig->getRxPayloadTypeNumber();
mCvoValue = pConfig->getCvoValue();
}
else if (mMediaType == IMS_MEDIA_TEXT)
{
TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
mPeerAddress = RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort());
mSamplingRate = pConfig->getSamplingRateKHz();
mRtpPayloadTx = pConfig->getTxPayloadTypeNumber();
mRtpPayloadRx = pConfig->getRxPayloadTypeNumber();
mRedundantPayload = pConfig->getRedundantPayload();
mRedundantLevel = pConfig->getRedundantLevel();
}
IMLOGD2("[SetConfig] peer Ip[%s], port[%d]", mPeerAddress.ipAddress, mPeerAddress.port);
}
bool RtpEncoderNode::IsSameConfig(void* config)
{
if (config == nullptr)
{
return true;
}
if (mMediaType == IMS_MEDIA_AUDIO)
{
AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
return (mPeerAddress ==
RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort()) &&
mSamplingRate == pConfig->getSamplingRateKHz() &&
mRtpPayloadTx == pConfig->getTxPayloadTypeNumber() &&
mRtpPayloadRx == pConfig->getRxPayloadTypeNumber() &&
mRtpTxDtmfPayload == pConfig->getTxDtmfPayloadTypeNumber() &&
mRtpRxDtmfPayload == pConfig->getRxDtmfPayloadTypeNumber() &&
mDtmfSamplingRate == pConfig->getDtmfsamplingRateKHz());
}
else if (mMediaType == IMS_MEDIA_VIDEO)
{
VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config);
return (mPeerAddress ==
RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort()) &&
mSamplingRate == pConfig->getSamplingRateKHz() &&
mRtpPayloadTx == pConfig->getTxPayloadTypeNumber() &&
mRtpPayloadRx == pConfig->getRxPayloadTypeNumber() &&
mCvoValue == pConfig->getCvoValue());
}
else if (mMediaType == IMS_MEDIA_TEXT)
{
TextConfig* pConfig = reinterpret_cast<TextConfig*>(config);
return (mPeerAddress ==
RtpAddress(pConfig->getRemoteAddress().c_str(), pConfig->getRemotePort()) &&
mSamplingRate == pConfig->getSamplingRateKHz() &&
mRtpPayloadTx == pConfig->getTxPayloadTypeNumber() &&
mRtpPayloadRx == pConfig->getRxPayloadTypeNumber() &&
mRedundantPayload == pConfig->getRedundantPayload() &&
mRedundantLevel == pConfig->getRedundantLevel());
}
return false;
}
void RtpEncoderNode::OnRtpPacket(unsigned char* data, uint32_t nSize)
{
SendDataToRearNode(MEDIASUBTYPE_RTPPACKET, data, nSize, 0, 0, 0);
}
void RtpEncoderNode::SetLocalAddress(const RtpAddress& address)
{
mLocalAddress = address;
}
void RtpEncoderNode::SetPeerAddress(const RtpAddress& address)
{
mPeerAddress = address;
}
bool RtpEncoderNode::SetCvoExtension(const int64_t facing, const int64_t orientation)
{
IMLOGD3("[SetCvoExtension] cvoValue[%d], facing[%ld], orientation[%ld]", mCvoValue, facing,
orientation);
if (mCvoValue > 0)
{
uint32_t rotation = 0;
uint32_t cameraId = 0;
if (facing == kCameraFacingRear)
{
cameraId = 1;
}
switch (orientation)
{
default:
case 0:
rotation = 0;
break;
case 270:
rotation = 1;
break;
case 180:
rotation = 2;
break;
case 90:
rotation = 3;
break;
}
if (cameraId == 1) // rear camera
{
if (rotation == 1) // CCW90
{
rotation = 3;
}
else if (rotation == 3) // CCW270
{
rotation = 1;
}
}
int8_t extensionData[4]; // 32bit
IMLOGD3("[SetCvoExtension] cvoValue[%d], facing[%d], orientation[%d]", mCvoValue, cameraId,
rotation);
extensionData[0] = (mCvoValue << 4) | 1; // local identifier and data length
extensionData[1] = (cameraId << 3) | rotation;
extensionData[2] = 0; // padding
extensionData[3] = 0; // padding
mListRtpExtension.clear();
mListRtpExtension.push_back(RtpHeaderExtensionInfo(
RtpHeaderExtensionInfo::kBitPatternForOneByteHeader, 1, extensionData, 4));
return true;
}
return false;
}
void RtpEncoderNode::SetRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension)
{
if (listExtension == nullptr || listExtension->empty())
{
return;
}
/**
* Check number of byte of the header. Based on RFC8285 4.2, one byte header has a local
* identifier in range of 1 to 14. Two byte header has is a range of 1 to 255.
*/
bool useTwoByteHeader = false;
int32_t totalPayloadLength = 0; // accumulate payload length except the header size
for (auto extension : *listExtension)
{
if (extension.getLocalIdentifier() > 15)
{
useTwoByteHeader = true;
}
totalPayloadLength += extension.getExtensionDataSize();
}
// accumulate header size
useTwoByteHeader ? totalPayloadLength += 2 * listExtension->size()
: totalPayloadLength += listExtension->size();
// padding size
int32_t paddingSize = totalPayloadLength % IMS_MEDIA_WORD_SIZE == 0
? 0
: IMS_MEDIA_WORD_SIZE - totalPayloadLength % IMS_MEDIA_WORD_SIZE;
totalPayloadLength += paddingSize;
int8_t* extensionData = new int8_t[totalPayloadLength];
int offset = 0;
for (auto extension : *listExtension)
{
if (useTwoByteHeader)
{
extensionData[offset++] = extension.getLocalIdentifier();
extensionData[offset++] = extension.getExtensionDataSize();
}
else
{
extensionData[offset++] =
extension.getLocalIdentifier() << 4 | (extension.getExtensionDataSize() - 1);
}
memcpy(extensionData + offset, extension.getExtensionData(),
extension.getExtensionDataSize());
offset += extension.getExtensionDataSize();
}
// add padding
memset(extensionData + offset, 0, paddingSize);
IMLOGD3("[SetRtpHeaderExtension] twoByte[%d], size[%d], list size[%d]", useTwoByteHeader,
totalPayloadLength, listExtension->size());
int16_t defineByProfile = useTwoByteHeader
? RtpHeaderExtensionInfo::kBitPatternForTwoByteHeader
: RtpHeaderExtensionInfo::kBitPatternForOneByteHeader;
mListRtpExtension.push_back(RtpHeaderExtensionInfo(
defineByProfile, totalPayloadLength / 4, extensionData, totalPayloadLength));
delete[] extensionData;
}
bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, uint32_t size)
{
uint32_t currentTimestamp;
uint32_t timeDiff;
uint32_t timestampDiff;
if (subtype == MEDIASUBTYPE_DTMFSTART)
{
IMLOGD0("[ProcessAudioData] SetDTMF mode true");
mDTMFMode = true;
mMark = true;
}
else if (subtype == MEDIASUBTYPE_DTMFEND)
{
IMLOGD0("[ProcessAudioData] SetDTMF mode false");
mDTMFMode = false;
mMark = true;
}
else if (subtype == MEDIASUBTYPE_DTMF_PAYLOAD)
{
if (mDTMFMode)
{
currentTimestamp = ImsMediaTimer::GetTimeInMilliSeconds();
timeDiff = currentTimestamp - mPrevTimestamp;
if (timeDiff < 20)
{
return false;
}
mMark ? mDtmfTimestamp = currentTimestamp : timeDiff = 0;
mPrevTimestamp = currentTimestamp;
timestampDiff = timeDiff * mSamplingRate;
IMLOGD_PACKET3(IM_PACKET_LOG_RTP,
"[ProcessAudioData] dtmf payload, size[%u], TS[%u], diff[%d]", size,
mDtmfTimestamp, timestampDiff);
mRtpSession->SendRtpPacket(
mRtpTxDtmfPayload, data, size, mDtmfTimestamp, mMark, timestampDiff);
mMark = false;
}
}
else // MEDIASUBTYPE_RTPPAYLOAD
{
if (mDTMFMode == false)
{
currentTimestamp = ImsMediaTimer::GetTimeInMilliSeconds();
if (mPrevTimestamp == 0)
{
timeDiff = 0;
mPrevTimestamp = currentTimestamp;
}
else
{
timeDiff = ((currentTimestamp - mPrevTimestamp) + 5) / 20 * 20;
if (timeDiff > 20)
{
mPrevTimestamp = currentTimestamp;
}
else if (timeDiff == 0)
{
return false;
}
else
{
mPrevTimestamp += timeDiff;
}
}
RtpPacket* packet = new RtpPacket();
packet->rtpDataType = kRtpDataTypeNormal;
mCallback->SendEvent(
kCollectPacketInfo, kStreamRtpTx, reinterpret_cast<uint64_t>(packet));
timestampDiff = timeDiff * mSamplingRate;
IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[ProcessAudioData] size[%u], TS[%u], diff[%d]", size,
currentTimestamp, timestampDiff);
if (!mListRtpExtension.empty())
{
mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, currentTimestamp, mMark,
timestampDiff, &mListRtpExtension.front());
mListRtpExtension.pop_front();
}
else
{
mRtpSession->SendRtpPacket(
mRtpPayloadTx, data, size, currentTimestamp, mMark, timestampDiff);
}
if (mMark)
{
mMark = false;
}
}
}
return true;
}
void RtpEncoderNode::ProcessVideoData(
ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp, bool mark)
{
IMLOGD_PACKET4(IM_PACKET_LOG_RTP, "[ProcessVideoData] subtype[%d], size[%d], TS[%u], mark[%d]",
subtype, size, timestamp, mark);
#ifdef SIMULATE_VIDEO_CVO_UPDATE
const int64_t kCameraFacing = kCameraFacingFront;
static int64_t sDeviceOrientation = 0;
static int64_t sCount = 0;
if ((++sCount % 100) == 0)
{
SetCvoExtension(kCameraFacing, (sDeviceOrientation += 90) % 360);
}
#endif
if (mCvoValue > 0 && mark && subtype == MEDIASUBTYPE_VIDEO_IDR_FRAME)
{
mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, 0,
mListRtpExtension.empty() ? nullptr : &mListRtpExtension.front());
}
else
{
mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, 0);
}
}
void RtpEncoderNode::ProcessTextData(
ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp, bool mark)
{
IMLOGD_PACKET4(IM_PACKET_LOG_RTP,
"[ProcessTextData] subtype[%d], size[%d], timestamp[%d], mark[%d]", subtype, size,
timestamp, mark);
uint32_t timeDiff;
if (mMark == true)
{
timeDiff = 0;
}
else
{
timeDiff = timestamp - mPrevTimestamp;
}
if (subtype == MEDIASUBTYPE_BITSTREAM_T140)
{
if (mRedundantLevel > 1 && mRedundantPayload > 0)
{
mRtpSession->SendRtpPacket(mRedundantPayload, data, size, timestamp, mark, timeDiff);
}
else
{
mRtpSession->SendRtpPacket(mRtpPayloadRx, data, size, timestamp, mark, timeDiff);
}
}
else if (subtype == MEDIASUBTYPE_BITSTREAM_T140_RED)
{
mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, timeDiff);
}
mMark = false;
mPrevTimestamp = timestamp;
}