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)