roc-toolkit: Support error codes and partial reads and writes in audio readers and writers

Problem

Here is how audio::IReader and audio::IWriter interfaces look like currently:

class IReader {
public:
    // can't fail
    // returns false on EOF; not used by most implementations
    virtual bool read(Frame& frame) = 0;
};

class IWriter {
public:
    // can't fail
    virtual void write(Frame& frame) = 0;
};

We need two improvements here:

  • Allow read() and write() operations to fail and report error to the upper code. This is needed to handle run-time error gracefully.

  • Allow read() and write() operations to process lesser samples than requested and report how much samples were actually processed. This is needed to implement PLC.

Solution

Convert the above interfaces to the following:

class IReader {
public:
    virtual ssize_t read(Frame& frame) = 0;
};

class IWriter {
public:
    virtual ssize_t write(Frame& frame) = 0;
};

(ssize_t is provided by roc_core/stddefs.h)

In particular:

  • On success, read() and write() will return zero or positive number of samples read or written, in range [0; frame.size()).

  • On failure, read() and write() will return a negative error code defined in roc_error module (roc_error/error_code.h).

  • On EOF, read() should return error::EOF. This error may be returned by various implementations of sndio::ISource (which inherits audio::IReader). Currently EOF is reported as returning false.

After changing the interfaces, we should also find and fix all audio::IReader and audio::IWriter implementations:

  • Fix function signature.

  • Fix invocation of nested audio readers and writers. Two fixes are needed:

    • if nested reader / writer returns a negative value, we should break and return that value to the upper level;

    • if nested reader / writer returns lesser samples than requested, we should either also break and return lesser samples to the upper samples, OR repeat the read / write operation until desired number of samples reached. What behavior we need depends on the specific implementation:

      • the following components should repeat read / write: audio::ResamplerReader, audio::ResamplerWriter, audio::Mixer, pipeline::Receiver, pipeline::Sender;

        (why? just because it’d be hard to handle partial reads / writes in these components and, on the other hand, we either don’t need it now)

      • the rest components can just return the number of samples returned from nested elements.

  • Fix unit tests for the modified components and add a few tests for the new behavior (test that error codes are forwarded and partial reads / writes are handled as expected).

Notes

Since currently read() and write() can not fail, after this change all implementations will actually always report that the frame was successfully and completely read or write, and error and partial read/write handling code will never trigger, except unit tests.

However, after finishing this task we will be able to add error reporting and partial reads to some components. This will be done separately.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 25 (13 by maintainers)

Commits related to this issue

Most upvoted comments

That makes things a lot clearer. Thanks! And I’ll add a comment to the packetizer code as well