#include "pch.h" #include "../common/comm.h" #include "api.h" #include "callback.h" #include "api/create_peerconnection_factory.h" #include "video_frame_observer.h" #include "data_channel_observer.h" #include "audio_frame_observer.h" #include "peer_connection.h" #include "sdp_utils.h" #include "p2p/client/basic_port_allocator.h" #include #include #ifdef WEBRTC_LINUX //#include //#include //#include #include "capture_op.h" #include "gsml_capturer.h" #endif #ifdef WEBRTC_LINUX #include "sanitize_string.h" #include "capture_op.h" #include "gsml_capturer.h" #include "VideoScaler.h" #include "VideoFilter.h" #endif struct mrsEnumerator { virtual ~mrsEnumerator() = default; virtual void dispose() = 0; }; rtc::scoped_refptr g_peer_connection_factory; #ifdef WEBRTC_LINUX std::unique_ptr g_video_decode_factory; #endif /// WebRTC worker thread. std::unique_ptr g_worker_thread; // #ifdef WIN32 // //rtc::Win32SocketServer w32_ss; // std::unique_ptr g_network_thread; // #else // rtc::AutoSocketServerThread g_network_thread; // #endif /// WebRTC signaling thread. std::unique_ptr g_signaling_thread; std::unordered_map< PeerConnectionHandle, rtc::scoped_refptr> g_peer_connection_map; /// Predefined name of the local video track. const std::string kLocalVideoLabel("local_video"); /// Predefined name of the local audio track. const std::string kLocalAudioLabel("local_audio"); const std::string kLocalDataChannel("local_channel"); /// WebRTC worker thread. const std::unique_ptr& GetWorkerThread() { return g_worker_thread; } /// WebRTC signaling thread. const std::unique_ptr& GetSignalingThread() { return g_signaling_thread; } void mrsCloseEnum(mrsEnumHandle* handleRef) { if (handleRef) { if (auto& handle = *handleRef) { handle->dispose(); delete handle; handle = nullptr; } } } void mrsEnumVideoCaptureDevicesAsync( mrsVideoCaptureDeviceEnumCallback callback, void* userData, mrsVideoCaptureDeviceEnumCompletedCallback completedCallback, void* completedCallbackUserData) { if (!callback) { return; } std::unique_ptr info( webrtc::VideoCaptureFactory::CreateDeviceInfo()); if (!info) { if (completedCallback) { (*completedCallback)(completedCallbackUserData); } } int num_devices = info->NumberOfDevices(); for (int i = 0; i < num_devices; ++i) { constexpr uint32_t kSize = 256; char name[kSize] = { 0 }; char id[kSize] = { 0 }; if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) { (*callback)(id, name, userData); } } if (completedCallback) { (*completedCallback)(completedCallbackUserData); } } std::unique_ptr CreateEncoderFactory(bool bNullCodec) { std::unique_ptr factory; /* if (bNullCodec) { // factory=webrtc::CreateBuiltinVideoEncoderFactory(); #ifdef WEBRTC_LINUX factory= std::make_unique(); #endif } else { */ factory=webrtc::CreateBuiltinVideoEncoderFactory(); //} return factory; } std::unique_ptr CreateDecoderFactory(bool nullCodec) { std::unique_ptr factory; /* if (nullCodec) { #ifdef WEBRTC_LINUX //factory= webrtc::CreateBuiltinVideoDecoderFactory(); factory = std::make_unique(); #endif } else { factory= webrtc::CreateBuiltinVideoDecoderFactory(); } */ factory = webrtc::CreateBuiltinVideoDecoderFactory(); return factory; } bool mrsWebrtcCreateFactory(bool nullCodec) { if (g_peer_connection_factory == nullptr) { g_worker_thread=(rtc::Thread::Create()); g_worker_thread->Start(); g_signaling_thread=(rtc::Thread::Create()); g_signaling_thread->Start(); #ifdef WEBRTC_LINUX g_video_decode_factory=CreateDecoderFactory(nullCodec); #endif g_peer_connection_factory = webrtc::CreatePeerConnectionFactory( nullptr, g_worker_thread.get(), g_signaling_thread.get(), nullptr, webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), CreateEncoderFactory(nullCodec), /* std::unique_ptr( new webrtc::MultiplexEncoderFactory( #ifdef WEBRTC_AARCH std::make_unique() #else std::make_unique() #endif )), */ CreateDecoderFactory(nullCodec), /* std::unique_ptr( new webrtc::MultiplexDecoderFactory( std::make_unique())),*/ nullptr, nullptr); } if (!g_peer_connection_factory.get()) { return false; } return true; } PeerConnectionHandle mrsPeerConnectionCreate() { // Ensure the factory exists // Setup the connection configuration webrtc::PeerConnectionInterface::RTCConfiguration config; config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; /* Json::Value root; Json::Reader jsonReader; std::ifstream ifile("Config.json"); int32_t Udpupper_port; int32_t Udplower_port; if (jsonReader.parse(ifile, root)) { Udpupper_port = root["Udpupper_port"].asInt(); Udplower_port = root["Udplower_port"].asInt(); } */ config.enable_dtls_srtp = false; config.enable_rtp_data_channel = true; webrtc::PeerConnectionInterface::IceServer server; server.uri = "stun:stun1.l.google.com:19302"; config.servers.push_back(server); server.uri = "turn:58.34.98.12:3478"; server.username = "ubuntu12"; server.password = "ubuntu12@123"; config.servers.push_back(server); config.combined_audio_video_bwe=true; //add-wfg std::unique_ptr port_allocator(new cricket::BasicPortAllocator(new rtc::BasicNetworkManager())); //port_allocator->SetPortRange(Udpupper_port, Udplower_port); port_allocator->SetPortRange(27504, 27525); config.enable_dtls_srtp = false; //< TODO - Should be true/unset for security //config.type = webrtc::PeerConnectionInterface::IceTransportsType::kAll; // Create the new peer connection rtc::scoped_refptr peer = new rtc::RefCountedObject(); /* webrtc::PeersConnectionDependencies dependencies(peer);*/ //add webrtc::PeerConnectionDependencies dependencies(std::move(peer)); //×¢تح /*rtc::scoped_refptr peer_connection = g_peer_connection_factory->CreatePeerConnection(config, nullptr, nullptr, peer.get());*/ //add rtc::scoped_refptr peer_connection = g_peer_connection_factory->CreatePeerConnection(config, std::move(port_allocator), nullptr, peer.get()); if (peer_connection.get() == nullptr) return {}; peer->SetPeerImpl(peer_connection); const PeerConnectionHandle handle{ peer.get() }; g_peer_connection_map.insert({ handle, std::move(peer) }); return handle; } void mrsPeerConnectionRegisterConnectedCallback( PeerConnectionHandle peerHandle, PeerConnectionConnectedCallback callback, void* user_data) { if (auto peer = static_cast(peerHandle)) { peer->RegisterConnectedCallback(Callback<>{callback, user_data}); } } void mrsPeerConnectionRegisterLocalSdpReadytoSendCallback( PeerConnectionHandle peerHandle, int32_t pid, int32_t index, PeerConnectionLocalSdpReadytoSendCallback callback, void* user_data) { if (auto peer = static_cast(peerHandle)) { peer->RegisterLocalSdpReadytoSendCallback( Callback{callback,user_data,pid,index}); } } void mrsPeerConnectionRegisterIceCandidateReadytoSendCallback( PeerConnectionHandle peerHandle, int32_t pid, int32_t view, PeerConnectionIceCandidateReadytoSendCallback callback, void* user_data) { if (auto peer = static_cast(peerHandle)) { peer->RegisterIceCandidateReadytoSendCallback( Callback{callback, user_data,pid,view}); } } void mrsPeerConnectionRegisterARGBLocalVideoFrameCallback( PeerConnectionHandle peerHandle, PeerConnectionARGBVideoFrameCallback callback, void* user_data) { if (auto peer = static_cast(peerHandle)) { peer->RegisterLocalVideoFrameCallback( ARGBFrameReadyCallback{callback, user_data }); } } void mrsPeerConnectionRegisterARGBRemoteVideoFrameCallback( PeerConnectionHandle peerHandle, PeerConnectionARGBVideoFrameCallback callback, void* user_data) { if (auto peer = static_cast(peerHandle)) { peer->RegisterRemoteVideoFrameCallback( ARGBFrameReadyCallback{callback, user_data }); } } void mrsPeerConnectionRegisterChannelCallback(PeerConnectionHandle peerHandle, PeerConnectionDataChannelMessageCallback message_callback, void* message_user_data, PeerConnectionDataChannelBufferingCallback buffering_callback, void* buffering_user_data, PeerConnectionDataChannelStateCallback state_callback, void* state_user_data) { if (auto peer = static_cast(peerHandle)) { peer->RegisterDataChannelCallback( DataChannelMessageCallback{ message_callback, message_user_data }, DataChannelBufferingCallback{ buffering_callback, buffering_user_data }, DataChannelStateCallback{ state_callback, state_user_data }); } } bool mrsPeerConnectionAddIceCandidate(PeerConnectionHandle peerHandle, const char* sdp, const int sdp_mline_index, const char* sdp_mid) { if (auto peer = static_cast(peerHandle)) { return peer->AddIceCandidate(sdp_mid, sdp_mline_index, sdp); } return false; } bool mrsPeerConnectionCreateOffer(PeerConnectionHandle peerHandle) { if (auto peer = static_cast(peerHandle)) { return peer->CreateOffer(); } return false; } bool mrsPeerConnectionCreateAnswer(PeerConnectionHandle peerHandle) { if (auto peer = static_cast(peerHandle)) { return peer->CreateAnswer(); } return false; } bool mrsPeerConnectionSetRemoteDescription(PeerConnectionHandle peerHandle, const char* type, const char* sdp) { if (auto peer = static_cast(peerHandle)) { return peer->SetRemoteDescription(type, sdp); } return false; } void mrsPeerConnectionClose(PeerConnectionHandle* peerHandlePtr) { if (peerHandlePtr) { if (auto peer = static_cast(*peerHandlePtr)) { auto it = g_peer_connection_map.find(peer); if (it != g_peer_connection_map.end()) { // This generally removes the last reference to the PeerConnection and // leads to its destruction, unless some background running task is // still using the connection. g_peer_connection_map.erase(it); if (g_peer_connection_map.empty()) { // Release the factory so that the threads are stopped and the DLL can // be unloaded. This is mandatory to be able to unload/reload in the // Unity Editor and be able to Play/Stop multiple times per Editor // process run. g_peer_connection_factory = nullptr; g_signaling_thread.reset(); g_worker_thread.reset(); } } } *peerHandlePtr = nullptr; } } #ifdef WEBRTC_LINUX bool mrsPeerConnectionAddLocalVideoTrack( PeerConnectionHandle peerHandle, RenderPosition type, int32_t index) { if(auto peer=static_cast(peerHandle)) { if (!g_peer_connection_factory) return false; std::unique_ptr op=std::make_unique(type,index); auto ptr=op.get(); peer->RegisterCaptureOp(op); rtc::scoped_refptr video_source = OpenGSMLCapture(ptr); if(!video_source) return false; rtc::scoped_refptr video_track = g_peer_connection_factory->CreateVideoTrack(kLocalVideoLabel+std::to_string(type), video_source); if (!video_track) { return false; } return peer->AddLocalVideoTrack(std::move(video_track), kLocalVideoLabel+std::to_string(type)); } return false; } bool mrsPeerConnectionSwitchCapture( PeerConnectionHandle peerHandle, bool front ) { if(auto peer=static_cast(peerHandle)) { peer->SwitchCapture(front); return true; } return false; } bool mrsPeerConnectionSetCtx(PeerConnectionHandle peerHandle,void * data) { if(auto peer=static_cast(peerHandle)) { peer->SetOtherCtx(data); return true; } return false; } void * mrsPeerConnectionCurrentCtx(PeerConnectionHandle peerHandle) { if(auto peer=static_cast(peerHandle)) { return peer->GetCurrentCtx(); } return nullptr; } #endif bool mrsPeerConnectionAddLocalAudioTrack(PeerConnectionHandle peerHandle) { if (auto peer = static_cast(peerHandle)) { if (!g_peer_connection_factory) return false; rtc::scoped_refptr audio_source = g_peer_connection_factory->CreateAudioSource(cricket::AudioOptions()); if (!audio_source) return false; rtc::scoped_refptr audio_track = g_peer_connection_factory->CreateAudioTrack(kLocalAudioLabel, audio_source); if (!audio_track) return false; return peer->AddLocalAudioTrack(std::move(audio_track)); } return false; } mrsResult mrsPeerConnectionAddDataChannel( PeerConnectionHandle peerHandle, bool ordered, bool reliable//, // PeerConnectionDataChannelMessageCallback message_callback, // void* message_user_data, // PeerConnectionDataChannelBufferingCallback buffering_callback, // void* buffering_user_data, // PeerConnectionDataChannelStateCallback state_callback, // void* state_user_data ) { if (auto peer = static_cast(peerHandle)) { return peer->AddDataChannel(kLocalDataChannel.c_str(), ordered, reliable); // DataChannelMessageCallback{ message_callback, message_user_data }, // DataChannelBufferingCallback{ buffering_callback, buffering_user_data }, // DataChannelStateCallback{ state_callback, state_user_data }); } return MRS_E_INVALID_PEER_HANDLE; } void mrsPeerConnectionRemoveLocalVideoTrack( PeerConnectionHandle peerHandle) { if (auto peer = static_cast(peerHandle)) { peer->RemoveLocalVideoTrack(); } } void mrsPeerConnectionRemoveLocalAudioTrack( PeerConnectionHandle peerHandle) { if (auto peer = static_cast(peerHandle)) { peer->RemoveLocalAudioTrack(); } } bool mrsPeerConnectionRemoveDataChannel(PeerConnectionHandle peerHandle) { if (auto peer = static_cast(peerHandle)) { return peer->RemoveDataChannel(); } return false; } bool mrsPeerConnectionSendDataChannelMessage(PeerConnectionHandle peerHandle, const void* data, uint64_t size) { if (auto peer = static_cast(peerHandle)) { return peer->SendDataChannelMessage(data, size); } return false; } bool mrsSdpForceCodecs(const char* message, const char* audio_codec_name, const char* video_codec_name, char* buffer, size_t* buffer_size) { RTC_CHECK(message); RTC_CHECK(buffer); RTC_CHECK(buffer_size); std::string message_str(message); std::string audio_codec_name_str; std::string video_codec_name_str; if (audio_codec_name) { audio_codec_name_str.assign(audio_codec_name); } if (video_codec_name) { video_codec_name_str.assign(video_codec_name); } std::string out_message = SdpForceCodecs(message_str, audio_codec_name_str, video_codec_name_str); const size_t capacity = *buffer_size; const size_t size = out_message.size(); *buffer_size = size + 1; if (capacity < size + 1) { return false; } memcpy(buffer, out_message.c_str(), size); buffer[size] = '\0'; return true; } void mrsMemCpy(void* dst, const void* src, size_t size) { memcpy(dst, src, size); } void mrsMemCpyStride(void* dst, int dst_stride, const void* src, int src_stride, int elem_size, int elem_count) { RTC_CHECK(dst); RTC_CHECK(dst_stride >= elem_size); RTC_CHECK(src); RTC_CHECK(src_stride >= elem_size); if ((dst_stride == elem_size) && (src_stride == elem_size)) { // If tightly packed, do a single memcpy() for performance const size_t total_size = (size_t)elem_size * elem_count; memcpy(dst, src, total_size); } else { // Otherwise, copy row by row for (int i = 0; i < elem_count; ++i) { memcpy(dst, src, elem_size); dst = (char*)dst + dst_stride; src = (const char*)src + src_stride; } } }