feat: add artboard volume to command queue/server (#12816) 88115b0949 Co-authored-by: David Skuza <david@rive.app>
diff --git a/.rive_head b/.rive_head index 8797046..71e5f7a 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -61822bb24793050f151e291788b912a2fea1cffb +88115b09496d99f10462da6e4ececcbd87988090
diff --git a/include/rive/command_queue.hpp b/include/rive/command_queue.hpp index efd415c..4a3ebb7 100644 --- a/include/rive/command_queue.hpp +++ b/include/rive/command_queue.hpp
@@ -254,6 +254,11 @@ uint64_t requestId, std::vector<std::string> stateMachineNames) {} + + virtual void onArtboardVolumeReceived(const ArtboardHandle, + uint64_t requestId, + float volume) + {} }; struct ViewModelInstanceData @@ -681,6 +686,11 @@ std::string path, uint64_t requestId = 0); + void setArtboardVolume(ArtboardHandle, + float volume, + uint64_t requestId = 0); + void requestArtboardVolume(ArtboardHandle, uint64_t requestId = 0); + void requestStateMachineNames(ArtboardHandle, uint64_t requestId = 0); void requestDefaultViewModelInfo(ArtboardHandle, FileHandle, @@ -881,6 +891,8 @@ getViewModelListSize, clearViewModelList, listFileAssets, + setArtboardVolume, + getArtboardVolume }; enum class Message @@ -920,7 +932,8 @@ imageError, audioError, fontError, - stateMachineError + stateMachineError, + artboardVolumeReceived }; friend class CommandServer;
diff --git a/src/command_queue.cpp b/src/command_queue.cpp index 01ad3f8..cbf1bac 100644 --- a/src/command_queue.cpp +++ b/src/command_queue.cpp
@@ -173,6 +173,26 @@ m_commandStream << requestId; } +void CommandQueue::setArtboardVolume(ArtboardHandle artboardHandle, + float volume, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::setArtboardVolume; + m_commandStream << artboardHandle; + m_commandStream << volume; + m_commandStream << requestId; +} + +void CommandQueue::requestArtboardVolume(ArtboardHandle artboardHandle, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::getArtboardVolume; + m_commandStream << artboardHandle; + m_commandStream << requestId; +} + void CommandQueue::deleteArtboard(ArtboardHandle artboardHandle, uint64_t requestId) { @@ -1249,6 +1269,34 @@ break; } + case Message::artboardVolumeReceived: + { + ArtboardHandle handle; + uint64_t requestId; + float volume; + m_messageStream >> handle; + m_messageStream >> requestId; + m_messageStream >> volume; + lock.unlock(); + + if (m_globalArtboardListener) + { + m_globalArtboardListener->onArtboardVolumeReceived( + handle, + requestId, + volume); + } + + auto itr = m_artboardListeners.find(handle); + if (itr != m_artboardListeners.end()) + { + itr->second->onArtboardVolumeReceived(itr->first, + requestId, + volume); + } + + break; + } case Message::viewModelInstanceViewModelNameReceived: { ViewModelInstanceHandle handle;
diff --git a/src/command_server.cpp b/src/command_server.cpp index 410dfcb..7ee5189 100644 --- a/src/command_server.cpp +++ b/src/command_server.cpp
@@ -1059,6 +1059,64 @@ } break; + case CommandQueue::Command::setArtboardVolume: + { + ArtboardHandle handle; + float volume; + uint64_t requestId; + commandStream >> handle; + commandStream >> volume; + commandStream >> requestId; + lock.unlock(); + + if (auto artboardInstance = getArtboardInstance(handle)) + { + artboardInstance->volume(volume); + } + else + { + ErrorReporter<ArtboardHandle>( + this, + handle, + requestId, + CommandQueue::Message::artboardError) + << "artboard " << handle + << " not found when trying to set artboard volume"; + } + } + break; + + case CommandQueue::Command::getArtboardVolume: + { + ArtboardHandle handle; + uint64_t requestId; + commandStream >> handle; + commandStream >> requestId; + lock.unlock(); + auto artboard = getArtboardInstance(handle); + if (artboard) + { + std::unique_lock<std::mutex> messageLock( + m_commandQueue->m_messageMutex); + messageStream + << CommandQueue::Message::artboardVolumeReceived; + messageStream << handle; + messageStream << requestId; + messageStream << artboard->volume(); + } + else + { + ErrorReporter<ArtboardHandle>( + this, + handle, + requestId, + CommandQueue::Message::artboardError) + << "Invalid artboard handle " << handle + << " when getting artboard volume"; + } + break; + } + case CommandQueue::Command::deleteArtboard: { ArtboardHandle handle;
diff --git a/tests/unit_tests/runtime/command_queue_test.cpp b/tests/unit_tests/runtime/command_queue_test.cpp index 28b69d7..6efb0d9 100644 --- a/tests/unit_tests/runtime/command_queue_test.cpp +++ b/tests/unit_tests/runtime/command_queue_test.cpp
@@ -2369,6 +2369,73 @@ serverThread.join(); } +class TestArtboardVolumeListener : public CommandQueue::ArtboardListener +{ +public: + virtual void onArtboardVolumeReceived(const ArtboardHandle handle, + uint64_t requestId, + float volume) override + { + CHECK(requestId == m_requestId); + CHECK(handle == m_handle); + m_receivedVolume = volume; + m_hasCallback = true; + } + + uint64_t m_requestId; + ArtboardHandle m_handle; + float m_receivedVolume = -1.0f; + bool m_hasCallback = false; +}; + +TEST_CASE("Set Artboard Volume / Get Artboard Volume", "[CommandQueue]") +{ + auto commandQueue = make_rcp<CommandQueue>(); + std::thread serverThread(server_thread, commandQueue); + + std::ifstream stream("assets/data_bind_test_cmdq.riv", std::ios::binary); + FileHandle fileHandle = commandQueue->loadFile( + std::vector<uint8_t>(std::istreambuf_iterator<char>(stream), {})); + + auto artboardHandle = commandQueue->instantiateDefaultArtboard(fileHandle); + + commandQueue->setArtboardVolume(artboardHandle, 0.5f); + + commandQueue->runOnce( + [artboardHandle = artboardHandle](CommandServer* server) { + auto artboard = server->getArtboardInstance(artboardHandle); + CHECK(artboard->volume() == 0.5f); + }); + + commandQueue->setArtboardVolume(artboardHandle, 0.0f); + + commandQueue->runOnce( + [artboardHandle = artboardHandle](CommandServer* server) { + auto artboard = server->getArtboardInstance(artboardHandle); + CHECK(artboard->volume() == 0.0f); + }); + + // Test getter via listener + TestArtboardVolumeListener volumeListener; + + auto listenerArtboard = + commandQueue->instantiateDefaultArtboard(fileHandle, &volumeListener); + volumeListener.m_handle = listenerArtboard; + volumeListener.m_requestId = 0x50; + + commandQueue->setArtboardVolume(listenerArtboard, 0.75f); + commandQueue->requestArtboardVolume(listenerArtboard, 0x50); + + wait_for_server(commandQueue.get()); + commandQueue->processMessages(); + + CHECK(volumeListener.m_hasCallback); + CHECK(volumeListener.m_receivedVolume == 0.75f); + + commandQueue->disconnect(); + serverThread.join(); +} + TEST_CASE("View Model Property Subscriptions", "[CommandQueue]") { auto commandQueue = make_rcp<CommandQueue>(); @@ -3335,11 +3402,13 @@ { CHECK(handle == m_handle); CHECK(error.size()); + m_requestIDs.push_back(requestId); ++m_receivedErrors; } size_t m_receivedErrors = 0; ArtboardHandle m_handle; + std::vector<uint64_t> m_requestIDs; }; TEST_CASE("artboard errors", "[CommandQueue]") @@ -3384,6 +3453,31 @@ serverThread.join(); } +TEST_CASE("Set Artboard Volume / Get Artboard Volume errors on invalid handles", + "[CommandQueue]") +{ + auto commandQueue = make_rcp<CommandQueue>(); + std::thread serverThread(server_thread, commandQueue); + + TestArtboardErrorListener errorListener; + auto invalidHandle = reinterpret_cast<rive::ArtboardHandle>(0xFF); + errorListener.m_handle = invalidHandle; + commandQueue->setGlobalArtboardListener(&errorListener); + + commandQueue->setArtboardVolume(invalidHandle, 0.5f, 0x51); + commandQueue->requestArtboardVolume(invalidHandle, 0x52); + + wait_for_server(commandQueue.get()); + commandQueue->processMessages(); + + CHECK(errorListener.m_receivedErrors == 2); + CHECK(errorListener.m_requestIDs[0] == 0x51); + CHECK(errorListener.m_requestIDs[1] == 0x52); + + commandQueue->disconnect(); + serverThread.join(); +} + class TestArtboardListener : public CommandQueue::ArtboardListener { public: