summaryrefslogtreecommitdiff
path: root/gr-blocks/lib/wavfile_sink_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-blocks/lib/wavfile_sink_impl.cc')
-rw-r--r--gr-blocks/lib/wavfile_sink_impl.cc97
1 files changed, 83 insertions, 14 deletions
diff --git a/gr-blocks/lib/wavfile_sink_impl.cc b/gr-blocks/lib/wavfile_sink_impl.cc
index 431919e7ed..09ff801822 100644
--- a/gr-blocks/lib/wavfile_sink_impl.cc
+++ b/gr-blocks/lib/wavfile_sink_impl.cc
@@ -46,20 +46,23 @@ namespace blocks {
wavfile_sink::sptr wavfile_sink::make(const char* filename,
int n_channels,
unsigned int sample_rate,
- int bits_per_sample)
+ int bits_per_sample,
+ bool append)
{
return gnuradio::get_initial_sptr(new wavfile_sink_impl(
- filename, n_channels, sample_rate, bits_per_sample));
+ filename, n_channels, sample_rate, bits_per_sample, append));
}
wavfile_sink_impl::wavfile_sink_impl(const char* filename,
int n_channels,
unsigned int sample_rate,
- int bits_per_sample)
+ int bits_per_sample,
+ bool append)
: sync_block("wavfile_sink",
io_signature::make(1, n_channels, sizeof(float)),
io_signature::make(0, 0, 0)),
d_h{}, // Init with zeros
+ d_append(append),
d_fp(nullptr),
d_new_fp(nullptr),
d_updated(false)
@@ -81,12 +84,23 @@ bool wavfile_sink_impl::open(const char* filename)
gr::thread::scoped_lock guard(d_mutex);
// we use the open system call to get access to the O_LARGEFILE flag.
- int flags = OUR_O_LARGEFILE | OUR_O_BINARY | O_CREAT | O_WRONLY | O_TRUNC;
- int fd;
+ int flags = OUR_O_LARGEFILE | OUR_O_BINARY;
+
+ if (!d_append) {
+ // We are generating a new file.
+ flags |= O_CREAT | O_WRONLY | O_TRUNC;
+ } else {
+ flags |= O_RDWR;
+ }
+ int fd;
if ((fd = ::open(filename, flags, 0664)) < 0) {
- GR_LOG_ERROR(d_logger,
- boost::format("::open: %s: %s") % filename % strerror(errno));
+ if (errno == ENOENT) {
+ throw std::runtime_error("WAV append mode requires target file to exist");
+ } else {
+ GR_LOG_ERROR(d_logger,
+ boost::format("::open: %s: %s") % filename % strerror(errno));
+ }
return false;
}
@@ -95,7 +109,7 @@ bool wavfile_sink_impl::open(const char* filename)
d_new_fp = nullptr;
}
- if (!(d_new_fp = fdopen(fd, "wb"))) {
+ if (!(d_new_fp = fdopen(fd, d_append ? "r+b" : "wb"))) {
GR_LOG_ERROR(d_logger,
boost::format("fdopen: %s: %s") % filename % strerror(errno));
@@ -103,12 +117,20 @@ bool wavfile_sink_impl::open(const char* filename)
return false;
}
- d_h.first_sample_pos = 44;
- if (!wavheader_write(
- d_new_fp, d_h.sample_rate, d_h.nchans, d_bytes_per_sample_new)) {
- GR_LOG_ERROR(d_logger, boost::format("could not save WAV header"));
- fclose(d_new_fp);
- return false;
+ if (d_append) {
+ // We are appending to an existing file, be extra careful here.
+ if (!check_append_compat_file(d_new_fp)) {
+ fclose(d_new_fp);
+ return false;
+ }
+ } else {
+ d_h.first_sample_pos = 44;
+ if (!wavheader_write(
+ d_new_fp, d_h.sample_rate, d_h.nchans, d_bytes_per_sample_new)) {
+ GR_LOG_ERROR(d_logger, boost::format("could not save WAV header"));
+ fclose(d_new_fp);
+ return false;
+ }
}
d_updated = true;
@@ -116,6 +138,47 @@ bool wavfile_sink_impl::open(const char* filename)
return true;
}
+bool wavfile_sink_impl::check_append_compat_file(FILE* fp)
+{
+
+ if (d_bytes_per_sample_new != d_h.bytes_per_sample) {
+ GR_LOG_ERROR(d_logger,
+ "bytes_per_sample is not allowed to change in append mode");
+ return false;
+ }
+
+ wav_header_info h_tmp{};
+ std::swap(d_h, h_tmp);
+
+ if (!wavheader_parse(fp, d_h)) {
+ GR_LOG_ERROR(d_logger, "invalid or incompatible WAV file");
+ return false;
+ }
+
+ if (d_h.sample_rate != h_tmp.sample_rate || d_h.nchans != h_tmp.nchans ||
+ d_h.bytes_per_sample != h_tmp.bytes_per_sample) {
+ GR_LOG_ERROR(d_logger,
+ "existing WAV file is incompatible with configured options");
+ return false;
+ }
+
+ // TODO: use GR_FSEEK, GR_FTELL.
+ if (fseek(d_new_fp, 0, SEEK_END) != 0) {
+ return false; // This can only happen if the file disappears under our feet.
+ }
+
+ long file_size = ftell(fp);
+ if (file_size - d_h.first_sample_pos != d_h.data_chunk_size) {
+ // This is complicated to properly implement for too little benefit.
+ GR_LOG_ERROR(d_logger,
+ "existing WAV file is incompatible (extra chunks at the end)");
+ return false;
+ }
+
+ return true;
+}
+
+
void wavfile_sink_impl::close()
{
gr::thread::scoped_lock guard(d_mutex);
@@ -230,6 +293,12 @@ void wavfile_sink_impl::set_bits_per_sample_unlocked(int bits_per_sample)
d_bytes_per_sample_new = bits_per_sample / 8;
}
+void wavfile_sink_impl::set_append(bool append)
+{
+ gr::thread::scoped_lock guard(d_mutex);
+ d_append = append;
+}
+
void wavfile_sink_impl::set_sample_rate(unsigned int sample_rate)
{
gr::thread::scoped_lock guard(d_mutex);