Skip to content

Commit

Permalink
separate player actions to current-song and player-files, and pass ea…
Browse files Browse the repository at this point in the history
…ch to the right controller
  • Loading branch information
blumamir committed Jan 30, 2020
1 parent 51124dc commit 3ed76af
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 130 deletions.
78 changes: 1 addition & 77 deletions src/audio_files_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,85 +6,9 @@

namespace wavplayeralsa {

void AudioFilesManager::Initialize(
AlsaFramesTransfer *alsa_frames_transfer,
const std::string &wav_dir)
void AudioFilesManager::Initialize(const std::string &wav_dir)
{
wav_dir_ = boost::filesystem::path(wav_dir);
alsa_frames_transfer_ = alsa_frames_transfer;
}

bool AudioFilesManager::NewSongRequest(const std::string &file_id, uint64_t start_offset_ms, std::stringstream &out_msg) {

if(file_id == alsa_frames_transfer_->GetFileId()) {
out_msg << "changed position of the current file '" << file_id << "'. new position in ms is: " << start_offset_ms << std::endl;
}
else {

// create the canonical full path of the file to play
boost::filesystem::path songPathInWavDir(file_id);
boost::filesystem::path songFullPath = wav_dir_ / songPathInWavDir;
std::string canonicalFullPath;
try {
canonicalFullPath = boost::filesystem::canonical(songFullPath).string();
}
catch (const std::exception &e) {
out_msg << "loading new audio file '" << file_id << "' failed. error: " << e.what();
return false;
}

try {
const std::string prev_file = alsa_frames_transfer_->GetFileId();
bool prev_file_was_playing = alsa_frames_transfer_->LoadNewFile(canonicalFullPath, file_id);

// message printing
const int SECONDS_PER_HOUR = (60 * 60);
uint64_t start_offset_sec = start_offset_ms / 1000;
uint64_t hours = start_offset_sec / SECONDS_PER_HOUR;
start_offset_sec = start_offset_sec - hours * SECONDS_PER_HOUR;
uint64_t minutes = start_offset_sec / 60;
uint64_t seconds = start_offset_sec % 60;
if(prev_file_was_playing && !prev_file.empty()) {
out_msg << "audio file successfully changed from '" << prev_file << "' to '" << file_id << "' and will be played ";
}
else {
out_msg << "will play audio file '" << file_id << "' ";
}
out_msg << "starting at position " << start_offset_ms << " ms " <<
"(" << hours << ":" <<
std::setfill('0') << std::setw(2) << minutes << ":" <<
std::setfill('0') << std::setw(2) << seconds << ")";
}
catch(const std::runtime_error &e) {
out_msg << "loading new audio file '" << file_id << "' failed. currently no audio file is loaded in the player and it is not playing. " <<
"reason for failure: " << e.what();
return false;
}
}

alsa_frames_transfer_->StartPlay(start_offset_ms);
return true;
}

bool AudioFilesManager::StopPlayRequest(std::stringstream &out_msg) {

bool was_playing = false;
try {
was_playing = alsa_frames_transfer_->Stop();
}
catch(const std::runtime_error &e) {
out_msg << "Unable to stop current audio file successfully, error: " << e.what();
return false;
}

const std::string &current_file_id = alsa_frames_transfer_->GetFileId();
if(current_file_id.empty() || !was_playing) {
out_msg << "no audio file is being played, so stop had no effect";
}
else {
out_msg << "current audio file '" << current_file_id << "' stopped playing";
}
return true;
}

std::list<std::string> AudioFilesManager::QueryFiles() {
Expand Down
22 changes: 3 additions & 19 deletions src/audio_files_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,24 @@
#include "spdlog/spdlog.h"

#include "player_actions_ifc.h"
#include "player_events_ifc.h"
#include "alsa_frames_transfer.h"

namespace wavplayeralsa {

/*
This class offloads some of the tasks of the alsa_frames_transfer, so the former one is more simple and thin.
These tasks are:
- it allow alsa_frames_transfer to publish PlayerEventsIfc calls on it's own thread, without need to know
or care about transfering the interface calls to the right clients and io service.
- it handles all the file_id and audio files manipulations and hands over to alsa_frames_transfer a clean
and proccessed file name.
- it handles some of the details involved in PlayerActionsIfc, for example: producing a human readable,
out_msg containing the action status.
*/
class AudioFilesManager :
public wavplayeralsa::PlayerActionsIfc
public wavplayeralsa::PlayerFilesActionsIfc
{

public:

void Initialize(AlsaFramesTransfer *alsa_frames_transfer, const std::string &wav_dir);
void Initialize(const std::string &wav_dir);

public:
// wavplayeralsa::PlayerActionsIfc
bool NewSongRequest(const std::string &file_id, uint64_t start_offset_ms, std::stringstream &out_msg);
bool StopPlayRequest(std::stringstream &out_msg);
// wavplayeralsa::PlayerFilesActionsIfc
std::list<std::string> QueryFiles();

private:
boost::filesystem::path wav_dir_;

AlsaFramesTransfer *alsa_frames_transfer_ = nullptr;

};


Expand Down
92 changes: 86 additions & 6 deletions src/current_song_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,27 @@ using json = nlohmann::json;
namespace wavplayeralsa
{

CurrentSongController::CurrentSongController(boost::asio::io_service &io_service, MqttApi *mqtt_service, WebSocketsApi *ws_service)
: ios_(io_service), throttle_timer_(io_service)
CurrentSongController::CurrentSongController(
boost::asio::io_service &io_service,
MqttApi *mqtt_service,
WebSocketsApi *ws_service,
AlsaFramesTransfer *alsa_service)
:
ios_(io_service),
mqtt_service_(mqtt_service),
ws_service_(ws_service),
alsa_service_(alsa_service),
throttle_timer_(io_service)
{
mqtt_service_ = mqtt_service;
ws_service_ = ws_service;

json j;
j["song_is_playing"] = false;
UpdateLastStatusMsg(j);
}

void CurrentSongController::Initialize(const std::string &player_uuid)
void CurrentSongController::Initialize(const std::string &player_uuid, const std::string &wav_dir)
{
player_uuid_ = player_uuid;
wav_dir_ = boost::filesystem::path(wav_dir);
}

void CurrentSongController::NewSongStatus(const std::string &file_id, uint64_t start_time_millis_since_epoch, double speed)
Expand All @@ -45,6 +52,79 @@ namespace wavplayeralsa
ios_.post(std::bind(&CurrentSongController::UpdateLastStatusMsg, this, j));
}

bool CurrentSongController::NewSongRequest(const std::string &file_id, uint64_t start_offset_ms, std::stringstream &out_msg) {

if(file_id == alsa_service_->GetFileId()) {
out_msg << "changed position of the current file '" << file_id << "'. new position in ms is: " << start_offset_ms << std::endl;
}
else {

// create the canonical full path of the file to play
boost::filesystem::path songPathInWavDir(file_id);
boost::filesystem::path songFullPath = wav_dir_ / songPathInWavDir;
std::string canonicalFullPath;
try {
canonicalFullPath = boost::filesystem::canonical(songFullPath).string();
}
catch (const std::exception &e) {
out_msg << "loading new audio file '" << file_id << "' failed. error: " << e.what();
return false;
}

try {
const std::string prev_file = alsa_service_->GetFileId();
bool prev_file_was_playing = alsa_service_->LoadNewFile(canonicalFullPath, file_id);

// message printing
const int SECONDS_PER_HOUR = (60 * 60);
uint64_t start_offset_sec = start_offset_ms / 1000;
uint64_t hours = start_offset_sec / SECONDS_PER_HOUR;
start_offset_sec = start_offset_sec - hours * SECONDS_PER_HOUR;
uint64_t minutes = start_offset_sec / 60;
uint64_t seconds = start_offset_sec % 60;
if(prev_file_was_playing && !prev_file.empty()) {
out_msg << "audio file successfully changed from '" << prev_file << "' to '" << file_id << "' and will be played ";
}
else {
out_msg << "will play audio file '" << file_id << "' ";
}
out_msg << "starting at position " << start_offset_ms << " ms " <<
"(" << hours << ":" <<
std::setfill('0') << std::setw(2) << minutes << ":" <<
std::setfill('0') << std::setw(2) << seconds << ")";
}
catch(const std::runtime_error &e) {
out_msg << "loading new audio file '" << file_id << "' failed. currently no audio file is loaded in the player and it is not playing. " <<
"reason for failure: " << e.what();
return false;
}
}

alsa_service_->StartPlay(start_offset_ms);
return true;
}

bool CurrentSongController::StopPlayRequest(std::stringstream &out_msg) {

bool was_playing = false;
try {
was_playing = alsa_service_->Stop();
}
catch(const std::runtime_error &e) {
out_msg << "Unable to stop current audio file successfully, error: " << e.what();
return false;
}

const std::string &current_file_id = alsa_service_->GetFileId();
if(current_file_id.empty() || !was_playing) {
out_msg << "no audio file is being played, so stop had no effect";
}
else {
out_msg << "current audio file '" << current_file_id << "' stopped playing";
}
return true;
}

void CurrentSongController::UpdateLastStatusMsg(const json &alsa_data)
{
json full_msg(alsa_data);
Expand Down
28 changes: 21 additions & 7 deletions src/current_song_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,41 @@

#include <string>
#include <boost/asio/deadline_timer.hpp>
#include <boost/filesystem.hpp>
#include "nlohmann/json_fwd.hpp"

#include <player_events_ifc.h>

#include <mqtt_api.h>
#include <web_sockets_api.h>
#include "player_events_ifc.h"
#include "player_actions_ifc.h"
#include "mqtt_api.h"
#include "web_sockets_api.h"
#include "alsa_frames_transfer.h"

using json = nlohmann::json;

namespace wavplayeralsa {

class CurrentSongController : public PlayerEventsIfc
class CurrentSongController :
public PlayerEventsIfc,
public CurrentSongActionsIfc
{

public:
CurrentSongController(boost::asio::io_service &io_service, MqttApi *mqtt_service, WebSocketsApi *ws_service);
CurrentSongController(boost::asio::io_service &io_service,
MqttApi *mqtt_service,
WebSocketsApi *ws_service,
AlsaFramesTransfer *alsa_service);

void Initialize(const std::string &player_uuid);
void Initialize(const std::string &player_uuid, const std::string &wav_dir);

public:
void NewSongStatus(const std::string &file_id, uint64_t start_time_millis_since_epoch, double speed);
void NoSongPlayingStatus(const std::string &file_id);

public:
// wavplayeralsa::CurrentSongActionsIfc
bool NewSongRequest(const std::string &file_id, uint64_t start_offset_ms, std::stringstream &out_msg);
bool StopPlayRequest(std::stringstream &out_msg);

private:
void UpdateLastStatusMsg(const json &alsa_data);
void ReportCurrentSongToServices(const boost::system::error_code& error);
Expand All @@ -34,9 +46,11 @@ namespace wavplayeralsa {
boost::asio::io_service &ios_;
MqttApi *mqtt_service_;
WebSocketsApi *ws_service_;
AlsaFramesTransfer *alsa_service_ = nullptr;

private:
std::string player_uuid_;
boost::filesystem::path wav_dir_;

private:
std::string last_status_msg_;
Expand Down
17 changes: 12 additions & 5 deletions src/http_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,17 @@ using json = nlohmann::json;

namespace wavplayeralsa {

void HttpApi::Initialize(std::shared_ptr<spdlog::logger> logger, boost::asio::io_service *io_service, PlayerActionsIfc *player_action_callback, uint16_t http_listen_port) {
void HttpApi::Initialize(
std::shared_ptr<spdlog::logger> logger,
boost::asio::io_service *io_service,
CurrentSongActionsIfc *current_song_action_callback,
PlayerFilesActionsIfc *player_files_action_callback,
uint16_t http_listen_port)
{

// set class members
player_action_callback_ = player_action_callback;
current_song_action_callback_ = current_song_action_callback;
player_files_action_callback_ = player_files_action_callback;
logger_ = logger;

server_.config.port = http_listen_port;
Expand Down Expand Up @@ -56,7 +63,7 @@ namespace wavplayeralsa {
}

void HttpApi::OnGetAvailableFiles(std::shared_ptr<HttpServer::Response> response, std::shared_ptr<HttpServer::Request> request) {
const std::list<std::string> fileIds = player_action_callback_->QueryFiles();
const std::list<std::string> fileIds = player_files_action_callback_->QueryFiles();
WriteJsonResponseSuccess(response, fileIds);
}

Expand Down Expand Up @@ -107,10 +114,10 @@ namespace wavplayeralsa {
std::stringstream handler_msg;
bool success;
if(file_id.empty()) {
success = player_action_callback_->StopPlayRequest(handler_msg);
success = current_song_action_callback_->StopPlayRequest(handler_msg);
}
else {
success = player_action_callback_->NewSongRequest(file_id, start_offset_ms, handler_msg);
success = current_song_action_callback_->NewSongRequest(file_id, start_offset_ms, handler_msg);
}

if(!success) {
Expand Down
10 changes: 8 additions & 2 deletions src/http_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ namespace wavplayeralsa {
class HttpApi {

public:
void Initialize(std::shared_ptr<spdlog::logger> logger, boost::asio::io_service *io_service, PlayerActionsIfc *player_action_callback, uint16_t http_listen_port);
void Initialize(
std::shared_ptr<spdlog::logger> logger,
boost::asio::io_service *io_service,
CurrentSongActionsIfc *current_song_action_callback,
PlayerFilesActionsIfc *player_files_action_callback,
uint16_t http_listen_port);

private:
void OnGetAvailableFiles(std::shared_ptr<HttpServer::Response> response, std::shared_ptr<HttpServer::Request> request);
Expand All @@ -34,7 +39,8 @@ namespace wavplayeralsa {

private:
// outside configurartion
PlayerActionsIfc *player_action_callback_;
CurrentSongActionsIfc *current_song_action_callback_;
PlayerFilesActionsIfc *player_files_action_callback_;
std::shared_ptr<spdlog::logger> logger_;

private:
Expand Down
3 changes: 1 addition & 2 deletions src/mqtt_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ namespace wavplayeralsa {

}

void MqttApi::Initialize(std::shared_ptr<spdlog::logger> logger, PlayerActionsIfc *player_action_callback, const std::string &mqtt_host, uint16_t mqtt_port) {
void MqttApi::Initialize(std::shared_ptr<spdlog::logger> logger, const std::string &mqtt_host, uint16_t mqtt_port) {

// set class members
player_action_callback_ = player_action_callback;
logger_ = logger;

const char *mqtt_client_id = "wavplayeralsa";
Expand Down
Loading

0 comments on commit 3ed76af

Please sign in to comment.