Skip to content
Snippets Groups Projects
Commit 44730161 authored by Jan Schlüter's avatar Jan Schlüter
Browse files

Cleanly stop recording if interrupted by CTRL+C or SIGTERM

parent e10b9fb6
No related branches found
No related tags found
2 merge requests!2HighBlueParser dev branch merged to empty main branch,!1High blue rec
...@@ -4,7 +4,7 @@ if(POLICY CMP0063) ...@@ -4,7 +4,7 @@ if(POLICY CMP0063)
endif() endif()
project(jasonrec) project(jasonrec)
set(JASONREC_VERSION "1.1") set(JASONREC_VERSION "1.2")
add_definitions(-DJASONREC_VERSION="${JASONREC_VERSION}") add_definitions(-DJASONREC_VERSION="${JASONREC_VERSION}")
find_path(LIBUSB_INCLUDE_DIR find_path(LIBUSB_INCLUDE_DIR
......
add_executable(jasonrec add_executable(jasonrec
recorder.cpp recorder.cpp
filewriter.cpp filewriter.cpp
cleanexit.cpp
main.cpp) main.cpp)
# compile as C++11 # compile as C++11
set_property(TARGET jasonrec set_property(TARGET jasonrec
...@@ -17,4 +18,3 @@ target_link_libraries(jasonrec ...@@ -17,4 +18,3 @@ target_link_libraries(jasonrec
${LIBUSB_LIBRARY}) ${LIBUSB_LIBRARY})
install(TARGETS jasonrec DESTINATION bin) install(TARGETS jasonrec DESTINATION bin)
/**
* Simple signal handler for clean termination of an application.
*
* Author: Jan Schlüter <jan.schluter@lis-lab.fr>
*/
#include <atomic>
#include <csignal>
#ifdef __unix__
#include <unistd.h>
#endif
std::atomic<bool> _exit_requested(false);
void caught_signal(int)
{
_exit_requested.store(true);
}
void allow_clean_exit() {
#ifdef __unix__
struct sigaction sa = {0};
sa.sa_handler = caught_signal;
sigfillset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
#else
signal(SIGINT, caught_signal);
signal(SIGTERM, caught_signal);
#endif
}
bool exit_requested() {
return _exit_requested.load();
}
/**
* Simple signal handler for clean termination of an application.
*
* Author: Jan Schlüter <jan.schluter@lis-lab.fr>
*/
#ifndef CLEANEXIT_H
#define CLEANEXIT_H
/**
* Set up signal handlers to make exit_requested() work.
*/
void allow_clean_exit();
/**
* Check if the application was requested to terminate.
* \returns whether the application was requested to terminate.
*/
bool exit_requested();
#endif
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include "recorder.h" #include "recorder.h"
#include "filewriter.h" #include "filewriter.h"
#include "cleanexit.h"
void print_usage(char *name) { void print_usage(char *name) {
std::cout << "SMIoT JASON Qualilife sound recorder"; std::cout << "SMIoT JASON Qualilife sound recorder";
...@@ -52,6 +53,7 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen, ...@@ -52,6 +53,7 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen,
} }
// start the recording loop // start the recording loop
std::cout << "Starting to record..." << std::endl; std::cout << "Starting to record..." << std::endl;
allow_clean_exit();
size_t total_samples_wanted = totallen * rate; size_t total_samples_wanted = totallen * rate;
size_t total_samples_read = 0; size_t total_samples_read = 0;
std::vector<std::int16_t> samples; std::vector<std::int16_t> samples;
...@@ -59,7 +61,12 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen, ...@@ -59,7 +61,12 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen,
recorder.start_recording(); recorder.start_recording();
// we will record until we have enough (or forever, if totallen == 0) // we will record until we have enough (or forever, if totallen == 0)
while ((total_samples_wanted == 0) || (total_samples_read < total_samples_wanted)) { while ((total_samples_wanted == 0) || (total_samples_read < total_samples_wanted)) {
recorder.get_samples(samples); if (exit_requested()) {
std::cout << "Termination requested." << std::endl;
break;
}
recorder.get_samples(samples, false, 500);
if (samples.size() > 0) {
total_samples_read += samples.size() / channels; total_samples_read += samples.size() / channels;
// if we have too much now, crop the last packet // if we have too much now, crop the last packet
if ((total_samples_wanted > 0) && (total_samples_read > total_samples_wanted)) { if ((total_samples_wanted > 0) && (total_samples_read > total_samples_wanted)) {
...@@ -68,6 +75,7 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen, ...@@ -68,6 +75,7 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen,
// pass it on to the file writer // pass it on to the file writer
filewriter->write(samples); filewriter->write(samples);
} }
}
recorder.stop_recording(); recorder.stop_recording();
std::cout << "Stopped recording." << std::endl; std::cout << "Stopped recording." << std::endl;
} }
......
...@@ -158,13 +158,13 @@ size_t JasonRecorder::receive_message(std::uint8_t *buffer, size_t length, size_ ...@@ -158,13 +158,13 @@ size_t JasonRecorder::receive_message(std::uint8_t *buffer, size_t length, size_
return received; return received;
} }
void JasonRecorder::get_samples(std::vector<std::int16_t> &samples, bool planar) { void JasonRecorder::get_samples(std::vector<std::int16_t> &samples, bool planar, size_t max_wait) {
if (!num_channels || !sample_rate) { if (!num_channels || !sample_rate) {
throw std::logic_error("must call set_format() first"); throw std::logic_error("must call set_format() first");
} }
std::array<std::uint8_t, 4 + MAX_PAYLOAD> buffer; std::array<std::uint8_t, 4 + MAX_PAYLOAD> buffer;
while (true) { while (true) {
size_t received = receive_message(buffer.data(), buffer.size()); size_t received = receive_message(buffer.data(), buffer.size(), max_wait);
if (received) { if (received) {
// we could read the payload length, but it is wrong for sample data // we could read the payload length, but it is wrong for sample data
//size_t length = buffer[1] << 8 + buffer[2]; //size_t length = buffer[1] << 8 + buffer[2];
...@@ -194,6 +194,11 @@ void JasonRecorder::get_samples(std::vector<std::int16_t> &samples, bool planar) ...@@ -194,6 +194,11 @@ void JasonRecorder::get_samples(std::vector<std::int16_t> &samples, bool planar)
break; break;
} }
} }
else if (max_wait > 0) {
// we timed out, we do not want to wait again
samples.resize(0);
break;
}
} }
} }
......
...@@ -95,8 +95,12 @@ public: ...@@ -95,8 +95,12 @@ public:
* \param[in] planar If true, return the samples in planar form, i.e., one * \param[in] planar If true, return the samples in planar form, i.e., one
* channel after the other, the format sent by the device. If false (the * channel after the other, the format sent by the device. If false (the
* default), interleave the channels as done in PCM WAVE files. * default), interleave the channels as done in PCM WAVE files.
* \param[in] max_wait Maximum time in milliseconds to block waiting for a
* packet from the device. If the time elapses before receiving any packets,
* or if a different type of packet was received, returns with an empty
* samples vector. Set to zero to wait indefinitely for a sample packet.
*/ */
void get_samples(std::vector<std::int16_t> &samples, bool planar=false); void get_samples(std::vector<std::int16_t> &samples, bool planar=false, size_t max_wait=0);
/** Converts samples from planar to interleaved form. /** Converts samples from planar to interleaved form.
* \param[in] input A pointer to the planar samples to read. * \param[in] input A pointer to the planar samples to read.
* \param[out] output A pointer to write the interleaved samples to. * \param[out] output A pointer to write the interleaved samples to.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment