~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/src/audio/ringbuffer.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 *  as that of the covered work.
34
34
 */
35
35
 
 
36
#include "ringbuffer.h"
 
37
#include "logger.h"
 
38
 
 
39
#include <chrono>
 
40
#include <utility> // for std::pair
36
41
#include <cstdlib>
37
42
#include <cstring>
38
 
#include <utility> // for std::pair
39
 
 
40
 
#include "logger.h"
41
 
#include "ringbuffer.h"
42
 
 
43
 
namespace {
 
43
 
44
44
// corresponds to 160 ms (about 5 rtp packets)
45
 
const size_t MIN_BUFFER_SIZE = 1280;
46
 
}
 
45
static const size_t MIN_BUFFER_SIZE = 1024;
47
46
 
48
47
// Create  a ring buffer with 'size' bytes
49
 
RingBuffer::RingBuffer(size_t size, const std::string &call_id) :
 
48
RingBuffer::RingBuffer(size_t size, const std::string &call_id, AudioFormat format /* = MONO */) :
50
49
    endPos_(0)
51
 
    , buffer_(std::max(size, MIN_BUFFER_SIZE), 1, 8000)
52
 
    , readpointers_()
 
50
    , buffer_(std::max(size, MIN_BUFFER_SIZE), format)
 
51
    , lock_()
 
52
    , not_empty_()
 
53
    , readoffsets_()
53
54
    , buffer_id_(call_id)
54
55
{
55
56
}
57
58
void
58
59
RingBuffer::flush(const std::string &call_id)
59
60
{
60
 
    storeReadPointer(endPos_, call_id);
 
61
    storeReadOffset(endPos_, call_id);
61
62
}
62
63
 
63
64
 
64
65
void
65
66
RingBuffer::flushAll()
66
67
{
67
 
    ReadPointer::iterator iter;
 
68
    ReadOffset::iterator iter;
68
69
 
69
 
    for (iter = readpointers_.begin(); iter != readpointers_.end(); ++iter)
 
70
    for (iter = readoffsets_.begin(); iter != readoffsets_.end(); ++iter)
70
71
        iter->second = endPos_;
71
72
}
72
73
 
76
77
    const size_t buffer_size = buffer_.frames();
77
78
    if (buffer_size == 0)
78
79
        return 0;
79
 
    const size_t startPos = (not readpointers_.empty()) ? getSmallestReadPointer() : 0;
 
80
    const size_t startPos = (not readoffsets_.empty()) ? getSmallestReadOffset() : 0;
80
81
    return (endPos_ + buffer_size - startPos) % buffer_size;
81
82
}
82
83
 
85
86
    const size_t buffer_size = buffer_.frames();
86
87
    if (buffer_size == 0)
87
88
        return 0;
88
 
    return (endPos_ + buffer_size - getReadPointer(call_id)) % buffer_size;
 
89
    return (endPos_ + buffer_size - getReadOffset(call_id)) % buffer_size;
89
90
}
90
91
 
91
92
void
92
93
RingBuffer::debug()
93
94
{
94
 
    DEBUG("Start=%d; End=%d; BufferSize=%d", getSmallestReadPointer(), endPos_, buffer_.frames());
 
95
    DEBUG("Start=%d; End=%d; BufferSize=%d", getSmallestReadOffset(), endPos_, buffer_.frames());
95
96
}
96
97
 
97
 
size_t RingBuffer::getReadPointer(const std::string &call_id) const
 
98
size_t RingBuffer::getReadOffset(const std::string &call_id) const
98
99
{
99
 
    if (hasNoReadPointers())
 
100
    if (hasNoReadOffsets())
100
101
        return 0;
101
 
 
102
 
    ReadPointer::const_iterator iter = readpointers_.find(call_id);
103
 
    return (iter != readpointers_.end()) ? iter->second : 0;
 
102
    ReadOffset::const_iterator iter = readoffsets_.find(call_id);
 
103
    return (iter != readoffsets_.end()) ? iter->second : 0;
104
104
}
105
105
 
106
106
size_t
107
 
RingBuffer::getSmallestReadPointer() const
 
107
RingBuffer::getSmallestReadOffset() const
108
108
{
109
 
    if (hasNoReadPointers())
 
109
    if (hasNoReadOffsets())
110
110
        return 0;
111
 
 
112
111
    size_t smallest = buffer_.frames();
113
 
 
114
 
    ReadPointer::const_iterator iter;
115
 
 
116
 
    for (iter = readpointers_.begin(); iter != readpointers_.end(); ++iter)
117
 
        if (iter->second < smallest)
118
 
            smallest = iter->second;
119
 
 
 
112
    for(auto const& iter : readoffsets_)
 
113
        smallest = std::min(smallest, iter.second);
120
114
    return smallest;
121
115
}
122
116
 
123
117
void
124
 
RingBuffer::storeReadPointer(size_t pointer_value, const std::string &call_id)
 
118
RingBuffer::storeReadOffset(size_t offset, const std::string &call_id)
125
119
{
126
 
    ReadPointer::iterator iter = readpointers_.find(call_id);
 
120
    ReadOffset::iterator iter = readoffsets_.find(call_id);
127
121
 
128
 
    if (iter != readpointers_.end())
129
 
        iter->second = pointer_value;
 
122
    if (iter != readoffsets_.end())
 
123
        iter->second = offset;
130
124
    else
131
 
        DEBUG("Cannot find \"%s\" readPointer in \"%s\" ringbuffer", call_id.c_str(), buffer_id_.c_str());
132
 
}
133
 
 
134
 
 
135
 
void
136
 
RingBuffer::createReadPointer(const std::string &call_id)
137
 
{
138
 
    if (!hasThisReadPointer(call_id))
139
 
        readpointers_.insert(std::pair<std::string, int> (call_id, endPos_));
140
 
}
141
 
 
142
 
 
143
 
void
144
 
RingBuffer::removeReadPointer(const std::string &call_id)
145
 
{
146
 
    ReadPointer::iterator iter = readpointers_.find(call_id);
147
 
 
148
 
    if (iter != readpointers_.end())
149
 
        readpointers_.erase(iter);
 
125
        DEBUG("Cannot find \"%s\" readOffset in \"%s\" ringbuffer", call_id.c_str(), buffer_id_.c_str());
 
126
}
 
127
 
 
128
 
 
129
void
 
130
RingBuffer::createReadOffset(const std::string &call_id)
 
131
{
 
132
    std::lock_guard<std::mutex> l(lock_);
 
133
    if (!hasThisReadOffset(call_id))
 
134
        readoffsets_.insert(std::pair<std::string, int> (call_id, endPos_));
 
135
}
 
136
 
 
137
 
 
138
void
 
139
RingBuffer::removeReadOffset(const std::string &call_id)
 
140
{
 
141
    std::lock_guard<std::mutex> l(lock_);
 
142
    ReadOffset::iterator iter = readoffsets_.find(call_id);
 
143
 
 
144
    if (iter != readoffsets_.end())
 
145
        readoffsets_.erase(iter);
150
146
}
151
147
 
152
148
 
153
149
bool
154
 
RingBuffer::hasThisReadPointer(const std::string &call_id) const
 
150
RingBuffer::hasThisReadOffset(const std::string &call_id) const
155
151
{
156
 
    return readpointers_.find(call_id) != readpointers_.end();
 
152
    return readoffsets_.find(call_id) != readoffsets_.end();
157
153
}
158
154
 
159
155
 
160
 
bool RingBuffer::hasNoReadPointers() const
 
156
bool RingBuffer::hasNoReadOffsets() const
161
157
{
162
 
    return readpointers_.empty();
 
158
    return readoffsets_.empty();
163
159
}
164
160
 
165
161
//
169
165
// This one puts some data inside the ring buffer.
170
166
void RingBuffer::put(AudioBuffer& buf)
171
167
{
172
 
    const size_t len = putLength();
 
168
    std::lock_guard<std::mutex> l(lock_);
173
169
    const size_t sample_num = buf.frames();
174
170
    const size_t buffer_size = buffer_.frames();
175
171
    if (buffer_size == 0)
176
172
        return;
177
173
 
 
174
    size_t len = putLength();
 
175
    if (buffer_size - len < sample_num)
 
176
        discard(sample_num);
178
177
    size_t toCopy = sample_num;
179
178
 
180
179
    // Add more channels if the input buffer holds more channels than the ring.
181
180
    if (buffer_.channels() < buf.channels())
182
181
        buffer_.setChannelNum(buf.channels());
183
182
 
184
 
    if (toCopy > buffer_size - len)
185
 
        toCopy = buffer_size - len;
186
 
 
187
183
    size_t in_pos = 0;
188
184
    size_t pos = endPos_;
189
185
 
200
196
    }
201
197
 
202
198
    endPos_ = pos;
 
199
    not_empty_.notify_all();
203
200
}
204
201
 
205
202
//
213
210
    return getLength(call_id);
214
211
}
215
212
 
216
 
// Get will move 'toCopy' bytes from the internal FIFO to 'buffer'
217
213
size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id)
218
214
{
219
 
    if (hasNoReadPointers())
220
 
        return 0;
221
 
 
222
 
    if (not hasThisReadPointer(call_id))
223
 
        return 0;
224
 
 
225
 
    const size_t len = getLength(call_id);
226
 
    const size_t sample_num = buf.frames();
 
215
    std::lock_guard<std::mutex> l(lock_);
 
216
 
 
217
    if (hasNoReadOffsets())
 
218
        return 0;
 
219
 
 
220
    if (not hasThisReadOffset(call_id))
 
221
        return 0;
 
222
 
227
223
    const size_t buffer_size = buffer_.frames();
228
224
    if (buffer_size == 0)
229
225
        return 0;
 
226
 
 
227
    size_t len = getLength(call_id);
 
228
    const size_t sample_num = buf.frames();
230
229
    size_t toCopy = std::min(sample_num, len);
 
230
    if (toCopy and toCopy != sample_num) {
 
231
        DEBUG("Partial get: %d/%d", toCopy, sample_num);
 
232
    }
231
233
 
232
234
    const size_t copied = toCopy;
233
235
 
234
236
    size_t dest = 0;
235
 
    size_t startPos = getReadPointer(call_id);
 
237
    size_t startPos = getReadOffset(call_id);
236
238
 
237
239
    while (toCopy > 0) {
238
240
        size_t block = toCopy;
247
249
        toCopy -= block;
248
250
    }
249
251
 
250
 
    storeReadPointer(startPos, call_id);
 
252
    storeReadOffset(startPos, call_id);
251
253
    return copied;
252
254
}
253
255
 
 
256
 
 
257
size_t RingBuffer::waitForDataAvailable(const std::string &call_id, const size_t min_data_length, const std::chrono::high_resolution_clock::time_point& deadline) const
 
258
{
 
259
    std::unique_lock<std::mutex> l(lock_);
 
260
    const size_t buffer_size = buffer_.frames();
 
261
    if (buffer_size < min_data_length) return 0;
 
262
    ReadOffset::const_iterator read_ptr = readoffsets_.find(call_id);
 
263
    if (read_ptr == readoffsets_.end()) return 0;
 
264
    size_t getl = 0;
 
265
    if (deadline == std::chrono::high_resolution_clock::time_point()) {
 
266
        not_empty_.wait(l, [=, &getl] {
 
267
                getl =  (endPos_ + buffer_size - read_ptr->second) % buffer_size;
 
268
                return getl >= min_data_length;
 
269
        });
 
270
    } else {
 
271
        not_empty_.wait_until(l, deadline, [=, &getl]{
 
272
                getl = (endPos_ + buffer_size - read_ptr->second) % buffer_size;
 
273
                return getl >= min_data_length;
 
274
        });
 
275
    }
 
276
    return getl;
 
277
}
 
278
 
254
279
size_t
255
280
RingBuffer::discard(size_t toDiscard, const std::string &call_id)
256
281
{
 
282
    std::lock_guard<std::mutex> l(lock_);
 
283
 
 
284
    const size_t buffer_size = buffer_.frames();
 
285
    if (buffer_size == 0)
 
286
        return 0;
 
287
 
257
288
    size_t len = getLength(call_id);
258
 
 
259
289
    if (toDiscard > len)
260
290
        toDiscard = len;
261
291
 
262
 
    size_t buffer_size = buffer_.frames();
 
292
    size_t startPos = (getReadOffset(call_id) + toDiscard) % buffer_size;
 
293
    storeReadOffset(startPos, call_id);
 
294
    return toDiscard;
 
295
}
 
296
 
 
297
size_t
 
298
RingBuffer::discard(size_t toDiscard)
 
299
{
 
300
    const size_t buffer_size = buffer_.frames();
263
301
    if (buffer_size == 0)
264
302
        return 0;
265
 
    size_t startPos = (getReadPointer(call_id) + toDiscard) % buffer_size;
266
 
 
267
 
    storeReadPointer(startPos, call_id);
268
 
 
 
303
 
 
304
    for (auto & r : readoffsets_) {
 
305
        size_t dst = (r.second + buffer_size - endPos_) % buffer_size;
 
306
        if (dst < toDiscard) {
 
307
            DEBUG("%s : discarding: %d frames", r.first.c_str(), toDiscard - dst);
 
308
            r.second = (r.second + toDiscard - dst) % buffer_size;
 
309
        }
 
310
    }
269
311
    return toDiscard;
270
312
}