Я пытаюсь создать аудио плагин, который может подключаться к локальному серверу Java и отправлять ему данные через сокет (TCP). Поскольку я услышал много хороших вещей об этом, я использую библиотеку ASIO Boost, чтобы сделать работу.
У меня довольно странная ошибка в моем коде: мой клиент AudioUnit C ++ (который я использую изнутри DAW, я тестирую с Ableton Live и Logic Pro) может нормально подключаться к моему Java-серверу, но когда я делаю запись операция, кажется, моя запись выполняется правильно только один раз (например, я могу контролировать любое входящее сообщение на моем Java-сервере, и только первое сообщение видно)
Я использую следующий код:
— Внутри заголовка:
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket mySocket(io_service);
boost::asio::ip::tcp::endpoint myEndpoint(boost::asio::ip::address::from_string("127.0.0.1"), 9001);
boost::system::error_code ignored_error;
— Внутри конструктора моего плагина
mySocket.connect(myEndpoint);
— И когда я пытаюсь отправить:
boost::asio::write(mySocket, boost::asio::buffer(datastring), ignored_error);
(вы заметите, что я не закрываю свою розетку, потому что я хотел бы, чтобы она жила вечно)
Я не думаю, что проблема исходит от моего Java-сервера (хотя я могу ошибаться!), Потому что я нашел способ заставить мой плагин C ++ «работать правильно» и отправлять все сообщения, которые я хочу:
Если я не открываю свой сокет после инициализации моего плагина, но непосредственно при попытке отправить сообщение, каждое сообщение получает мой удаленный сервер. Т.е. каждый раз, когда я вызываю sendMessage (), я делаю следующее:
try {
// Connect to the Java application
mySocket.connect(myEndpoint);
// Write the data
boost::asio::write(mySocket, boost::asio::buffer(datastring), ignored_error);
// Disconnect
mySocket.close();
} catch (const std::exception & e) {std::cout << "Couldn't initialize socket\n";}
Тем не менее, я не слишком доволен этим кодом: мне приходится отправлять около 1000 сообщений в секунду — хотя это может быть не слишком много, но я не думаю, что открытие сокета и подключение к конечной точке всегда эффективны (это операция блокировки тоже)
Любая информация, которая может привести меня в правильном направлении, будет принята с благодарностью!
Для получения дополнительной информации, вот мой код в немного более полной версии (с бесполезными вещами, сокращенными, чтобы сделать его коротким)
#include <cstdlib>
#include <fstream>
#include "PluginProcessor.h"#include "PluginEditor.h"#include "SignalMessages.pb.h"using boost::asio::local::stream_protocol;
//==============================================================================
// Default parameter values
const int defaultAveragingBufferSize = 256;
const int defaultMode = 0;
const float defaultInputSensitivity = 1.0;
const int defaultChannel = 1;
const int defaultMonoStereo = 1; //Mono processing//==============================================================================
// Variables used by the audio algorithm
int nbBufValProcessed = 0;
float signalSum = 0;
// Used for beat detection
float signalAverageEnergy = 0;
float signalInstantEnergy = 0;
const int thresholdFactor = 5;
const int averageEnergyBufferSize = 11025; //0.25 seconds
//==============================================================================
// Socket used to forward data to the Processing application, and the variables associated with it
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket mySocket(io_service);
boost::asio::ip::tcp::endpoint myEndpoint(boost::asio::ip::address::from_string("127.0.0.1"), 9001);
boost::system::error_code ignored_error;
//==============================================================================
SignalProcessorAudioProcessor::SignalProcessorAudioProcessor()
{
averagingBufferSize = defaultAveragingBufferSize;
inputSensitivity = defaultInputSensitivity;
mode = defaultMode;
monoStereo = defaultMonoStereo;
channel = defaultChannel;// Connect to the remote server
// Note for stack overflow : this is where I'd like connect to my server !
mySocket.connect(myEndpoint);
}
SignalProcessorAudioProcessor::~SignalProcessorAudioProcessor()
{
}//==============================================================================void SignalProcessorAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
// In case we have more outputs than inputs, clear any output
// channels that doesn't contain input data
for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
buffer.clear (i, 0, buffer.getNumSamples());
//////////////////////////////////////////////////////////////////
// This is the most important part of my code, audio processing takes place here !
// Note for stack overflow : this shouldn't be very interesting, as it is not related to my current problem
for (int channel = 0; channel < std::getNumInputChannels(); ++channel)
{
const float* channelData = buffer.getReadPointer (channel);
for (int i=0; i<buffer.getNumSamples(); i++) {
signalSum += std::abs(channelData[i]);
signalAverageEnergy = ((signalAverageEnergy * (averageEnergyBufferSize-1)) + std::abs(channelData[i])) / averageEnergyBufferSize;
}
}
nbBufValProcessed += buffer.getNumSamples();
if (nbBufValProcessed >= averagingBufferSize) {
signalInstantEnergy = signalSum / (averagingBufferSize * monoStereo);
// If the instant signal energy is thresholdFactor times greater than the average energy, consider that a beat is detected
if (signalInstantEnergy > signalAverageEnergy*thresholdFactor) {
//Set the new signal Average Energy to the value of the instant energy, to avoid having bursts of false beat detections
signalAverageEnergy = signalInstantEnergy;
//Create an impulse signal - note for stack overflow : these are Google Protocol buffer messages, serialization is faster this way
Impulse impulse;
impulse.set_signalid(channel);
std::string datastringImpulse;
impulse.SerializeToString(&datastringImpulse);
sendMessage(datastringImpulse);
}
nbBufValProcessed = 0;
signalSum = 0;
}
}
//==============================================================================
void SignalProcessorAudioProcessor::sendMessage(std::string datastring) {
try {
// Write the data
boost::asio::write(mySocket, boost::asio::buffer(datastring), ignored_error);
} catch (const std::exception & e) {
std::cout << "Caught an error while trying to initialize the socket - the Java server might not be ready\n";
std::cerr << e.what();
}
}//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new SignalProcessorAudioProcessor();
}
Задача ещё не решена.