summaryrefslogtreecommitdiff
path: root/indra/llwebrtc
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwebrtc')
-rw-r--r--indra/llwebrtc/CMakeLists.txt55
-rw-r--r--indra/llwebrtc/llwebrtc.cpp486
-rw-r--r--indra/llwebrtc/llwebrtc.h127
-rw-r--r--indra/llwebrtc/llwebrtc_impl.h177
4 files changed, 845 insertions, 0 deletions
diff --git a/indra/llwebrtc/CMakeLists.txt b/indra/llwebrtc/CMakeLists.txt
new file mode 100644
index 0000000000..c0e2520a22
--- /dev/null
+++ b/indra/llwebrtc/CMakeLists.txt
@@ -0,0 +1,55 @@
+# -*- cmake -*-
+
+# some webrtc headers require C++ 20
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+
+set(CMAKE_GENERATOR_TOOLSET "clang_cl_x64")
+
+include(00-Common)
+include(Linking)
+include(WebRTC)
+
+project(llwebrtc)
+
+message(STATUS "C Compiler executable: ${CMAKE_C_COMPILER}")
+message(STATUS "CXX Compiler executable: ${CMAKE_CXX_COMPILER}")
+message(STATUS "Linker executable: ${CMAKE_LINKER}")
+message(STATUS "SharedLib: ${SHARED_LIB_STAGING_DIR}")
+
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
+
+set(llwebrtc_SOURCE_FILES
+ llwebrtc.cpp
+ )
+
+set(llwebrtc_HEADER_FILES
+ CMakeLists.txt
+ llwebrtc.h
+ llwebrtc_impl.h
+ )
+
+list(APPEND llwebrtc_SOURCE_FILES ${llwebrtc_HEADER_FILES})
+
+add_library (llwebrtc SHARED ${llwebrtc_SOURCE_FILES})
+
+set_target_properties(llwebrtc PROPERTIES PUBLIC_HEADER llwebrtc.h)
+
+target_link_libraries(llwebrtc PRIVATE ll::webrtc
+ secur32
+ winmm
+ dmoguids
+ wmcodecdspuuid
+ msdmo
+ strmiids
+ iphlpapi)
+target_include_directories( llwebrtc INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+
+set_property(TARGET llwebrtc PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDebug")
+
+install(TARGETS llwebrtc RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/sharedlibs/RelWithDebInfo")
+
+# Add tests
+if (LL_TESTS)
+endif (LL_TESTS)
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
new file mode 100644
index 0000000000..5e71a00b60
--- /dev/null
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -0,0 +1,486 @@
+/**
+ * @file llaccordionctrl.cpp
+ * @brief Accordion panel implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llwebrtc_impl.h"
+#include <algorithm>
+
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "api/media_stream_interface.h"
+#include "api/media_stream_track.h"
+
+namespace llwebrtc
+{
+
+void LLWebRTCImpl::init()
+{
+ mAnswerReceived = false;
+ rtc::InitializeSSL();
+ mTaskQueueFactory = webrtc::CreateDefaultTaskQueueFactory();
+
+ mNetworkThread = rtc::Thread::CreateWithSocketServer();
+ mNetworkThread->SetName("WebRTCNetworkThread", nullptr);
+ mNetworkThread->Start();
+ mWorkerThread = rtc::Thread::Create();
+ mWorkerThread->SetName("WebRTCWorkerThread", nullptr);
+ mWorkerThread->Start();
+ mSignalingThread = rtc::Thread::Create();
+ mSignalingThread->SetName("WebRTCSignalingThread", nullptr);
+ mSignalingThread->Start();
+
+ mSignalingThread->PostTask(
+ [this]()
+ {
+ mDeviceModule = webrtc::CreateAudioDeviceWithDataObserver(webrtc::AudioDeviceModule::AudioLayer::kPlatformDefaultAudio,
+ mTaskQueueFactory.get(),
+ std::unique_ptr<webrtc::AudioDeviceDataObserver>(this));
+ mDeviceModule->Init();
+ updateDevices();
+ });
+}
+
+void LLWebRTCImpl::refreshDevices()
+{
+ mSignalingThread->PostTask([this]() { updateDevices(); });
+}
+
+void LLWebRTCImpl::setDevicesObserver(LLWebRTCDevicesObserver *observer) { mVoiceDevicesObserverList.emplace_back(observer); }
+
+void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
+{
+ std::vector<LLWebRTCDevicesObserver *>::iterator it =
+ std::find(mVoiceDevicesObserverList.begin(), mVoiceDevicesObserverList.end(), observer);
+ if (it != mVoiceDevicesObserverList.end())
+ {
+ mVoiceDevicesObserverList.erase(it);
+ }
+}
+
+void LLWebRTCImpl::setCaptureDevice(const std::string &id)
+{
+ mSignalingThread->PostTask(
+ [this, id]()
+ {
+ int16_t captureDeviceCount = mDeviceModule->RecordingDevices();
+ for (int16_t index = 0; index < captureDeviceCount; index++)
+ {
+ char name[webrtc::kAdmMaxDeviceNameSize];
+ char guid[webrtc::kAdmMaxGuidSize];
+ mDeviceModule->RecordingDeviceName(index, name, guid);
+ if (id == guid || id == name)
+ {
+ mDeviceModule->SetRecordingDevice(index);
+ break;
+ }
+ }
+ });
+}
+
+void LLWebRTCImpl::setRenderDevice(const std::string &id)
+{
+ mSignalingThread->PostTask(
+ [this, id]()
+ {
+ int16_t renderDeviceCount = mDeviceModule->RecordingDevices();
+ for (int16_t index = 0; index < renderDeviceCount; index++)
+ {
+ char name[webrtc::kAdmMaxDeviceNameSize];
+ char guid[webrtc::kAdmMaxGuidSize];
+ mDeviceModule->PlayoutDeviceName(index, name, guid);
+ if (id == guid || id == name)
+ {
+ mDeviceModule->SetPlayoutDevice(index);
+ break;
+ }
+ }
+ });
+}
+
+void LLWebRTCImpl::updateDevices()
+{
+ int16_t renderDeviceCount = mDeviceModule->PlayoutDevices();
+ LLWebRTCVoiceDeviceList renderDeviceList;
+ for (int16_t index = 0; index < renderDeviceCount; index++)
+ {
+ char name[webrtc::kAdmMaxDeviceNameSize];
+ char guid[webrtc::kAdmMaxGuidSize];
+ mDeviceModule->PlayoutDeviceName(index, name, guid);
+ renderDeviceList.emplace_back(name, guid);
+ }
+ for (auto &observer : mVoiceDevicesObserverList)
+ {
+ observer->OnRenderDevicesChanged(renderDeviceList);
+ }
+
+ int16_t captureDeviceCount = mDeviceModule->RecordingDevices();
+ LLWebRTCVoiceDeviceList captureDeviceList;
+ for (int16_t index = 0; index < captureDeviceCount; index++)
+ {
+ char name[webrtc::kAdmMaxDeviceNameSize];
+ char guid[webrtc::kAdmMaxGuidSize];
+ mDeviceModule->RecordingDeviceName(index, name, guid);
+ captureDeviceList.emplace_back(name, guid);
+ }
+ for (auto &observer : mVoiceDevicesObserverList)
+ {
+ observer->OnCaptureDevicesChanged(captureDeviceList);
+ }
+}
+
+void LLWebRTCImpl::setTuningMode(bool enable)
+{
+ mSignalingThread->PostTask(
+ [this, enable]()
+ {
+ if (enable)
+ {
+ mDeviceModule->InitMicrophone();
+ mDeviceModule->InitRecording();
+ mDeviceModule->StartRecording();
+ mDeviceModule->SetMicrophoneMute(false);
+ }
+ else
+ {
+ mDeviceModule->StopRecording();
+ }
+ });
+}
+
+double LLWebRTCImpl::getTuningMicrophoneEnergy() { return mTuningEnergy; }
+
+void LLWebRTCImpl::OnCaptureData(const void *audio_samples,
+ const size_t num_samples,
+ const size_t bytes_per_sample,
+ const size_t num_channels,
+ const uint32_t samples_per_sec)
+{
+ if (bytes_per_sample != 4)
+ {
+ return;
+ }
+
+ double energy = 0;
+ const short *samples = (const short *) audio_samples;
+ for (size_t index = 0; index < num_samples * num_channels; index++)
+ {
+ double sample = (static_cast<double>(samples[index]) / (double) 32768);
+ energy += sample * sample;
+ }
+ mTuningEnergy = std::sqrt(energy);
+}
+
+void LLWebRTCImpl::OnRenderData(const void *audio_samples,
+ const size_t num_samples,
+ const size_t bytes_per_sample,
+ const size_t num_channels,
+ const uint32_t samples_per_sec)
+{
+}
+
+//
+// LLWebRTCSignalInterface
+//
+
+void LLWebRTCImpl::setSignalingObserver(LLWebRTCSignalingObserver *observer) { mSignalingObserverList.emplace_back(observer); }
+
+void LLWebRTCImpl::unsetSignalingObserver(LLWebRTCSignalingObserver *observer)
+{
+ std::vector<LLWebRTCSignalingObserver *>::iterator it =
+ std::find(mSignalingObserverList.begin(), mSignalingObserverList.end(), observer);
+ if (it != mSignalingObserverList.end())
+ {
+ mSignalingObserverList.erase(it);
+ }
+}
+
+bool LLWebRTCImpl::initializeConnection()
+{
+ RTC_DCHECK(!mPeerConnection);
+ RTC_DCHECK(!mPeerConnectionFactory);
+ mAnswerReceived = false;
+ mPeerConnectionFactory = webrtc::CreatePeerConnectionFactory(mNetworkThread.get(),
+ mWorkerThread.get(),
+ mSignalingThread.get(),
+ nullptr /* default_adm */,
+ webrtc::CreateBuiltinAudioEncoderFactory(),
+ webrtc::CreateBuiltinAudioDecoderFactory(),
+ nullptr /* video_encoder_factory */,
+ nullptr /* video_decoder_factory */,
+ nullptr /* audio_mixer */,
+ nullptr /* audio_processing */);
+
+ if (!mPeerConnectionFactory)
+ {
+ shutdownConnection();
+ return false;
+ }
+
+ webrtc::PeerConnectionInterface::RTCConfiguration config;
+ config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
+ webrtc::PeerConnectionInterface::IceServer 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
+ {
+ shutdownConnection();
+ return false;
+ }
+
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->signaling_state();
+
+ cricket::AudioOptions audioOptions;
+ audioOptions.auto_gain_control = true;
+ audioOptions.echo_cancellation = true;
+ audioOptions.noise_suppression = true;
+
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream");
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ mPeerConnectionFactory->CreateAudioTrack("SLAudio", mPeerConnectionFactory->CreateAudioSource(cricket::AudioOptions()).get()));
+ audio_track->set_enabled(true);
+ stream->AddTrack(audio_track);
+
+ mPeerConnection->AddTrack(audio_track, {"SLStream"});
+ mPeerConnection->SetLocalDescription(rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface>(this));
+
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->signaling_state();
+
+ return mPeerConnection != nullptr;
+}
+
+void LLWebRTCImpl::shutdownConnection()
+{
+ mPeerConnection = nullptr;
+ mPeerConnectionFactory = nullptr;
+}
+
+void LLWebRTCImpl::AnswerAvailable(const std::string &sdp)
+{
+ mSignalingThread->PostTask(
+ [this, sdp]()
+ {
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->peer_connection_state();
+ mPeerConnection->SetRemoteDescription(webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp),
+ rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface>(this));
+ mAnswerReceived = true;
+ for (auto &observer : mSignalingObserverList)
+ {
+ for (auto &candidate : mCachedIceCandidates)
+ {
+ LLWebRTCIceCandidate ice_candidate;
+ ice_candidate.candidate = candidate->candidate().ToString();
+ ice_candidate.mline_index = candidate->sdp_mline_index();
+ ice_candidate.sdp_mid = candidate->sdp_mid();
+ observer->OnIceCandidate(ice_candidate);
+ }
+ mCachedIceCandidates.clear();
+ if (mPeerConnection->ice_gathering_state() == webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringComplete)
+ {
+ for (auto &observer : mSignalingObserverList)
+ {
+ observer->OnIceGatheringState(llwebrtc::LLWebRTCSignalingObserver::IceGatheringState::ICE_GATHERING_COMPLETE);
+ }
+ }
+ }
+ });
+}
+
+void LLWebRTCImpl::setMute(bool mute)
+{
+ mSignalingThread->PostTask(
+ [this,mute]()
+ {
+ auto senders = mPeerConnection->GetSenders();
+
+ RTC_LOG(LS_INFO) << __FUNCTION__ << (mute ? "disabling" : "enabling") << " streams count "
+ << senders.size();
+
+ for (auto& sender : senders)
+ {
+ sender->track()->set_enabled(!mute);
+ }
+ });
+}
+
+//
+// PeerConnectionObserver implementation.
+//
+
+void LLWebRTCImpl::OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
+ const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams)
+{
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << receiver->id();
+}
+
+void LLWebRTCImpl::OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)
+{
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << receiver->id();
+}
+
+void LLWebRTCImpl::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state)
+{
+ LLWebRTCSignalingObserver::IceGatheringState webrtc_new_state = LLWebRTCSignalingObserver::IceGatheringState::ICE_GATHERING_NEW;
+ switch (new_state)
+ {
+ case webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringNew:
+ webrtc_new_state = LLWebRTCSignalingObserver::IceGatheringState::ICE_GATHERING_NEW;
+ break;
+ case webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringGathering:
+ webrtc_new_state = LLWebRTCSignalingObserver::IceGatheringState::ICE_GATHERING_GATHERING;
+ break;
+ case webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringComplete:
+ webrtc_new_state = LLWebRTCSignalingObserver::IceGatheringState::ICE_GATHERING_COMPLETE;
+ break;
+ default:
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << " Bad Ice Gathering State" << new_state;
+ webrtc_new_state = LLWebRTCSignalingObserver::IceGatheringState::ICE_GATHERING_NEW;
+ return;
+ }
+
+ if (mAnswerReceived)
+ {
+ for (auto &observer : mSignalingObserverList)
+ {
+ observer->OnIceGatheringState(webrtc_new_state);
+ }
+ }
+}
+
+// Called any time the PeerConnectionState changes.
+void LLWebRTCImpl::OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state)
+{
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << " Peer Connection State Change " << new_state;
+}
+
+void LLWebRTCImpl::OnIceCandidate(const webrtc::IceCandidateInterface *candidate)
+{
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
+
+ if (!candidate)
+ {
+ RTC_LOG(LS_ERROR) << __FUNCTION__ << " No Ice Candidate Given";
+ return;
+ }
+ if (mAnswerReceived)
+ {
+ for (auto &observer : mSignalingObserverList)
+ {
+ LLWebRTCIceCandidate ice_candidate;
+ ice_candidate.candidate = candidate->candidate().ToString();
+ ice_candidate.mline_index = candidate->sdp_mline_index();
+ ice_candidate.sdp_mid = candidate->sdp_mid();
+ observer->OnIceCandidate(ice_candidate);
+ }
+ }
+ else
+ {
+ mCachedIceCandidates.push_back(
+ webrtc::CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), candidate->candidate()));
+ }
+}
+
+//
+// CreateSessionDescriptionObserver implementation.
+//
+void LLWebRTCImpl::OnSuccess(webrtc::SessionDescriptionInterface *desc)
+{
+ std::string sdp;
+ desc->ToString(&sdp);
+ RTC_LOG(LS_INFO) << sdp;
+
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->signaling_state();
+ for (auto &observer : mSignalingObserverList)
+ {
+ observer->OnOfferAvailable(sdp);
+ }
+}
+
+void LLWebRTCImpl::OnFailure(webrtc::RTCError error) { RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message(); }
+
+//
+// SetRemoteDescriptionObserverInterface implementation.
+//
+void LLWebRTCImpl::OnSetRemoteDescriptionComplete(webrtc::RTCError error)
+{
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->signaling_state();
+ if (!error.ok())
+ {
+ RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message();
+ return;
+ }
+ for (auto &observer : mSignalingObserverList)
+ {
+ observer->OnAudioEstablished(this);
+ }
+}
+
+//
+// SetLocalDescriptionObserverInterface implementation.
+//
+void LLWebRTCImpl::OnSetLocalDescriptionComplete(webrtc::RTCError error)
+{
+ RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->signaling_state();
+ if (!error.ok())
+ {
+ RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message();
+ return;
+ }
+ auto desc = mPeerConnection->pending_local_description();
+ std::string sdp;
+ desc->ToString(&sdp);
+ for (auto &observer : mSignalingObserverList)
+ {
+ observer->OnOfferAvailable(sdp);
+ }
+}
+
+rtc::RefCountedObject<LLWebRTCImpl> *gWebRTCImpl = nullptr;
+LLWebRTCDeviceInterface *getDeviceInterface() { return gWebRTCImpl; }
+LLWebRTCSignalInterface *getSignalingInterface() { return gWebRTCImpl; }
+
+void init()
+{
+ gWebRTCImpl = new rtc::RefCountedObject<LLWebRTCImpl>();
+ gWebRTCImpl->AddRef();
+ gWebRTCImpl->init();
+}
+} // namespace llwebrtc \ No newline at end of file
diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h
new file mode 100644
index 0000000000..121efaab86
--- /dev/null
+++ b/indra/llwebrtc/llwebrtc.h
@@ -0,0 +1,127 @@
+/**
+ * @file llaccordionctrl.cpp
+ * @brief Accordion panel implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLWEBRTC_H
+#define LLWEBRTC_H
+
+#include <string>
+#include <vector>
+
+#ifdef LL_MAKEDLL
+#ifdef WEBRTC_WIN
+#define LLSYMEXPORT __declspec(dllexport)
+#elif WEBRTC_LINUX
+#define LLSYMEXPORT __attribute__((visibility("default")))
+#else
+#define LLSYMEXPORT /**/
+#endif
+#else
+#define LLSYMEXPORT /**/
+#endif // LL_MAKEDLL
+
+namespace llwebrtc
+{
+LLSYMEXPORT void init();
+
+struct LLWebRTCIceCandidate
+{
+ std::string candidate;
+ std::string sdp_mid;
+ int mline_index;
+};
+
+class LLWebRTCVoiceDevice
+{
+ public:
+ std::string display_name; // friendly value for the user
+ std::string id; // internal value for selection
+
+ LLWebRTCVoiceDevice(const std::string &display_name, const std::string &id) :
+ display_name(display_name),
+ id(id) {};
+};
+
+typedef std::vector<LLWebRTCVoiceDevice> LLWebRTCVoiceDeviceList;
+
+class LLWebRTCDevicesObserver
+{
+ public:
+ virtual void OnRenderDevicesChanged(const LLWebRTCVoiceDeviceList &render_devices) = 0;
+ virtual void OnCaptureDevicesChanged(const LLWebRTCVoiceDeviceList &capture_devices) = 0;
+};
+
+class LLWebRTCDeviceInterface
+{
+ public:
+
+ virtual void refreshDevices() = 0;
+
+ virtual void setCaptureDevice(const std::string& id) = 0;
+ virtual void setRenderDevice(const std::string& id) = 0;
+
+ virtual void setDevicesObserver(LLWebRTCDevicesObserver *observer) = 0;
+ virtual void unsetDevicesObserver(LLWebRTCDevicesObserver *observer) = 0;
+
+ virtual void setTuningMode(bool enable) = 0;
+ virtual double getTuningMicrophoneEnergy() = 0;
+};
+
+class LLWebRTCAudioInterface
+{
+ public:
+ virtual void setMute(bool mute) = 0;
+};
+
+class LLWebRTCSignalingObserver
+{
+ public:
+ enum IceGatheringState{
+ ICE_GATHERING_NEW,
+ ICE_GATHERING_GATHERING,
+ ICE_GATHERING_COMPLETE
+ };
+ virtual void OnIceGatheringState(IceGatheringState state) = 0;
+ virtual void OnIceCandidate(const LLWebRTCIceCandidate& candidate) = 0;
+ virtual void OnOfferAvailable(const std::string& sdp) = 0;
+ virtual void OnAudioEstablished(LLWebRTCAudioInterface *audio_interface) = 0;
+};
+
+class LLWebRTCSignalInterface
+{
+ public:
+ virtual void setSignalingObserver(LLWebRTCSignalingObserver* observer) = 0;
+ virtual void unsetSignalingObserver(LLWebRTCSignalingObserver* observer) = 0;
+
+ virtual bool initializeConnection() = 0;
+ virtual void shutdownConnection() = 0;
+ virtual void AnswerAvailable(const std::string &sdp) = 0;
+};
+
+LLSYMEXPORT LLWebRTCDeviceInterface* getDeviceInterface();
+LLSYMEXPORT LLWebRTCSignalInterface* getSignalingInterface();
+}
+
+#endif // LLWEBRTC_H \ No newline at end of file
diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h
new file mode 100644
index 0000000000..10916e5a25
--- /dev/null
+++ b/indra/llwebrtc/llwebrtc_impl.h
@@ -0,0 +1,177 @@
+/**
+ * @file llaccordionctrl.cpp
+ * @brief Accordion panel implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLWEBRTC_IMPL_H
+#define LLWEBRTC_IMPL_H
+
+#define LL_MAKEDLL
+#define WEBRTC_WIN 1
+#include "llwebrtc.h"
+// WebRTC Includes
+#ifdef WEBRTC_WIN
+#pragma warning(disable : 4996)
+#endif // WEBRTC_WIN
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/ssl_adapter.h"
+#include "rtc_base/thread.h"
+#include "api/peer_connection_interface.h"
+#include "api/media_stream_interface.h"
+#include "api/create_peerconnection_factory.h"
+#include "modules/audio_device/include/audio_device.h"
+#include "modules/audio_device/include/audio_device_data_observer.h"
+#include "rtc_base/task_queue.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/task_queue/default_task_queue_factory.h"
+#include "modules/audio_device/include/audio_device_defines.h"
+
+
+namespace llwebrtc
+{
+
+class LLWebRTCImpl : public LLWebRTCDeviceInterface,
+ public LLWebRTCSignalInterface,
+ public LLWebRTCAudioInterface,
+ public webrtc::AudioDeviceDataObserver,
+ public webrtc::PeerConnectionObserver,
+ public webrtc::CreateSessionDescriptionObserver,
+ public webrtc::SetRemoteDescriptionObserverInterface,
+ public webrtc::SetLocalDescriptionObserverInterface
+
+{
+ public:
+ LLWebRTCImpl() :
+ mTuningEnergy(0.0)
+ {
+ }
+ ~LLWebRTCImpl() {}
+
+ void init();
+
+ //
+ // LLWebRTCDeviceInterface
+ //
+
+ void refreshDevices() override;
+
+ void setDevicesObserver(LLWebRTCDevicesObserver *observer) override;
+ void unsetDevicesObserver(LLWebRTCDevicesObserver *observer) override;
+ void setCaptureDevice(const std::string& id) override;
+
+ void setRenderDevice(const std::string& id) override;
+
+ void setTuningMode(bool enable) override;
+ double getTuningMicrophoneEnergy() override;
+
+
+ void OnCaptureData(const void *audio_samples,
+ const size_t num_samples,
+ const size_t bytes_per_sample,
+ const size_t num_channels,
+ const uint32_t samples_per_sec) override;
+
+ void OnRenderData(const void *audio_samples,
+ const size_t num_samples,
+ const size_t bytes_per_sample,
+ const size_t num_channels,
+ const uint32_t samples_per_sec) override;
+
+ //
+ // LLWebRTCSignalInterface
+ //
+
+ void setSignalingObserver(LLWebRTCSignalingObserver *observer) override;
+ void unsetSignalingObserver(LLWebRTCSignalingObserver *observer) override;
+ bool initializeConnection() override;
+ void shutdownConnection() override;
+ void AnswerAvailable(const std::string &sdp) override;
+
+
+ //
+ // LLWebRTCAudioInterface
+ //
+ void setMute(bool mute) override;
+
+ //
+ // PeerConnectionObserver implementation.
+ //
+
+ void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override {}
+ void OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
+ const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) override;
+ void OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;
+ void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> channel) override {}
+ void OnRenegotiationNeeded() override {}
+ void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override {};
+ void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
+ void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
+ void OnIceConnectionReceivingChange(bool receiving) override {}
+ void OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state) override;
+
+ //
+ // CreateSessionDescriptionObserver implementation.
+ //
+ void OnSuccess(webrtc::SessionDescriptionInterface *desc) override;
+ void OnFailure(webrtc::RTCError error) override;
+
+ //
+ // SetRemoteDescriptionObserverInterface implementation.
+ //
+ void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override;
+
+ //
+ // SetLocalDescriptionObserverInterface implementation.
+ //
+ void OnSetLocalDescriptionComplete(webrtc::RTCError error) override;
+
+ protected:
+ std::unique_ptr<rtc::Thread> mNetworkThread;
+ std::unique_ptr<rtc::Thread> mWorkerThread;
+ std::unique_ptr<rtc::Thread> mSignalingThread;
+ rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
+ webrtc::PeerConnectionInterface::RTCConfiguration mConfiguration;
+ std::unique_ptr<webrtc::TaskQueueFactory> mTaskQueueFactory;
+
+
+ // Devices
+ void updateDevices();
+ rtc::scoped_refptr<webrtc::AudioDeviceModule> mDeviceModule;
+ std::vector<LLWebRTCDevicesObserver *> mVoiceDevicesObserverList;
+
+ double mTuningEnergy;
+
+ // signaling
+ std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList;
+ std::vector<std::unique_ptr<webrtc::IceCandidateInterface>> mCachedIceCandidates;
+ bool mAnswerReceived;
+
+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
+};
+
+}
+
+#endif // LLWEBRTC_IMPL_H \ No newline at end of file