blob: de96c7b0f1e428753734c059adcd8404348c4a4f [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CHRE_PLATFORM_AOC_AUDIO_FILTER_H_
#define CHRE_PLATFORM_AOC_AUDIO_FILTER_H_
#include "chre_api/chre/audio.h"
#include "efw/include/filter.h"
#include "filters/audio/common/include/audio_metadata.h"
namespace chre {
/**
* This class implements an audio filter, whose primary purpose is to
* read audio samples from a shared ring buffer, process it, and route
* it to registered audio clients. 'Filter', in this context, means a
* data processing unit (audio data itself is raw, with no actual filtering
* done on it). The audio filter is fully controlled by an instance of an
* audio controller object (see audio_controller.h). The interaction occurs
* as follows:
* - The controller instantiates a filter, and upon notification from the
* remote core that a ring buffer is available, binds it to the filter.
* - The controller also binds an IPC Pipe to the filter's input. The pipe's
* primary (and only) purpose is to notify the filter that there's fresh
* data in the ring buffer.
* - The filter then reads the ring buffer, does some processing (strip
* timestamps, format data, etc.), and sends said data out to clients via
* the CHRE AudioRequestManager.
* The filter instantiates a worker thread, which is woken up by any one of
* the following two mechanisms (outside of the automatic watchdog pet wakeup):
* - 'Signal': A signal is an internal (to the core) command, sent by the main
* audio controller, to notify the filter of local (to the core) conditions.
* For example, CHRE called a free data event, which the controller receives,
* and notifies the filter. Signals are processed by overloading the
* SignalProcessor method of the filter base class.
* - 'Input': An input is a cross core notification that the filter registers
* to, via the pipe that's bound to it. On a pipe notification, the thread
* wakes up to read/process data, which is done by overloading the
* InputProcessor method of the filter base class.
*
* TODO:
* 1 - Audio samples are currently collected and processed in SRAM, need to
* copy out to DRAM before passing to nanoapps, to free up the 2-sec
* buffer to resume collecting samples.
* 2 - Only a single channel (of the 4 available) is currently supported
* (blocked by 1)..
* 3 - The Input processor drops audio samples while the current buffer
* is being serviced by clients (blocked by 1)
*/
class AudioFilter : public Filter {
public:
// Defines the index of a signal sent by the controller
// on receiving CHRE's freeAudioDataEvent.
static constexpr size_t kBufferReleasedSignalIndex = 0;
// Defines the index at which the audio controller's IPC pipe binds to
// the filter input. Note that this is dictated by the 'Num Inputs'
// parameter to the filter constructor.
static constexpr size_t kPipeIndex = 0;
// Defines the index at which the audio controller's IPC ring buffer
// binds to the filter's ring buffer array. Note that this is dictated
// by the 'Num Ring Buffers' parameter to the filter constructor.
static constexpr size_t kRingIndex = 0;
static constexpr uint32_t kSupportedSampleRate = 16000;
static constexpr uint32_t kSupportedDurationSeconds = 2;
AudioFilter();
/**
* Callback that's called at the start of the 'Start' method,
* and before the worker thread has been instantiated.
*
* @return 0 on success, -1 otherwise.
*/
int StartCallback() override final;
/**
* Callback that gets called at the end of the 'Stop' method,
* and after the worker thread has been shutdown.
*
* @return true on success
*/
bool StopCallback() override final;
/**
* Method that handles commands that are internal to the core,
* typically sent by the audio controller. The argument to the
* function is predicated by the 'Command Depth' argument to the
* constructor. If the filter is expected to process a new signal,
* then the constructor argument needs to be incremented as well,
* as any index exceeding this is automatically dropped.
*
* @param index Signal ID (less than command depth) sent by the
* controller
*
* @return true on valid command and processing success
*/
bool SignalProcessor(int index) override final;
/**
* Method that handles cross core pipe notifications, if one was bound
* to the filter's input. The 'pin' argument to the function is predicated
* by the 'Num Filter Inputs' argument to the constructor. If the filter is
* expected to process a new input (via a new pipe being bound to its
* input), then the constructor argument needs to be incremented as well,
* as any index exceeding this is automatically dropped. The pipe index
* depends on the order that InputBind was called. No lookup is provided,
* and the application is expected to keep track of this (maybe via an
* external enum).
*
* @param pin Index of the input pipe that was bound to the filter.
*
* @param message Input pipe notification to be processed. This can be
* a nullptr - which just means that the pipe wanted to notify a certain
* condition, but had no metadata to provide.
*
* @param size Input message size. Can be zero, if the pipe had no
* metadata to send.
*/
void InputProcessor(int pin, void *message, size_t size) override final;
/**
* Callback that's invoked on CHRE's release audio data event.
*
* TODO: This needs to be refactored when we store audio samples in DRAM.
*/
void OnBufferReleased();
private:
static constexpr size_t kSamplesPer2Sec =
kSupportedSampleRate * kSupportedDurationSeconds;
int16_t mSampleBuffer[kSamplesPer2Sec];
void *mRingBufferHandle = nullptr;
size_t mSampleCount = 0;
bool mBufferInUse = false;
struct chreAudioDataEvent mDataEvent = {
.version = CHRE_AUDIO_DATA_EVENT_VERSION,
.reserved = {0, 0, 0},
.handle = 0,
.timestamp = 0,
.sampleRate = kSupportedSampleRate,
.sampleCount = 0,
.format = CHRE_AUDIO_DATA_FORMAT_16_BIT_SIGNED_PCM,
.samplesS16 = nullptr};
};
} // namespace chre
#endif // CHRE_PLATFORM_AOC_AUDIO_FILTER_H_