|  | /* | 
|  | * | 
|  | *    Copyright (c) 2025 Project CHIP Authors | 
|  | * | 
|  | *    Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | *    you may not use this file except in compliance with the License. | 
|  | *    You may obtain a copy of the License at | 
|  | * | 
|  | *        http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | *    Unless required by applicable law or agreed to in writing, software | 
|  | *    distributed under the License is distributed on an "AS IS" BASIS, | 
|  | *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | *    See the License for the specific language governing permissions and | 
|  | *    limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "WebRTCTransportRequestorManager.h" | 
|  | #include <app/clusters/webrtc-transport-requestor-server/webrtc-transport-requestor-cluster.h> | 
|  | #include <controller/webrtc/access_control/WebRTCAccessControl.h> | 
|  | #include <platform/PlatformManager.h> | 
|  |  | 
|  | using namespace chip; | 
|  | using namespace chip::app; | 
|  | using namespace chip::app::Clusters; | 
|  |  | 
|  | namespace chip { | 
|  | namespace python { | 
|  |  | 
|  | // The callback methods provided by python. | 
|  | OnOfferCallback gOnOfferCallback                 = nullptr; | 
|  | OnAnswerCallback gOnAnswerCallback               = nullptr; | 
|  | OnICECandidatesCallback gOnICECandidatesCallback = nullptr; | 
|  | OnEndCallback gOnEndCallback                     = nullptr; | 
|  |  | 
|  | } // namespace python | 
|  | } // namespace chip | 
|  |  | 
|  | using namespace chip::python; | 
|  |  | 
|  | void WebRTCTransportRequestorManager::Init() | 
|  | { | 
|  | Controller::AccessControl::InitAccessControl(kWebRTCRequesterDynamicEndpointId); | 
|  |  | 
|  | mWebRTCRegisteredServerCluster.Create(kWebRTCRequesterDynamicEndpointId, *this); | 
|  | CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(mWebRTCRegisteredServerCluster.Registration()); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(AppServer, "Failed to register WebRTCTransportRequestor on endpoint %u: %" CHIP_ERROR_FORMAT, | 
|  | kWebRTCRequesterDynamicEndpointId, err.Format()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void WebRTCTransportRequestorManager::Shutdown() | 
|  | { | 
|  | CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(&mWebRTCRegisteredServerCluster.Cluster()); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(AppServer, "WebRTCTransportRequestor unregister error: %" CHIP_ERROR_FORMAT, err.Format()); | 
|  | } | 
|  | mWebRTCRegisteredServerCluster.Destroy(); | 
|  | } | 
|  |  | 
|  | void WebRTCTransportRequestorManager::InitCallbacks(OnOfferCallback onOnOfferCallback, OnAnswerCallback onAnswerCallback, | 
|  | OnICECandidatesCallback onICECandidatesCallback, OnEndCallback onEndCallback) | 
|  | { | 
|  | gOnOfferCallback         = onOnOfferCallback; | 
|  | gOnAnswerCallback        = onAnswerCallback; | 
|  | gOnICECandidatesCallback = onICECandidatesCallback; | 
|  | gOnEndCallback           = onEndCallback; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR WebRTCTransportRequestorManager::HandleOffer(uint16_t sessionId, const OfferArgs & args) | 
|  | { | 
|  | std::string offer = args.sdp; | 
|  | int err           = gOnOfferCallback(sessionId, offer.c_str()); | 
|  | return err == 0 ? CHIP_NO_ERROR : CHIP_ERROR_INCORRECT_STATE; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR WebRTCTransportRequestorManager::HandleAnswer(uint16_t sessionId, const std::string & sdpAnswer) | 
|  | { | 
|  | std::string answer = sdpAnswer; | 
|  | int err            = gOnAnswerCallback(sessionId, answer.c_str()); | 
|  | return err == 0 ? CHIP_NO_ERROR : CHIP_ERROR_INCORRECT_STATE; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR WebRTCTransportRequestorManager::HandleICECandidates(uint16_t sessionId, | 
|  | const std::vector<ICECandidateStruct> & candidates) | 
|  | { | 
|  | std::vector<OwnedIceCandidate> remoteCandidates; | 
|  | remoteCandidates.reserve(candidates.size()); | 
|  | std::vector<IceCandidate> cStrings; | 
|  | cStrings.reserve(candidates.size()); | 
|  |  | 
|  | if (candidates.empty()) | 
|  | { | 
|  | ChipLogError(Camera, "Candidate list is empty. At least one candidate is expected."); | 
|  | return CHIP_ERROR_INVALID_ARGUMENT; | 
|  | } | 
|  |  | 
|  | for (const auto & candidate : candidates) | 
|  | { | 
|  | OwnedIceCandidate aIceCandidate; | 
|  | aIceCandidate.candidate     = std::make_unique<std::string>(candidate.candidate.begin(), candidate.candidate.end()); | 
|  | bool isSdpMidNull           = candidate.SDPMid.IsNull(); | 
|  | aIceCandidate.sdpMid        = isSdpMidNull | 
|  | ? nullptr | 
|  | : std::make_unique<std::string>(candidate.SDPMid.Value().begin(), candidate.SDPMid.Value().end()); | 
|  | aIceCandidate.sdpMLineIndex = candidate.SDPMLineIndex.IsNull() ? -1 : static_cast<int>(candidate.SDPMLineIndex.Value()); | 
|  | aIceCandidate.view = IceCandidate{ aIceCandidate.candidate->c_str(), isSdpMidNull ? nullptr : aIceCandidate.sdpMid->c_str(), | 
|  | aIceCandidate.sdpMLineIndex }; | 
|  | remoteCandidates.push_back(std::move(aIceCandidate)); | 
|  | } | 
|  |  | 
|  | for (const auto & candidate : remoteCandidates) | 
|  | { | 
|  | cStrings.push_back(candidate.view); | 
|  | } | 
|  |  | 
|  | int err = gOnICECandidatesCallback(sessionId, cStrings.data(), static_cast<int>(cStrings.size())); | 
|  | return err == 0 ? CHIP_NO_ERROR : CHIP_ERROR_INCORRECT_STATE; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR WebRTCTransportRequestorManager::HandleEnd(uint16_t sessionId, WebRTCTransportRequestor::WebRTCEndReasonEnum reasonCode) | 
|  | { | 
|  | int err = gOnEndCallback(sessionId, static_cast<uint8_t>(reasonCode)); | 
|  | return err == 0 ? CHIP_NO_ERROR : CHIP_ERROR_INCORRECT_STATE; | 
|  | } | 
|  |  | 
|  | void WebRTCTransportRequestorManager::UpsertSession( | 
|  | const chip::app::Clusters::Globals::Structs::WebRTCSessionStruct::Type & session) | 
|  | { | 
|  | mWebRTCRegisteredServerCluster.Cluster().UpsertSession(session); | 
|  | } |