Skip to content

Commit

Permalink
Linux tv-casting-app: simplified Endpoints APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
sharadb-amazon committed Dec 7, 2023
1 parent b3ef405 commit 7614353
Show file tree
Hide file tree
Showing 11 changed files with 612 additions and 34 deletions.
5 changes: 5 additions & 0 deletions examples/tv-casting-app/tv-casting-common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,24 @@ chip_data_model("tv-casting-common") {

# Add simplified casting API files here
sources += [
#"core/Attribute.h",
"core/CastingApp.cpp",
"core/CastingApp.h",
"core/CastingPlayer.cpp",
"core/CastingPlayer.h",
"core/CastingPlayerDiscovery.cpp",
"core/CastingPlayerDiscovery.h",
"core/Cluster.h",
"core/Endpoint.h",
"core/Types.h",
"support/AppParameters.h",
"support/CastingStore.cpp",
"support/CastingStore.h",
"support/ChipDeviceEventHandler.cpp",
"support/ChipDeviceEventHandler.h",
"support/DataProvider.h",
"support/EndpointListLoader.cpp",
"support/EndpointListLoader.h",
]

deps = [
Expand Down
76 changes: 76 additions & 0 deletions examples/tv-casting-app/tv-casting-common/core/Attribute.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
*
* Copyright (c) 2023 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 "Cluster.h"
#include "Types.h"

#include "lib/support/logging/CHIPLogging.h"

namespace matter {
namespace casting {
namespace core {

enum ReadAttributeError
{
READ_ATTRIBUTE_NO_ERROR
};

enum WriteAttributeError
{
WRITE_ATTRIBUTE_NO_ERROR
};

template <typename ValueType>
using ReadAttributeCallback = std::function<void(Optional<ValueType> before, ValueType after, ReadAttributeError)>;

using WriteAttributeCallback = std::function<void(WriteAttributeError)>;

class BaseCluster;

template <typename ValueType>
class Attribute
{
private:
memory::Weak<BaseCluster> cluster;
ValueType value;

public:
Attribute(memory::Weak<BaseCluster> cluster) { this->cluster = cluster; }

~Attribute() {}

Attribute() = delete;
Attribute(Attribute & other) = delete;
void operator=(const Attribute &) = delete;

protected:
memory::Strong<BaseCluster> GetCluster() const { return cluster.lock(); }

public:
ValueType GetValue();
void Read(ReadAttributeCallback<ValueType> onRead);
void Write(ValueType value, WriteAttributeCallback onWrite);
bool SubscribeAttribute(AttributeId attributeId, ReadAttributeCallback<ValueType> callback);
bool UnsubscribeAttribute(AttributeId attributeId, ReadAttributeCallback<ValueType> callback);
};

}; // namespace core
}; // namespace casting
}; // namespace matter
81 changes: 55 additions & 26 deletions examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/

#include "CastingPlayer.h"
#include "Endpoint.h"

#include "support/CastingStore.h"

#include <app/server/Server.h>
Expand All @@ -27,7 +29,8 @@ namespace core {

CastingPlayer * CastingPlayer::mTargetCastingPlayer = nullptr;

void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, unsigned long long int commissioningWindowTimeoutSec)
void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, unsigned long long int commissioningWindowTimeoutSec,
EndpointFilter * desiredEndpointFilter)
{
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection called");

Expand All @@ -46,40 +49,48 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, uns
mCommissioningWindowTimeoutSec = commissioningWindowTimeoutSec;
mTargetCastingPlayer = this;

// If this CastingPlayer is the cache of CastingPlayers the app previously connected to (and has nodeId and fabricIndex of),
// simply Find or Re-establish the CASE session and return early
// If *this* CastingPlayer was previously connected to, its nodeId, fabricIndex and other attributes should be present
// in the CastingStore cache. If that is the case, AND, the cached data contains the endpoint desired by the client, if any,
// as per desiredEndpointFilter, simply Find or Re-establish the CASE session and return early
if (cachedCastingPlayers.size() != 0)
{
it = std::find_if(cachedCastingPlayers.begin(), cachedCastingPlayers.end(),
[this](const core::CastingPlayer & castingPlayerParam) { return castingPlayerParam == *this; });

// found the CastingPlayer in cache
if (it != cachedCastingPlayers.end())
{
unsigned index = (unsigned int) std::distance(cachedCastingPlayers.begin(), it);
*this = cachedCastingPlayers[index];

FindOrEstablishSession(
nullptr,
[](void * context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) {
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection Connection to CastingPlayer successful");
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_CONNECTED;
support::CastingStore::GetInstance()->AddOrUpdate(*CastingPlayer::GetTargetCastingPlayer());
VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_NO_ERROR, CastingPlayer::GetTargetCastingPlayer());
},
[](void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) {
ChipLogError(AppServer, "CastingPlayer::VerifyOrEstablishConnection Connection to CastingPlayer failed");
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
support::CastingStore::GetInstance()->Delete(*CastingPlayer::GetTargetCastingPlayer());
VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(error, nullptr);
mTargetCastingPlayer = nullptr;
});
return; // FindOrEstablishSession called. Return early.
if (desiredEndpointFilter == nullptr || ContainsDesiredEndpoint(&cachedCastingPlayers[index], desiredEndpointFilter))
{
*this = cachedCastingPlayers[index];

FindOrEstablishSession(
nullptr,
[](void * context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) {
ChipLogProgress(AppServer,
"CastingPlayer::VerifyOrEstablishConnection Connection to CastingPlayer successful");
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_CONNECTED;
support::CastingStore::GetInstance()->AddOrUpdate(*CastingPlayer::GetTargetCastingPlayer());
VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_NO_ERROR,
CastingPlayer::GetTargetCastingPlayer());
},
[](void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) {
ChipLogError(AppServer, "CastingPlayer::VerifyOrEstablishConnection Connection to CastingPlayer failed");
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
support::CastingStore::GetInstance()->Delete(*CastingPlayer::GetTargetCastingPlayer());
VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(error, nullptr);
mTargetCastingPlayer = nullptr;
});
return; // FindOrEstablishSession called. Return early.
}
}
}

// this CastingPlayer is not in the list of cached CastingPlayers previously connected to. This VerifyOrEstablishConnection call
// this CastingPlayer is not in the list of cached CastingPlayers previously connected to or the cached data
// does not contain the endpoint the client desires to interact with. So, this VerifyOrEstablishConnection call
// will require User Directed Commissioning.
if (chip::Server::GetInstance().GetFailSafeContext().IsFailSafeArmed())
{
Expand All @@ -101,13 +112,13 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, uns
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "CastingPlayer::VerifyOrEstablishConnection failed with %" CHIP_ERROR_FORMAT, err.Format());
support::ChipDeviceEventHandler::SetUdcStatus(false);
mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec;
mOnCompleted = nullptr;
mTargetCastingPlayer = nullptr;
ChipLogError(AppServer, "CastingPlayer::VerifyOrEstablishConnection failed with %" CHIP_ERROR_FORMAT, err.Format());
mOnCompleted(err, nullptr);
mOnCompleted = nullptr;
}
}

Expand Down Expand Up @@ -165,6 +176,24 @@ void CastingPlayer::FindOrEstablishSession(void * clientContext, chip::OnDeviceC
connectionContext->mOnConnectionFailureCallback);
}

bool CastingPlayer::ContainsDesiredEndpoint(core::CastingPlayer * cachedCastingPlayer, EndpointFilter * desiredEndpointFilter)
{
std::vector<memory::Strong<Endpoint>> cachedEndpoints = cachedCastingPlayer->GetEndpoints();
for (const auto & cachedEndpoint : cachedEndpoints)
{
bool match = true;
match = match && (desiredEndpointFilter->vendorId == 0 || cachedEndpoint->GetVendorId() == desiredEndpointFilter->vendorId);
match =
match && (desiredEndpointFilter->productId == 0 || cachedEndpoint->GetProductId() == desiredEndpointFilter->productId);
// TODO: check deviceTypeList and clusterList as well
if (match)
{
return true;
}
}
return false;
}

void CastingPlayer::LogDetail() const
{
if (strlen(mAttributes.id) != 0)
Expand Down
23 changes: 19 additions & 4 deletions examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

#pragma once

#include "Endpoint.h"
#include "Types.h"
#include "support/ChipDeviceEventHandler.h"
#include "support/EndpointListLoader.h"

#include "lib/support/logging/CHIPLogging.h"
#include <inet/IPAddress.h>
Expand All @@ -36,6 +38,13 @@ const int kPortMaxLength = 5; // port is uint16_t
const int kIdMaxLength = chip::Dnssd::kHostNameMaxLength + kPortMaxLength + 1;
const unsigned long long int kCommissioningWindowTimeoutSec = 3 * 60; // 3 minutes

struct EndpointFilter
{
uint16_t vendorId = 0;
uint16_t productId = 0;
std::vector<chip::app::Clusters::Descriptor::Structs::DeviceTypeStruct::DecodableType> deviceTypeList;
};

class CastingPlayerAttributes
{
public:
Expand All @@ -55,6 +64,8 @@ class CastingPlayerAttributes
chip::FabricIndex fabricIndex = 0;
};

class Endpoint;

/**
* @brief Represents CastingPlayer ConnectionState.
*
Expand Down Expand Up @@ -109,7 +120,8 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>
* Defaults to kCommissioningWindowTimeoutSec.
*/
void VerifyOrEstablishConnection(ConnectCallback onCompleted,
unsigned long long int commissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec);
unsigned long long int commissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec,
EndpointFilter * desiredEndpointFilter = nullptr);
void LogDetail() const;

const char * GetId() const { return mAttributes.id; }
Expand Down Expand Up @@ -140,12 +152,12 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>

void SetFabricIndex(chip::FabricIndex fabricIndex) { mAttributes.fabricIndex = fabricIndex; }

// void RegisterEndpoint(const memory::Strong<Endpoint> endpoint) { endpoints.push_back(endpoint); }
void RegisterEndpoint(const memory::Strong<Endpoint> endpoint) { endpoints.push_back(endpoint); }

// const std::vector<memory::Strong<Endpoint>> GetEndpoints() const { return endpoints; }
const std::vector<memory::Strong<Endpoint>> GetEndpoints() const { return endpoints; }

private:
// std::vector<memory::Strong<Endpoint>> endpoints;
std::vector<memory::Strong<Endpoint>> endpoints;
ConnectionState mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
CastingPlayerAttributes mAttributes;
static CastingPlayer * mTargetCastingPlayer;
Expand Down Expand Up @@ -184,10 +196,13 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>
void FindOrEstablishSession(void * clientContext, chip::OnDeviceConnected onDeviceConnected,
chip::OnDeviceConnectionFailure onDeviceConnectionFailure);

bool ContainsDesiredEndpoint(core::CastingPlayer * cachedCastingPlayer, EndpointFilter * desiredEndpointFilter);

// ChipDeviceEventHandler handles chip::DeviceLayer::ChipDeviceEvent events and helps the CastingPlayer class commission with
// and connect to a CastingPlayer
friend class support::ChipDeviceEventHandler;
friend class ConnectionContext;
friend class support::EndpointListLoader;
};

class ConnectionContext
Expand Down
54 changes: 54 additions & 0 deletions examples/tv-casting-app/tv-casting-common/core/Cluster.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
*
* Copyright (c) 2023 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 "Endpoint.h"
#include "Types.h"

#include "lib/support/logging/CHIPLogging.h"

namespace matter {
namespace casting {
namespace core {

class Endpoint;

// Base cluster class
class BaseCluster
{
private:
protected:
memory::Weak<Endpoint> endpoint;

public:
BaseCluster(memory::Weak<Endpoint> endpoint) { this->endpoint = endpoint; }

virtual ~BaseCluster() {}

BaseCluster() = delete;
BaseCluster(BaseCluster & other) = delete;
void operator=(const BaseCluster &) = delete;

protected:
memory::Weak<Endpoint> GetEndpoint() const { return endpoint.lock(); }
};

}; // namespace core
}; // namespace casting
}; // namespace matter
Loading

0 comments on commit 7614353

Please sign in to comment.