gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

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 }