5G-MAG Reference Tools - MBMS Modem
MultichannelRingbuffer.cpp
Go to the documentation of this file.
1 // 5G-MAG Reference Tools
2 // MBMS Modem Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Affero General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Affero General Public License for more details.
15 //
16 // You should have received a copy of the GNU Affero General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 #include "MultichannelRingbuffer.h"
21 
22 #include <memory>
23 #include "spdlog/spdlog.h"
24 
26  : _size( size )
27  , _channels( channels )
28  , _used( 0 )
29  , _head( 0 )
30 {
31  for (auto ch = 0; ch < _channels; ch++) {
32  auto buf = (char*)srsran_vec_malloc( _size);
33  //auto buf = (char*)malloc(_size);
34  if (buf == nullptr) {
35  throw "Could not allocate memory";
36  }
37  _buffers.push_back(buf);
38  }
39  spdlog::debug("Created {}-channel ringbuffer with size {}", _channels, _size );
40 }
41 
43 {
44  for (auto buffer : _buffers) {
45  if (buffer) free(buffer);
46  }
47 }
48 
49 auto MultichannelRingbuffer::read_head() -> std::vector<void*>
50 {
51 // _mutex.lock();
52  std::lock_guard<std::mutex> lock(_mutex);
53  std::vector<void*> buffers(_channels, nullptr);
54  for (auto ch = 0; ch < _channels; ch++) {
55  buffers[ch] = (void*)(_buffers[ch]); // Return the beggining of the buffer;
56  }
57  _head = 0;
58  _used = 0;
59  return buffers;
60 }
61 
62 auto MultichannelRingbuffer::write_head(size_t* writeable) -> std::vector<void*>
63 {
64 // _mutex.lock();
65  std::lock_guard<std::mutex> lock(_mutex);
66  std::vector<void*> buffers(_channels, nullptr);
67  if (_size == _used) { // In this case we return a nullptr. Because read_head and read functions we should never see a situation where we try to read this returned nullptr. Usually never reach exactly te end of the buffer.
68  *writeable = 0;
69  } else {
70  auto tail = (_head + _used) % _size;
71  if (tail < _head) {
72  *writeable = _head - tail;
73  } else {
74  *writeable = _size - tail;
75  }
76  for (auto ch = 0; ch < _channels; ch++) {
77  buffers[ch] = (void*)(_buffers[ch] + tail);
78  }
79  }
80 
81  return buffers;
82 }
83 
84 auto MultichannelRingbuffer::commit(size_t written) -> void
85 {
86  assert(written >= 0);
87  assert(written <= free_size());
88  std::lock_guard<std::mutex> lock(_mutex);
89  _used += written;
90 // _mutex.unlock();
91 }
92 
93 auto MultichannelRingbuffer::read(std::vector<char*> dest, size_t size) -> void
94 {
95  assert(dest.size() >= _channels);
96  assert(size <= used_size());
97  assert(size >= 0);
98 
99  std::lock_guard<std::mutex> lock(_mutex);
100  auto end = (_head + size) % _size;
101 
102  if (end <= _head) {
103  auto first_part = _size - _head;
104  auto second_part = size - first_part;
105  for (auto ch = 0; ch < _channels; ch++) {
106  memcpy(dest[ch], _buffers[ch] + _head, first_part);
107  memcpy(dest[ch] + first_part, _buffers[ch], second_part);
108  }
109  } else {
110  for (auto ch = 0; ch < _channels; ch++) {
111  memcpy(dest[ch], _buffers[ch] + _head, size);
112  }
113  }
114  _head = (_head + size) % _size;
115  _used -= size;
116 }
void read(std::vector< char * > dest, size_t bytes)
std::vector< void * > read_head()
std::vector< char * > _buffers
std::vector< void * > write_head(size_t *writeable)
MultichannelRingbuffer(size_t size, size_t channels)