Skip to content

Commit

Permalink
trying to fix glitches in audio capture, again ...
Browse files Browse the repository at this point in the history
implementing new
LockFreeQueue.cpp
  • Loading branch information
Shaji Khan committed Mar 5, 2024
1 parent 37cde59 commit 27c64f9
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 9 deletions.
1 change: 1 addition & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ add_library( # Sets the name of the library.
PluginControl.cpp
Plugin2.cpp
Meter.cpp
LockFreeQueue.cpp
)

# Searches for a specified prebuilt library and stores the path as a
Expand Down
17 changes: 13 additions & 4 deletions app/src/main/cpp/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ oboe::Result Engine::openStreams() {
warnIfNotLowLatency(mPlayStream);

setupRecordingStreamParameters(&inBuilder, mSampleRate);
inBuilder.setBufferCapacityInFrames(160);
inBuilder.setFramesPerDataCallback(160);
inBuilder.setFramesPerCallback(160);
// inBuilder.setBufferCapacityInFrames(160);
// inBuilder.setFramesPerDataCallback(160);
// inBuilder.setFramesPerCallback(160);

result = inBuilder.openStream(mRecordingStream);

Expand All @@ -152,7 +152,6 @@ oboe::Result Engine::openStreams() {

mFullDuplexPass.setInputStream(mRecordingStream);
mFullDuplexPass.setOutputStream(mPlayStream);
mPlayStream->getDataCallback()->onAudioReady(outputCapture);

// Load LADSPA Plugin here

Expand Down Expand Up @@ -526,4 +525,14 @@ std::string Engine::tuneLatency () {
LOGD ("%s",tmp);
OUT
return std::string (tmp) ;
}

void Engine::test () {
float * sampleData ;

oboe::Result result ;
while (mIsEffectOn) {
result = mPlayStream->read(&sampleData, 192, 0) ;
LOGD("read %d result", result);
}
}
4 changes: 3 additions & 1 deletion app/src/main/cpp/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

class Engine : public oboe::AudioStreamCallback {
public:
virtual oboe::DataCallbackResult outputCapture (
static oboe::DataCallbackResult outputCapture (
std::shared_ptr<oboe::AudioStream> inputStream,
const void *inputData,
int numOutputFrames) {
Expand Down Expand Up @@ -78,6 +78,8 @@ std::string LIBRARY_PATH ;
std::shared_ptr<oboe::AudioStream> mPlayStream;


void test();

private:
int32_t mRecordingDeviceId = oboe::kUnspecified;
int32_t mPlaybackDeviceId = oboe::kUnspecified;
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/cpp/FileWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "FileWriter.h"

int FileWriter::buffer_write_index = 0 ;
LockFreeQueue<buffer_t*, 1024> FileWriter::lockFreeQueue;
void * FileWriter::mp3_buffer = NULL;
bool FileWriter:: useStaticBuffer = false ;
staticBuffer_t FileWriter::buffers [1025] ;
Expand Down Expand Up @@ -553,9 +554,10 @@ int FileWriter::process(int nframes, const float *arg) {

// bg_buffer->pos += nframes;
bg_buffer->pos = nframes;
lockFreeQueue.push(bg_buffer);
// LOGD("return writing [%d] %d", processed, nframes);
processed++;
vringbuffer_return_writing(vringbuffer,bg_buffer);
// vringbuffer_return_writing(vringbuffer,bg_buffer);
// current_buffer->data = (float *) arg;
// current_buffer->pos = nframes;
// disk_write(bg_buffer->data, nframes);
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/cpp/FileWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "opus_projection.h"
#include "opusenc.h"
#include "lame.h"
#include "LockFreeQueue.h"

// TIL you can do this here also
#ifdef __cplusplus
Expand Down Expand Up @@ -62,6 +63,8 @@ class FileWriter {
static OggOpusComments *comments;
static lame_t lame ;

static LockFreeQueue<buffer_t *, 1024> lockFreeQueue ;

static int num_channels;
static OpusEncoder *encoder;
static OggOpusEnc * oggOpusEnc ;
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/cpp/LockFreeQueue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//
// Created by djshaji on 3/5/24.
//

#include "LockFreeQueue.h"
156 changes: 156 additions & 0 deletions app/src/main/cpp/LockFreeQueue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
//
// Created by djshaji on 3/5/24.
//
/*
* Copyright 2018 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 AMP_RACK_LOCKFREEQUEUE_H
#define AMP_RACK_LOCKFREEQUEUE_H

#include <cstdint>
#include <atomic>

/**
* A lock-free queue for single consumer, single producer. Not thread-safe when using multiple
* consumers or producers.
*
* Example code:
*
* LockFreeQueue<int, 1024> myQueue;
* int value = 123;
* myQueue.push(value);
* myQueue.pop(value);
*
* @tparam T - The item type
* @tparam CAPACITY - Maximum number of items which can be held in the queue. Must be a power of 2.
* Must be less than the maximum value permissible in INDEX_TYPE
* @tparam INDEX_TYPE - The internal index type, defaults to uint32_t. Changing this will affect
* the maximum capacity. Included for ease of unit testing because testing queue lengths of
* UINT32_MAX can be time consuming and is not always possible.
*/

template <typename T, uint32_t CAPACITY, typename INDEX_TYPE = uint32_t>
class LockFreeQueue {
public:

/**
* Implementation details:
*
* We have 2 counters: readCounter and writeCounter. Each will increment until it reaches
* INDEX_TYPE_MAX, then wrap to zero. Unsigned integer overflow is defined behaviour in C++.
*
* Each time we need to access our data array we call mask() which gives us the index into the
* array. This approach avoids having a "dead item" in the buffer to distinguish between full
* and empty states. It also allows us to have a size() method which is easily calculated.
*
* IMPORTANT: This implementation is only thread-safe with a single reader thread and a single
* writer thread. Have more than one of either will result in Bad Things™.
*/

static constexpr bool isPowerOfTwo(uint32_t n) { return (n & (n - 1)) == 0; }
static_assert(isPowerOfTwo(CAPACITY), "Capacity must be a power of 2");
static_assert(std::is_unsigned<INDEX_TYPE>::value, "Index type must be unsigned");

/**
* Pop a value off the head of the queue
*
* @param val - element will be stored in this variable
* @return true if value was popped successfully, false if the queue is empty
*/
bool pop(T &val) {
if (isEmpty()){
return false;
} else {
val = buffer[mask(readCounter)];
++readCounter;
return true;
}
}

/**
* Add an item to the back of the queue
*
* @param item - The item to add
* @return true if item was added, false if the queue was full
*/
bool push(const T& item) {
if (isFull()){
return false;
} else {
buffer[mask(writeCounter)] = item;
++writeCounter;
return true;
}
}

/**
* Get the item at the front of the queue but do not remove it
*
* @param item - item will be stored in this variable
* @return true if item was stored, false if the queue was empty
*/
bool peek(T &item) const {
if (isEmpty()){
return false;
} else {
item = buffer[mask(readCounter)];
return true;
}
}

/**
* Get the number of items in the queue
*
* @return number of items in the queue
*/
INDEX_TYPE size() const {

/**
* This is worth some explanation:
*
* Whilst writeCounter is greater than readCounter the result of (write - read) will always
* be positive. Simple.
*
* But when writeCounter is equal to INDEX_TYPE_MAX (e.g. UINT32_MAX) the next push will
* wrap it around to zero, the start of the buffer, making writeCounter less than
* readCounter so the result of (write - read) will be negative.
*
* But because we're returning an unsigned type return value will be as follows:
*
* returnValue = INDEX_TYPE_MAX - (write - read)
*
* e.g. if write is 0, read is 150 and the INDEX_TYPE is uint8_t where the max value is
* 255 the return value will be (255 - (0 - 150)) = 105.
*
*/
return writeCounter - readCounter;
};

private:

bool isEmpty() const { return readCounter == writeCounter; }

bool isFull() const { return size() == CAPACITY; }

INDEX_TYPE mask(INDEX_TYPE n) const { return static_cast<INDEX_TYPE>(n & (CAPACITY - 1)); }

T buffer[CAPACITY];
std::atomic<INDEX_TYPE> writeCounter { 0 };
std::atomic<INDEX_TYPE> readCounter { 0 };

};

#endif //AMP_RACK_LOCKFREEQUEUE_H
8 changes: 5 additions & 3 deletions app/src/main/cpp/native-lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,11 +649,13 @@ Java_com_shajikhan_ladspa_amprack_AudioEngine_testLV2(JNIEnv *env, jclass clazz)
// engine ->addPluginToRack(0,0);

// engine->addPluginToRackLazy("rkrlv2.so", 0, SharedLibrary::LV2);
engine ->meter->env->CallStaticVoidMethod(
engine->meter->mainActivity,
engine->meter->setMixerMeter, 1.0f, true);
// engine ->meter->env->CallStaticVoidMethod(
// engine->meter->mainActivity,
// engine->meter->setMixerMeter, 1.0f, true);

engine->test () ;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_shajikhan_ladspa_amprack_AudioEngine_setLibraryPath(JNIEnv *env, jclass clazz,
Expand Down

0 comments on commit 27c64f9

Please sign in to comment.