Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add http server #2

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ set(MODULES
src/WavFileWriter.cpp
src/madlld-1.1p1/bstdfile.c
src/pdjson/pdjson.c
src/HttpServer.cpp
)

set(SRCS
Expand Down
115 changes: 115 additions & 0 deletions src/HttpServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "HttpServer.h"

#include <iostream>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <boost/filesystem.hpp>

#include "AudioFileReader.h"
#include "FileFormat.h"
#include "Mp3AudioFileReader.h"
#include "SndFileAudioFileReader.h"
#include "WaveformGenerator.h"
#include "WaveformUtil.h"
#include "crow/crow_all.h"
#include "WaveformBuffer.h"

static std::unique_ptr<AudioFileReader> createAudioFileReader(
const boost::filesystem::path& input_filename,
const Options& options)
{
std::unique_ptr<AudioFileReader> reader;
// auto input_format = options.getInputFormat();
auto input_format = FileFormat::Mp3; // TODO: Input format should be derived from file, not options.

if (input_format == FileFormat::Wav ||
input_format == FileFormat::Flac ||
input_format == FileFormat::Ogg ||
input_format == FileFormat::Opus) {
reader.reset(new SndFileAudioFileReader);
}
else if (input_format == FileFormat::Mp3) {
reader.reset(new Mp3AudioFileReader);
}
else if (input_format == FileFormat::Raw) {
SndFileAudioFileReader* sndfile_audio_file_reader = new SndFileAudioFileReader;
reader.reset(sndfile_audio_file_reader);

sndfile_audio_file_reader->configure(
options.getRawAudioChannels(),
options.getRawAudioSampleRate(),
options.getRawAudioFormat()
);
}
else {
// throwError("Unknown file type: %1%", input_filename);
throw ;
}

return reader;
}

void HttpServer::run(const Options& options) {
std::cout << "Starting Http server" << std::endl;
std::cout << "Listening on port " << options.getServerPort() << std::endl;
std::cout << "Media dir: " << options.getInputFilename() << std::endl;

crow::SimpleApp app;

CROW_ROUTE(app, "/generate-waveform-data/<string>")([this, &options](std::string filename){
try {
std::ostringstream os;
auto result = generateWaveformData(filename, options, os);
if(result) {
return crow::response(os.str());
} else {
return crow::response(500);
}
} catch(...) {
// catch(...) isn't particularly good form - we should really be throwing & catching specific exceptions.
// That would mean updating the error handling throughout the rest of the app though, which I'm a bit
// loathe to do.
return crow::response(500);
}
});

app.port(options.getServerPort()).multithreaded().run();
}

bool HttpServer::generateWaveformData(std::string filename, const Options& options, std::ostream& outstream) {
boost::filesystem::path fs_filename (filename);
boost::filesystem::path src = options.getInputFilename() / fs_filename;

if(!boost::filesystem::exists(src)) {
return false;
}

std::unique_ptr<ScaleFactor> scale_factor;
scale_factor.reset(new PixelsPerSecondScaleFactor(options.getPixelsPerSecond()));
std::unique_ptr<AudioFileReader> audio_file_reader = createAudioFileReader(src, options);

if (!audio_file_reader->open(src.string().c_str())) {
return false;
}

WaveformBuffer buffer;
WaveformGenerator processor(buffer, options.getSplitChannels(), *scale_factor);

if (!audio_file_reader->run(processor)) {
return false;
}

if (options.isAutoAmplitudeScale() && buffer.getSize() > 0) {
const double amplitude_scale = WaveformUtil::getAmplitudeScale(
buffer, 0, buffer.getSize()
);

WaveformUtil::scaleWaveformAmplitude(buffer, amplitude_scale);
}

buffer.saveAsJson(outstream, options.getBits());

return true;
}
17 changes: 17 additions & 0 deletions src/HttpServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "AudioFileReader.h"
#include "Options.h"
#include <string>

class HttpServer {
public:
void run(const Options& options);

private:
bool generateWaveformData(std::string filename, const Options& options, std::ostream& outstream);
};

static std::unique_ptr<AudioFileReader> createAudioFileReader(
const boost::filesystem::path& input_filename,
const Options& options);
14 changes: 14 additions & 0 deletions src/OptionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "FileFormat.h"
#include "FileUtil.h"
#include "GdImageRenderer.h"
#include "HttpServer.h"
#include "Mp3AudioFileReader.h"
#include "Log.h"
#include "Options.h"
Expand All @@ -47,7 +48,9 @@
#include <boost/format.hpp>

#include <cassert>
#include <ostream>
#include <string>
#include <iostream>

//------------------------------------------------------------------------------

Expand Down Expand Up @@ -688,6 +691,12 @@ bool OptionHandler::run(const Options& options)

setLogLevel(options.getQuiet());

if(options.serverMode()) {
HttpServer httpServer{};
httpServer.run(options);
return true;
}

bool success = true;

try {
Expand All @@ -710,6 +719,7 @@ bool OptionHandler::run(const Options& options)
output_filename,
options
);
std::cout << "shouldConvertAudioFormat : " << success << std::endl;
}
else if (shouldGenerateWaveformData(input_format, output_format)) {
success = generateWaveformData(
Expand All @@ -719,6 +729,7 @@ bool OptionHandler::run(const Options& options)
output_format,
options
);
std::cout << "shouldGenerateWaveformData : " << success << std::endl;
}
else if (shouldConvertWaveformData(input_format, output_format, options)) {
success = convertWaveformData(
Expand All @@ -728,6 +739,7 @@ bool OptionHandler::run(const Options& options)
output_format,
options
);
std::cout << "shouldConvertWaveformData : " << success << std::endl;
}
else if (shouldRenderWaveformImage(input_format, output_format)) {
success = renderWaveformImage(
Expand All @@ -736,6 +748,7 @@ bool OptionHandler::run(const Options& options)
output_filename,
options
);
std::cout << "shouldRenderWaveformImage : " << success << std::endl;
}
else if (shouldResampleWaveformData(input_format, output_format, options)) {
success = resampleWaveformData(
Expand All @@ -745,6 +758,7 @@ bool OptionHandler::run(const Options& options)
output_format,
options
);
std::cout << "shouldResampleWaveformData : " << success << std::endl;
}
else {
log(Error) << "Can't generate "
Expand Down
24 changes: 21 additions & 3 deletions src/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ Options::Options() :
amplitude_scale_(1.0),
png_compression_level_(-1), // default
raw_sample_rate_(0),
raw_channels_(0)
raw_channels_(0),
server_mode_(false)
{
}

Expand Down Expand Up @@ -268,6 +269,13 @@ bool Options::parseCommandLine(int argc, const char* const* argv)
"format for raw audio input "
"(s8, u8, s16le, s16be, s24le, s24be, s32le, s32be, "
"f32le, f32be, f64le, f64be)"
)(
"server",
"run in server mode"
)(
"port,p",
po::value<int>(&server_port_)->default_value(5040),
"port to listen on (default 5040)"
);

po::variables_map variables_map;
Expand All @@ -279,6 +287,7 @@ bool Options::parseCommandLine(int argc, const char* const* argv)

help_ = variables_map.count("help") != 0;
version_ = variables_map.count("version") != 0;
server_mode_ = hasOptionValue(variables_map, "server");

if (help_ || version_) {
return true;
Expand Down Expand Up @@ -324,11 +333,20 @@ bool Options::parseCommandLine(int argc, const char* const* argv)
bool has_raw_channels = hasOptionValue(variables_map, "raw-channels");
bool has_raw_format = hasOptionValue(variables_map, "raw-format");

if (input_filename_.empty() && !has_input_format_) {
reportError("Must specify either input filename or input format");
if (input_filename_.empty() && !has_input_format_ && !server_mode_) {
reportError("Must specify either input filename, input format or start in server mode");
return false;
}

if (input_filename_.empty() && server_mode_) {
reportError("Must specify input dir for server mode");
return false;
}

if(server_mode_ && !input_filename_.empty()) {
return true;
}

input_format_ = has_input_format_ ?
FileFormat::fromString(input_format) :
getFormatFromFileExtension(input_filename_);
Expand Down
6 changes: 6 additions & 0 deletions src/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ class Options

void reportError(const std::string& message) const;

bool serverMode() const {return server_mode_;}
int getServerPort() const {return server_port_;}

private:
void handleAmplitudeScaleOption(const std::string& option_value);
void handleZoomOption(const std::string& option_value);
Expand Down Expand Up @@ -198,6 +201,9 @@ class Options
int raw_sample_rate_;
int raw_channels_;
std::string raw_format_;

bool server_mode_;
int server_port_;
};

//------------------------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion src/WaveformBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ class WaveformBuffer
bool saveAsText(const char* filename, int bits = 16) const;
bool saveAsJson(const char* filename, int bits = 16) const;

private:
void save(std::ostream& stream, int bits) const;
void saveAsText(std::ostream& stream, int bits) const;
void saveAsJson(std::ostream& stream, int bits) const;
Expand Down
Loading