diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..966d5bf
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+wfr
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f3430a..459d152 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD 14)
add_executable(${APP_NAME} main.cpp src/ALSADevice.cpp src/ALSADevice.h src/MemoryPool.cpp src/MemoryPool.h utils/Semaphore.h utils/Semaphore.cpp src/SampleWriter.h src/Timestamp.h
#src/SampleReceiver.h
- src/audio_types.h)
+ src/audio_types.h src/ServerBeacon.cpp src/ServerBeacon.h)
find_package(Threads REQUIRED)
if (THREADS_FOUND)
diff --git a/MATLAB/read_syncdata.m b/MATLAB/read_syncdata.m
index 4f3bf44..4fc769d 100644
--- a/MATLAB/read_syncdata.m
+++ b/MATLAB/read_syncdata.m
@@ -1,39 +1,46 @@
-% settings
-DATASET_DIR = 'test';
-TS_FILE = 'ts';
-SAMPLE_FILE_PREFIX = 'ch_';
-FILE_EXT = 'dat';
-CHANNELS = 2;
+function ds = read_syncdata(DATASET_DIR)
+ % settings
+ %DATASET_DIR = 'test_20221';
+ TS_FILE = 'ts';
+ SAMPLE_FILE_PREFIX = 'ch_';
+ FILE_EXT = 'dat';
+ CHANNELS = 2;
-% computed values
-FN_TS = strcat(DATASET_DIR, '/', TS_FILE, '.', FILE_EXT);
+ % computed values
+ FN_TS = strcat(DATASET_DIR, '/', TS_FILE, '.', FILE_EXT);
-for ch=0:1:(CHANNELS-1)
- FN_SAMPLE{ch+1} = strcat(DATASET_DIR, '/', SAMPLE_FILE_PREFIX, num2str(ch), '.', FILE_EXT);
-end
+ for ch=0:1:(CHANNELS-1)
+ FN_SAMPLE{ch+1} = strcat(DATASET_DIR, '/', SAMPLE_FILE_PREFIX, num2str(ch), '.', FILE_EXT);
+ end
-% load timestamps
-f = fopen(FN_TS ,'r');
-ts = fread(f,[2,Inf],'uint32');
-fclose(f);
-
-% take first element as t0
-ts(1,:) = ts(1,:) - ts(1,1);
-
-% create fractional timestamp
-ts = ts(1,:) + ts(2,:) / 1E+09;
-
-% get sample count
-sample_cnt = length(ts);
-
-% load samples
-s = zeros(CHANNELS, sample_cnt);
-for ch=1:CHANNELS
- f = fopen(FN_SAMPLE{ch},'r');
- d = fread(f, [1,Inf],'int16');
- s(ch,:) = d;
+ % load timestamps
+ f = fopen(FN_TS ,'r');
+ ts = fread(f,[2,Inf],'uint32');
fclose(f);
-end
-plot(ts(1,1:100), s(1,1:100))
\ No newline at end of file
+ % take first element as t0
+ %ts(1,:) = ts(1,:) - 1636036145;
+
+ % create fractional timestamp
+ ts = ts(1,:) + ts(2,:) / 1E+09;
+
+ % get sample count
+ sample_cnt = length(ts);
+
+ % load samples
+ s = zeros(CHANNELS, sample_cnt);
+ for ch=1:CHANNELS
+ f = fopen(FN_SAMPLE{ch},'r');
+ d = fread(f, [1,Inf],'int16');
+ s(ch,:) = d;
+ fclose(f);
+ end
+
+ %figure(1)
+ %plot(ts(1,1:100), s(1,1:100), 'x')
+ %xlim([ts(1) ts(100)])
+ %hold on
+
+ ds = [ts' s'];
+end
\ No newline at end of file
diff --git a/MATLAB/sync_datasets.m b/MATLAB/sync_datasets.m
new file mode 100644
index 0000000..71319f8
--- /dev/null
+++ b/MATLAB/sync_datasets.m
@@ -0,0 +1,72 @@
+function sds = sync_datasets(dss)
+ % load datasets
+ len = length(dss);
+ sds = {};
+ first_ts = [];
+ last_ts = [];
+ for i=1:len
+ ds = read_syncdata(dss{i});
+ first_ts(i) = ds(1:1);
+ last_ts(i) = ds(end,1);
+ sds{i} = ds;
+ end
+
+ % get first and last common timestamp
+ ts0 = max(first_ts);
+ tsend = min(last_ts);
+
+ for i=1:len
+ ds = sds{i};
+ ds = ds(ds(:,1) > ts0 + (ds(2,1) - ds(1,1)) / 2 & ds(:,1) < tsend, :); % drop non-common sections
+ ds(:,1) = ds(:,1) - ts0; % substract ts0 from each dataset's timestamp array
+ sds{i} = ds;
+ end
+
+ % create plot
+ figure(1)
+
+ % plot samples
+ subplot(2,1,1);
+
+ marks = ['-', '-o'];
+
+ PLOTRANGE = 1:100;
+
+ % get beginning indices
+ for i=1:len
+ ds = sds{i};
+ ts = ds(:,1);
+
+ s = size(ds);
+
+ %for k = 2:s(2);
+ for k = 2:2
+ %plot(ts(1:100),ds(1:100,k), marks(k-1));
+ plot(ts(PLOTRANGE),ds(PLOTRANGE,k), 'x');
+ hold on
+ end
+ end
+
+ grid on
+ xlabel("Time [s]");
+ ylabel("Sample");
+ xlim([ts(PLOTRANGE(1)) ts(PLOTRANGE(end))]);
+
+ % plot timestamp errors
+ subplot(2,1,2);
+
+ ds_ref = sds{1};
+ ts_ref = ds_ref(:,1);
+
+ for i = 2:len
+ ts_err = ts(PLOTRANGE) - ts_ref(PLOTRANGE);
+ plot(ts_ref(PLOTRANGE), ts_err * 1E+09);
+ hold on
+ end
+
+ grid on
+ xlabel("Time [s]");
+ ylabel("Time error [ns]");
+ xlim([ts(PLOTRANGE(1)) ts(PLOTRANGE(end))]);
+
+endfunction
diff --git a/main.cpp b/main.cpp
index 8b58bb3..87a72eb 100644
--- a/main.cpp
+++ b/main.cpp
@@ -144,7 +144,7 @@ uint8_t pRecvBuf[8096] __attribute__ ((aligned (32)));
int main(int argc, char * argv[]) {
ALSADevice dev(PERIOD_LEN, SAMPLE_RATE);
MemoryPool pool(STEREO_BUF_LEN, 1000);
- //SampleWriter sw("test", 2, STEREO_BUF_LEN / 2);
+ //SampleWriter sw(std::string("test_") + argv[1], 2, STEREO_BUF_LEN / 2);
//std::this_thread::sleep_for(std::chrono::seconds(1));
diff --git a/src/ServerBeacon.cpp b/src/ServerBeacon.cpp
new file mode 100644
index 0000000..c098f34
--- /dev/null
+++ b/src/ServerBeacon.cpp
@@ -0,0 +1,133 @@
+//
+// Created by epagris on 2021. 11. 11..
+//
+
+#include
+#include
+#include
+#include "ServerBeacon.h"
+
+const in_addr ServerBeacon::DEFAULT_MULTICAST_ADDR = {inet_addr("224.0.2.21")};
+
+ServerBeacon::ServerBeacon() : mRunning(false) {
+ setMulticastAddr(DEFAULT_MULTICAST_ADDR);
+ setPort(DEFAULT_PORT);
+ setAnnouncePeriod(DEFAULT_ANNOUNCE_PERIOD_MS);
+}
+
+ServerBeacon::ServerBeacon(const in_addr &addr, unsigned short port, size_t announcePeriod_ms) : mRunning(false) {
+ setMulticastAddr(addr);
+ setPort(port);
+ setAnnouncePeriod(announcePeriod_ms);
+}
+
+void ServerBeacon::setMulticastAddr(const in_addr &addr) {
+ mAddr = addr;
+}
+
+in_addr ServerBeacon::getMulticastAddr() const {
+ return mAddr;
+}
+
+
+void ServerBeacon::setPort(unsigned short port) {
+ mBeaconPort = port;
+}
+
+unsigned short ServerBeacon::getPort() const {
+ return mBeaconPort;
+}
+
+void ServerBeacon::setAnnouncePeriod(size_t period_ms) {
+ mAnnPeriod_ms = period_ms;
+}
+
+size_t ServerBeacon::getAnnouncePeriod() const {
+ return mAnnPeriod_ms;
+}
+
+void ServerBeacon::startBeacon() {
+ if (mRunning) {
+ std::cerr << "Could not start beacon: already running!" << std::endl;
+ return;
+ }
+
+ mBeaconSoc = socket(AF_INET, SOCK_DGRAM, 0); // create socket
+ if (mBeaconSoc == -1) {
+ std::cerr << "Could not open socket in " << __FUNCTION__ << "!" << std::endl;
+ return;
+ }
+
+ // set socket options
+ int opt = 1;
+ setsockopt(mBeaconSoc, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
+
+ // bind to ip-address and port
+ sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_addr = mAddr;
+ addr.sin_port = htons(mBeaconPort);
+
+ if (bind(mBeaconSoc, (const sockaddr *) &addr, sizeof(addr)) == -1) {
+ std::cerr << "Could not bind to IP address and/or port in " << __FUNCTION__ << "!" << std::endl;
+ close(mBeaconSoc);
+ return;
+ }
+
+ // the beacon is running now!
+ mRunning = true;
+
+ // start beacon thread
+ mpBeaconThread = std::make_shared(fn_BeaconThread, this);
+}
+
+void ServerBeacon::stopBeacon() {
+ mRunning = false;
+}
+
+std::list ServerBeacon::getNodesOnNetwork() {
+ return std::list();
+}
+
+
+// -------------------------------------------
+
+void ServerBeacon::fn_BeaconThread(ServerBeacon *pSB) {
+ // beacon message used to send and receive information
+ BeaconMsg msg;
+
+ //
+
+ // select-related structures
+ fd_set read_fds;
+ timeval tv;
+
+ // fill-in select parameters
+ FD_ZERO(&read_fds);
+ FD_SET(pSB->mBeaconSoc, &read_fds);
+
+ // fill-in timeout value
+ tv.tv_sec = pSB->mAnnPeriod_ms / 1000;
+ tv.tv_usec = (pSB->mAnnPeriod_ms % 1000) * 1000;
+
+ while (pSB->mRunning) {
+ msg.server_nClient = 1; // we are the server
+ msg.terminalPort = 0; // we have no inbound terminal port
+
+ send(pSB->mBeaconSoc, &msg, sizeof(BeaconMsg), 0); // send the announce message
+
+ // ------------------
+
+ // copy parameters
+ fd_set cur_rfds = read_fds;
+ timeval cur_tv = tv;
+
+ while (select(1, &cur_rfds, nullptr, nullptr, &cur_tv) != 0) {
+ // receive response
+ recv(pSB->mBeaconSoc, &msg, sizeof(BeaconMsg), 0);
+
+ // store response
+ }
+
+ }
+}
diff --git a/src/ServerBeacon.h b/src/ServerBeacon.h
new file mode 100644
index 0000000..a1279d2
--- /dev/null
+++ b/src/ServerBeacon.h
@@ -0,0 +1,56 @@
+//
+// Created by epagris on 2021. 11. 11..
+//
+
+#ifndef WFR_SERVERBEACON_H
+#define WFR_SERVERBEACON_H
+
+#include
+#include
+#include
+#include
+#include
+
+class ServerBeacon {
+public:
+ static constexpr unsigned short DEFAULT_PORT = 8021; // default port for multicast messages
+ static const in_addr DEFAULT_MULTICAST_ADDR; // default multicast address
+ static constexpr size_t DEFAULT_ANNOUNCE_PERIOD_MS = 1000; // default announce period
+private:
+ // structure for storing nodes
+ struct ClientNodeInfo {
+ in_addr addr; // address of client
+ uint16_t terminalPort;
+ };
+private:
+ int mBeaconSoc; // beacon socket
+ in_addr mAddr; // address
+ unsigned short mBeaconPort; // port
+ size_t mAnnPeriod_ms; // announce period
+ std::list mNodes; // nodes
+ bool mRunning; // does the beacon operate?
+private:
+ std::shared_ptr mpBeaconThread; // thread running the beacon
+ static void fn_BeaconThread(ServerBeacon * pSB); // function running in beacon thread
+private:
+ // structure for beacon MSG
+ struct BeaconMsg {
+ uint8_t server_nClient; // server or client
+ uint16_t terminalPort; // port of terminal
+ };
+public:
+ ServerBeacon(); // constr.
+ explicit ServerBeacon(const in_addr& addr, unsigned short port, size_t announcePeriod_ms); // constr. with beacon port and announce period
+ void setMulticastAddr(const in_addr& addr); // set multicasting address
+ in_addr getMulticastAddr() const; // set multicasting address
+ void setPort(unsigned short port); // set port BEFORE starting beacon
+ unsigned short getPort() const; // get beacon port
+ void setAnnouncePeriod(size_t period_ms); // set announce period
+ size_t getAnnouncePeriod() const; // get announce period
+ void startBeacon(); // start the beacon
+ void stopBeacon(); // stop the beacon
+ std::list getNodesOnNetwork(); // get nodes connected to the same network
+};
+
+
+#endif //WFR_SERVERBEACON_H
diff --git a/src/audio_types.h b/src/audio_types.h
index 3cbd64b..09cc7df 100644
--- a/src/audio_types.h
+++ b/src/audio_types.h
@@ -7,7 +7,7 @@
#include
-#define STEREO_BUF_LEN (648)
+#define STEREO_BUF_LEN (2 * 192)
#define PERIOD_LEN (STEREO_BUF_LEN / 2)
#define SAMPLE_RATE (48000)