diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8d14cad842dc23e00c67e6371d530047b4f3882f..3eaad61d151a225bb5e87ab90cdbdb0933cb6415 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,7 +4,7 @@ if(POLICY CMP0063)
 endif()
 
 project(jasonrec)
-set(JASONREC_VERSION "1.1")
+set(JASONREC_VERSION "1.2")
 add_definitions(-DJASONREC_VERSION="${JASONREC_VERSION}")
 
 find_path(LIBUSB_INCLUDE_DIR
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0f3186179766a0caf5f9ed0b0eafa09f39a69035..3a9ed88ff9ef8b948129bd0d5613341499e14236 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_executable(jasonrec
 	recorder.cpp
 	filewriter.cpp
+	cleanexit.cpp
 	main.cpp)
 # compile as C++11
 set_property(TARGET jasonrec
@@ -17,4 +18,3 @@ target_link_libraries(jasonrec
 	${LIBUSB_LIBRARY})
 
 install(TARGETS jasonrec DESTINATION bin)
-
diff --git a/src/cleanexit.cpp b/src/cleanexit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bd977c8327f21ed2dfce4625bb2d89edffabcce8
--- /dev/null
+++ b/src/cleanexit.cpp
@@ -0,0 +1,35 @@
+/**
+ * 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();
+}
diff --git a/src/cleanexit.h b/src/cleanexit.h
new file mode 100644
index 0000000000000000000000000000000000000000..24a88dd473897e30a69d9f3010128315095de43b
--- /dev/null
+++ b/src/cleanexit.h
@@ -0,0 +1,21 @@
+/**
+ * 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
diff --git a/src/main.cpp b/src/main.cpp
index 8c503216b0d79ba8a9cf9ccb2d393d6828473fe8..20c7756354ce4c891e86a9dd6b089bf6d0bcbfd8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,6 +8,7 @@
 #include <memory>
 #include "recorder.h"
 #include "filewriter.h"
+#include "cleanexit.h"
 
 void print_usage(char *name) {
     std::cout << "SMIoT JASON Qualilife sound recorder";
@@ -52,6 +53,7 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen,
         }
         // start the recording loop
         std::cout << "Starting to record..." << std::endl;
+        allow_clean_exit();
         size_t total_samples_wanted = totallen * rate;
         size_t total_samples_read = 0;
         std::vector<std::int16_t> samples;
@@ -59,14 +61,20 @@ int record(size_t channels, size_t rate, std::string &filename, float chunklen,
             recorder.start_recording();
             // we will record until we have enough (or forever, if totallen == 0)
             while ((total_samples_wanted == 0) || (total_samples_read < total_samples_wanted)) {
-                recorder.get_samples(samples);
-                total_samples_read += samples.size() / channels;
-                // if we have too much now, crop the last packet
-                if ((total_samples_wanted > 0) && (total_samples_read > total_samples_wanted)) {
-                    samples.resize(samples.size() - (total_samples_read - total_samples_wanted) * channels);
+                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;
+                    // if we have too much now, crop the last packet
+                    if ((total_samples_wanted > 0) && (total_samples_read > total_samples_wanted)) {
+                        samples.resize(samples.size() - (total_samples_read - total_samples_wanted) * channels);
+                    }
+                    // pass it on to the file writer
+                    filewriter->write(samples);
                 }
-                // pass it on to the file writer
-                filewriter->write(samples);
             }
             recorder.stop_recording();
             std::cout << "Stopped recording." << std::endl;
diff --git a/src/recorder.cpp b/src/recorder.cpp
index 8c5e33e8609d4c82275ab1021897965abce3347f..6c73ea7f283223ea3072312d30b1d91a4c886cd3 100644
--- a/src/recorder.cpp
+++ b/src/recorder.cpp
@@ -158,13 +158,13 @@ size_t JasonRecorder::receive_message(std::uint8_t *buffer, size_t length, size_
     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) {
         throw std::logic_error("must call set_format() first");
     }
     std::array<std::uint8_t, 4 + MAX_PAYLOAD> buffer;
     while (true) {
-        size_t received = receive_message(buffer.data(), buffer.size());
+        size_t received = receive_message(buffer.data(), buffer.size(), max_wait);
         if (received) {
             // we could read the payload length, but it is wrong for sample data
             //size_t length = buffer[1] << 8 + buffer[2];
@@ -194,6 +194,11 @@ void JasonRecorder::get_samples(std::vector<std::int16_t> &samples, bool planar)
                 break;
             }
         }
+        else if (max_wait > 0) {
+            // we timed out, we do not want to wait again
+            samples.resize(0);
+            break;
+        }
     }
 }
 
diff --git a/src/recorder.h b/src/recorder.h
index 0c92ed1d5af86e1edd98f00ade553c0ece077e07..3bfb7dc5c859f0a8f58e4e639936bc556399ffdd 100644
--- a/src/recorder.h
+++ b/src/recorder.h
@@ -95,8 +95,12 @@ public:
      * \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
      * 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.
      * \param[in] input A pointer to the planar samples to read.
      * \param[out] output A pointer to write the interleaved samples to.