~aleteoryx/muditaos

481c4238bfa242377ed02600eef17e770dbf7af6 — Marcin Smoczyński 5 years ago 86dc1e2
[EGD-4004] audio: fix routing synchronization (#880)

Protect copying to buffers with mutex locks. Fix C style copying.

Add sanity checks to detect synchronization issues when routing.
M changelog.md => changelog.md +1 -0
@@ 16,6 16,7 @@
### Other

* `[appmgr]` Application manager documentation added.
* `[audio]` Improve synchronization during calls.

## [0.43.1 2020-10-23]


M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +38 -6
@@ 8,9 8,15 @@

#include <bsp_audio.hpp>
#include <log/log.hpp>
#include <mutex.hpp>

#include <algorithm>
#include <optional>
#include <cstring>
#include <vector>

// enforced optimization is needed for std::vector::insert and std::fill to be
// as quick as memcpy and memset respectively
#pragma GCC optimize("O3")

namespace audio
{


@@ 23,19 29,32 @@ namespace audio
        audioDeviceCallback =
            [this](const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer) -> std::int32_t {
            if (inputBuffer != nullptr) {
                cpp_freertos::LockGuard lock(audioMutex);
                receivedFramesDiffAudio++;

                if (framesPerBuffer > audioDeviceBuffer.size()) {
                    audioDeviceBuffer.resize(framesPerBuffer, 0);
                }

                if (muteEnable) {
                    memset(&audioDeviceBuffer[0], 0, framesPerBuffer * sizeof(std::int16_t));
                    std::fill(std::begin(audioDeviceBuffer), std::end(audioDeviceBuffer), 0);
                }
                else {
                    memcpy(&audioDeviceBuffer[0], inputBuffer, framesPerBuffer * sizeof(std::int16_t));
                    auto rangeStart = static_cast<const std::uint16_t *>(inputBuffer);
                    auto rangeEnd   = rangeStart + framesPerBuffer;
                    std::copy(rangeStart, rangeEnd, std::begin(audioDeviceBuffer));
                }
            }

            if (outputBuffer != nullptr) {
                cpp_freertos::LockGuard lock(cellularMutex);
                receivedFramesDiffCellular--;

                if (receivedFramesDiffCellular != 0) {
                    LOG_FATAL("Audio router synchronization fail, diff = %d", receivedFramesDiffCellular);
                    receivedFramesDiffCellular = 0;
                }

                if (framesPerBuffer > audioDeviceCellularBuffer.size()) {
                    audioDeviceCellularBuffer.resize(framesPerBuffer, 0);
                }


@@ 48,14 67,27 @@ namespace audio
        audioDeviceCellularCallback =
            [this](const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer) -> std::int32_t {
            if (inputBuffer != nullptr) {
                cpp_freertos::LockGuard lock(cellularMutex);
                receivedFramesDiffCellular++;

                if (framesPerBuffer > audioDeviceCellularBuffer.size()) {
                    audioDeviceCellularBuffer.resize(framesPerBuffer, 0);
                }

                memcpy(&audioDeviceCellularBuffer[0], inputBuffer, framesPerBuffer * sizeof(std::int16_t));
                auto rangeStart = static_cast<const std::uint16_t *>(inputBuffer);
                auto rangeEnd   = rangeStart + framesPerBuffer;
                std::copy(rangeStart, rangeEnd, std::begin(audioDeviceCellularBuffer));
            }

            if (outputBuffer != nullptr) {
                cpp_freertos::LockGuard lock(audioMutex);
                receivedFramesDiffAudio--;

                if (receivedFramesDiffAudio != 0) {
                    LOG_FATAL("Audio router synchronization fail, diff = %d", receivedFramesDiffAudio);
                    receivedFramesDiffAudio = 0;
                }

                if (framesPerBuffer > audioDeviceBuffer.size()) {
                    audioDeviceBuffer.resize(framesPerBuffer, 0);
                }


@@ 65,8 97,8 @@ namespace audio
            return framesPerBuffer;
        };

        audioDeviceBuffer.resize(1024, 0);
        audioDeviceCellularBuffer.resize(1024, 0);
        audioDeviceBuffer.resize(INPUT_BUFFER_START_SIZE, 0);
        audioDeviceCellularBuffer.resize(INPUT_BUFFER_START_SIZE, 0);

        constexpr audio::Gain defaultRoutingEarspeakerGain       = 20;
        constexpr audio::Volume defaultRoutingEarspeakerVolume   = 10;

M module-audio/Audio/Operation/RouterOperation.hpp => module-audio/Audio/Operation/RouterOperation.hpp +16 -7
@@ 9,6 9,7 @@
#include <Audio/AudioCommon.hpp>
#include <Audio/Profiles/Profile.hpp>
#include <bsp/audio/bsp_audio.hpp>
#include <mutex.hpp>

#include <memory>
#include <functional>


@@ 21,6 22,10 @@ namespace audio
{
    class RouterOperation : public Operation
    {
        using AudioCallback =
            std::function<std::int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>;
        static const std::size_t INPUT_BUFFER_START_SIZE = 1024;

      public:
        RouterOperation(
            const char *file,


@@ 45,17 50,21 @@ namespace audio
        bool muteEnable = false;

        std::unique_ptr<Encoder> enc;

        std::unique_ptr<bsp::AudioDevice> audioDevice;
        std::unique_ptr<bsp::AudioDevice> audioDeviceCellular;
        std::function<std::int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>
            audioDeviceCallback = nullptr;
        std::function<std::int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>
            audioDeviceCellularCallback = nullptr;

        AudioCallback audioDeviceCallback         = nullptr;
        AudioCallback audioDeviceCellularCallback = nullptr;

        std::vector<std::int16_t> audioDeviceBuffer;
        std::vector<std::int16_t> audioDeviceCellularBuffer;
        std::vector<std::int16_t> channel1Buffer;
        std::vector<std::int16_t> channel2Buffer;
        std::vector<std::int16_t> mixBuffer;

        cpp_freertos::MutexStandard audioMutex;
        cpp_freertos::MutexStandard cellularMutex;

        int receivedFramesDiffAudio    = 0;
        int receivedFramesDiffCellular = 0;
    };

} // namespace audio