deviceConnection.cpp (6090B)
1 #include "deviceConnection.h" 2 3 #include "remoteDevice.h" 4 #include "dsp56kEmu/logging.h" 5 #include "networkLib/logging.h" 6 7 namespace bridgeClient 8 { 9 static constexpr uint32_t g_replyTimeoutSecs = 10; 10 11 DeviceConnection::DeviceConnection(RemoteDevice& _device, std::unique_ptr<networkLib::TcpStream>&& _stream) : TcpConnection(std::move(_stream)), m_device(_device) 12 { 13 m_handleReplyFunc = [](bridgeLib::Command, baseLib::BinaryStream&){}; 14 15 // send plugin description and device creation parameters, this will cause the server to either boot the device or ask for the rom if it doesn't have it yet 16 send(bridgeLib::Command::PluginInfo, m_device.getPluginDesc()); 17 18 // do not send rom data now but only if the server asks for it 19 sendDeviceCreateParams(false); 20 } 21 22 DeviceConnection::~DeviceConnection() 23 { 24 shutdown(); 25 } 26 27 void DeviceConnection::handleCommand(const bridgeLib::Command _command, baseLib::BinaryStream& _in) 28 { 29 switch (_command) 30 { 31 case bridgeLib::Command::RequestRom: 32 sendDeviceCreateParams(true); 33 break; 34 default: 35 TcpConnection::handleCommand(_command, _in); 36 break; 37 } 38 } 39 40 void DeviceConnection::handleData(const bridgeLib::DeviceDesc& _desc) 41 { 42 m_deviceDesc = _desc; 43 m_device.onBootFinished(_desc); 44 } 45 46 void DeviceConnection::handleDeviceInfo(baseLib::BinaryStream& _in) 47 { 48 TcpConnection::handleDeviceInfo(_in); 49 m_handleReplyFunc(bridgeLib::Command::DeviceInfo, _in); 50 } 51 52 void DeviceConnection::handleException(const networkLib::NetException& _e) 53 { 54 m_device.onDisconnect(); 55 } 56 57 void DeviceConnection::sendDeviceCreateParams(const bool _sendRom) 58 { 59 bridgeLib::DeviceCreateParams p; 60 p.params = m_device.getDeviceCreateParams(); 61 if(!_sendRom) 62 p.params.romData.clear(); 63 send(bridgeLib::Command::DeviceCreateParams, p); 64 } 65 66 bool DeviceConnection::processAudio(const synthLib::TAudioInputs& _inputs, const synthLib::TAudioOutputs& _outputs, const uint32_t _size, const uint32_t _latency) 67 { 68 m_audioBuffers.writeInput(_inputs, _size); 69 70 std::unique_lock lock(m_cvWaitMutex); 71 72 const auto haveEnoughOutput = m_audioBuffers.getOutputSize() >= _size; 73 74 m_audioBuffers.setLatency(_latency, haveEnoughOutput ? 0 : _size); 75 76 const auto sendSize = m_audioBuffers.getInputSize(); 77 78 if(haveEnoughOutput) 79 { 80 lock.unlock(); 81 82 if(sendSize > 0) 83 sendAudio(m_audioBuffers, m_device.getChannelCountIn(), sendSize); 84 m_audioBuffers.readOutput(_outputs, _size); 85 } 86 else 87 { 88 assert(sendSize > 0); 89 sendAudio(m_audioBuffers, m_device.getChannelCountIn(), sendSize); 90 91 m_cvWait.wait_for(lock, std::chrono::seconds(g_replyTimeoutSecs), [this, _size] 92 { 93 return m_audioBuffers.getOutputSize() >= _size; 94 }); 95 96 if(m_audioBuffers.getOutputSize() < _size) 97 { 98 LOG("Receive timeout, closing connection"); 99 close(); 100 return false; 101 } 102 103 m_audioBuffers.readOutput(_outputs, _size); 104 } 105 return true; 106 } 107 108 void DeviceConnection::handleAudio(baseLib::BinaryStream& _in) 109 { 110 { 111 std::unique_lock lock(m_cvWaitMutex); 112 TcpConnection::handleAudio(m_audioBuffers, _in); 113 } 114 115 m_cvWait.notify_one(); 116 } 117 118 void DeviceConnection::handleMidi(const synthLib::SMidiEvent& _e) 119 { 120 m_midiOut.push_back(_e); 121 } 122 123 void DeviceConnection::readMidiOut(std::vector<synthLib::SMidiEvent>& _midiOut) 124 { 125 _midiOut.insert(_midiOut.end(), m_midiOut.begin(), m_midiOut.end()); 126 m_midiOut.clear(); 127 } 128 129 bool DeviceConnection::getDeviceState(std::vector<uint8_t>& _state, synthLib::StateType _type) 130 { 131 return sendAwaitReply([this, _type] 132 { 133 bridgeLib::RequestDeviceState s; 134 s.type = _type; 135 send(bridgeLib::Command::RequestDeviceState, s); 136 }, [&](baseLib::BinaryStream& _in) 137 { 138 const auto& s = TcpConnection::getDeviceState().state; 139 _state.insert(_state.end(), s.begin(), s.end()); 140 }, bridgeLib::Command::DeviceState); 141 } 142 143 void DeviceConnection::handleDeviceState(baseLib::BinaryStream& _in) 144 { 145 TcpConnection::handleDeviceState(_in); 146 m_handleReplyFunc(bridgeLib::Command::DeviceState, _in); 147 } 148 149 bool DeviceConnection::setDeviceState(const std::vector<uint8_t>& _state, const synthLib::StateType _type) 150 { 151 if(_state.empty()) 152 return false; 153 154 auto& s = TcpConnection::getDeviceState(); 155 s.state = _state; 156 s.type = _type; 157 158 sendAwaitReply([&] 159 { 160 send(bridgeLib::Command::DeviceState, s); 161 }, [](baseLib::BinaryStream&) 162 { 163 }, bridgeLib::Command::DeviceInfo); 164 return true; 165 } 166 167 void DeviceConnection::setSamplerate(const float _samplerate) 168 { 169 sendAwaitReply([&] 170 { 171 bridgeLib::SetSamplerate sr; 172 sr.samplerate = _samplerate; 173 send(bridgeLib::Command::SetSamplerate, sr); 174 }, [&](baseLib::BinaryStream&) 175 { 176 }, bridgeLib::Command::DeviceInfo); 177 } 178 179 void DeviceConnection::setStateFromUnknownCustomData(const std::vector<uint8_t>& _state) 180 { 181 sendAwaitReply([&] 182 { 183 bridgeLib::SetUnknownCustomData d; 184 d.data = _state; 185 send(bridgeLib::Command::SetUnknownCustomData, d); 186 }, [&](baseLib::BinaryStream&) 187 { 188 }, bridgeLib::Command::DeviceInfo); 189 } 190 191 void DeviceConnection::setDspClockPercent(const uint32_t _percent) 192 { 193 sendAwaitReply([&] 194 { 195 bridgeLib::SetDspClockPercent p; 196 p.percent = _percent; 197 send(bridgeLib::Command::SetDspClockPercent, p); 198 }, [&](baseLib::BinaryStream&) 199 { 200 }, bridgeLib::Command::DeviceInfo); 201 } 202 203 bool DeviceConnection::sendAwaitReply(const std::function<void()>& _send, const std::function<void(baseLib::BinaryStream&)>& _reply, const bridgeLib::Command _replyCommand) 204 { 205 bool receiveDone = false; 206 207 m_handleReplyFunc = [&](const bridgeLib::Command _command, baseLib::BinaryStream& _in) 208 { 209 if(_command != _replyCommand) 210 return; 211 212 _reply(_in); 213 214 { 215 std::unique_lock lockCv(m_cvWaitMutex); 216 receiveDone = true; 217 } 218 m_cvWait.notify_one(); 219 }; 220 221 _send(); 222 223 std::unique_lock lockCv(m_cvWaitMutex); 224 m_cvWait.wait_for(lockCv, std::chrono::seconds(g_replyTimeoutSecs), [&] 225 { 226 return receiveDone; 227 }); 228 229 m_handleReplyFunc = [](bridgeLib::Command, baseLib::BinaryStream&) 230 { 231 }; 232 233 if(receiveDone) 234 return true; 235 LOG("Receive timeout, closing connection"); 236 close(); 237 return false; 238 } 239 }