blob: 8bcedc32cafb3cb6149f7e7c5be167312b0caf02 [file] [log] [blame]
/*
* 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.
*/
#pragma once
#include <app-common/zap-generated/cluster-objects.h>
#include <app/CommandSender.h>
#include <app/ConcreteCommandPath.h>
#include <app/MessageDef/StatusIB.h>
#include <app/OperationalSessionSetup.h>
#include <app/clusters/webrtc-transport-requestor-server/webrtc-transport-requestor-cluster.h>
#include <controller/python/matter/native/PyChipError.h>
#include <lib/core/DataModelTypes.h>
#include <lib/core/ScopedNodeId.h>
#include <lib/core/TLV.h>
using PyObject = void *;
using OnCommandSenderResponseCallback = void (*)(PyObject appContext, chip::EndpointId endpointId, chip::ClusterId clusterId,
chip::CommandId commandId, size_t index,
std::underlying_type_t<chip::Protocols::InteractionModel::Status> status,
chip::ClusterStatus clusterStatus, const uint8_t * payload, uint32_t length);
using OnCommandSenderErrorCallback = void (*)(PyObject appContext,
std::underlying_type_t<chip::Protocols::InteractionModel::Status> status,
chip::ClusterStatus clusterStatus, PyChipError chiperror);
using OnCommandSenderDoneCallback = void (*)(PyObject appContext);
class WebRTCTransportProviderClient : public chip::app::CommandSender::Callback
{
public:
using StreamUsageEnum = chip::app::Clusters::Globals::StreamUsageEnum;
WebRTCTransportProviderClient() :
mOnConnectedCallback(OnDeviceConnected, this), mOnConnectionFailureCallback(OnDeviceConnectionFailure, this){};
~WebRTCTransportProviderClient() = default;
// methods to be called from python
void Init(uint64_t nodeId, uint8_t fabricIndex, uint16_t endpoint);
PyChipError SendCommand(void * appContext, uint16_t endpointId, uint32_t clusterId, uint32_t commandId, const uint8_t * payload,
size_t length);
void InitCallbacks(OnCommandSenderResponseCallback onCommandSenderResponseCallback,
OnCommandSenderErrorCallback onCommandSenderErrorCallback,
OnCommandSenderDoneCallback onCommandSenderDoneCallback);
/////////// CommandSender Callback Interface /////////
void OnResponse(chip::app::CommandSender * client, const chip::app::ConcreteCommandPath & path,
const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override;
void OnError(const chip::app::CommandSender * client, CHIP_ERROR error) override;
void OnDone(chip::app::CommandSender * client) override;
private:
enum class CommandType : uint8_t
{
kUndefined = 0,
kSolicitOffer = 1,
kProvideOffer = 2,
};
enum class State : uint8_t
{
Idle, ///< Default state, no communication initiated yet
Connecting, ///< Waiting for OnDeviceConnected or OnDeviceConnectionFailure callbacks to be called
};
chip::ScopedNodeId mPeerId;
chip::EndpointId mEndpointId = chip::kInvalidEndpointId;
CommandType mCommandType = CommandType::kUndefined;
std::unique_ptr<chip::app::CommandSender> mCommandSender;
// Data needed to send the WebRTCTransportProvider commands
chip::app::Clusters::WebRTCTransportProvider::Commands::SolicitOffer::Type mSolicitOfferData;
chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideOffer::Type mProvideOfferData;
chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideAnswer::Type mProvideAnswerData;
chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideICECandidates::Type mProvideICECandidatesData;
StreamUsageEnum mCurrentStreamUsage = StreamUsageEnum::kUnknownEnumValue;
PyObject mAppContext = nullptr;
// We store the SDP here so that mProvideOfferData.sdp points to a stable buffer.
std::string mSdpString;
State mState = State::Idle;
// Store the ICECandidates here to use to send asynchronously.
std::vector<std::string> mClientICECandidates;
chip::Callback::Callback<chip::OnDeviceConnected> mOnConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnConnectionFailureCallback;
OnCommandSenderResponseCallback gOnCommandSenderResponseCallback = nullptr;
OnCommandSenderErrorCallback gOnCommandSenderErrorCallback = nullptr;
OnCommandSenderDoneCallback gOnCommandSenderDoneCallback = nullptr;
static void OnDeviceConnected(void * context, chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle);
static void OnDeviceConnectionFailure(void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error);
CHIP_ERROR ProvideOffer(const uint8_t * payload, size_t length);
CHIP_ERROR SolicitOffer(const uint8_t * payload, size_t length);
// Command Sender Callback methods
template <class T>
CHIP_ERROR SendCommand(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle,
chip::CommandId commandId, const T & requestData)
{
mCommandSender =
std::make_unique<chip::app::CommandSender>(this, &exchangeMgr,
/* isTimedRequest = */ false,
/* suppressResponse = */ false, sessionHandle->AllowsLargePayload());
VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_NO_MEMORY);
chip::app::CommandPathParams commandPath = { mEndpointId, chip::app::Clusters::WebRTCTransportProvider::Id, commandId,
chip::app::CommandPathFlags::kEndpointIdValid };
chip::app::CommandSender::AddRequestDataParameters addRequestDataParams(chip::NullOptional);
ReturnErrorOnFailure(mCommandSender->AddRequestData(commandPath, requestData, addRequestDataParams));
return mCommandSender->SendCommandRequest(sessionHandle);
}
CHIP_ERROR SendCommandForType(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle,
CommandType commandType);
void MoveToState(const State targetState);
void HandleProvideOfferResponse(chip::TLV::TLVReader data);
void HandleSolicitOfferResponse(chip::TLV::TLVReader data);
};