21#include <Ocp1DS100ObjectDefinitions.h>
52 m_ocp1IPAddress = juce::IPAddress(
"127.0.0.1");
57 m_ocp1Connection = std::make_unique<NanoOcp1::NanoOcp1Client>(m_ocp1IPAddress.toString(), m_ocp1Port,
false);
59 m_ocp1Connection->onConnectionEstablished = [=]() {
63 m_ocp1DeviceGUID =
"";
64 m_ocp1DeviceStackIdent = -1;
65 m_connectedDbDeviceModel = DbDeviceModel::InvalidDev;
69 QueryObjectValue(RemoteObject::Fixed_GUID, {});
72 m_ocp1Connection->onConnectionLost = [=]() {
73 DeleteObjectSubscriptions();
74 ClearPendingHandles();
76 m_ocp1DeviceGUID =
"";
77 m_ocp1DeviceStackIdent = -1;
78 m_connectedDbDeviceModel = DbDeviceModel::InvalidDev;
80 if (getState() > State::Connecting)
83 startTimer(m_ocp1Timeout * 20);
87 m_ocp1Connection->onDataReceived = [=](
const juce::MemoryBlock& data) {
88 return ocp1MessageReceived(data);
98 clearSingletonInstance();
101void DeviceController::setState(
const State& s, juce::NotificationType notificationType)
103 std::function<juce::String(
State)> stateToString = [=](
State state) {
123 if (m_currentState != s)
125 DBG(juce::String(__FUNCTION__) <<
" " << stateToString(s));
128 if (
onStateChanged && juce::NotificationType::sendNotification == notificationType)
135 return m_currentState;
142 DBG(juce::String(__FUNCTION__) <<
" - nothing to do as we're not disconnected");
150 startTimer(m_ocp1Timeout * 20);
163 if (m_ocp1Connection)
164 m_ocp1Connection->disconnect(m_ocp1Timeout);
171 DBG(juce::String(__FUNCTION__) <<
" new connection params: " << ip.toString() <<
":" << port <<
" (t:" << timeoutMs <<
")");
172 m_ocp1IPAddress = ip;
174 jassert(0 < timeoutMs);
175 m_ocp1Timeout = timeoutMs;
186 return { m_ocp1IPAddress, m_ocp1Port, m_ocp1Timeout };
193 m_ocp1Connection->connectToSocket(m_ocp1IPAddress.toString(), m_ocp1Port, m_ocp1Timeout);
206 setState(scm->getState());
231void DeviceController::CreateKnownONosMap()
350 for (
auto& roisKV : m_ROIsToDefsMap)
351 for (auto& objDefKV : roisKV.second)
352 m_ONoToROIMap[objDefKV.second.m_targetOno] = { roisKV.first, objDefKV.first };
377std::optional<std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>> DeviceController::GetObjectDefinition(
const RemoteObject::RemObjIdent& roi,
const RemObjAddr& addr,
bool useDefinitionRemapping)
379 std::int32_t first = addr.pri;
380 std::int32_t second = addr.sec;
385 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Fixed_GUID());
387 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Settings_DeviceName());
389 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Status_StatusText());
391 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Status_AudioNetworkSampleStatus());
393 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Error_GnrlErr());
395 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Error_ErrorText());
397 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_Name(first));
399 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_Flip(first));
401 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_P1_real(first));
403 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_P2_real(first));
405 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_P3_real(first));
407 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_P4_real(first));
409 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_P1_virtual(first));
411 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_CoordinateMappingSettings_P3_virtual(first));
416 if (!useDefinitionRemapping)
418 DBG(juce::String(__FUNCTION__) +
" skipping Positioning_SourcePosition X Y XY");
424 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Positioning_Source_Position(first));
429 if (!useDefinitionRemapping)
431 DBG(juce::String(__FUNCTION__) +
" skipping CoordinateMapping_SourcePosition X Y XY");
438 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Positioning_Source_Spread(first));
440 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Positioning_Source_DelayMode(first));
442 if (m_ocp1DeviceStackIdent >= 1)
443 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Positioning_Speaker_Position(first));
445 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Positioning_Source_Speaker_Position(first));
447 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_FunctionGroup_Name(first));
449 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_FunctionGroup_Delay(first));
451 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_FunctionGroup_SpreadFactor(first));
453 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_Mute(first));
455 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_Gain(first));
457 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_Delay(first));
459 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_DelayEnable(first));
461 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_EqEnable(first));
463 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_Polarity(first));
465 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_ChannelName(first));
467 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_LevelMeterPreMute(first));
469 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_LevelMeterPostMute(first));
471 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixInput_ReverbSendGain(first));
473 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixNode_Enable(first, second));
475 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixNode_Gain(first, second));
477 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixNode_Delay(first, second));
479 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixNode_DelayEnable(first, second));
481 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_Mute(first));
483 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_Gain(first));
485 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_Delay(first));
487 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_DelayEnable(first));
489 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_EqEnable(first));
491 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_Polarity(first));
493 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_ChannelName(first));
495 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_LevelMeterPreMute(first));
497 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixOutput_LevelMeterPostMute(first));
499 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixSettings_ReverbRoomId());
501 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixSettings_ReverbPredelayFactor());
503 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_MatrixSettings_ReverbRearLevel());
505 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_ReverbInput_Gain(second, first));
507 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_ReverbInputProcessing_Mute(first));
509 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_ReverbInputProcessing_Gain(first));
511 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_ReverbInputProcessing_EqEnable(first));
513 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_ReverbInputProcessing_LevelMeter(first));
515 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Scene_SceneIndex());
517 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Scene_SceneName());
522 if (!useDefinitionRemapping)
525 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_SceneAgent());
528 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_Scene_SceneComment());
530 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_SoundObjectRouting_Mute(second, first));
532 return std::unique_ptr<NanoOcp1::Ocp1CommandDefinition>(
new NanoOcp1::DS100::dbOcaObjectDef_SoundObjectRouting_Gain(second, first));
539bool DeviceController::ocp1MessageReceived(
const juce::MemoryBlock& data)
541 std::unique_ptr<NanoOcp1::Ocp1Message> msgObj = NanoOcp1::Ocp1Message::UnmarshalOcp1Message(data);
544 switch (msgObj->GetMessageType())
546 case NanoOcp1::Ocp1Message::Notification:
548 NanoOcp1::Ocp1Notification* notifObj =
static_cast<NanoOcp1::Ocp1Notification*
>(msgObj.get());
550 if (UpdateObjectValue(notifObj))
553 DBG(juce::String(__FUNCTION__) <<
" Got an unhandled OCA notification for ONo 0x"
554 << juce::String::toHexString(notifObj->GetEmitterOno()));
557 case NanoOcp1::Ocp1Message::Response:
559 NanoOcp1::Ocp1Response* responseObj =
static_cast<NanoOcp1::Ocp1Response*
>(msgObj.get());
561 auto handle = responseObj->GetResponseHandle();
562 if (responseObj->GetResponseStatus() != 0)
564 DBG(juce::String(__FUNCTION__) <<
" Got an OCA response (handle:" << NanoOcp1::HandleToString(handle) <<
565 ") with status " << NanoOcp1::StatusToString(responseObj->GetResponseStatus()));
567 auto externalId = -1;
568 PopPendingSubscriptionHandle(handle);
569 PopPendingGetValueHandle(handle);
570 PopPendingSetValueHandle(handle, externalId);
574 else if (PopPendingSubscriptionHandle(handle))
576 if (!HasPendingSubscriptions())
583 if (HasPendingGetValues())
592 auto GetValONo = PopPendingGetValueHandle(handle);
593 if (0x00 != GetValONo)
595 if (!UpdateObjectValue(GetValONo, responseObj))
597 DBG(juce::String(__FUNCTION__) <<
" Got an unhandled OCA getvalue response message (handle:"
598 << NanoOcp1::HandleToString(handle) +
", targetONo:0x" << juce::String::toHexString(GetValONo) <<
")");
603 if (!HasPendingGetValues())
609 if (!HasPendingSubscriptions())
618 auto externalId = -1;
619 auto SetValONo = PopPendingSetValueHandle(handle, externalId);
620 if (0x00 != SetValONo)
622 if (!HasPendingSetValues())
631 DBG(juce::String(__FUNCTION__) <<
" Got an OCA response for UNKNOWN handle " << NanoOcp1::HandleToString(handle) <<
632 "; status " << NanoOcp1::StatusToString(responseObj->GetResponseStatus()) <<
633 "; paramCount " << juce::String(responseObj->GetParamCount()));
638 case NanoOcp1::Ocp1Message::KeepAlive:
658bool DeviceController::CreateObjectSubscriptions()
663 auto handle = std::uint32_t(0);
669 auto objDefOpt = GetObjectDefinition(activeObj.Id, activeObj.Addr);
675 auto& objDef = objDefOpt.value();
679 success = success && m_ocp1Connection->sendData(NanoOcp1::Ocp1CommandResponseRequired(objDef->AddSubscriptionCommand(), handle).GetMemoryBlock());
685 AddPendingSubscriptionHandle(handle);
693bool DeviceController::DeleteObjectSubscriptions()
698bool DeviceController::QueryObjectValues()
707 success = QueryObjectValue(activeObj.Id, activeObj.Addr) && success;
715bool DeviceController::QueryObjectValue(
const RemoteObject::RemObjIdent roi,
const RemObjAddr& addr)
717 auto handle = std::uint32_t(0);
720 auto objDefOpt = GetObjectDefinition(roi, addr,
true);
726 auto& objDef = objDefOpt.value();
731 bool success = m_ocp1Connection->sendData(NanoOcp1::Ocp1CommandResponseRequired(objDef->GetValueCommand(), handle).GetMemoryBlock());
732 AddPendingGetValueHandle(handle, objDef->m_targetOno);
742 auto handle = std::uint32_t(0);
744 auto objDefOpt = GetObjectDefinition(remObj.
Id, remObj.
Addr,
true);
748 auto& objDef = objDefOpt.value();
752 bool success = m_ocp1Connection->sendData(NanoOcp1::Ocp1CommandResponseRequired(objDef->SetValueCommand(remObj.
Var), handle).GetMemoryBlock());
753 AddPendingSetValueHandle(handle, objDef->m_targetOno, remObj.
Addr.
pri);
756 <<
"(" << remObj.
Addr.
toNiceString() <<
" handle:" << NanoOcp1::HandleToString(handle) <<
")");
761void DeviceController::AddPendingSubscriptionHandle(
const std::uint32_t handle)
763 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
767 m_pendingSubscriptionHandles.push_back(handle);
770bool DeviceController::PopPendingSubscriptionHandle(
const std::uint32_t handle)
772 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
774 auto it = std::find(m_pendingSubscriptionHandles.begin(), m_pendingSubscriptionHandles.end(), handle);
775 if (it != m_pendingSubscriptionHandles.end())
779 m_pendingSubscriptionHandles.erase(it);
786bool DeviceController::HasPendingSubscriptions()
788 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
790 return !m_pendingSubscriptionHandles.empty();
793void DeviceController::AddPendingGetValueHandle(
const std::uint32_t handle,
const std::uint32_t ONo)
795 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
800 m_pendingGetValueHandlesWithONo.insert(std::make_pair(handle, ONo));
803const std::uint32_t DeviceController::PopPendingGetValueHandle(
const std::uint32_t handle)
805 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
807 auto it = std::find_if(m_pendingGetValueHandlesWithONo.begin(), m_pendingGetValueHandlesWithONo.end(), [handle](
const auto& val) { return val.first == handle; });
808 if (it != m_pendingGetValueHandlesWithONo.end())
810 auto ONo = it->second;
814 m_pendingGetValueHandlesWithONo.erase(it);
821bool DeviceController::HasPendingGetValues()
823 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
825 return !m_pendingGetValueHandlesWithONo.empty();
828void DeviceController::AddPendingSetValueHandle(
const std::uint32_t handle,
const std::uint32_t ONo,
int externalId)
830 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
835 m_pendingSetValueHandlesWithONo.insert(std::make_pair(handle, std::make_pair(ONo, externalId)));
838const std::uint32_t DeviceController::PopPendingSetValueHandle(
const std::uint32_t handle,
int& externalId)
840 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
842 auto it = std::find_if(m_pendingSetValueHandlesWithONo.begin(), m_pendingSetValueHandlesWithONo.end(), [handle](
const auto& val) { return val.first == handle; });
843 if (it != m_pendingSetValueHandlesWithONo.end())
845 auto ONo = it->second.first;
846 externalId = it->second.second;
850 m_pendingSetValueHandlesWithONo.erase(it);
857bool DeviceController::HasPendingSetValues()
859 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
861 return !m_pendingGetValueHandlesWithONo.empty();
864const std::optional<std::pair<std::uint32_t, int>> DeviceController::HasPendingSetValue(
const std::uint32_t ONo)
866 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
868 auto it = std::find_if(m_pendingSetValueHandlesWithONo.begin(), m_pendingSetValueHandlesWithONo.end(), [ONo](
const auto& val) { return val.second.first == ONo; });
869 if (it != m_pendingSetValueHandlesWithONo.end())
874 return std::optional<std::pair<std::uint32_t, int>>(std::make_pair(it->first, it->second.second));
877 return std::optional<std::pair<std::uint32_t, int>>();
880void DeviceController::ClearPendingHandles()
882 std::lock_guard<std::mutex> l(m_pendingHandlesMutex);
884 m_pendingSubscriptionHandles.clear();
885 m_pendingGetValueHandlesWithONo.clear();
886 m_pendingSetValueHandlesWithONo.clear();
889bool DeviceController::UpdateObjectValue(NanoOcp1::Ocp1Notification* notifObj)
891 auto it = m_ONoToROIMap.find(notifObj->GetEmitterOno());
892 if (it != m_ONoToROIMap.end())
894 auto& [roi, addr] = it->second;
895 return UpdateObjectValue(roi,
dynamic_cast<NanoOcp1::Ocp1Message*
>(notifObj),
896 { addr, m_ROIsToDefsMap.at(roi).at(addr) });
902bool DeviceController::UpdateObjectValue(
const std::uint32_t ONo, NanoOcp1::Ocp1Response* responseObj)
904 auto it = m_ONoToROIMap.find(ONo);
905 if (it != m_ONoToROIMap.end())
907 auto& [roi, addr] = it->second;
908 return UpdateObjectValue(roi,
dynamic_cast<NanoOcp1::Ocp1Message*
>(responseObj),
909 { addr, m_ROIsToDefsMap.at(roi).at(addr) });
931bool DeviceController::UpdateObjectValue(
const RemoteObject::RemObjIdent roi, NanoOcp1::Ocp1Message* msgObj,
const std::pair<RemObjAddr, NanoOcp1::Ocp1CommandDefinition>& objectDetails)
933 NanoOcp1::Ocp1DataType datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_NONE;
939 auto guid = NanoOcp1::DataToString(msgObj->GetParameterData(), &ok);
941 ProcessGuidAndSubscribe(guid);
952 datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_UINT8;
964 datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_UINT16;
967 datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_INT32;
989 datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_FLOAT32;
1001 datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_STRING;
1012 datatype = NanoOcp1::Ocp1DataType::OCP1DATATYPE_DB_POSITION;
1016 <<
" (" <<
static_cast<int>(objectDetails.first.pri) <<
"," <<
static_cast<int>(objectDetails.first.sec) <<
") ");
1020 auto val = NanoOcp1::Variant(msgObj->GetParameterData(), datatype);
1021 auto ro = RemoteObject(roi, objectDetails.first, val);
1022 postMessage(
new RemoteObjectReceivedMessage(ro));
1029 return m_activeRemoteObjects;
1037 m_activeRemoteObjects = remObjs;
1059void DeviceController::ProcessGuidAndSubscribe(
const juce::String newGuid)
1061 if (newGuid == m_ocp1DeviceGUID)
1064 if (SetOcaRevisionAndDeviceModel(newGuid))
1065 m_ocp1DeviceGUID = newGuid;
1070 if (m_ocp1DeviceStackIdent >= 1)
1087 CreateObjectSubscriptions();
1088 QueryObjectValues();
1108bool DeviceController::SetOcaRevisionAndDeviceModel(
const juce::String& guid)
1110 if (guid.length() != 8)
1112 if (!guid.startsWith(
"DB00"))
1115 int deviceBytes = 2;
1117 if (guid.getLastCharacters(deviceBytes) ==
"D0")
1119 else if (guid.getLastCharacters(deviceBytes) ==
"D1")
1121 else if (guid.getLastCharacters(deviceBytes) ==
"D2")
1126 int versionBytesIndexStart = 4;
1127 auto versionChars = guid.substring(versionBytesIndexStart, versionBytesIndexStart + 2);
1128 int ocp1DeviceStackIdent;
1129 switch (dbDeviceModel)
1132 if (versionChars >=
"0C")
1133 ocp1DeviceStackIdent = 1;
1135 ocp1DeviceStackIdent = 0;
1136 DBG(juce::String(__FUNCTION__) <<
" detected DS100 (ocp stack:" << ocp1DeviceStackIdent <<
") " << guid);
1139 ocp1DeviceStackIdent = 1;
1140 DBG(juce::String(__FUNCTION__) <<
" detected DS100D (ocp stack:" << ocp1DeviceStackIdent <<
") " << guid);
1143 if (versionChars >=
"02")
1144 ocp1DeviceStackIdent = 1;
1146 ocp1DeviceStackIdent = 0;
1147 DBG(juce::String(__FUNCTION__) <<
" detected DS100M (ocp stack:" << ocp1DeviceStackIdent <<
") " << guid);
1153 m_connectedDbDeviceModel = dbDeviceModel;
1154 m_ocp1DeviceStackIdent = ocp1DeviceStackIdent;
Carries a decoded RemoteObject across the thread boundary via JUCE's message queue.
Carries a State value across the thread boundary via JUCE's message queue.
Singleton that owns the OCP.1 (AES70) TCP connection to a d&b audiotechnik DS100 device and exposes a...
const State getState() const
Returns the current connection/subscription state.
void timerCallback() override
juce::Timer callback — retries connectToSocket() while in Connecting state.
std::function< bool(const RemoteObject &)> onRemoteObjectReceived
Called on the JUCE message thread when a notification or get-value response is decoded for a subscrib...
static constexpr std::uint16_t sc_MAX_INPUTS_CHANNELS
DbDeviceModel
Identifies which DS100 hardware variant is connected.
@ DS100M
DS100M (Milan network audio variant).
@ DS100D
DS100D (Dante network audio variant).
const std::tuple< juce::IPAddress, int, int > getConnectionParameters()
Returns the current connection parameters as {ip, port, timeoutMs}.
bool connect()
Initiates the TCP connection. No-op if not in Disconnected state.
static constexpr std::uint16_t sc_MAX_FUNCTION_GROUPS
void handleMessage(const juce::Message &message) override
juce::MessageListener callback — dispatches messages posted from the socket thread.
bool SetObjectValue(const RemoteObject &remObj)
Sends a SetValue command to the device for the given remote object.
virtual ~DeviceController()
static constexpr std::uint16_t sc_MAX_OUTPUT_CHANNELS
bool SetActiveRemoteObjects(const std::vector< RemoteObject > &remObjs)
Sets the list of remote objects to subscribe to on the next connection.
State
Represents the logical phase of the OCP.1 connection.
@ Connected
All subscriptions confirmed and all initial values received.
@ Connecting
TCP connect in progress; timer retries until success.
@ GetValues
GetValue responses being collected.
@ Subscribing
AddSubscription commands sent, awaiting acknowledgements.
@ Disconnected
No TCP connection exists; no resources are allocated.
@ Subscribed
All subscriptions confirmed; GetValue queries still pending.
void setConnectionParameters(juce::IPAddress ip, int port, int timeoutMs=150)
Updates connection parameters and reconnects if currently connected.
const std::vector< RemoteObject > & GetActiveRemoteObjects()
Returns the active subscription list last set by SetActiveRemoteObjects().
static constexpr std::uint16_t sc_MAX_REVERB_ZONES
std::function< void(const State state)> onStateChanged
Called on the JUCE message thread whenever the connection state changes.
void disconnect()
Closes the TCP connection and resets state to Disconnected. Safe to call from any state,...
std::int16_t pri
Primary index (channel, speaker, group, zone…). 0 = not used.
juce::String toNiceString() const
static constexpr std::int16_t sc_INV
A fully-qualified remote parameter including its type, address, and current value.
static juce::String GetObjectDescription(const RemObjIdent roi)
@ CoordinateMappingSettings_P1virtual
@ Positioning_SpeakerPosition
@ CoordinateMapping_SourcePosition_Y
@ CoordinateMapping_SourcePosition
@ Status_AudioNetworkSampleStatus
@ MatrixOutput_LevelMeterPostMute
@ Positioning_SourcePosition_XY
@ CoordinateMappingSettings_P3real
@ CoordinateMappingSettings_P4real
@ Positioning_SourcePosition_Y
@ MatrixInput_ReverbSendGain
@ CoordinateMappingSettings_Name
@ CoordinateMappingSettings_Flip
@ CoordinateMappingSettings_P1real
@ MatrixInput_LevelMeterPostMute
@ CoordinateMapping_SourcePosition_X
@ CoordinateMapping_SourcePosition_XY
@ MatrixSettings_ReverbPredelayFactor
@ Positioning_SourceSpread
@ CoordinateMappingSettings_P3virtual
@ ReverbInputProcessing_Mute
@ Positioning_SourcePosition
@ CoordinateMappingSettings_P2real
@ MatrixOutput_LevelMeterPreMute
@ ReverbInputProcessing_EqEnable
@ Positioning_SourceDelayMode
@ MatrixOutput_DelayEnable
@ SoundObjectRouting_Gain
@ MatrixOutput_ChannelName
@ ReverbInputProcessing_LevelMeter
@ MatrixInput_DelayEnable
@ MatrixInput_LevelMeterPreMute
@ ReverbInputProcessing_Gain
@ Fixed_GUID
Read-only 8-char device GUID; queried before any subscriptions.
@ MatrixSettings_ReverbRearLevel
@ SoundObjectRouting_Mute
@ Positioning_SourcePosition_X
@ MatrixInput_ChannelName
@ MatrixSettings_ReverbRoomId
@ FunctionGroup_SpreadFactor