clientConnection.cpp (8082B)
1 #include "clientConnection.h" 2 3 #include "server.h" 4 #include "bridgeLib/error.h" 5 #include "networkLib/logging.h" 6 7 namespace bridgeServer 8 { 9 static constexpr uint32_t g_audioBufferSize = 16384; 10 11 ClientConnection::ClientConnection(Server& _server, std::unique_ptr<networkLib::TcpStream>&& _stream, std::string _name) 12 : TcpConnection(std::move(_stream)) 13 , m_server(_server) 14 , m_name(std::move(_name)) 15 { 16 for(size_t i=0; i<m_audioInputBuffers.size(); ++i) 17 { 18 auto& buf = m_audioInputBuffers[i]; 19 buf.resize(g_audioBufferSize); 20 m_audioInputs[i] = buf.data(); 21 } 22 23 for(size_t i=0; i<m_audioOutputBuffers.size(); ++i) 24 { 25 auto& buf = m_audioOutputBuffers[i]; 26 buf.resize(g_audioBufferSize); 27 m_audioOutputs[i] = buf.data(); 28 } 29 30 m_midiIn.reserve(1024); 31 m_midiOut.reserve(4096); 32 33 getDeviceState().state.reserve(8 * 1024 * 1024); 34 } 35 36 ClientConnection::~ClientConnection() 37 { 38 shutdown(); 39 destroyDevice(); 40 } 41 42 void ClientConnection::handleMidi(const synthLib::SMidiEvent& _e) 43 { 44 m_midiIn.push_back(_e); 45 } 46 47 void ClientConnection::handleData(const bridgeLib::PluginDesc& _desc) 48 { 49 m_pluginDesc = _desc; 50 LOGNET(networkLib::LogLevel::Info, "Client " << m_name << " identified as plugin " << _desc.pluginName << ", version " << _desc.pluginVersion); 51 m_name = m_pluginDesc.pluginName + '-' + m_name; 52 createDevice(); 53 } 54 55 void ClientConnection::handleData(const bridgeLib::DeviceCreateParams& _params) 56 { 57 const auto& p = _params.params; 58 59 if(p.romData.empty()) 60 { 61 // if no rom data has been transmitted, try to load from cache 62 const auto& romData = m_server.getRomPool().getRom(p.romHash); 63 64 if(!romData.empty()) 65 { 66 // if we have the ROM, we are good to go 67 LOGNET(networkLib::LogLevel::Info, "ROM " << p.romName << " with hash " << p.romHash.toString() << " found, transfer skipped"); 68 69 m_deviceCreateParams = p; 70 m_deviceCreateParams.romData = romData; 71 72 createDevice(); 73 } 74 else 75 { 76 if(m_romRequested) 77 { 78 LOGNET(networkLib::LogLevel::Warning, "Client " << m_name << " failed to provide rom that we asked for, disconnecting"); 79 close(); 80 return; 81 } 82 83 // If not, ask client to send it 84 send(bridgeLib::Command::RequestRom); 85 LOGNET(networkLib::LogLevel::Info, "ROM " << p.romName << " with hash " << p.romHash.toString() << " not found, requesting client to send it"); 86 m_romRequested = true; 87 } 88 } 89 else 90 { 91 // client sent the rom. Validate transmission by comparing hashes 92 const baseLib::MD5 calculatedHash(p.romData); 93 if(calculatedHash != p.romHash) 94 { 95 LOGNET(networkLib::LogLevel::Error, "Calculated hash " << calculatedHash.toString() << " of ROM " << p.romName << " does not match sent hash " << p.romHash.toString() << ", transfer error"); 96 close(); 97 } 98 99 LOGNET(networkLib::LogLevel::Info, "Adding ROM " << p.romName << " with hash " << p.romHash.toString() << " to pool"); 100 m_server.getRomPool().addRom(p.romName, p.romData); 101 102 m_deviceCreateParams = p; 103 104 createDevice(); 105 } 106 } 107 108 void ClientConnection::handleAudio(baseLib::BinaryStream& _in) 109 { 110 if(!m_device) 111 { 112 errorClose(bridgeLib::ErrorCode::UnexpectedCommand, "Audio data without valid device"); 113 return; 114 } 115 116 const auto numSamples = TcpConnection::handleAudio(const_cast<float* const*>(m_audioInputs.data()), _in); 117 118 m_device->process(m_audioInputs, m_audioOutputs, numSamples, m_midiIn, m_midiOut); 119 120 for (const auto& midiOut : m_midiOut) 121 send(midiOut); 122 123 sendAudio(m_audioOutputs.data(), std::min(static_cast<uint32_t>(m_audioOutputs.size()), m_device->getChannelCountOut()), numSamples); 124 125 m_midiIn.clear(); 126 127 m_device->release(m_midiOut); 128 } 129 130 void ClientConnection::sendDeviceState(const synthLib::StateType _type) 131 { 132 if(!m_device) 133 return; 134 135 std::scoped_lock lock(m_mutexDeviceState); 136 auto& state = getDeviceState(); 137 state.type = _type; 138 139 state.state.clear(); 140 m_device->getState(state.state, _type); 141 142 send(bridgeLib::Command::DeviceState, state); 143 } 144 145 void ClientConnection::handleRequestDeviceState(bridgeLib::RequestDeviceState& _requestDeviceState) 146 { 147 if(!m_device) 148 { 149 errorClose(bridgeLib::ErrorCode::UnexpectedCommand, "Device state request without valid device"); 150 return; 151 } 152 153 sendDeviceState(_requestDeviceState.type); 154 } 155 156 void ClientConnection::handleDeviceState(bridgeLib::DeviceState& _in) 157 { 158 if(!m_device) 159 { 160 errorClose(bridgeLib::ErrorCode::UnexpectedCommand, "Device state without valid device"); 161 return; 162 } 163 164 m_device->setState(_in.state, _in.type); 165 sendDeviceInfo(); 166 } 167 168 void ClientConnection::handleDeviceState(baseLib::BinaryStream& _in) 169 { 170 std::scoped_lock lock(m_mutexDeviceState); 171 TcpConnection::handleDeviceState(_in); 172 } 173 174 void ClientConnection::handleException(const networkLib::NetException& _e) 175 { 176 exit(true); 177 m_server.onClientException(*this, _e); 178 } 179 180 void ClientConnection::handleData(const bridgeLib::SetSamplerate& _params) 181 { 182 if(!m_device) 183 { 184 errorClose(bridgeLib::ErrorCode::UnexpectedCommand, "Set samplerate request without valid device"); 185 return; 186 } 187 188 m_device->setSamplerate(_params.samplerate); 189 sendDeviceInfo(); 190 } 191 192 void ClientConnection::handleData(const bridgeLib::SetDspClockPercent& _params) 193 { 194 if(!m_device) 195 { 196 errorClose(bridgeLib::ErrorCode::UnexpectedCommand, "Set DSP clock request without valid device"); 197 return; 198 } 199 200 m_device->setDspClockPercent(_params.percent); 201 sendDeviceInfo(); 202 } 203 204 void ClientConnection::handleData(const bridgeLib::SetUnknownCustomData& _params) 205 { 206 if(!m_device) 207 { 208 errorClose(bridgeLib::ErrorCode::UnexpectedCommand, "Set custom data request without valid device"); 209 return; 210 } 211 212 m_device->setStateFromUnknownCustomData(_params.data); 213 sendDeviceInfo(); 214 } 215 216 void ClientConnection::sendDeviceInfo() 217 { 218 bridgeLib::DeviceDesc deviceDesc; 219 220 deviceDesc.samplerate = m_device->getSamplerate(); 221 deviceDesc.outChannels = m_device->getChannelCountOut(); 222 deviceDesc.inChannels = m_device->getChannelCountIn(); 223 deviceDesc.dspClockPercent = m_device->getDspClockPercent(); 224 deviceDesc.dspClockHz = m_device->getDspClockHz(); 225 deviceDesc.latencyInToOut = m_device->getInternalLatencyInputToOutput(); 226 deviceDesc.latencyMidiToOut = m_device->getInternalLatencyMidiToOutput(); 227 228 deviceDesc.preferredSamplerates.reserve(64); 229 deviceDesc.supportedSamplerates.reserve(64); 230 231 m_device->getPreferredSamplerates(deviceDesc.preferredSamplerates); 232 m_device->getSupportedSamplerates(deviceDesc.supportedSamplerates); 233 234 send(bridgeLib::Command::DeviceInfo, deviceDesc); 235 } 236 237 void ClientConnection::createDevice() 238 { 239 if(m_pluginDesc.pluginVersion == 0 || m_deviceCreateParams.romData.empty()) 240 return; 241 242 m_device = m_server.getPlugins().createDevice(m_deviceCreateParams, m_pluginDesc); 243 244 if(!m_device) 245 { 246 errorClose(bridgeLib::ErrorCode::FailedToCreateDevice,"Failed to create device"); 247 return; 248 } 249 250 const auto& d = m_pluginDesc; 251 LOGNET(networkLib::LogLevel::Info, "Created new device for plugin '" << d.pluginName << "', version " << d.pluginVersion << ", id " << d.plugin4CC); 252 253 // recover a previously lost connection if possible 254 const auto cachedDeviceState = m_server.getCachedDeviceState(d.sessionId); 255 256 if(cachedDeviceState.isValid()) 257 { 258 LOGNET(networkLib::LogLevel::Info, m_name << ": Recovering previous device state for session id " << d.sessionId); 259 send(bridgeLib::Command::DeviceState, cachedDeviceState); 260 m_device->setState(cachedDeviceState.state, cachedDeviceState.type); 261 } 262 263 sendDeviceInfo(); 264 } 265 266 void ClientConnection::destroyDevice() 267 { 268 if(!m_device) 269 return; 270 271 if(isValid()) 272 sendDeviceState(synthLib::StateTypeGlobal); 273 274 m_server.getPlugins().destroyDevice(m_pluginDesc, m_device); 275 m_device = nullptr; 276 } 277 278 void ClientConnection::errorClose(const bridgeLib::ErrorCode _code, const std::string& _err) 279 { 280 LOGNET(networkLib::LogLevel::Error, m_name + ": " + _err); 281 282 bridgeLib::Error err; 283 err.code = _code; 284 err.msg = _err; 285 286 send(bridgeLib::Command::Error, err); 287 std::this_thread::sleep_for(std::chrono::seconds(1)); 288 close(); 289 } 290 }