blob: bc7c9de937b021d73fbeba3eb1496c36808b1395 [file]
/*
*
* Copyright (c) 2026 Project CHIP Authors
* All rights reserved.
*
* 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/CommandHandler.h>
#include <app/ConcreteCommandPath.h>
#include <lib/core/ScopedNodeId.h>
namespace chip {
namespace app {
namespace Clusters {
namespace AvAnalysis {
/**
* A camera-bound command (EstablishAnalysisStream, RemoveAnalysisStream, ActivateAnalysisStream,
* DeactivateAnalysisStream) cannot be answered until the camera responds, so its CommandHandler is
* parked here and the interaction advances through this state machine
* Exactly one interaction exists at a time; a command arriving while InFlight() is answered Busy.
*/
class CameraInteraction
{
public:
enum class State : uint8_t
{
kIdle, // No camera interaction in flight
kEstablishing, // VideoStreamAllocate awaiting the camera's answer
kRemoving, // VideoStreamDeallocate awaiting the camera's answer
kActivating, // WebRTC session initiation awaiting the offer exchange's outcome
kDeactivating, // WebRTC EndSession awaiting the camera's answer
};
State GetState() const { return mState; }
bool InFlight() const { return mState != State::kIdle; }
/**
* The camera the in-flight interaction is bound to.
*/
const ScopedNodeId & CameraNode() const { return mCameraNode; }
/**
* The AnalysisStreamID the in-flight interaction is about
*/
uint16_t AnalysisStreamId() const { return mAnalysisStreamId; }
/**
* The camera endpoint having WebRTCTransportProvider
*/
EndpointId WebRTCEndpoint() const { return mWebRTCEndpoint; }
/**
* Enters aState, parking the command so it can be answered when the camera responds.
*/
void Begin(State aState, CommandHandler & aHandler, const ConcreteCommandPath & aPath, const ScopedNodeId & aCameraNode,
uint16_t aAnalysisStreamId = 0, EndpointId aWebRTCEndpoint = kInvalidEndpointId)
{
mState = aState;
mHandle = CommandHandler::Handle(&aHandler);
mPath = aPath;
mCameraNode = aCameraNode;
mAnalysisStreamId = aAnalysisStreamId;
mWebRTCEndpoint = aWebRTCEndpoint;
aHandler.FlushAcksRightAwayOnSlowCommand();
}
/**
* Rolls back a Begin whose camera request could not be started
*/
void Abort()
{
mState = State::kIdle;
mHandle = CommandHandler::Handle();
ClearInteractionState();
}
/**
* Ends the interaction: returns the parked handle. The camera node and stream id are cleared,
* so callers needing them must read them before completing.
*/
CommandHandler::Handle Complete(ConcreteCommandPath & outPath)
{
outPath = mPath;
mState = State::kIdle;
ClearInteractionState();
return std::move(mHandle);
}
private:
void ClearInteractionState()
{
mAnalysisStreamId = 0;
mWebRTCEndpoint = kInvalidEndpointId;
mCameraNode = ScopedNodeId();
mPath = ConcreteCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId);
}
State mState = State::kIdle;
uint16_t mAnalysisStreamId = 0;
EndpointId mWebRTCEndpoint = kInvalidEndpointId;
CommandHandler::Handle mHandle;
ConcreteCommandPath mPath = ConcreteCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId);
ScopedNodeId mCameraNode;
};
} // namespace AvAnalysis
} // namespace Clusters
} // namespace app
} // namespace chip