Touch up parcel voice enable/disable.
parent
a60593164e
commit
a7509747b2
|
|
@ -86,7 +86,9 @@ void LLWebRTCImpl::init()
|
|||
mPlayoutDevice = 0;
|
||||
mRecordingDevice = 0;
|
||||
rtc::InitializeSSL();
|
||||
rtc::LogMessage::LogToDebug(rtc::LS_WARNING);
|
||||
rtc::LogMessage::LogToDebug(rtc::LS_NONE);
|
||||
rtc::LogMessage::SetLogToStderr(true);
|
||||
|
||||
mTaskQueueFactory = webrtc::CreateDefaultTaskQueueFactory();
|
||||
|
||||
mNetworkThread = rtc::Thread::CreateWithSocketServer();
|
||||
|
|
@ -98,7 +100,7 @@ void LLWebRTCImpl::init()
|
|||
mSignalingThread = rtc::Thread::Create();
|
||||
mSignalingThread->SetName("WebRTCSignalingThread", nullptr);
|
||||
mSignalingThread->Start();
|
||||
|
||||
|
||||
mWorkerThread->PostTask(
|
||||
[this]()
|
||||
{
|
||||
|
|
@ -466,93 +468,98 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection()
|
|||
RTC_DCHECK(!mPeerConnection);
|
||||
mAnswerReceived = false;
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration config;
|
||||
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
|
||||
webrtc::PeerConnectionInterface::IceServer server;
|
||||
server.uri = "stun:roxie-turn.staging.secondlife.io:3478";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun1.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun2.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun3.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun4.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
|
||||
webrtc::PeerConnectionDependencies pc_dependencies(this);
|
||||
auto error_or_peer_connection = mPeerConnectionFactory->CreatePeerConnectionOrError(config, std::move(pc_dependencies));
|
||||
if (error_or_peer_connection.ok())
|
||||
{
|
||||
mPeerConnection = std::move(error_or_peer_connection.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << "Error creating peer connection: " << error_or_peer_connection.error().message();
|
||||
return false;
|
||||
}
|
||||
|
||||
webrtc::DataChannelInit init;
|
||||
init.ordered = true;
|
||||
|
||||
auto data_channel_or_error = mPeerConnection->CreateDataChannelOrError("SLData", &init);
|
||||
if (data_channel_or_error.ok())
|
||||
{
|
||||
mDataChannel = std::move(data_channel_or_error.value());
|
||||
|
||||
mDataChannel->RegisterObserver(this);
|
||||
}
|
||||
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->signaling_state();
|
||||
|
||||
cricket::AudioOptions audioOptions;
|
||||
audioOptions.auto_gain_control = true;
|
||||
audioOptions.echo_cancellation = false; // incompatible with opus stereo
|
||||
audioOptions.noise_suppression = true;
|
||||
|
||||
mLocalStream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream");
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
|
||||
mPeerConnectionFactory->CreateAudioTrack("SLAudio", mPeerConnectionFactory->CreateAudioSource(audioOptions).get()));
|
||||
audio_track->set_enabled(true);
|
||||
mLocalStream->AddTrack(audio_track);
|
||||
|
||||
mPeerConnection->AddTrack(audio_track, {"SLStream"});
|
||||
|
||||
auto senders = mPeerConnection->GetSenders();
|
||||
|
||||
for (auto &sender : senders)
|
||||
{
|
||||
webrtc::RtpParameters params;
|
||||
webrtc::RtpCodecParameters codecparam;
|
||||
codecparam.name = "opus";
|
||||
codecparam.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||
codecparam.clock_rate = 48000;
|
||||
codecparam.num_channels = 2;
|
||||
codecparam.parameters["stereo"] = "1";
|
||||
codecparam.parameters["sprop-stereo"] = "1";
|
||||
params.codecs.push_back(codecparam);
|
||||
sender->SetParameters(params);
|
||||
}
|
||||
|
||||
auto receivers = mPeerConnection->GetReceivers();
|
||||
for (auto &receiver : receivers)
|
||||
{
|
||||
webrtc::RtpParameters params;
|
||||
webrtc::RtpCodecParameters codecparam;
|
||||
codecparam.name = "opus";
|
||||
codecparam.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||
codecparam.clock_rate = 48000;
|
||||
codecparam.num_channels = 2;
|
||||
codecparam.parameters["stereo"] = "1";
|
||||
codecparam.parameters["sprop-stereo"] = "1";
|
||||
params.codecs.push_back(codecparam);
|
||||
receiver->SetParameters(params);
|
||||
}
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions offerOptions;
|
||||
mPeerConnection->CreateOffer(this, offerOptions);
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this]()
|
||||
{
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration config;
|
||||
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
|
||||
webrtc::PeerConnectionInterface::IceServer server;
|
||||
server.uri = "stun:roxie-turn.staging.secondlife.io:3478";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun1.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun2.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun3.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
server.uri = "stun:stun4.l.google.com:19302";
|
||||
config.servers.push_back(server);
|
||||
|
||||
config.set_min_port(60000);
|
||||
config.set_max_port(60100);
|
||||
|
||||
webrtc::PeerConnectionDependencies pc_dependencies(this);
|
||||
auto error_or_peer_connection = mPeerConnectionFactory->CreatePeerConnectionOrError(config, std::move(pc_dependencies));
|
||||
if (error_or_peer_connection.ok())
|
||||
{
|
||||
mPeerConnection = std::move(error_or_peer_connection.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << "Error creating peer connection: " << error_or_peer_connection.error().message();
|
||||
return;
|
||||
}
|
||||
|
||||
webrtc::DataChannelInit init;
|
||||
init.ordered = true;
|
||||
|
||||
auto data_channel_or_error = mPeerConnection->CreateDataChannelOrError("SLData", &init);
|
||||
if (data_channel_or_error.ok())
|
||||
{
|
||||
mDataChannel = std::move(data_channel_or_error.value());
|
||||
|
||||
mDataChannel->RegisterObserver(this);
|
||||
}
|
||||
|
||||
cricket::AudioOptions audioOptions;
|
||||
audioOptions.auto_gain_control = true;
|
||||
audioOptions.echo_cancellation = false; // incompatible with opus stereo
|
||||
audioOptions.noise_suppression = true;
|
||||
|
||||
mLocalStream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream");
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
|
||||
mPeerConnectionFactory->CreateAudioTrack("SLAudio", mPeerConnectionFactory->CreateAudioSource(audioOptions).get()));
|
||||
audio_track->set_enabled(true);
|
||||
mLocalStream->AddTrack(audio_track);
|
||||
|
||||
mPeerConnection->AddTrack(audio_track, {"SLStream"});
|
||||
|
||||
auto senders = mPeerConnection->GetSenders();
|
||||
|
||||
for (auto &sender : senders)
|
||||
{
|
||||
webrtc::RtpParameters params;
|
||||
webrtc::RtpCodecParameters codecparam;
|
||||
codecparam.name = "opus";
|
||||
codecparam.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||
codecparam.clock_rate = 48000;
|
||||
codecparam.num_channels = 2;
|
||||
codecparam.parameters["stereo"] = "1";
|
||||
codecparam.parameters["sprop-stereo"] = "1";
|
||||
params.codecs.push_back(codecparam);
|
||||
sender->SetParameters(params);
|
||||
}
|
||||
|
||||
auto receivers = mPeerConnection->GetReceivers();
|
||||
for (auto &receiver : receivers)
|
||||
{
|
||||
webrtc::RtpParameters params;
|
||||
webrtc::RtpCodecParameters codecparam;
|
||||
codecparam.name = "opus";
|
||||
codecparam.kind = cricket::MEDIA_TYPE_AUDIO;
|
||||
codecparam.clock_rate = 48000;
|
||||
codecparam.num_channels = 2;
|
||||
codecparam.parameters["stereo"] = "1";
|
||||
codecparam.parameters["sprop-stereo"] = "1";
|
||||
params.codecs.push_back(codecparam);
|
||||
receiver->SetParameters(params);
|
||||
}
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions offerOptions;
|
||||
mPeerConnection->CreateOffer(this, offerOptions);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -839,7 +846,7 @@ void LLWebRTCPeerConnectionImpl::OnIceCandidate(const webrtc::IceCandidateInterf
|
|||
else
|
||||
{
|
||||
mCachedIceCandidates.push_back(
|
||||
webrtc::CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), candidate->candidate()));
|
||||
webrtc::CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), candidate->candidate()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -878,21 +885,16 @@ void LLWebRTCPeerConnectionImpl::OnSuccess(webrtc::SessionDescriptionInterface *
|
|||
sdp_mangled_stream << sdp_line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, sdp_mangled_stream.str());
|
||||
|
||||
|
||||
|
||||
mPeerConnection->SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface>(
|
||||
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, sdp_mangled_stream.str())),
|
||||
rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface>(this));
|
||||
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << " Local SDP: " << sdp_mangled_stream.str();
|
||||
|
||||
|
||||
|
||||
for (auto &observer : mSignalingObserverList)
|
||||
{
|
||||
observer->OnOfferAvailable(sdp_mangled_stream.str());
|
||||
}
|
||||
|
||||
mPeerConnection->SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface>(webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, sdp_mangled_stream.str())),
|
||||
rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface>(this));
|
||||
}
|
||||
|
||||
void LLWebRTCPeerConnectionImpl::OnFailure(webrtc::RTCError error) { RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message(); }
|
||||
|
|
@ -930,7 +932,6 @@ void LLWebRTCPeerConnectionImpl::OnSetRemoteDescriptionComplete(webrtc::RTCError
|
|||
//
|
||||
void LLWebRTCPeerConnectionImpl::OnSetLocalDescriptionComplete(webrtc::RTCError error)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -455,17 +455,29 @@ void LLWebRTCVoiceClient::idle(void* user_data)
|
|||
//
|
||||
//
|
||||
|
||||
void LLWebRTCVoiceClient::predProcessSessionStates(const LLWebRTCVoiceClient::sessionStatePtr_t& session)
|
||||
{
|
||||
session->processSessionStates();
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::sessionState::processSessionStates()
|
||||
{
|
||||
std::map<std::string, connectionPtr_t>::iterator iter;
|
||||
for (iter = mWebRTCConnections.begin(); iter != mWebRTCConnections.end();)
|
||||
auto iter = mSessions.begin();
|
||||
while (iter != mSessions.end())
|
||||
{
|
||||
if (!iter->second->connectionStateMachine())
|
||||
if (!iter->second->processConnectionStates())
|
||||
{
|
||||
iter = mSessions.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LLWebRTCVoiceClient::sessionState::processConnectionStates()
|
||||
{
|
||||
std::list<connectionPtr_t>::iterator iter = mWebRTCConnections.begin();
|
||||
|
||||
while (iter != mWebRTCConnections.end())
|
||||
{
|
||||
if (!iter->get()->connectionStateMachine())
|
||||
{
|
||||
iter = mWebRTCConnections.erase(iter);
|
||||
}
|
||||
|
|
@ -474,6 +486,7 @@ void LLWebRTCVoiceClient::sessionState::processSessionStates()
|
|||
++iter;
|
||||
}
|
||||
}
|
||||
return !mWebRTCConnections.empty();
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::voiceConnectionCoro()
|
||||
|
|
@ -488,33 +501,39 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
|
|||
llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
|
||||
// add session for region or parcel voice.
|
||||
LLViewerRegion *regionp = gAgent.getRegion();
|
||||
if (!regionp)
|
||||
if (!regionp || regionp->getRegionID().isNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (regionp->getRegionID().isNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (mVoiceEnabled && (!mAudioSession || mAudioSession->mIsSpatial))
|
||||
|
||||
if (mVoiceEnabled && (!mAudioSession || mAudioSession->isSpatial()) && !mNextAudioSession)
|
||||
{
|
||||
// check to see if parcel changed.
|
||||
std::string channelID = regionp->getRegionID().asString();
|
||||
|
||||
LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
|
||||
S32 parcel_local_id = INVALID_PARCEL_ID;
|
||||
if (parcel && parcel->getLocalID() != INVALID_PARCEL_ID && !parcel->getParcelFlagUseEstateVoiceChannel())
|
||||
if (parcel && parcel->getLocalID() != INVALID_PARCEL_ID)
|
||||
{
|
||||
parcel_local_id = parcel->getLocalID();
|
||||
channelID += "-" + std::to_string(parcel->getLocalID());
|
||||
if (!parcel->getParcelFlagAllowVoice())
|
||||
{
|
||||
channelID.clear();
|
||||
}
|
||||
else if (!parcel->getParcelFlagUseEstateVoiceChannel())
|
||||
{
|
||||
parcel_local_id = parcel->getLocalID();
|
||||
channelID += "-" + std::to_string(parcel->getLocalID());
|
||||
}
|
||||
}
|
||||
if (!mAudioSession || channelID != mAudioSession->mChannelID)
|
||||
|
||||
if ((mNextAudioSession && channelID != mNextAudioSession->mChannelID) ||
|
||||
(!mAudioSession && !channelID.empty()) ||
|
||||
(mAudioSession && channelID != mAudioSession->mChannelID))
|
||||
{
|
||||
setSpatialChannel(channelID, "", parcel_local_id);
|
||||
}
|
||||
}
|
||||
sessionState::for_each(boost::bind(predProcessSessionStates, _1));
|
||||
reapEmptySessions();
|
||||
sessionState::processSessionStates();
|
||||
if (mVoiceEnabled)
|
||||
{
|
||||
updatePosition();
|
||||
|
|
@ -829,7 +848,7 @@ void LLWebRTCVoiceClient::predUpdateOwnVolume(const LLWebRTCVoiceClient::session
|
|||
|
||||
void LLWebRTCVoiceClient::predSendData(const LLWebRTCVoiceClient::sessionStatePtr_t& session, const std::string& spatial_data, const std::string& volume_data)
|
||||
{
|
||||
if (session->mIsSpatial && !spatial_data.empty())
|
||||
if (session->isSpatial() && !spatial_data.empty())
|
||||
{
|
||||
session->sendData(spatial_data);
|
||||
}
|
||||
|
|
@ -843,7 +862,7 @@ void LLWebRTCVoiceClient::sessionState::sendData(const std::string &data)
|
|||
{
|
||||
for (auto& connection : mWebRTCConnections)
|
||||
{
|
||||
connection.second->sendData(data);
|
||||
connection->sendData(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -852,7 +871,7 @@ void LLWebRTCVoiceClient::sessionState::setMuteMic(bool muted)
|
|||
mMuted = muted;
|
||||
for (auto& connection : mWebRTCConnections)
|
||||
{
|
||||
connection.second->setMuteMic(muted);
|
||||
connection->setMuteMic(muted);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -861,7 +880,7 @@ void LLWebRTCVoiceClient::sessionState::setMicGain(F32 gain)
|
|||
mMicGain = gain;
|
||||
for (auto& connection : mWebRTCConnections)
|
||||
{
|
||||
connection.second->setMicGain(gain);
|
||||
connection->setMicGain(gain);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -870,7 +889,7 @@ void LLWebRTCVoiceClient::sessionState::setSpeakerVolume(F32 volume)
|
|||
mSpeakerVolume = volume;
|
||||
for (auto& connection : mWebRTCConnections)
|
||||
{
|
||||
connection.second->setSpeakerVolume(volume);
|
||||
connection->setSpeakerVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -878,52 +897,6 @@ void LLWebRTCVoiceClient::sendLocalAudioUpdates()
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
void LLWebRTCVoiceClient::joinedAudioSession(const sessionStatePtr_t &session)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Joined Audio Session" << LL_ENDL;
|
||||
if(mAudioSession != session)
|
||||
{
|
||||
sessionStatePtr_t oldSession = mAudioSession;
|
||||
|
||||
mAudioSession = session;
|
||||
mAudioSessionChanged = true;
|
||||
|
||||
// The old session may now need to be deleted.
|
||||
reapSession(oldSession);
|
||||
}
|
||||
|
||||
// This is the session we're joining.
|
||||
if(mIsJoiningSession)
|
||||
{
|
||||
LLSD WebRTCevent(LLSDMap("channel", session->mChannelID)
|
||||
("session", "joined"));
|
||||
|
||||
mWebRTCPump.post(WebRTCevent);
|
||||
|
||||
if(!session->mIsChannel)
|
||||
{
|
||||
// this is a p2p session. Make sure the other end is added as a participant.
|
||||
participantStatePtr_t participant(session->addParticipant(LLUUID(session->mChannelID)));
|
||||
if(participant)
|
||||
{
|
||||
if(participant->mAvatarIDValid)
|
||||
{
|
||||
lookupName(participant->mAvatarID);
|
||||
}
|
||||
else if(!session->mName.empty())
|
||||
{
|
||||
participant->mDisplayName = session->mName;
|
||||
avatarNameResolved(participant->mAvatarID, session->mName);
|
||||
}
|
||||
|
||||
// TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here?
|
||||
LL_INFOS("Voice") << "added caller as participant (" << participant->mAvatarID << ")"<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::reapSession(const sessionStatePtr_t &session)
|
||||
{
|
||||
if(session)
|
||||
|
|
@ -950,19 +923,6 @@ void LLWebRTCVoiceClient::reapSession(const sessionStatePtr_t &session)
|
|||
}
|
||||
|
||||
|
||||
void LLWebRTCVoiceClient::leftAudioSession(const sessionStatePtr_t &session)
|
||||
{
|
||||
if (mAudioSession == session)
|
||||
{
|
||||
LLSD WebRTCevent(LLSDMap("channel", session->mChannelID)
|
||||
("session", "removed"));
|
||||
|
||||
mWebRTCPump.post(WebRTCevent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LLWebRTCVoiceClient::muteListChanged()
|
||||
{
|
||||
// The user's mute list has been updated. Go through the current participant list and sync it with the mute list.
|
||||
|
|
@ -1215,149 +1175,47 @@ void LLWebRTCVoiceClient::removeParticipantByID(const std::string &channelID, co
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for parcel boundary crossing
|
||||
bool LLWebRTCVoiceClient::checkParcelChanged(bool update)
|
||||
bool LLWebRTCVoiceClient::switchChannel(const std::string channelID,
|
||||
sessionState::ESessionType session_type,
|
||||
S32 parcel_local_id)
|
||||
{
|
||||
LLViewerRegion *region = gAgent.getRegion();
|
||||
LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
|
||||
|
||||
if(region && parcel)
|
||||
{
|
||||
S32 parcelLocalID = parcel->getLocalID();
|
||||
std::string regionName = region->getName();
|
||||
|
||||
// LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
|
||||
|
||||
// The region name starts out empty and gets filled in later.
|
||||
// Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
|
||||
// If either is empty, wait for the next time around.
|
||||
if(!regionName.empty())
|
||||
{
|
||||
if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
|
||||
{
|
||||
// We have changed parcels. Initiate a parcel channel lookup.
|
||||
if (update)
|
||||
{
|
||||
mCurrentParcelLocalID = parcelLocalID;
|
||||
mCurrentRegionName = regionName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLWebRTCVoiceClient::switchChannel(
|
||||
const std::string channelID,
|
||||
bool spatial,
|
||||
bool no_reconnect,
|
||||
bool is_p2p,
|
||||
std::string hash,
|
||||
S32 parcel_local_id)
|
||||
{
|
||||
bool needsSwitch = false;
|
||||
|
||||
if (mAudioSession)
|
||||
{
|
||||
if (mSessionTerminateRequested)
|
||||
// If we're already in a channel, or if we're joining one, terminate
|
||||
// so we can rejoin with the new session data.
|
||||
sessionTerminate();
|
||||
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
|
||||
deleteSession(mAudioSession);
|
||||
}
|
||||
|
||||
if (channelID.empty())
|
||||
{
|
||||
// Leave any channel we may be in
|
||||
LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
|
||||
|
||||
if (mNextAudioSession)
|
||||
{
|
||||
// If a terminate has been requested, we need to compare against where the URI we're already headed to.
|
||||
if(mNextAudioSession)
|
||||
{
|
||||
if (mNextAudioSession->mChannelID != channelID)
|
||||
needsSwitch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mNextAudioSession is null -- this probably means we're on our way back to spatial.
|
||||
if (!channelID.empty())
|
||||
{
|
||||
// We do want to process a switch in this case.
|
||||
needsSwitch = true;
|
||||
}
|
||||
}
|
||||
deleteSession(mNextAudioSession);
|
||||
}
|
||||
else
|
||||
// If voice was on, turn it off
|
||||
if (LLVoiceClient::getInstance()->getUserPTTState())
|
||||
{
|
||||
// Otherwise, compare against the URI we're in now.
|
||||
if(mAudioSession)
|
||||
{
|
||||
if (mAudioSession->mChannelID != channelID)
|
||||
{
|
||||
needsSwitch = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!channelID.empty())
|
||||
{
|
||||
// mAudioSession is null -- it's not clear what case would cause this.
|
||||
// For now, log it as a warning and see if it ever crops up.
|
||||
LL_WARNS("Voice") << "No current audio session... Forcing switch" << LL_ENDL;
|
||||
needsSwitch = true;
|
||||
}
|
||||
}
|
||||
LLVoiceClient::getInstance()->setUserPTTState(false);
|
||||
}
|
||||
|
||||
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mNextAudioSession || mNextAudioSession->mChannelID != channelID)
|
||||
if (mNextAudioSession)
|
||||
{
|
||||
needsSwitch = true;
|
||||
deleteSession(mNextAudioSession);
|
||||
}
|
||||
LL_DEBUGS("Voice") << "switching to channel " << channelID << LL_ENDL;
|
||||
mNextAudioSession = addSession(channelID, parcel_local_id);
|
||||
mNextAudioSession->mSessionType = session_type;
|
||||
}
|
||||
|
||||
if(needsSwitch)
|
||||
{
|
||||
if (mAudioSession)
|
||||
{
|
||||
// If we're already in a channel, or if we're joining one, terminate
|
||||
// so we can rejoin with the new session data.
|
||||
sessionTerminate();
|
||||
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
|
||||
deleteSession(mAudioSession);
|
||||
}
|
||||
|
||||
if (channelID.empty())
|
||||
{
|
||||
// Leave any channel we may be in
|
||||
LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
|
||||
|
||||
if (mNextAudioSession)
|
||||
{
|
||||
mAudioSession->shutdownAllConnections();
|
||||
}
|
||||
sessionStatePtr_t oldSession = mNextAudioSession;
|
||||
mNextAudioSession.reset();
|
||||
|
||||
// The old session may now need to be deleted.
|
||||
reapSession(oldSession);
|
||||
|
||||
// If voice was on, turn it off
|
||||
if (LLVoiceClient::getInstance()->getUserPTTState())
|
||||
{
|
||||
LLVoiceClient::getInstance()->setUserPTTState(false);
|
||||
}
|
||||
|
||||
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mNextAudioSession)
|
||||
{
|
||||
deleteSession(mNextAudioSession);
|
||||
}
|
||||
LL_DEBUGS("Voice") << "switching to channel " << channelID << LL_ENDL;
|
||||
mNextAudioSession = addSession(channelID, parcel_local_id);
|
||||
mNextAudioSession->mIsSpatial = spatial;
|
||||
mNextAudioSession->mReconnect = !no_reconnect;
|
||||
mNextAudioSession->mIsP2P = is_p2p;
|
||||
}
|
||||
}
|
||||
|
||||
return needsSwitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::joinSession(const sessionStatePtr_t &session)
|
||||
|
|
@ -1376,7 +1234,7 @@ void LLWebRTCVoiceClient::setNonSpatialChannel(
|
|||
const std::string &uri,
|
||||
const std::string &credentials)
|
||||
{
|
||||
switchChannel(uri, false, false, false, credentials);
|
||||
switchChannel(uri, sessionState::SESSION_TYPE_P2P);
|
||||
}
|
||||
|
||||
bool LLWebRTCVoiceClient::setSpatialChannel(
|
||||
|
|
@ -1386,7 +1244,7 @@ bool LLWebRTCVoiceClient::setSpatialChannel(
|
|||
|
||||
LL_DEBUGS("Voice") << "got spatial channel uri: \"" << uri << "\"" << LL_ENDL;
|
||||
|
||||
if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial)))
|
||||
if((mAudioSession && !mAudioSession->isSpatial()) || (mNextAudioSession && !mNextAudioSession->isSpatial()))
|
||||
{
|
||||
// User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
|
||||
LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
|
||||
|
|
@ -1394,13 +1252,13 @@ bool LLWebRTCVoiceClient::setSpatialChannel(
|
|||
}
|
||||
else
|
||||
{
|
||||
return switchChannel(uri, true, false, false, "", parcel_local_id);
|
||||
return switchChannel(uri, parcel_local_id == INVALID_PARCEL_ID ? sessionState::SESSION_TYPE_ESTATE : sessionState::SESSION_TYPE_PARCEL, parcel_local_id);
|
||||
}
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::callUser(const LLUUID &uuid)
|
||||
{
|
||||
switchChannel(uuid.asString(), false, true, true);
|
||||
switchChannel(uuid.asString(), sessionState::SESSION_TYPE_P2P);
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::endUserIMSession(const LLUUID &uuid)
|
||||
|
|
@ -1419,9 +1277,7 @@ bool LLWebRTCVoiceClient::answerInvite(std::string &channelID)
|
|||
sessionStatePtr_t session(findP2PSession(LLUUID(channelID)));
|
||||
if(session)
|
||||
{
|
||||
session->mIsSpatial = false;
|
||||
session->mReconnect = false;
|
||||
session->mIsP2P = true;
|
||||
session->mSessionType = sessionState::ESessionType::SESSION_TYPE_P2P;
|
||||
|
||||
joinSession(session);
|
||||
return true;
|
||||
|
|
@ -1604,7 +1460,7 @@ bool LLWebRTCVoiceClient::inSpatialChannel(void)
|
|||
|
||||
if(mAudioSession)
|
||||
{
|
||||
result = mAudioSession->mIsSpatial;
|
||||
result = mAudioSession->isSpatial();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -2061,34 +1917,12 @@ BOOL LLWebRTCVoiceClient::getAreaVoiceDisabled()
|
|||
return mAreaVoiceDisabled;
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::reapEmptySessions()
|
||||
{
|
||||
sessionState::reapEmptySessions();
|
||||
|
||||
// mAudioSession or mNextAudioSession was reaped,
|
||||
// so reset them.
|
||||
if (mAudioSession && !sessionState::hasSession(mAudioSession->mChannelID))
|
||||
{
|
||||
mAudioSession.reset();
|
||||
}
|
||||
if (mNextAudioSession && !sessionState::hasSession(mNextAudioSession->mChannelID))
|
||||
{
|
||||
mNextAudioSession.reset();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
std::map<std::string, LLWebRTCVoiceClient::sessionState::ptr_t> LLWebRTCVoiceClient::sessionState::mSessions;
|
||||
|
||||
|
||||
LLWebRTCVoiceClient::sessionState::sessionState() :
|
||||
mErrorStatusCode(0),
|
||||
mIsChannel(false),
|
||||
mIsSpatial(false),
|
||||
mIsP2P(false),
|
||||
mIncoming(false),
|
||||
mVoiceActive(false),
|
||||
mReconnect(false),
|
||||
mVolumeDirty(false),
|
||||
mMuteDirty(false),
|
||||
mParticipantsChanged(false)
|
||||
|
|
@ -2102,8 +1936,7 @@ LLWebRTCVoiceClient::sessionState::ptr_t LLWebRTCVoiceClient::sessionState::crea
|
|||
|
||||
sessionState::ptr_t session(new sessionState());
|
||||
session->mChannelID = channelID;
|
||||
connectionPtr_t connection = connectionPtr_t(new LLVoiceWebRTCConnection(region_id, parcelLocalID, channelID));
|
||||
session->mWebRTCConnections[channelID] = connection;
|
||||
session->mWebRTCConnections.emplace_back(new LLVoiceWebRTCConnection(region_id, parcelLocalID, channelID));
|
||||
|
||||
session->mPrimaryConnectionID = channelID;
|
||||
|
||||
|
|
@ -2202,7 +2035,7 @@ void LLWebRTCVoiceClient::sessionState::for_eachPredicate(const std::pair<std::s
|
|||
LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::findP2PSession(const LLUUID &agent_id)
|
||||
{
|
||||
sessionStatePtr_t result = sessionState::matchSessionByChannelID(agent_id.asString());
|
||||
if (result && result->mIsP2P)
|
||||
if (result && result->mSessionType == sessionState::SESSION_TYPE_P2P)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
|
@ -2217,7 +2050,7 @@ void LLWebRTCVoiceClient::sessionState::shutdownAllConnections()
|
|||
{
|
||||
for (auto &&connection : mWebRTCConnections)
|
||||
{
|
||||
connection.second->shutDown();
|
||||
connection->shutDown();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2277,14 +2110,16 @@ void LLWebRTCVoiceClient::deleteSession(const sessionStatePtr_t &session)
|
|||
verifySessionState();
|
||||
session->shutdownAllConnections();
|
||||
// If this is the current audio session, clean up the pointer which will soon be dangling.
|
||||
if(mAudioSession == session)
|
||||
bool deleteAudioSession = mAudioSession == session;
|
||||
bool deleteNextAudioSession = mNextAudioSession == session;
|
||||
if (deleteAudioSession)
|
||||
{
|
||||
mAudioSession.reset();
|
||||
mAudioSessionChanged = true;
|
||||
}
|
||||
|
||||
// ditto for the next audio session
|
||||
if(mNextAudioSession == session)
|
||||
if (deleteNextAudioSession)
|
||||
{
|
||||
mNextAudioSession.reset();
|
||||
}
|
||||
|
|
@ -2696,73 +2531,68 @@ void LLVoiceWebRTCConnection::OnPeerShutDown()
|
|||
|
||||
void LLVoiceWebRTCConnection::processIceUpdates()
|
||||
{
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
if (mShutDown || LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (mShutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID);
|
||||
if (!regionp || !regionp->capabilitiesReceived())
|
||||
{
|
||||
LL_DEBUGS("Voice") << "no capabilities for ice gathering; waiting " << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url = regionp->getCapability("VoiceSignalingRequest");
|
||||
if (url.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Voice") << "region ready to complete voice signaling; url=" << url << LL_ENDL;
|
||||
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
|
||||
|
||||
bool iceCompleted = false;
|
||||
LLSD body;
|
||||
{
|
||||
if (!mTrickling)
|
||||
{
|
||||
if (mIceCandidates.size())
|
||||
if (!mIceCandidates.empty() || mIceCompleted)
|
||||
{
|
||||
LLSD candidates = LLSD::emptyArray();
|
||||
for (auto &ice_candidate : mIceCandidates)
|
||||
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID);
|
||||
if (!regionp || !regionp->capabilitiesReceived())
|
||||
{
|
||||
LLSD body_candidate;
|
||||
body_candidate["sdpMid"] = ice_candidate.sdp_mid;
|
||||
body_candidate["sdpMLineIndex"] = ice_candidate.mline_index;
|
||||
body_candidate["candidate"] = ice_candidate.candidate;
|
||||
candidates.append(body_candidate);
|
||||
LL_DEBUGS("Voice") << "no capabilities for ice gathering; waiting " << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
body["candidates"] = candidates;
|
||||
mIceCandidates.clear();
|
||||
|
||||
std::string url = regionp->getCapability("VoiceSignalingRequest");
|
||||
if (url.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Voice") << "region ready to complete voice signaling; url=" << url << LL_ENDL;
|
||||
if (!mIceCandidates.empty()) {
|
||||
LLSD candidates = LLSD::emptyArray();
|
||||
for (auto &ice_candidate : mIceCandidates)
|
||||
{
|
||||
LLSD body_candidate;
|
||||
body_candidate["sdpMid"] = ice_candidate.sdp_mid;
|
||||
body_candidate["sdpMLineIndex"] = ice_candidate.mline_index;
|
||||
body_candidate["candidate"] = ice_candidate.candidate;
|
||||
candidates.append(body_candidate);
|
||||
}
|
||||
body["candidates"] = candidates;
|
||||
mIceCandidates.clear();
|
||||
}
|
||||
else if (mIceCompleted)
|
||||
{
|
||||
LLSD body_candidate;
|
||||
body_candidate["completed"] = true;
|
||||
body["candidate"] = body_candidate;
|
||||
iceCompleted = mIceCompleted;
|
||||
mIceCompleted = false;
|
||||
}
|
||||
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(
|
||||
new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCConnection::onIceUpdateComplete, this, iceCompleted, _1),
|
||||
boost::bind(&LLVoiceWebRTCConnection::onIceUpdateError, this, 3, url, body, iceCompleted, _1));
|
||||
mOutstandingRequests++;
|
||||
mTrickling = true;
|
||||
}
|
||||
else if (mIceCompleted)
|
||||
{
|
||||
LLSD body_candidate;
|
||||
body_candidate["completed"] = true;
|
||||
body["candidate"] = body_candidate;
|
||||
iceCompleted = mIceCompleted;
|
||||
mIceCompleted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCConnection::onIceUpdateComplete, this, iceCompleted, _1),
|
||||
boost::bind(&LLVoiceWebRTCConnection::onIceUpdateError, this, 3, url, body, iceCompleted, _1));
|
||||
mOutstandingRequests++;
|
||||
mTrickling = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2862,7 +2692,7 @@ void LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure(std::string url, i
|
|||
}
|
||||
|
||||
bool LLVoiceWebRTCConnection::connectionStateMachine()
|
||||
{
|
||||
{
|
||||
processIceUpdates();
|
||||
|
||||
switch (getVoiceConnectionState())
|
||||
|
|
@ -2872,6 +2702,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
|
|||
if (mShutDown)
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_DISCONNECT);
|
||||
break;
|
||||
}
|
||||
mTrickling = false;
|
||||
mIceCompleted = false;
|
||||
|
|
|
|||
|
|
@ -330,7 +330,9 @@ public:
|
|||
bool isCallBackPossible();
|
||||
bool isTextIMPossible();
|
||||
|
||||
void processSessionStates();
|
||||
static void processSessionStates();
|
||||
|
||||
bool processConnectionStates();
|
||||
|
||||
void OnConnectionEstablished(const std::string &channelID);
|
||||
void OnConnectionFailure(const std::string &channelID);
|
||||
|
|
@ -347,6 +349,15 @@ public:
|
|||
|
||||
bool isEmpty() { return mWebRTCConnections.empty(); }
|
||||
|
||||
bool isSpatial() { return mSessionType == SESSION_TYPE_ESTATE || mSessionType == SESSION_TYPE_PARCEL; }
|
||||
|
||||
typedef enum e_session_type
|
||||
{
|
||||
SESSION_TYPE_ESTATE = 1,
|
||||
SESSION_TYPE_PARCEL,
|
||||
SESSION_TYPE_P2P
|
||||
} ESessionType;
|
||||
|
||||
std::string mHandle;
|
||||
std::string mGroupHandle;
|
||||
std::string mChannelID;
|
||||
|
|
@ -362,9 +373,8 @@ public:
|
|||
LLUUID mIMSessionID;
|
||||
LLUUID mCallerID;
|
||||
int mErrorStatusCode;
|
||||
bool mIsChannel; // True for both group and spatial channels (false for p2p, PSTN)
|
||||
bool mIsSpatial; // True for spatial channels
|
||||
bool mIsP2P;
|
||||
ESessionType mSessionType;
|
||||
|
||||
bool mIncoming;
|
||||
bool mVoiceActive;
|
||||
bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
|
||||
|
|
@ -381,16 +391,17 @@ public:
|
|||
LLUUID mVoiceFontID;
|
||||
|
||||
static void VerifySessions();
|
||||
static bool hasSession(const std::string &sessionID) { return mSessions.find(sessionID) != mSessions.end(); }
|
||||
static bool hasSession(const std::string &sessionID)
|
||||
{ return mSessions.find(sessionID) != mSessions.end(); }
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, connectionPtr_t> mWebRTCConnections;
|
||||
std::string mPrimaryConnectionID;
|
||||
std::list<connectionPtr_t> mWebRTCConnections;
|
||||
std::string mPrimaryConnectionID;
|
||||
static std::map<std::string, ptr_t> mSessions; // canonical list of outstanding sessions.
|
||||
|
||||
sessionState();
|
||||
|
||||
static std::map<std::string, ptr_t> mSessions; // canonical list of outstanding sessions.
|
||||
|
||||
static void for_eachPredicate(const std::pair<std::string, LLWebRTCVoiceClient::sessionState::wptr_t> &a, sessionFunc_t func);
|
||||
|
||||
|
|
@ -406,7 +417,6 @@ public:
|
|||
// Private Member Functions
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
static void predProcessSessionStates(const LLWebRTCVoiceClient::sessionStatePtr_t &session);
|
||||
static void predOnConnectionEstablished(const LLWebRTCVoiceClient::sessionStatePtr_t &session, std::string channelID);
|
||||
static void predOnConnectionFailure(const LLWebRTCVoiceClient::sessionStatePtr_t &session, std::string channelID);
|
||||
static void predSendData(const LLWebRTCVoiceClient::sessionStatePtr_t &session, const std::string& spatial_data, const std::string& volume_data);
|
||||
|
|
@ -415,7 +425,6 @@ public:
|
|||
static void predSetMicGain(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 volume);
|
||||
static void predSetSpeakerVolume(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 volume);
|
||||
static void predShutdownSession(const LLWebRTCVoiceClient::sessionStatePtr_t &session);
|
||||
void reapEmptySessions();
|
||||
|
||||
//////////////////////////////
|
||||
/// @name TVC/Server management and communication
|
||||
|
|
@ -476,9 +485,6 @@ public:
|
|||
|
||||
void verifySessionState(void);
|
||||
|
||||
void joinedAudioSession(const sessionStatePtr_t &session);
|
||||
void leftAudioSession(const sessionStatePtr_t &session);
|
||||
|
||||
// This is called in several places where the session _may_ need to be deleted.
|
||||
// It contains logic for whether to delete the session or keep it around.
|
||||
void reapSession(const sessionStatePtr_t &session);
|
||||
|
|
@ -596,12 +602,8 @@ private:
|
|||
bool mIsInitialized;
|
||||
bool mShutdownComplete;
|
||||
|
||||
bool checkParcelChanged(bool update = false);
|
||||
bool switchChannel(const std::string channelID,
|
||||
bool spatial = true,
|
||||
bool no_reconnect = false,
|
||||
bool is_p2p = false,
|
||||
std::string hash = "",
|
||||
sessionState::ESessionType sessionType,
|
||||
S32 parcel_local_id = INVALID_PARCEL_ID);
|
||||
void joinSession(const sessionStatePtr_t &session);
|
||||
|
||||
|
|
@ -808,6 +810,10 @@ protected:
|
|||
}
|
||||
EVoiceConnectionState getVoiceConnectionState()
|
||||
{
|
||||
if (mVoiceStateMutex.isLocked())
|
||||
{
|
||||
LL_WARNS("Voice") << "LOCKED." << LL_ENDL;
|
||||
}
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
return mVoiceConnectionState;
|
||||
}
|
||||
|
|
@ -839,6 +845,7 @@ protected:
|
|||
llwebrtc::LLWebRTCDataInterface *mWebRTCDataInterface;
|
||||
};
|
||||
|
||||
#define VOICE_ELAPSED LLVoiceTimer(__FUNCTION__);
|
||||
|
||||
#endif //LL_WebRTC_VOICE_CLIENT_H
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue