remoteDevice.cpp (7091B)
1 #include "remoteDevice.h" 2 3 #include "udpClient.h" 4 5 #include "bridgeLib/types.h" 6 7 #include "dsp56kEmu/logging.h" 8 9 #include "networkLib/tcpClient.h" 10 #include "networkLib/tcpStream.h" 11 12 #include "synthLib/deviceException.h" 13 14 #include "deviceConnection.h" 15 16 #include <condition_variable> 17 18 #include "baseLib/filesystem.h" 19 20 #include "networkLib/exception.h" 21 #include "networkLib/logging.h" 22 23 namespace bridgeClient 24 { 25 static constexpr uint32_t g_udpTimeout = 5; // seconds 26 static constexpr uint32_t g_tcpTimeout = 5; // seconds 27 28 RemoteDevice::RemoteDevice(const synthLib::DeviceCreateParams& _params, bridgeLib::PluginDesc&& _desc, const std::string& _host/* = {}*/, uint32_t _port/* = 0*/) : Device(_params), m_pluginDesc(std::move(_desc)) 29 { 30 getDeviceCreateParams().romHash = baseLib::MD5(getDeviceCreateParams().romData); 31 getDeviceCreateParams().romName = baseLib::filesystem::getFilenameWithoutPath(getDeviceCreateParams().romName); 32 33 m_pluginDesc.protocolVersion = bridgeLib::g_protocolVersion; 34 createConnection(_host, _port); 35 } 36 37 RemoteDevice::~RemoteDevice() 38 { 39 m_connection.reset(); 40 } 41 42 float RemoteDevice::getSamplerate() const 43 { 44 return m_deviceDesc.samplerate; 45 } 46 47 bool RemoteDevice::isValid() const 48 { 49 return m_valid; 50 } 51 52 bool RemoteDevice::getState(std::vector<uint8_t>& _state, const synthLib::StateType _type) 53 { 54 return safeCall([&] 55 { 56 return m_connection->getDeviceState(_state, _type); 57 }, [&] 58 { 59 // if there is no valid connection anymore attempt to grab the latest state that was sent 60 if(!m_connection) 61 return; 62 auto& state = static_cast<bridgeLib::TcpConnection*>(m_connection.get())->getDeviceState(); 63 _state.insert(_state.end(), state.state.begin(), state.state.end()); 64 }); 65 } 66 67 bool RemoteDevice::setState(const std::vector<uint8_t>& _state, const synthLib::StateType _type) 68 { 69 if(!isValid()) 70 return false; 71 return m_connection->setDeviceState(_state, _type); 72 } 73 74 uint32_t RemoteDevice::getChannelCountIn() 75 { 76 return m_deviceDesc.inChannels; 77 } 78 79 uint32_t RemoteDevice::getChannelCountOut() 80 { 81 return m_deviceDesc.outChannels; 82 } 83 84 bool RemoteDevice::setDspClockPercent(const uint32_t _percent) 85 { 86 return safeCall([&] 87 { 88 m_connection->setDspClockPercent(_percent); 89 return true; 90 }); 91 } 92 93 uint32_t RemoteDevice::getDspClockPercent() const 94 { 95 return m_deviceDesc.dspClockPercent; 96 } 97 98 uint64_t RemoteDevice::getDspClockHz() const 99 { 100 return m_deviceDesc.dspClockHz; 101 } 102 103 uint32_t RemoteDevice::getInternalLatencyInputToOutput() const 104 { 105 return m_deviceDesc.latencyInToOut; 106 } 107 108 uint32_t RemoteDevice::getInternalLatencyMidiToOutput() const 109 { 110 return m_deviceDesc.latencyMidiToOut; 111 } 112 113 void RemoteDevice::getPreferredSamplerates(std::vector<float>& _dst) const 114 { 115 _dst = m_deviceDesc.preferredSamplerates; 116 } 117 118 void RemoteDevice::getSupportedSamplerates(std::vector<float>& _dst) const 119 { 120 _dst = m_deviceDesc.supportedSamplerates; 121 } 122 123 bool RemoteDevice::setSamplerate(const float _samplerate) 124 { 125 return safeCall([&] 126 { 127 m_connection->setSamplerate(_samplerate); 128 return true; 129 }); 130 } 131 132 bool RemoteDevice::setStateFromUnknownCustomData(const std::vector<uint8_t>& _state) 133 { 134 return safeCall([&] 135 { 136 m_connection->setStateFromUnknownCustomData(_state); 137 return true; 138 }); 139 } 140 141 void RemoteDevice::onBootFinished(const bridgeLib::DeviceDesc& _desc) 142 { 143 { 144 std::unique_lock lock(m_cvWaitMutex); 145 m_deviceDesc = _desc; 146 } 147 m_cvWait.notify_one(); 148 } 149 150 void RemoteDevice::onDisconnect() 151 { 152 { 153 std::unique_lock lock(m_cvWaitMutex); 154 m_valid = false; 155 } 156 m_cvWait.notify_one(); 157 } 158 159 void RemoteDevice::readMidiOut(std::vector<synthLib::SMidiEvent>& _midiOut) 160 { 161 safeCall([&] 162 { 163 m_connection->readMidiOut(_midiOut); 164 return true; 165 }); 166 } 167 168 void RemoteDevice::processAudio(const synthLib::TAudioInputs& _inputs, const synthLib::TAudioOutputs& _outputs, const size_t _samples) 169 { 170 safeCall([&] 171 { 172 return m_connection->processAudio(_inputs, _outputs, static_cast<uint32_t>(_samples), getExtraLatencySamples()); 173 }); 174 } 175 176 bool RemoteDevice::sendMidi(const synthLib::SMidiEvent& _ev, std::vector<synthLib::SMidiEvent>& _response) 177 { 178 return safeCall([&] 179 { 180 return m_connection->send(_ev); 181 }); 182 } 183 184 bool RemoteDevice::safeCall(const std::function<bool()>& _func, const std::function<void()>& _onFail/* = [] {}*/) 185 { 186 if(!isValid()) 187 { 188 _onFail(); 189 return false; 190 } 191 192 try 193 { 194 if(!_func()) 195 { 196 onDisconnect(); 197 _onFail(); 198 } 199 } 200 catch(networkLib::NetException& e) 201 { 202 LOG(e.what()); 203 onDisconnect(); 204 _onFail(); 205 } 206 return true; 207 } 208 209 void RemoteDevice::createConnection(const std::string& _host, uint32_t _port) 210 { 211 // wait for UDP connection up to 5 seconds 212 bridgeLib::ServerInfo si; 213 std::string host = _host; 214 215 if(_host.empty() || !_port) 216 { 217 UdpClient udpClient(m_pluginDesc, [&](const std::string& _hostname, const bridgeLib::ServerInfo& _si, const bridgeLib::Error& _err) 218 { 219 if(_err.code != bridgeLib::ErrorCode::Ok) 220 return; 221 { 222 std::unique_lock lock(m_cvWaitMutex); 223 si = _si; 224 host = _hostname; 225 LOG("Found server "<< _hostname << ':' << si.portTcp); 226 } 227 m_cvWait.notify_one(); 228 }); 229 230 std::unique_lock lockCv(m_cvWaitMutex); 231 if(!m_cvWait.wait_for(lockCv, std::chrono::seconds(g_udpTimeout), [&si] 232 { 233 return si.protocolVersion == bridgeLib::g_protocolVersion; 234 })) 235 { 236 throw synthLib::DeviceException(synthLib::DeviceError::RemoteUdpConnectFailed, "No server found"); 237 } 238 } 239 else 240 { 241 si.portTcp = _port; 242 } 243 244 // wait for TCP connection for another 5 seconds 245 std::unique_ptr<networkLib::TcpStream> stream; 246 247 LOG("Connecting to "<< host << ':' << si.portTcp); 248 249 networkLib::TcpClient client(host, si.portTcp,[&](std::unique_ptr<networkLib::TcpStream> _tcpStream) 250 { 251 { 252 std::unique_lock lock(m_cvWaitMutex); 253 stream = std::move(_tcpStream); 254 } 255 m_cvWait.notify_one(); 256 }); 257 258 { 259 std::unique_lock lockCv(m_cvWaitMutex); 260 if(!m_cvWait.wait_for(lockCv, std::chrono::seconds(g_tcpTimeout), [&stream] 261 { 262 return stream.get() && stream->isValid(); 263 })) 264 { 265 throw synthLib::DeviceException(synthLib::DeviceError::RemoteTcpConnectFailed, "Failed to connect to " + host + ':' + std::to_string(si.portTcp)); 266 } 267 } 268 269 // we are connected. Wait for device info as long as the connection is alive. The server will either 270 // close it if the requirements are not fulfilled (plugin not existing on server) or will eventually 271 // send device info after the device has bene opened on the server 272 m_connection.reset(new DeviceConnection(*this, std::move(stream))); 273 274 std::unique_lock lockCv(m_cvWaitMutex); 275 m_cvWait.wait(lockCv, [this]() 276 { 277 // continue waiting if the connection is still active but we didn't receive a device desc yet 278 return !m_connection->isValid() || m_deviceDesc.outChannels > 0; 279 }); 280 281 if(!m_connection->isValid() || m_deviceDesc.outChannels == 0) 282 throw synthLib::DeviceException(synthLib::DeviceError::RemoteTcpConnectFailed); 283 284 m_valid = true; 285 286 LOG("Connection established successfully"); 287 } 288 }