Merge pull request #1021 from secondlife/roxie/webrtc-voice-workqueue
WebRTC: Make callbacks from webrtc-proper launch workqueue jobs to run code on the main thread, instead of relying on mutexes and such.master
commit
6047b61b2a
|
|
@ -2901,15 +2901,29 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>creds</key>
|
||||
<string>github</string>
|
||||
<key>hash</key>
|
||||
<string>8b0191fae0860782a3e79b886364129c433cfd6b</string>
|
||||
<string>a49fb3bb8aaf8325e7c6c4b6036db3da16afa2c9</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://api.github.com/repos/secondlife/3p-webrtc-build/releases/assets/157215889</string>
|
||||
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.53/webrtc-m114.5735.08.53.8337236647-darwin64-8337236647.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>598baa054f63624a8e16883541c1f3dc7aa15a8a</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.53/webrtc-m114.5735.08.53.8337236647-linux64-8337236647.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
|
|
@ -2917,11 +2931,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>creds</key>
|
||||
<string>github</string>
|
||||
<key>hash</key>
|
||||
<string>64eccac933cee532dc065d9f9729a21d8347aae4</string>
|
||||
<string>59d5f2e40612ab7b0b1a5da8ba288f48d5979216</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://api.github.com/repos/secondlife/3p-webrtc-build/releases/assets/157215892</string>
|
||||
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.53/webrtc-m114.5735.08.53.8337236647-windows64-8337236647.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
|
|
@ -2934,7 +2948,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>vcs_url</key>
|
||||
<string>https://github.com/secondlife/3p-webrtc-build</string>
|
||||
<key>version</key>
|
||||
<string>m114.5735.08.52.8319849783</string>
|
||||
<string>m114.5735.08.53.8337236647</string>
|
||||
</map>
|
||||
<key>xmlrpc-epi</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -562,8 +562,10 @@ void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_conn
|
|||
// Most peer connection (signaling) happens on
|
||||
// the signaling thread.
|
||||
|
||||
LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
|
||||
LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
|
||||
mWebRTCImpl(nullptr),
|
||||
mClosing(false),
|
||||
mPeerConnection(nullptr),
|
||||
mMute(false),
|
||||
mAnswerReceived(false)
|
||||
{
|
||||
|
|
@ -580,13 +582,24 @@ void LLWebRTCPeerConnectionImpl::init(LLWebRTCImpl * webrtc_impl)
|
|||
}
|
||||
void LLWebRTCPeerConnectionImpl::terminate()
|
||||
{
|
||||
mWebRTCImpl->SignalingBlockingCall(
|
||||
[this]()
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection;
|
||||
mPeerConnection.swap(connection);
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel;
|
||||
mDataChannel.swap(dataChannel);
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> localStream;
|
||||
mLocalStream.swap(localStream);
|
||||
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[=]()
|
||||
{
|
||||
if (mPeerConnection)
|
||||
if (connection)
|
||||
{
|
||||
mPeerConnection->Close();
|
||||
mPeerConnection = nullptr;
|
||||
connection->Close();
|
||||
}
|
||||
if (dataChannel)
|
||||
{
|
||||
dataChannel->UnregisterObserver();
|
||||
dataChannel->Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -710,24 +723,9 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection()
|
|||
|
||||
bool LLWebRTCPeerConnectionImpl::shutdownConnection()
|
||||
{
|
||||
if (mPeerConnection)
|
||||
{
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this]()
|
||||
{
|
||||
if (mPeerConnection)
|
||||
{
|
||||
mPeerConnection->Close();
|
||||
mPeerConnection = nullptr;
|
||||
}
|
||||
for (auto &observer : mSignalingObserverList)
|
||||
{
|
||||
observer->OnPeerConnectionShutdown();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
mClosing = true;
|
||||
terminate();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable)
|
||||
|
|
@ -1057,14 +1055,16 @@ void LLWebRTCPeerConnectionImpl::OnSuccess(webrtc::SessionDescriptionInterface *
|
|||
}
|
||||
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << " Local SDP: " << sdp_mangled_stream.str();
|
||||
|
||||
std::string mangled_sdp = sdp_mangled_stream.str();
|
||||
for (auto &observer : mSignalingObserverList)
|
||||
{
|
||||
observer->OnOfferAvailable(sdp_mangled_stream.str());
|
||||
observer->OnOfferAvailable(mangled_sdp);
|
||||
}
|
||||
|
||||
mPeerConnection->SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface>(
|
||||
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, mangled_sdp)),
|
||||
rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface>(this));
|
||||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -192,9 +192,6 @@ class LLWebRTCSignalingObserver
|
|||
// Called when the data channel has been established and data
|
||||
// transfer can begin.
|
||||
virtual void OnDataChannelReady(LLWebRTCDataInterface *data_interface) = 0;
|
||||
|
||||
// Called when a peer connection has finished shutting down.
|
||||
virtual void OnPeerConnectionShutdown() = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -346,21 +346,23 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
|
|||
|
||||
LLWebRTCImpl * mWebRTCImpl;
|
||||
|
||||
bool mClosing;
|
||||
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
|
||||
|
||||
bool mMute;
|
||||
bool mMute;
|
||||
|
||||
// signaling
|
||||
std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList;
|
||||
std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList;
|
||||
std::vector<std::unique_ptr<webrtc::IceCandidateInterface>> mCachedIceCandidates;
|
||||
bool mAnswerReceived;
|
||||
bool mAnswerReceived;
|
||||
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> mLocalStream;
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> mLocalStream;
|
||||
|
||||
// data
|
||||
std::vector<LLWebRTCDataObserver *> mDataObserverList;
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
|
||||
std::vector<LLWebRTCDataObserver *> mDataObserverList;
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @file LLWebRTCVoiceClient.cpp
|
||||
* @file llvoicewebrtc.cpp
|
||||
* @brief Implementation of LLWebRTCVoiceClient class which is the interface to the voice client process.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
|
|
@ -585,8 +585,19 @@ void LLWebRTCVoiceClient::setDevicesListUpdated(bool state)
|
|||
mDevicesListUpdated = state;
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
|
||||
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices)
|
||||
// the singleton 'this' pointer will outlive the work queue.
|
||||
void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList& render_devices,
|
||||
const llwebrtc::LLWebRTCVoiceDeviceList& capture_devices)
|
||||
{
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=]
|
||||
{
|
||||
OnDevicesChangedImpl(render_devices, capture_devices);
|
||||
});
|
||||
}
|
||||
|
||||
void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
|
||||
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices)
|
||||
{
|
||||
std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
|
|
@ -1412,6 +1423,7 @@ void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled)
|
|||
updatePosition();
|
||||
if (!mIsCoroutineActive)
|
||||
{
|
||||
mMainQueue = LL::WorkQueue::getInstance("mainloop");
|
||||
LLCoros::instance().launch("LLWebRTCVoiceClient::voiceConnectionCoro",
|
||||
boost::bind(&LLWebRTCVoiceClient::voiceConnectionCoro, LLWebRTCVoiceClient::getInstance()));
|
||||
}
|
||||
|
|
@ -2000,6 +2012,7 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s
|
|||
|
||||
mWebRTCPeerConnectionInterface = llwebrtc::newPeerConnection();
|
||||
mWebRTCPeerConnectionInterface->setSignalingObserver(this);
|
||||
mMainQueue = LL::WorkQueue::getInstance("mainloop");
|
||||
}
|
||||
|
||||
LLVoiceWebRTCConnection::~LLVoiceWebRTCConnection()
|
||||
|
|
@ -2026,32 +2039,35 @@ LLVoiceWebRTCConnection::~LLVoiceWebRTCConnection()
|
|||
// negotiated, updates about the best connectivity paths may trickle in. These need to be
|
||||
// sent to the Secondlife WebRTC server via the simulator so that both sides have a clear
|
||||
// view of the network environment.
|
||||
|
||||
// callback from llwebrtc
|
||||
void LLVoiceWebRTCConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState state)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Ice Gathering voice account. " << state << LL_ENDL;
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=] {
|
||||
LL_DEBUGS("Voice") << "Ice Gathering voice account. " << state << LL_ENDL;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState::ICE_GATHERING_COMPLETE:
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
mIceCompleted = true;
|
||||
break;
|
||||
}
|
||||
case llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState::ICE_GATHERING_NEW:
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
mIceCompleted = false;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (state)
|
||||
{
|
||||
case llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState::ICE_GATHERING_COMPLETE:
|
||||
{
|
||||
mIceCompleted = true;
|
||||
break;
|
||||
}
|
||||
case llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState::ICE_GATHERING_NEW:
|
||||
{
|
||||
mIceCompleted = false;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate &candidate)
|
||||
// callback from llwebrtc
|
||||
void LLVoiceWebRTCConnection::OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate& candidate)
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
mIceCandidates.push_back(candidate);
|
||||
LL::WorkQueue::postMaybe(mMainQueue, [=] { mIceCandidates.push_back(candidate); });
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::onIceUpdateComplete(bool ice_completed, const LLSD &result)
|
||||
|
|
@ -2182,39 +2198,74 @@ void LLVoiceWebRTCConnection::processIceUpdates()
|
|||
// and is passed to the simulator via a CAP, which then passes
|
||||
// it on to the Secondlife WebRTC server.
|
||||
|
||||
//
|
||||
// The LLWebRTCVoiceConnection object will not be deleted
|
||||
// before the webrtc connection itself is shut down, so
|
||||
// we shouldn't be getting this callback on a nonexistant
|
||||
// this pointer.
|
||||
|
||||
// callback from llwebrtc
|
||||
void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "On Offer Available." << LL_ENDL;
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
mChannelSDP = sdp;
|
||||
if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START)
|
||||
{
|
||||
mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION;
|
||||
}
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=] {
|
||||
if (mShutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LL_DEBUGS("Voice") << "On Offer Available." << LL_ENDL;
|
||||
mChannelSDP = sdp;
|
||||
if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START)
|
||||
{
|
||||
mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Notifications from the webrtc library.
|
||||
void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface)
|
||||
|
||||
//
|
||||
// The LLWebRTCVoiceConnection object will not be deleted
|
||||
// before the webrtc connection itself is shut down, so
|
||||
// we shouldn't be getting this callback on a nonexistant
|
||||
// this pointer.
|
||||
// nor should audio_interface be invalid if the LLWebRTCVoiceConnection
|
||||
// is shut down.
|
||||
|
||||
// callback from llwebrtc
|
||||
void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface* audio_interface)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL;
|
||||
mWebRTCAudioInterface = audio_interface;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=] {
|
||||
if (mShutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL;
|
||||
mWebRTCAudioInterface = audio_interface;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The LLWebRTCVoiceConnection object will not be deleted
|
||||
// before the webrtc connection itself is shut down, so
|
||||
// we shouldn't be getting this callback on a nonexistant
|
||||
// this pointer.
|
||||
|
||||
// callback from llwebrtc
|
||||
void LLVoiceWebRTCConnection::OnRenegotiationNeeded()
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Voice channel requires renegotiation." << LL_ENDL;
|
||||
if (!mShutDown)
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
}
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=] {
|
||||
LL_DEBUGS("Voice") << "Voice channel requires renegotiation." << LL_ENDL;
|
||||
if (!mShutDown)
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::OnPeerConnectionShutdown()
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_EXIT);
|
||||
mOutstandingRequests--; // shut down is an async call which is handled on a webrtc thread.
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::setMuteMic(bool muted)
|
||||
{
|
||||
|
|
@ -2284,7 +2335,7 @@ void LLVoiceWebRTCConnection::sendData(const std::string &data)
|
|||
|
||||
// Tell the simulator that we're shutting down a voice connection.
|
||||
// The simulator will pass this on to the Secondlife WebRTC server.
|
||||
bool LLVoiceWebRTCConnection::breakVoiceConnection(bool corowait)
|
||||
void LLVoiceWebRTCConnection::breakVoiceConnection()
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Disconnecting voice." << LL_ENDL;
|
||||
if (mWebRTCDataInterface)
|
||||
|
|
@ -2297,96 +2348,53 @@ bool LLVoiceWebRTCConnection::breakVoiceConnection(bool corowait)
|
|||
if (!regionp || !regionp->capabilitiesReceived())
|
||||
{
|
||||
LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_EXIT);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url = regionp->getCapability("ProvisionVoiceAccountRequest");
|
||||
if (url.empty())
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Voice") << "region ready for voice break; url=" << url << LL_ENDL;
|
||||
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("parcelVoiceInfoRequest", httpPolicy));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
|
||||
LLVoiceWebRTCStats::getInstance()->provisionAttemptStart();
|
||||
LLSD body;
|
||||
body["logout"] = TRUE;
|
||||
body["viewer_session"] = mViewerSession;
|
||||
body["voice_server_type"] = REPORTED_VOICE_SERVER_TYPE;
|
||||
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess, this, _1),
|
||||
boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure, this, url, 3, body, _1));
|
||||
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(
|
||||
new LLCoreHttpUtil::HttpCoroutineAdapter("LLVoiceWebRTCAdHocConnection::breakVoiceConnection",
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
|
||||
httpOpts->setWantHeaders(true);
|
||||
|
||||
mOutstandingRequests++;
|
||||
return true;
|
||||
}
|
||||
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT);
|
||||
|
||||
void LLVoiceWebRTCConnection::OnVoiceDisconnectionRequestSuccess(const LLSD &result)
|
||||
{
|
||||
mOutstandingRequests--;
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// tell the server to shut down the connection as a courtesy.
|
||||
// shutdownConnection will drop the WebRTC connection which will
|
||||
// also shut things down.
|
||||
LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts);
|
||||
|
||||
if (mWebRTCPeerConnectionInterface)
|
||||
{
|
||||
if (mWebRTCPeerConnectionInterface->shutdownConnection())
|
||||
{
|
||||
mOutstandingRequests++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::OnVoiceDisconnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result)
|
||||
{
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
mOutstandingRequests--;
|
||||
return;
|
||||
}
|
||||
if (retries >= 0)
|
||||
{
|
||||
// retry a few times.
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess, this, _1),
|
||||
boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure, this, url, retries - 1, body, _1));
|
||||
return;
|
||||
}
|
||||
if (mWebRTCPeerConnectionInterface)
|
||||
{
|
||||
mOutstandingRequests++;
|
||||
mWebRTCPeerConnectionInterface->shutdownConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_EXIT);
|
||||
}
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_EXIT);
|
||||
|
||||
mOutstandingRequests--;
|
||||
}
|
||||
|
||||
|
||||
// Tell the simulator to tell the Secondlife WebRTC server that we want a voice
|
||||
// connection. The SDP is sent up as part of this, and the simulator will respond
|
||||
// with an 'answer' which is in the form of another SDP. The webrtc library
|
||||
// will use the offer and answer to negotiate the session.
|
||||
bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection()
|
||||
void LLVoiceWebRTCSpatialConnection::requestVoiceConnection()
|
||||
{
|
||||
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID);
|
||||
|
||||
|
|
@ -2394,13 +2402,15 @@ bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection()
|
|||
if (!regionp || !regionp->capabilitiesReceived())
|
||||
{
|
||||
LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL;
|
||||
return false;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url = regionp->getCapability("ProvisionVoiceAccountRequest");
|
||||
if (url.empty())
|
||||
{
|
||||
return false;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Voice") << "region ready for voice provisioning; url=" << url << LL_ENDL;
|
||||
|
|
@ -2410,7 +2420,6 @@ bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection()
|
|||
LLSD jsep;
|
||||
jsep["type"] = "offer";
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
jsep["sdp"] = mChannelSDP;
|
||||
}
|
||||
body["jsep"] = jsep;
|
||||
|
|
@ -2420,27 +2429,42 @@ bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection()
|
|||
}
|
||||
body["channel_type"] = "local";
|
||||
body["voice_server_type"] = WEBRTC_VOICE_SERVER_TYPE;
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(
|
||||
new LLCoreHttpUtil::HttpCoroutineAdapter("LLVoiceWebRTCAdHocConnection::requestVoiceConnection",
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestSuccess, this, _1),
|
||||
boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestFailure, this, url, 3, body, _1));
|
||||
httpOpts->setWantHeaders(true);
|
||||
mOutstandingRequests++;
|
||||
return true;
|
||||
LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts);
|
||||
|
||||
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnVoiceConnectionRequestSuccess(result);
|
||||
}
|
||||
mOutstandingRequests--;
|
||||
}
|
||||
|
||||
void LLVoiceWebRTCConnection::OnVoiceConnectionRequestSuccess(const LLSD &result)
|
||||
{
|
||||
mOutstandingRequests--;
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLVoiceWebRTCStats::getInstance()->provisionAttemptEnd(true);
|
||||
|
||||
if (result.has("viewer_session") && result.has("jsep") && result["jsep"].has("type") && result["jsep"]["type"] == "answer" &&
|
||||
if (result.has("viewer_session") &&
|
||||
result.has("jsep") &&
|
||||
result["jsep"].has("type") &&
|
||||
result["jsep"]["type"] == "answer" &&
|
||||
result["jsep"].has("sdp"))
|
||||
{
|
||||
mRemoteChannelSDP = result["jsep"]["sdp"].asString();
|
||||
|
|
@ -2455,35 +2479,9 @@ void LLVoiceWebRTCConnection::OnVoiceConnectionRequestSuccess(const LLSD &result
|
|||
|
||||
LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response"
|
||||
<< " channel sdp " << mRemoteChannelSDP << LL_ENDL;
|
||||
|
||||
mWebRTCPeerConnectionInterface->AnswerAvailable(mRemoteChannelSDP);
|
||||
}
|
||||
|
||||
|
||||
void LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result)
|
||||
{
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
mOutstandingRequests--;
|
||||
return;
|
||||
}
|
||||
if (retries >= 0)
|
||||
{
|
||||
LL_WARNS("Voice") << "Failure connecting to voice, retrying." << body << " RESULT: " << result << LL_ENDL;
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCConnection::OnVoiceConnectionRequestSuccess, this, _1),
|
||||
boost::bind(&LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure, this, url, retries - 1, body, _1));
|
||||
return;
|
||||
}
|
||||
LL_WARNS("Voice") << "Unable to connect voice." << body << " RESULT: " << result << LL_ENDL;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
mOutstandingRequests--;
|
||||
}
|
||||
|
||||
|
||||
// Primary state machine for negotiating a single voice connection to the
|
||||
// Secondlife WebRTC server.
|
||||
bool LLVoiceWebRTCConnection::connectionStateMachine()
|
||||
|
|
@ -2530,14 +2528,9 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
|
|||
// Ask the sim to ask the Secondlife WebRTC server for a connection to
|
||||
// a given voice channel. On completion, we'll move on to the
|
||||
// VOICE_STATE_SESSION_ESTABLISHED via a callback on a webrtc thread.
|
||||
if (!requestVoiceConnection())
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
}
|
||||
else
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_CONNECTION_WAIT);
|
||||
}
|
||||
setVoiceConnectionState(VOICE_STATE_CONNECTION_WAIT);
|
||||
LLCoros::getInstance()->launch("LLVoiceWebRTCConnection::requestVoiceConnectionCoro",
|
||||
boost::bind(&LLVoiceWebRTCConnection::requestVoiceConnectionCoro, this));
|
||||
break;
|
||||
|
||||
case VOICE_STATE_CONNECTION_WAIT:
|
||||
|
|
@ -2611,7 +2604,8 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
|
|||
break;
|
||||
|
||||
case VOICE_STATE_DISCONNECT:
|
||||
breakVoiceConnection(true);
|
||||
LLCoros::instance().launch("LLVoiceWebRTCConnection::breakVoiceConnection",
|
||||
boost::bind(&LLVoiceWebRTCConnection::breakVoiceConnection, this));
|
||||
break;
|
||||
|
||||
case VOICE_STATE_WAIT_FOR_EXIT:
|
||||
|
|
@ -2620,7 +2614,6 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
|
|||
case VOICE_STATE_SESSION_EXIT:
|
||||
{
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
if (!mShutDown)
|
||||
{
|
||||
mVoiceConnectionState = VOICE_STATE_START_SESSION;
|
||||
|
|
@ -2649,19 +2642,35 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
|
|||
}
|
||||
|
||||
// Data has been received on the webrtc data channel
|
||||
void LLVoiceWebRTCConnection::OnDataReceived(const std::string &data, bool binary)
|
||||
// incoming data will be a json structure (if it's not binary.) We may pack
|
||||
// binary for size reasons. Most of the keys in the json objects are
|
||||
// single or double characters for size reasons.
|
||||
// The primary element is:
|
||||
// An object where each key is an agent id. (in the future, we may allow
|
||||
// integer indices into an agentid list, populated on join commands. For size.
|
||||
// Each key will point to a json object with keys identifying what's updated.
|
||||
// 'p' - audio source power (level/volume) (int8 as int)
|
||||
// 'j' - object of join data (currently only a boolean 'p' marking a primary participant)
|
||||
// 'l' - boolean, always true if exists.
|
||||
// 'v' - boolean - voice activity has been detected.
|
||||
|
||||
// llwebrtc callback
|
||||
void LLVoiceWebRTCConnection::OnDataReceived(const std::string& data, bool binary)
|
||||
{
|
||||
// incoming data will be a json structure (if it's not binary.) We may pack
|
||||
// binary for size reasons. Most of the keys in the json objects are
|
||||
// single or double characters for size reasons.
|
||||
// The primary element is:
|
||||
// An object where each key is an agent id. (in the future, we may allow
|
||||
// integer indices into an agentid list, populated on join commands. For size.
|
||||
// Each key will point to a json object with keys identifying what's updated.
|
||||
// 'p' - audio source power (level/volume) (int8 as int)
|
||||
// 'j' - object of join data (currently only a boolean 'p' marking a primary participant)
|
||||
// 'l' - boolean, always true if exists.
|
||||
// 'v' - boolean - voice activity has been detected.
|
||||
LL::WorkQueue::postMaybe(mMainQueue, [=] { LLVoiceWebRTCConnection::OnDataReceivedImpl(data, binary); });
|
||||
}
|
||||
|
||||
//
|
||||
// The LLWebRTCVoiceConnection object will not be deleted
|
||||
// before the webrtc connection itself is shut down, so
|
||||
// we shouldn't be getting this callback on a nonexistant
|
||||
// this pointer.
|
||||
void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool binary)
|
||||
{
|
||||
if (mShutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (binary)
|
||||
{
|
||||
|
|
@ -2769,13 +2778,30 @@ void LLVoiceWebRTCConnection::OnDataReceived(const std::string &data, bool binar
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The LLWebRTCVoiceConnection object will not be deleted
|
||||
// before the webrtc connection itself is shut down, so
|
||||
// we shouldn't be getting this callback on a nonexistant
|
||||
// this pointer.
|
||||
// nor should data_interface be invalid if the LLWebRTCVoiceConnection
|
||||
// is shut down.
|
||||
|
||||
// llwebrtc callback
|
||||
void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface)
|
||||
{
|
||||
if (data_interface)
|
||||
{
|
||||
mWebRTCDataInterface = data_interface;
|
||||
mWebRTCDataInterface->setDataObserver(this);
|
||||
}
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=] {
|
||||
if (mShutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_interface)
|
||||
{
|
||||
mWebRTCDataInterface = data_interface;
|
||||
mWebRTCDataInterface->setDataObserver(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// tell the Secondlife WebRTC server that
|
||||
|
|
@ -2872,7 +2898,7 @@ LLVoiceWebRTCAdHocConnection::~LLVoiceWebRTCAdHocConnection()
|
|||
// as they go to a different set of Secondlife WebRTC servers.
|
||||
// They also require credentials for the given channels.
|
||||
// So, we have a separate requestVoiceConnection call.
|
||||
bool LLVoiceWebRTCAdHocConnection::requestVoiceConnection()
|
||||
void LLVoiceWebRTCAdHocConnection::requestVoiceConnection()
|
||||
{
|
||||
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID);
|
||||
|
||||
|
|
@ -2880,13 +2906,15 @@ bool LLVoiceWebRTCAdHocConnection::requestVoiceConnection()
|
|||
if (!regionp || !regionp->capabilitiesReceived())
|
||||
{
|
||||
LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL;
|
||||
return false;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url = regionp->getCapability("ProvisionVoiceAccountRequest");
|
||||
if (url.empty())
|
||||
{
|
||||
return false;
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
return;
|
||||
}
|
||||
|
||||
LLVoiceWebRTCStats::getInstance()->provisionAttemptStart();
|
||||
|
|
@ -2894,7 +2922,6 @@ bool LLVoiceWebRTCAdHocConnection::requestVoiceConnection()
|
|||
LLSD jsep;
|
||||
jsep["type"] = "offer";
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
jsep["sdp"] = mChannelSDP;
|
||||
}
|
||||
body["jsep"] = jsep;
|
||||
|
|
@ -2903,12 +2930,26 @@ bool LLVoiceWebRTCAdHocConnection::requestVoiceConnection()
|
|||
body["channel_type"] = "multiagent";
|
||||
body["voice_server_type"] = WEBRTC_VOICE_SERVER_TYPE;
|
||||
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(
|
||||
url,
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
body,
|
||||
boost::bind(&LLVoiceWebRTCAdHocConnection::OnVoiceConnectionRequestSuccess, this, _1),
|
||||
boost::bind(&LLVoiceWebRTCAdHocConnection::OnVoiceConnectionRequestFailure, this, url, 3, body, _1));
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(
|
||||
new LLCoreHttpUtil::HttpCoroutineAdapter("LLVoiceWebRTCAdHocConnection::requestVoiceConnection",
|
||||
LLCore::HttpRequest::DEFAULT_POLICY_ID));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
|
||||
httpOpts->setWantHeaders(true);
|
||||
mOutstandingRequests++;
|
||||
return true;
|
||||
LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts);
|
||||
|
||||
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnVoiceConnectionRequestSuccess(result);
|
||||
}
|
||||
mOutstandingRequests--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,8 @@ public:
|
|||
void OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
|
||||
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices) override;
|
||||
//@}
|
||||
|
||||
void OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
|
||||
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices);
|
||||
|
||||
struct participantState
|
||||
{
|
||||
|
|
@ -445,6 +446,8 @@ private:
|
|||
/// Clean up objects created during a voice session.
|
||||
void cleanUp();
|
||||
|
||||
LL::WorkQueue::weak_t mMainQueue;
|
||||
|
||||
bool mTuningMode;
|
||||
F32 mTuningMicGain;
|
||||
int mTuningSpeakerVolume;
|
||||
|
|
@ -585,7 +588,6 @@ class LLVoiceWebRTCConnection :
|
|||
void OnOfferAvailable(const std::string &sdp) override;
|
||||
void OnRenegotiationNeeded() override;
|
||||
void OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface) override;
|
||||
void OnPeerConnectionShutdown() override;
|
||||
//@}
|
||||
|
||||
/////////////////////////
|
||||
|
|
@ -596,6 +598,8 @@ class LLVoiceWebRTCConnection :
|
|||
void OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) override;
|
||||
//@}
|
||||
|
||||
void OnDataReceivedImpl(const std::string &data, bool binary);
|
||||
|
||||
void sendJoin();
|
||||
void sendData(const std::string &data);
|
||||
|
||||
|
|
@ -618,12 +622,10 @@ class LLVoiceWebRTCConnection :
|
|||
|
||||
void shutDown()
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
mShutDown = true;
|
||||
}
|
||||
|
||||
void OnVoiceConnectionRequestSuccess(const LLSD &body);
|
||||
void OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result);
|
||||
|
||||
protected:
|
||||
typedef enum e_voice_connection_state
|
||||
|
|
@ -644,11 +646,10 @@ class LLVoiceWebRTCConnection :
|
|||
} EVoiceConnectionState;
|
||||
|
||||
EVoiceConnectionState mVoiceConnectionState;
|
||||
LLMutex mVoiceStateMutex;
|
||||
LL::WorkQueue::weak_t mMainQueue;
|
||||
|
||||
void setVoiceConnectionState(EVoiceConnectionState new_voice_connection_state)
|
||||
{
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
|
||||
if (new_voice_connection_state & VOICE_STATE_SESSION_STOPPING)
|
||||
{
|
||||
// the new state is shutdown or restart.
|
||||
|
|
@ -666,19 +667,13 @@ class LLVoiceWebRTCConnection :
|
|||
}
|
||||
EVoiceConnectionState getVoiceConnectionState()
|
||||
{
|
||||
if (mVoiceStateMutex.isLocked())
|
||||
{
|
||||
LL_WARNS("Voice") << "LOCKED." << LL_ENDL;
|
||||
}
|
||||
LLMutexLock lock(&mVoiceStateMutex);
|
||||
return mVoiceConnectionState;
|
||||
}
|
||||
|
||||
virtual bool requestVoiceConnection() = 0;
|
||||
virtual void requestVoiceConnection() = 0;
|
||||
void requestVoiceConnectionCoro() { requestVoiceConnection(); }
|
||||
|
||||
bool breakVoiceConnection(bool wait);
|
||||
void OnVoiceDisconnectionRequestSuccess(const LLSD &body);
|
||||
void OnVoiceDisconnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result);
|
||||
void breakVoiceConnection();
|
||||
|
||||
LLUUID mRegionID;
|
||||
LLUUID mViewerSession;
|
||||
|
|
@ -725,7 +720,7 @@ class LLVoiceWebRTCSpatialConnection :
|
|||
|
||||
protected:
|
||||
|
||||
bool requestVoiceConnection() override;
|
||||
void requestVoiceConnection() override;
|
||||
|
||||
S32 mParcelLocalID;
|
||||
};
|
||||
|
|
@ -740,7 +735,7 @@ class LLVoiceWebRTCAdHocConnection : public LLVoiceWebRTCConnection
|
|||
bool isSpatial() override { return false; }
|
||||
|
||||
protected:
|
||||
bool requestVoiceConnection() override;
|
||||
void requestVoiceConnection() override;
|
||||
|
||||
std::string mCredentials;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue