Skip to content

Commit

Permalink
Allow negative offset (#2)
Browse files Browse the repository at this point in the history
* remove unused alsa avail settings

* feat: allow to set negative song offset

* docs: add negative offset to README

* fix: right msg for negative offset play
  • Loading branch information
blumamir authored Apr 15, 2020
1 parent d982fd7 commit 064fe75
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 28 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ example with curl:
```
curl -X PUT -H "Content-Type: application/json" -d "{\"file_id\": \"<file_name>.wav\", \"start_offset_ms\":0}" "http://127.0.0.1:8080/api/current-song"
```
`start_offset_ms` can be negative, in which case song will start to play in the future.

To stop an audio file which is currently playing, send a json to uri http://YOUR_IP:HTTP_LISTEN_PORT/api/current-song with empty or missing 'file_id':
`{ "file_id": "" }` or `{}`
Expand Down
10 changes: 7 additions & 3 deletions src/current_song_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace wavplayeralsa

bool CurrentSongController::NewSongRequest(
const std::string &file_id,
uint64_t start_offset_ms,
int64_t start_offset_ms,
std::stringstream &out_msg,
uint32_t *play_seq_id)
{
Expand Down Expand Up @@ -101,7 +101,7 @@ namespace wavplayeralsa
}
else {
static const int SECONDS_PER_HOUR = (60 * 60);
uint64_t start_offset_sec = start_offset_ms / 1000;
uint64_t start_offset_sec = std::abs(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;
Expand All @@ -115,7 +115,11 @@ namespace wavplayeralsa
out_msg << "starting at position " << start_offset_ms << " ms " <<
"(" << hours << ":" <<
std::setfill('0') << std::setw(2) << minutes << ":" <<
std::setfill('0') << std::setw(2) << seconds << ")";
std::setfill('0') << std::setw(2) << seconds;
if(start_offset_ms < 0) {
out_msg << " in the future";
}
out_msg << ")";
}

try {
Expand Down
2 changes: 1 addition & 1 deletion src/current_song_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace wavplayeralsa {

bool NewSongRequest(
const std::string &file_id,
uint64_t start_offset_ms,
int64_t start_offset_ms,
std::stringstream &out_msg,
uint32_t *play_seq_id);

Expand Down
4 changes: 2 additions & 2 deletions src/http_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ namespace wavplayeralsa {
}
}

uint64_t start_offset_ms = 0;
int64_t start_offset_ms = 0;
// use it only if it is found in the json
if(request_json.find("start_offset_ms") != request_json.end()) {
try {
start_offset_ms = request_json["start_offset_ms"].get<uint64_t>();
start_offset_ms = request_json["start_offset_ms"].get<int64_t>();
}
catch(json::exception &e) {
std::stringstream err_stream;
Expand Down
2 changes: 1 addition & 1 deletion src/player_actions_ifc.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace wavplayeralsa {

virtual bool NewSongRequest(
const std::string &file_id,
uint64_t start_offset_ms,
int64_t start_offset_ms,
std::stringstream &out_msg,
uint32_t *play_seq_id) = 0;

Expand Down
48 changes: 28 additions & 20 deletions src/services/alsa_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace wavplayeralsa
~AlsaPlaybackService();

public:
void Play(int32_t offset_in_ms);
void Play(int64_t offset_in_ms);
bool Stop();
const std::string GetFileId() const { return file_id_; }

Expand Down Expand Up @@ -66,7 +66,7 @@ namespace wavplayeralsa
snd_pcm_t *alsa_playback_handle_ = nullptr;

// what is the next frame to be delivered to alsa
uint64_t curr_position_frames_ = 0;
int64_t curr_position_frames_ = 0;

// snd file
private:
Expand Down Expand Up @@ -395,8 +395,8 @@ namespace wavplayeralsa
return false;
}

void AlsaPlaybackService::Play(int32_t offset_in_ms) {
void AlsaPlaybackService::Play(int64_t offset_in_ms) {

if(!initialized_) {
throw std::runtime_error("tried to play wav file on an uninitialzed alsa service");
}
Expand All @@ -406,11 +406,11 @@ namespace wavplayeralsa
}

double position_in_seconds = (double)offset_in_ms / 1000.0;
curr_position_frames_ = position_in_seconds * (double)frame_rate_;
if(curr_position_frames_ > total_frame_in_file_) {
curr_position_frames_ = total_frame_in_file_;
curr_position_frames_ = position_in_seconds * (double)frame_rate_;
curr_position_frames_ = std::min(curr_position_frames_, (int64_t)total_frame_in_file_);
if(curr_position_frames_ >= 0) {
sf_count_t seek_res = snd_file_.seek(curr_position_frames_, SEEK_SET);
}
sf_count_t seek_res = snd_file_.seek(curr_position_frames_, SEEK_SET);

logger_->info("start playing file {} from position {} mili-seconds ({} seconds)", file_id_, offset_in_ms, position_in_seconds);
playing_thread_ = std::thread(&AlsaPlaybackService::PlayingThreadMain, this);
Expand Down Expand Up @@ -473,19 +473,28 @@ namespace wavplayeralsa
// we want to deliver as many frames as possible.
// we can put frames_to_deliver number of frames, but the buffer can only hold frames_capacity_in_buffer_ frames
frames_to_deliver = std::min(frames_to_deliver, frames_capacity_in_buffer_);
unsigned int bytes_to_deliver = frames_to_deliver * bytes_per_frame_;

// read the frames from the file. TODO: what if readRaw fails?
char buffer_for_transfer[TRANSFER_BUFFER_SIZE];
bytes_to_deliver = snd_file_.readRaw(buffer_for_transfer, bytes_to_deliver);
if(bytes_to_deliver < 0) {
err_desc << "Failed reading raw frames from snd file. returned: " << sf_error_number(bytes_to_deliver);
throw std::runtime_error(err_desc.str());

bool start_in_future = (curr_position_frames_ < 0);
if(!start_in_future) {
unsigned int bytes_to_deliver = frames_to_deliver * bytes_per_frame_;
bytes_to_deliver = snd_file_.readRaw(buffer_for_transfer, bytes_to_deliver);
if(bytes_to_deliver < 0) {
err_desc << "Failed reading raw frames from snd file. returned: " << sf_error_number(bytes_to_deliver);
throw std::runtime_error(err_desc.str());
}
if(bytes_to_deliver == 0) {
logger_->info("play_seq_id: {}. done writing all frames to pcm. waiting for audio device to play remaining frames in the buffer", play_seq_id_);
ios_.post(std::bind(&AlsaPlaybackService::PcmDrainLoop, this, boost::system::error_code()));
return;
}
}
if(bytes_to_deliver == 0) {
logger_->info("play_seq_id: {}. done writing all frames to pcm. waiting for audio device to play remaining frames in the buffer", play_seq_id_);
ios_.post(std::bind(&AlsaPlaybackService::PcmDrainLoop, this, boost::system::error_code()));
return;
else {
frames_to_deliver = std::min(frames_to_deliver, (snd_pcm_sframes_t)-curr_position_frames_);
unsigned int bytes_to_deliver = frames_to_deliver * bytes_per_frame_;
bzero(buffer_for_transfer, bytes_to_deliver);
}

int frames_written = snd_pcm_writei(alsa_playback_handle_, buffer_for_transfer, frames_to_deliver);
Expand All @@ -495,7 +504,7 @@ namespace wavplayeralsa
}

curr_position_frames_ += frames_written;
if(frames_written != frames_to_deliver) {
if( (curr_position_frames_ >= 0) && (start_in_future || (frames_written != frames_to_deliver))) {
logger_->warn("play_seq_id: {}. transfered to alsa less frame then requested. frames_to_deliver: {}, frames_written: {}", play_seq_id_, frames_to_deliver, frames_written);
snd_file_.seek(curr_position_frames_, SEEK_SET);
}
Expand Down Expand Up @@ -536,7 +545,6 @@ namespace wavplayeralsa
void AlsaPlaybackService::CheckSongStartTime() {
int err;
snd_pcm_sframes_t delay = 0;
int64_t pos_in_frames = 0;

if( (err = snd_pcm_delay(alsa_playback_handle_, &delay)) < 0) {
std::stringstream err_desc;
Expand All @@ -548,7 +556,7 @@ namespace wavplayeralsa
if(delay < 4096) {
return;
}
pos_in_frames = curr_position_frames_ - delay;
int64_t pos_in_frames = curr_position_frames_ - delay;
int64_t ms_since_audio_file_start = ((pos_in_frames * (int64_t)1000) / (int64_t)frame_rate_);

struct timeval tv;
Expand Down
2 changes: 1 addition & 1 deletion src/services/alsa_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace wavplayeralsa

public:
virtual const std::string GetFileId() const = 0;
virtual void Play(int32_t offset_in_ms) = 0;
virtual void Play(int64_t offset_in_ms) = 0;
virtual bool Stop() = 0;

};
Expand Down

0 comments on commit 064fe75

Please sign in to comment.