blob: c06ddc3834aa860428688fda0dd65e615a7bd364 [file] [log] [blame]
/**
* 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 <AudioSession.h>
#include <ImsMediaTrace.h>
#include <ImsMediaEventHandler.h>
#include <ImsMediaAudioUtil.h>
#include <AudioConfig.h>
#include <string>
AudioSession::AudioSession()
{
IMLOGD0("[AudioSession]");
std::unique_ptr<MediaQualityAnalyzer> analyzer(new MediaQualityAnalyzer());
mMediaQualityAnalyzer = std::move(analyzer);
mMediaQualityAnalyzer->setCallback(this);
}
AudioSession::~AudioSession()
{
IMLOGD0("[~AudioSession]");
mMediaQualityAnalyzer->stop();
while (mListGraphRtpTx.size() > 0)
{
AudioStreamGraphRtpTx* graph = mListGraphRtpTx.front();
if (graph->getState() == kStreamStateRunning)
{
graph->stop();
}
mListGraphRtpTx.pop_front();
delete graph;
}
while (mListGraphRtpRx.size() > 0)
{
AudioStreamGraphRtpRx* graph = mListGraphRtpRx.front();
if (graph->getState() == kStreamStateRunning)
{
graph->stop();
}
mListGraphRtpRx.pop_front();
delete graph;
}
while (mListGraphRtcp.size() > 0)
{
AudioStreamGraphRtcp* graph = mListGraphRtcp.front();
if (graph->getState() == kStreamStateRunning)
{
graph->stop();
}
mListGraphRtcp.pop_front();
delete graph;
}
}
SessionState AudioSession::getState()
{
SessionState state = kSessionStateOpened;
for (auto& graph : mListGraphRtpTx)
{
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
state = kSessionStateSending;
break;
}
}
for (auto& graph : mListGraphRtpRx)
{
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
return state == kSessionStateSending ? kSessionStateActive : kSessionStateReceiving;
}
}
for (auto& graph : mListGraphRtcp)
{
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
return state == kSessionStateSending ? kSessionStateSending : kSessionStateSuspended;
}
}
return state;
}
ImsMediaResult AudioSession::startGraph(RtpConfig* config)
{
IMLOGI0("[startGraph]");
if (config == nullptr)
{
return RESULT_INVALID_PARAM;
}
AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
if (std::strcmp(pConfig->getRemoteAddress().c_str(), "") == 0)
{
return RESULT_INVALID_PARAM;
}
IMLOGI1("[startGraph] state[%d]", getState());
if (mMediaQualityAnalyzer != nullptr)
{
mMediaQualityAnalyzer->setConfig(reinterpret_cast<AudioConfig*>(config));
mMediaQualityAnalyzer->start();
}
ImsMediaResult ret = RESULT_NOT_READY;
IMLOGD1("[startGraph] mListGraphRtpTx size[%d]", mListGraphRtpTx.size());
AudioStreamGraphRtpTx* graphTx = AudioStreamGraph::findGraph(mListGraphRtpTx,
[&config](AudioStreamGraphRtpTx* graph)
{
return graph != nullptr && graph->isSameGraph(config);
});
if (graphTx != nullptr)
{
ret = graphTx->update(config);
if (ret != RESULT_SUCCESS)
{
IMLOGE1("[startGraph] update error[%d]", ret);
return ret;
}
}
else
{
mListGraphRtpTx.push_back(new AudioStreamGraphRtpTx(this, mRtpFd));
if (mListGraphRtpTx.back()->create(config) == RESULT_SUCCESS)
{
ret = mListGraphRtpTx.back()->start();
if (ret != RESULT_SUCCESS)
{
IMLOGE1("[startGraph] start error[%d]", ret);
return ret;
}
}
}
IMLOGD1("[startGraph] ListGraphRtpRx size[%d]", mListGraphRtpRx.size());
AudioStreamGraphRtpRx* graphRx = AudioStreamGraph::findGraph(mListGraphRtpRx,
[&config](AudioStreamGraphRtpRx* graph)
{
return graph != nullptr && graph->isSameGraph(config);
});
if (graphRx != nullptr)
{
graphRx->setMediaQualityThreshold(&mThreshold);
ret = graphRx->update(config);
if (ret != RESULT_SUCCESS)
{
IMLOGE1("[startGraph] update error[%d]", ret);
return ret;
}
}
else
{
mListGraphRtpRx.push_back(new AudioStreamGraphRtpRx(this, mRtpFd));
if (mListGraphRtpRx.back()->create(config) == RESULT_SUCCESS)
{
mListGraphRtpRx.back()->setMediaQualityThreshold(&mThreshold);
ret = mListGraphRtpRx.back()->start();
if (ret != RESULT_SUCCESS)
{
IMLOGE1("[startGraph] start error[%d]", ret);
return ret;
}
}
}
IMLOGD1("[startGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size());
AudioStreamGraphRtcp* graphRtcp = AudioStreamGraph::findGraph(mListGraphRtcp,
[&config](AudioStreamGraphRtcp* graph)
{
return graph != nullptr && graph->isSameGraph(config);
});
if (graphRtcp != nullptr)
{
graphRtcp->setMediaQualityThreshold(&mThreshold);
ret = graphRtcp->update(config);
if (ret != RESULT_SUCCESS)
{
IMLOGE1("[startGraph] update error[%d]", ret);
return ret;
}
}
else
{
mListGraphRtcp.push_back(new AudioStreamGraphRtcp(this, mRtcpFd));
if (mListGraphRtcp.back()->create(config) == RESULT_SUCCESS)
{
mListGraphRtcp.back()->setMediaQualityThreshold(&mThreshold);
ret = mListGraphRtcp.back()->start();
if (ret != RESULT_SUCCESS)
{
IMLOGE1("[startGraph] start error[%d]", ret);
return ret;
}
}
}
return ret;
}
ImsMediaResult AudioSession::addGraph(RtpConfig* config, bool enableRtcp)
{
IMLOGD1("[addGraph], enable rtcp[%d]", enableRtcp);
if (config == nullptr || std::strcmp(config->getRemoteAddress().c_str(), "") == 0)
{
return RESULT_INVALID_PARAM;
}
if (IsGraphAlreadyExist(config) || mListGraphRtpTx.empty())
{
return startGraph(config);
}
if (enableRtcp) // update current graph to inactive mode
{
for (auto& graph : mListGraphRtpTx)
{
if (graph != nullptr)
{
graph->stop();
}
}
for (auto& graph : mListGraphRtpRx)
{
if (graph != nullptr)
{
graph->stop();
}
}
for (auto& graph : mListGraphRtcp)
{
if (graph != nullptr && graph->getState() != kStreamStateRunning)
{
graph->start();
}
}
return startGraph(config);
}
else
{
return confirmGraph(config);
}
}
ImsMediaResult AudioSession::confirmGraph(RtpConfig* config)
{
if (config == nullptr || std::strcmp(config->getRemoteAddress().c_str(), "") == 0)
{
return RESULT_INVALID_PARAM;
}
if (mListGraphRtpTx.empty() || mListGraphRtpRx.empty() || mListGraphRtcp.empty())
{
return startGraph(config);
}
/** Stop and delete unmatched running instances of StreamGraph. */
for (std::list<AudioStreamGraphRtpTx*>::iterator iter = mListGraphRtpTx.begin();
iter != mListGraphRtpTx.end();)
{
AudioStreamGraphRtpTx* graph = *iter;
if (graph != nullptr && !graph->isSameGraph(config))
{
graph->stop();
iter = mListGraphRtpTx.erase(iter);
delete graph;
}
else
{
iter++;
}
}
IMLOGD1("[confirmGraph] mListGraphTx size[%d]", mListGraphRtpTx.size());
for (std::list<AudioStreamGraphRtpRx*>::iterator iter = mListGraphRtpRx.begin();
iter != mListGraphRtpRx.end();)
{
AudioStreamGraphRtpRx* graph = *iter;
if (graph != nullptr && !graph->isSameGraph(config))
{
graph->stop();
iter = mListGraphRtpRx.erase(iter);
delete graph;
}
else
{
iter++;
}
}
IMLOGD1("[confirmGraph] mListGraphRx size[%d]", mListGraphRtpRx.size());
for (std::list<AudioStreamGraphRtcp*>::iterator iter = mListGraphRtcp.begin();
iter != mListGraphRtcp.end();)
{
AudioStreamGraphRtcp* graph = *iter;
if (graph != nullptr && !graph->isSameGraph(config))
{
graph->stop();
iter = mListGraphRtcp.erase(iter);
delete graph;
}
else
{
iter++;
}
}
IMLOGD1("[confirmGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size());
return startGraph(config);
}
ImsMediaResult AudioSession::deleteGraph(RtpConfig* config)
{
IMLOGI0("[deleteGraph]");
bool bFound = false;
for (std::list<AudioStreamGraphRtpTx*>::iterator iter = mListGraphRtpTx.begin();
iter != mListGraphRtpTx.end();)
{
AudioStreamGraphRtpTx* graph = *iter;
if (graph == nullptr)
{
continue;
}
if (graph->isSameGraph(config))
{
graph->stop();
iter = mListGraphRtpTx.erase(iter);
delete graph;
bFound = true;
break;
}
else
{
iter++;
}
}
if (bFound == false)
{
return RESULT_INVALID_PARAM;
}
IMLOGD1("[deleteGraph] mListGraphRtpTx size[%d]", mListGraphRtpTx.size());
for (std::list<AudioStreamGraphRtpRx*>::iterator iter = mListGraphRtpRx.begin();
iter != mListGraphRtpRx.end();)
{
AudioStreamGraphRtpRx* graph = *iter;
if (graph == nullptr)
{
continue;
}
if (graph->isSameGraph(config))
{
if (graph->getState() == kStreamStateRunning)
{
graph->stop();
}
iter = mListGraphRtpRx.erase(iter);
delete graph;
break;
}
else
{
iter++;
}
}
IMLOGD1("[deleteGraph] mListGraphRtpRx size[%d]", mListGraphRtpRx.size());
for (std::list<AudioStreamGraphRtcp*>::iterator iter = mListGraphRtcp.begin();
iter != mListGraphRtcp.end();)
{
AudioStreamGraphRtcp* graph = *iter;
if (graph == nullptr)
{
continue;
}
if (graph->isSameGraph(config))
{
if (graph->getState() == kStreamStateRunning)
{
graph->stop();
}
iter = mListGraphRtcp.erase(iter);
delete graph;
break;
}
else
{
iter++;
}
}
IMLOGD1("[deleteGraph] mListGraphRtcp size[%d]", mListGraphRtcp.size());
return RESULT_SUCCESS;
}
void AudioSession::onEvent(int32_t type, uint64_t param1, uint64_t param2)
{
switch (type)
{
case kImsMediaEventStateChanged:
if (mState != getState())
{
mState = getState();
}
break;
case kImsMediaEventNotifyError:
break;
case kImsMediaEventFirstPacketReceived:
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioFirstMediaPacketInd, mSessionId, param1, param2);
break;
case kImsMediaEventHeaderExtensionReceived:
ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioRtpHeaderExtensionInd,
mSessionId, param1, param2);
break;
case kImsMediaEventMediaQualityStatus:
ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioMediaQualityStatusInd,
mSessionId, param1, param2);
break;
case kAudioTriggerAnbrQueryInd:
/** TODO: add implementation */
break;
case kAudioDtmfReceivedInd:
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioDtmfReceivedInd, mSessionId, param1, param2);
break;
case kAudioCallQualityChangedInd:
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioCallQualityChangedInd, mSessionId, param1);
break;
case kRequestAudioCmr:
case kRequestAudioCmrEvs:
case kRequestSendRtcpXrReport:
ImsMediaEventHandler::SendEvent(
"AUDIO_REQUEST_EVENT", type, mSessionId, param1, param2);
break;
case kRequestRoundTripTimeDelayUpdate:
case kRequestAudioPlayingStatus:
case kCollectPacketInfo:
case kCollectOptionalInfo:
case kCollectRxRtpStatus:
case kCollectJitterBufferSize:
case kGetRtcpXrReportBlock:
if (mMediaQualityAnalyzer != nullptr)
{
mMediaQualityAnalyzer->SendEvent(type, param1, param2);
}
else
{
switch (type)
{
case kCollectRxRtpStatus:
case kCollectOptionalInfo:
if (param1)
{
delete reinterpret_cast<SessionCallbackParameter*>(param1);
}
break;
case kCollectPacketInfo:
if (param2)
{
delete reinterpret_cast<RtpPacket*>(param2);
}
break;
}
}
break;
default:
break;
}
}
void AudioSession::setMediaQualityThreshold(const MediaQualityThreshold& threshold)
{
IMLOGI0("[setMediaQualityThreshold]");
mThreshold = threshold;
if (mMediaQualityAnalyzer != nullptr)
{
mMediaQualityAnalyzer->setMediaQualityThreshold(threshold);
}
}
void AudioSession::sendDtmf(char digit, int duration)
{
if (mListGraphRtpTx.empty())
{
return;
}
for (std::list<AudioStreamGraphRtpTx*>::iterator iter = mListGraphRtpTx.begin();
iter != mListGraphRtpTx.end(); iter++)
{
AudioStreamGraphRtpTx* graph = *iter;
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
graph->sendDtmf(digit, duration);
}
}
}
bool AudioSession::IsGraphAlreadyExist(RtpConfig* config)
{
if (mListGraphRtpTx.size() != 0)
{
for (auto& graph : mListGraphRtpTx)
{
if (graph != nullptr && graph->isSameGraph(config))
{
return true;
}
}
}
return false;
}
uint32_t AudioSession::getGraphSize(ImsMediaStreamType type)
{
switch (type)
{
case kStreamRtpTx:
return mListGraphRtpTx.size();
case kStreamRtpRx:
return mListGraphRtpRx.size();
case kStreamRtcp:
return mListGraphRtcp.size();
}
return 0;
}
void AudioSession::sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension)
{
for (auto& graph : mListGraphRtpTx)
{
if (graph != nullptr)
{
graph->sendRtpHeaderExtension(listExtension);
}
}
}
void AudioSession::SendInternalEvent(int32_t type, uint64_t param1, uint64_t param2)
{
switch (type)
{
case kRequestAudioCmr:
case kRequestAudioCmrEvs:
for (std::list<AudioStreamGraphRtpTx*>::iterator iter = mListGraphRtpTx.begin();
iter != mListGraphRtpTx.end(); iter++)
{
AudioStreamGraphRtpTx* graph = *iter;
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
type == kRequestAudioCmr ? graph->processCmr(static_cast<uint32_t>(param1))
: graph->processCmr(static_cast<uint32_t>(param1),
static_cast<uint32_t>(param2));
}
}
if (type == kRequestAudioCmrEvs)
{
for (std::list<AudioStreamGraphRtpRx*>::iterator iter = mListGraphRtpRx.begin();
iter != mListGraphRtpRx.end(); iter++)
{
AudioStreamGraphRtpRx* graph = *iter;
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
graph->processCmr(
static_cast<uint32_t>(param1), static_cast<uint32_t>(param2));
}
}
}
break;
case kRequestSendRtcpXrReport:
for (std::list<AudioStreamGraphRtcp*>::iterator iter = mListGraphRtcp.begin();
iter != mListGraphRtcp.end(); iter++)
{
AudioStreamGraphRtcp* graph = *iter;
if (graph != nullptr && graph->getState() == kStreamStateRunning)
{
graph->OnEvent(type, param1, param2);
}
}
break;
default:
break;
}
}
bool AudioSession::deactivate()
{
IMLOGI0("[deactivate]");
for (auto& graph : mListGraphRtpTx)
{
if (graph != nullptr)
{
graph->stop();
}
}
for (auto& graph : mListGraphRtpRx)
{
if (graph != nullptr)
{
graph->stop();
}
}
SessionState state = getState();
if (state == kSessionStateActive || state == kSessionStateReceiving ||
state == kSessionStateSending)
{
return false;
}
return true;
}