From ed1d7eeab617fc8effa04215d26b65ee5d815d8f Mon Sep 17 00:00:00 2001 From: MaKi983 Date: Fri, 10 May 2024 12:14:46 +0200 Subject: [PATCH 1/4] Try to fix video performance --- .../cpp/libomxvideocodec-jni/OMXSource.cpp | 61 +------------------ 1 file changed, 3 insertions(+), 58 deletions(-) diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp index 04655ac3..4831977b 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp @@ -7,9 +7,7 @@ #include #include -#define DEFAULT_WIDTH "480" -#define DEFAULT_HEIGHT "800" -#define DEFAULT_FRAMERATE "30" +#define BUFFERS_SIZE 10 using namespace android; @@ -21,7 +19,7 @@ OMXSource::OMXSource(int width, int height, int fps, std::mutex& mutex): bufferSize_ = (width * height * 3) / 2; - format_ = new MetaData; + format_ = new MetaData(); format_->setInt32(kKeyWidth, width); format_->setInt32(kKeyHeight, height); format_->setInt32(kKeyStride, width); @@ -34,7 +32,7 @@ OMXSource::OMXSource(int width, int height, int fps, std::mutex& mutex): format_->setInt32(kKeyMaxInputSize, bufferSize_); format_->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); - for (int i = 0; i <= 4; i++) { + for (int i = 0; i < BUFFERS_SIZE; i++) { group_.add_buffer(new MediaBuffer(bufferSize_)); writeBuffers_.push(new Packet(bufferSize_)); } @@ -58,14 +56,6 @@ OMXSource::~OMXSource() { } } -//void OMXSource::waitForMediaBuffer() { -// std::unique_lock codeclock(mutex_); -// while (mediaBuffers_.empty() && !quitFlag_) { -// auto t1 = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); -// cond_.wait_until(codeclock, t1); -// } -//} - void OMXSource::waitForReadBuffer(){ std::unique_lock codeclock(mutex_); while (readBuffers_.empty() && !quitFlag_) { @@ -87,10 +77,6 @@ Packet::Pointer OMXSource::getWriteBuffer(){ return nextWriteBuffer(); } -//status_t OMXSource::getMediaBuffer(MediaBuffer** buffer){ -// return group_.acquire_buffer(buffer); -//} - int OMXSource::queueReadBuffer(Packet* buffer){ std::unique_lock codeclock(mutex_); if (!quitFlag_) { @@ -103,37 +89,6 @@ int OMXSource::queueReadBuffer(Packet* buffer){ return OK; } -//status_t OMXSource::queueMediaBuffer(MediaBuffer* buffer){ -// std::unique_lock codeclock(mutex_); -// if (!quitFlag_) { -// mediaBuffers_.push(buffer); -// Log_v("mediabuffers size: %d", mediaBuffers_.size()); -// codeclock.unlock(); -// cond_.notify_one(); -// } -// return OK; -//} - -//int OMXSource::queueBuffer(unsigned char* buffer, size_t len, uint64_t timestamp){ -// std::unique_lock codeclock(mMutex); -// -// if (!mQuitFlag) { -// int64_t t = timestamp; -// if (t < 0){ -// t = 0; -// } -// Packet *p = new Packet(); -// p->buf = buffer; -// p->len = len; -// p->timestamp = t; -// mBuffers.push(p); -// -// codeclock.unlock(); -// mCond.notify_one(); -// } -// return OK; -//} - sp OMXSource::getFormat(){ return format_; } @@ -158,16 +113,6 @@ Packet::Pointer OMXSource::nextWriteBuffer(){ return buffer; } -//MediaBuffer* OMXSource::nextMediaBuffer(){ -// std::unique_lock codeclock(mutex_); -// -// MediaBuffer* buffer; -// buffer = mediaBuffers_.front(); -// writeBuffers_.pop(); -// -// return buffer; -//} - status_t OMXSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) { if (Log::isVerbose()) Log_v("read"); waitForReadBuffer(); From 37715e16634d6515bb1396ec283f6709063ddc3b Mon Sep 17 00:00:00 2001 From: MaKi983 Date: Fri, 12 Jul 2024 11:48:52 +0200 Subject: [PATCH 2/4] OMX video codec refactor and performance improvement --- .../it/smg/hu/projection/OMXVideoOutput.java | 4 +- .../it/smg/hu/projection/VideoOutput.java | 3 +- .../main/cpp/libomxvideocodec-jni/Android.mk | 5 +- .../cpp/libomxvideocodec-jni/OMXDecoder.cpp | 1 - .../cpp/libomxvideocodec-jni/OMXSource.cpp | 93 +++------- .../main/cpp/libomxvideocodec-jni/OMXSource.h | 39 +--- .../libomxvideocodec-jni/OMXVideoCodec.cpp | 171 ++++++++++-------- .../cpp/libomxvideocodec-jni/OMXVideoCodec.h | 23 ++- .../main/cpp/libomxvideocodec-jni/Packet.h | 56 ++++++ .../it_smg_libs_videocodec_OMXVideoCodec.cpp | 111 ++++++++++++ .../it_smg_libs_videocodec_OMXVideoCodec.h | 30 +++ .../smg/libs/omxvideocodec/OMXVideoCodec.java | 30 +-- 12 files changed, 366 insertions(+), 200 deletions(-) create mode 100644 omxvideocodec/src/main/cpp/libomxvideocodec-jni/Packet.h create mode 100644 omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.cpp create mode 100644 omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.h diff --git a/app/src/main/java/it/smg/hu/projection/OMXVideoOutput.java b/app/src/main/java/it/smg/hu/projection/OMXVideoOutput.java index df64f120..6319aa1c 100644 --- a/app/src/main/java/it/smg/hu/projection/OMXVideoOutput.java +++ b/app/src/main/java/it/smg/hu/projection/OMXVideoOutput.java @@ -9,7 +9,7 @@ public class OMXVideoOutput extends VideoOutput /*implements Runnable*/ { - private static final String TAG = "OMXVideoOutputLegacy"; + private static final String TAG = "OMXVideoOutput"; private OMXVideoCodec videoCodec_; private int frameSize_; @@ -54,6 +54,7 @@ public boolean init() { @Override public void write(long timestamp, ByteBuffer data) { if (configured_ && running_) { + if (Log.isVerbose()) Log.v(TAG, "video message size: " + data.limit()); videoCodec_.mediaDecode(timestamp, data, data.limit()); } } @@ -65,6 +66,7 @@ public void stop() { running_ = false; configured_ = false; videoCodec_.shutdown(); + if(Log.isInfo()) Log.i(TAG, "deleted"); videoCodec_ = null; } } diff --git a/app/src/main/java/it/smg/hu/projection/VideoOutput.java b/app/src/main/java/it/smg/hu/projection/VideoOutput.java index cd743522..d9b0658e 100644 --- a/app/src/main/java/it/smg/hu/projection/VideoOutput.java +++ b/app/src/main/java/it/smg/hu/projection/VideoOutput.java @@ -36,10 +36,9 @@ public VideoOutput(SurfaceView surfaceView){ protected int fpsFromSettings(int fps){ switch (fps){ - case 1: - return 30; case 2: return 60; + case 1: default: return 30; } diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Android.mk b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Android.mk index d4fb3fab..96c6168f 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Android.mk +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Android.mk @@ -8,7 +8,8 @@ ANDROID_LIB := $(EXT_LIB)/$(TARGET_ARCH_ABI)/system/hrv LOCAL_MODULE := libomxvideocodec-jni LOCAL_SRC_FILES := OMXVideoCodec.cpp \ OMXDecoder.cpp \ - OMXSource.cpp + OMXSource.cpp \ + it_smg_libs_videocodec_OMXVideoCodec.cpp LOCAL_LDLIBS += -llog -landroid -l$(ANDROID_LIB)/libstagefright.so -l$(ANDROID_LIB)/libutils.so -l$(ANDROID_LIB)/libcutils.so @@ -22,7 +23,7 @@ LOCAL_SHARED_LIBRARIES := common LOCAL_CFLAGS += -DHAVE_PTHREADS -g -funwind-tables -Wl,--no-merge-exidx-entries -fno-omit-frame-pointer LOCAL_LDFLAGS := -Wl,--allow-multiple-definition -LOCAL_CPPFLAGS += -fno-rtti +LOCAL_CPPFLAGS += -fno-rtti -fexceptions LOCAL_ARM_NEON := true include $(BUILD_SHARED_LIBRARY) diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXDecoder.cpp b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXDecoder.cpp index 97958bc4..f8db09ea 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXDecoder.cpp +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXDecoder.cpp @@ -68,7 +68,6 @@ status_t OMXDecoder::read(){ MediaSource::ReadOptions options; options.setLateBy(0); status_t ret = decoder_->read(&videoBuffer, &options); - if (Log::isVerbose()) Log_v("videoBuffer: %p", videoBuffer); if (ret == OK) { if (videoBuffer->range_length() > 0) { // If video frame availabe, render it to mNativeWindow diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp index 4831977b..7b867687 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.cpp @@ -7,7 +7,7 @@ #include #include -#define BUFFERS_SIZE 10 +#define BUFFERS_SIZE 5 using namespace android; @@ -15,9 +15,11 @@ using namespace android; // https://vec.io/posts/use-android-hardware-decoder-with-omxcodec-in-ndk // https://stackoverflow.com/questions/9832503/android-include-native-stagefright-features-in-my-own-project OMXSource::OMXSource(int width, int height, int fps, std::mutex& mutex): - format_(NULL), mutex_(mutex), quitFlag_(false){ + format_(NULL), mutex_(mutex), quitFlag_(false) /*, bufferPool_(50, cChunkSize)*/ +{ - bufferSize_ = (width * height * 3) / 2; + size_t bufferSize = (width * height * 3) / 2; + if (Log::isVerbose()) Log_v("BufferSize: %d", bufferSize); format_ = new MetaData(); format_->setInt32(kKeyWidth, width); @@ -29,114 +31,70 @@ OMXSource::OMXSource(int width, int height, int fps, std::mutex& mutex): format_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); format_->setInt32(kKeyVideoLevel, OMX_VIDEO_AVCLevel31); format_->setInt32(kKeyVideoProfile, OMX_VIDEO_AVCProfileBaseline); - format_->setInt32(kKeyMaxInputSize, bufferSize_); + format_->setInt32(kKeyMaxInputSize, bufferSize); format_->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); for (int i = 0; i < BUFFERS_SIZE; i++) { - group_.add_buffer(new MediaBuffer(bufferSize_)); - writeBuffers_.push(new Packet(bufferSize_)); + group_.add_buffer(new MediaBuffer(cChunkSize)); } } OMXSource::~OMXSource() { if (Log::isDebug()) Log_d("destructor"); - - while (!writeBuffers_.empty()){ - if (Log::isDebug()) Log_d("delete write buffers"); - Packet::Pointer p = writeBuffers_.front(); - writeBuffers_.pop(); - delete p; - } - - while (!readBuffers_.empty()){ - if (Log::isDebug()) Log_d("delete read buffers"); - Packet* p = readBuffers_.front(); - readBuffers_.pop(); - delete p; - } -} - -void OMXSource::waitForReadBuffer(){ - std::unique_lock codeclock(mutex_); - while (readBuffers_.empty() && !quitFlag_) { - auto t1 = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); - cond_.wait_until(codeclock, t1); - } } -void OMXSource::waitForWriteBuffer(){ +void OMXSource::waitForBuffer(){ std::unique_lock codeclock(mutex_); - while (writeBuffers_.empty() && !quitFlag_) { + while (pbuffers_.empty() && !quitFlag_) { + if (Log::isVerbose()) Log_v("buffers empty"); auto t1 = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); cond_.wait_until(codeclock, t1); } } -Packet::Pointer OMXSource::getWriteBuffer(){ - waitForWriteBuffer(); - return nextWriteBuffer(); -} - -int OMXSource::queueReadBuffer(Packet* buffer){ +void OMXSource::queueBuffer(Packet::Pointer packet){ std::unique_lock codeclock(mutex_); if (!quitFlag_) { - readBuffers_.push(buffer); - if (Log::isVerbose()) Log_v("readbuffers size: %d", readBuffers_.size()); - if (Log::isVerbose()) Log_v("writebuffer size: %d", writeBuffers_.size()); + pbuffers_.push(packet); codeclock.unlock(); cond_.notify_one(); } - return OK; } sp OMXSource::getFormat(){ return format_; } -Packet::Pointer OMXSource::nextReadBuffer(){ +Packet::Pointer OMXSource::nextBuffer(){ std::unique_lock codeclock(mutex_); - - Packet::Pointer buffer; - buffer = readBuffers_.front(); - readBuffers_.pop(); - - return buffer; -} - -Packet::Pointer OMXSource::nextWriteBuffer(){ - std::unique_lock codeclock(mutex_); - - Packet::Pointer buffer; - buffer = writeBuffers_.front(); - writeBuffers_.pop(); - + Packet::Pointer buffer = pbuffers_.front(); + pbuffers_.pop(); return buffer; } status_t OMXSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) { if (Log::isVerbose()) Log_v("read"); - waitForReadBuffer(); + waitForBuffer(); if (Log::isVerbose()) Log_v("found buffer"); if (!quitFlag_) { - Packet* p = nextReadBuffer(); + Packet::Pointer p = nextBuffer(); + common::DataConstBuffer b(p->buffer); status_t ret = group_.acquire_buffer(buffer); - if (Log::isVerbose()) Log_v("buffer_ %p", p); if (ret == OK) { + memcpy((*buffer)->data(), b.cdata, b.size); - memcpy((*buffer)->data(), p->buf, p->len); - - (*buffer)->set_range(0, (size_t) p->len); + (*buffer)->set_range(0, (size_t) b.size); (*buffer)->meta_data()->clear(); (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, 1); (*buffer)->meta_data()->setInt64(kKeyTime, p->timestamp); +// (*buffer)->meta_data()->setInt64(kKeyTime, 0); } - p->clear(); - writeBuffers_.push(p); + delete p; return ret; } @@ -154,10 +112,13 @@ status_t OMXSource::start(MetaData *params){ status_t OMXSource::stop() { if (!quitFlag_) { if (Log::isInfo()) Log_i("stop"); - std::unique_lock codeclock(mutex_); - quitFlag_ = true; + { + std::unique_lock codeclock(mutex_); + quitFlag_ = true; + } if (Log::isVerbose()) Log_v("quit flag to true"); } return OK; } + diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.h b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.h index 5e9b6efe..3871c053 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.h +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXSource.h @@ -6,31 +6,14 @@ #include #include #include +#include "Packet.h" using namespace android; -struct Packet { - typedef Packet* Pointer; - - Packet(int bufferSize){ - buf = new unsigned char[bufferSize]; - } - unsigned char* buf; - size_t len; - uint64_t timestamp; - - void clear(){ - len = 0; - timestamp = 0; - } - -// ~Packet(){ delete[] buf; } - ~Packet(){ free(buf); } -}; - class OMXSource : public MediaSource { public: typedef OMXSource* Pointer; + static constexpr common::Data::size_type cChunkSize = 38406 * 2; OMXSource(int width, int height, int fps, std::mutex& mutex); @@ -38,13 +21,8 @@ class OMXSource : public MediaSource { virtual status_t start(MetaData *params = NULL); virtual status_t stop(); virtual sp getFormat(); - int queueReadBuffer(Packet::Pointer buffer); -// status_t queueMediaBuffer(MediaBuffer* buffer); - Packet::Pointer getWriteBuffer(); -// status_t getMediaBuffer(MediaBuffer** buffer); - void waitForReadBuffer(); - void waitForWriteBuffer(); -// void waitForMediaBuffer(); + void queueBuffer(Packet::Pointer packet); + void waitForBuffer(); virtual status_t pause() { return ERROR_UNSUPPORTED; @@ -61,16 +39,11 @@ class OMXSource : public MediaSource { private: sp format_; MediaBufferGroup group_; - std::queue readBuffers_; - std::queue writeBuffers_; - std::queue mediaBuffers_; + std::queue pbuffers_; std::mutex& mutex_; std::condition_variable cond_; - size_t bufferSize_; bool quitFlag_; -// MediaBuffer* nextMediaBuffer(); - Packet::Pointer nextReadBuffer(); - Packet::Pointer nextWriteBuffer(); + Packet::Pointer nextBuffer(); }; diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.cpp b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.cpp index a4a8f233..4efd6d82 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.cpp +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.cpp @@ -9,14 +9,13 @@ #include #include -OMXVideoCodec::OMXVideoCodec(JNIEnv* env, jobject androidApp) : JNIBase(env, androidApp, "OMXVideoCodec") - , fps_(0), omxDecoderThreadRunning_(false), decoderThreadInitialized_(false), decoderThreadQuitFlag_(false) -{ +OMXVideoCodec::OMXVideoCodec() + : fps_(0), omxDecoderThreadRunning_(false), decoderThreadInitialized_(false), decoderThreadQuitFlag_(false), tmpPacket_(nullptr){ } -OMXVideoCodec::~OMXVideoCodec() { - Log_i("destructor"); -} +//OMXVideoCodec::~OMXVideoCodec() { +// Log_i("destructor"); +//} status_t OMXVideoCodec::init(int fps){ fps_ = fps; @@ -24,13 +23,15 @@ status_t OMXVideoCodec::init(int fps){ // Create decoder thread and wait until ready if (Log::isInfo()) Log_i("start omxDecoderThread"); - std::unique_lock codeclock(codecMutex_); + feedBufferThread_ = std::thread(&OMXVideoCodec::init_feedBufferThread, this); omxDecoderThread_ = std::thread(&OMXVideoCodec::init_omxDecoderThread, this); + + std::unique_lock codeclock(codecMutex_); while (!decoderThreadInitialized_){ omxDecoderCond_.wait(codeclock); } codeclock.unlock(); - Log_i("omxDecoderThread ready"); + if (Log::isInfo()) Log_i("omxDecoderThread ready"); return omxDecoder_->getStatus(); } @@ -44,6 +45,17 @@ void OMXVideoCodec::shutdown(){ if (Log::isDebug()) Log_d("Stop omxSource"); omxSource_->stop(); + ALooper_removeFd(bufferThreadLooper_, messagePipe_[0]); + close(messagePipe_[0]); + close(messagePipe_[1]); + ALooper_release(bufferThreadLooper_); + if (Log::isDebug()) Log_d("Stopping feedBufferThread"); + + if (feedBufferThread_.joinable()){ + if (Log::isDebug()) Log_d("joining feedBuffer thread"); + feedBufferThread_.join(); + } + if (omxDecoderThreadRunning_) { if (Log::isDebug()) Log_d("Stopping omxDecoderThread"); @@ -66,8 +78,8 @@ void OMXVideoCodec::shutdown(){ void OMXVideoCodec::init_omxDecoderThread() { if (Log::isInfo()) Log_i("omxDecoderThread begins"); - JNIEnv* env; - JNIBase::javaAttachThread("OMXCodec thread", &env); +// JNIEnv* env; +// JNIBase::javaAttachThread("OMXCodec thread", &env); omxSource_ = new OMXSource(screenSize_.width, screenSize_.height, fps_, codecMutex_); @@ -94,7 +106,7 @@ void OMXVideoCodec::init_omxDecoderThread() { if (Log::isInfo()) Log_i("omxDecoderThread ends"); omxDecoderThreadRunning_ = false; - JNIBase::javaDetachThread(); +// JNIBase::javaDetachThread(); } void OMXVideoCodec::setNativeWindow(ANativeWindow* nativeWindow, int height, int width){ @@ -104,9 +116,9 @@ void OMXVideoCodec::setNativeWindow(ANativeWindow* nativeWindow, int height, int screenSize_.height = height; } -void OMXVideoCodec::setSps(unsigned char* buf, int len){ - if (Log::isDebug()) Log_d("sps packet len %d", len); - omxSource_->getFormat()->setData(kKeyAVCC, kTypeAVCC, buf, len); +void OMXVideoCodec::setSps(common::DataConstBuffer &b){ + if (Log::isDebug()) Log_d("sps packet len %d", b.size); + omxSource_->getFormat()->setData(kKeyAVCC, kTypeAVCC, b.cdata, b.size); } OMXSource::Pointer OMXVideoCodec::source() { @@ -117,76 +129,91 @@ OMXDecoder::Pointer OMXVideoCodec::decoder() { return omxDecoder_; } -//////////////////////////////////////////////////////////////////////////////////////////////////// - -extern "C" -JNIEXPORT jlong JNICALL -Java_it_smg_libs_omxvideocodec_OMXVideoCodec_createNativeApp(JNIEnv* env, jobject application) { - OMXVideoCodec::Pointer codec = new OMXVideoCodec(env, application); - return (jlong)((size_t)codec); -} +int OMXVideoCodec::looperCallback(int fd, int events, void *data) { + OMXVideoCodec::Pointer self = (OMXVideoCodec::Pointer)data; -extern "C" -JNIEXPORT void JNICALL -Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeSurfaceInit(JNIEnv *env, jobject thiz, jlong handle, jobject surface, - jint width, jint height) { - auto omxCodec = (OMXVideoCodec::Pointer) handle; - ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface); - omxCodec->setNativeWindow(nativeWindow, height, width); -} + if (self->decoderThreadQuitFlag_){ + if(Log::isVerbose()) Log_v("looperCB: decoder is stopping, return"); + return 0; + } -extern "C" -JNIEXPORT void JNICALL -Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeFinalize(JNIEnv *env, jobject thiz, jlong handle) { - auto omxCodec = (OMXVideoCodec::Pointer) handle; - omxCodec->shutdown(); - delete omxCodec; -} + common::Data bufferData(OMXSource::cChunkSize); + int size = read(fd, &bufferData[0], OMXSource::cChunkSize); + if (Log::isVerbose()) Log_v("looperCB: readed= %d", size); + + int idx = 0; + while (size > 0){ + Packet::Pointer packet; + if (self->tmpPacket_ != nullptr){ + if (Log::isVerbose()) Log_v("looperCB: found prev packet, complete it"); + packet = self->tmpPacket_; + self->tmpPacket_ = nullptr; + size_t remainingSize = packet->size - packet->buffer.size(); + if (Log::isVerbose()) Log_v("looperCB: prev packet remaining size %d", remainingSize); + size_t currentSize = remainingSize; + if (size < remainingSize){ + currentSize = size; + } + common::DataConstBuffer b(&bufferData[0], currentSize); + common::copy(packet->buffer, b); + size -= remainingSize; + if (Log::isVerbose()) Log_v("looperCB: remaining size= %d", size); + idx += remainingSize; + } else { + packet = Packet::fromData(bufferData, idx); + size_t packetSize = packet->packetSize(); + if (Log::isVerbose()) Log_v("looperCB: packetSize= %d", packetSize); + size -= packetSize; + if (Log::isVerbose()) Log_v("looperCB: remaining size= %d", size); + idx += packetSize; + } -extern "C" -JNIEXPORT jboolean JNICALL -Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeInit(JNIEnv *env, jobject thiz, jlong handle, jint fps) { - status_t ret = 1; + if (size < 0){ + if (Log::isVerbose()) Log_v("looperCB: packet not complete, keep it"); + self->tmpPacket_ = packet; + } else { + if (self->decoderThreadQuitFlag_){ + if(Log::isVerbose()) Log_v("looperCB: decoder is stopping, do not send buffer to queue"); + return 0; + } - auto omxCodec = (OMXVideoCodec::Pointer) handle; - ret = omxCodec->init(fps); + if (Log::isVerbose()) Log_v("looperCB: send buffer to queue"); + self->source()->queueBuffer(packet); + } + } - return ret == 0 ? JNI_TRUE : JNI_FALSE; + return 1; // continue listening for events } -extern "C" -JNIEXPORT void JNICALL -Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeConsume(JNIEnv *env, jobject thiz, jlong handle, - jobject buf, int len, jlong t) { - auto omxCodec = (OMXVideoCodec::Pointer) handle; - jbyte *bufferData = (jbyte *) env->GetDirectBufferAddress(buf); - - Packet* buffer = omxCodec->source()->getWriteBuffer(); - - if (Log::isVerbose()) Log_v("mediabuffer: %p", buffer); - - memcpy(buffer->buf, bufferData, len); +void OMXVideoCodec::queueBuffer(common::DataConstBuffer& buffer, int64_t timestamp) { + if (decoderThreadQuitFlag_){ + if(Log::isVerbose()) Log_v("decoder is stopping, return"); + return; + } - buffer->timestamp = t; - if (t <= 0){ - buffer->timestamp = 0; + const auto p1 = std::chrono::system_clock::now(); + int64_t ts = std::chrono::duration_cast(p1.time_since_epoch()).count(); + if (timestamp == 0){ + ts = 0; } - buffer->len = len; - omxCodec->source()->queueReadBuffer(buffer); -} + common::Data data = Packet::toData(buffer, ts); + common::DataConstBuffer b(data); -extern "C" -JNIEXPORT void JNICALL -Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeSetSps(JNIEnv *env, jobject thiz, - jlong handle, jobject buf, - jint len) { - auto omxCodec = (OMXVideoCodec::Pointer) handle; + write(messagePipe_[1], &b.cdata[0], b.size); +} - unsigned char* tmp = new unsigned char[len]; +void OMXVideoCodec::init_feedBufferThread() { + Log_v("init_feedBufferThread"); + bufferThreadLooper_ = ALooper_prepare(0); + ALooper_acquire(bufferThreadLooper_); + pipe(messagePipe_); + ALooper_addFd(bufferThreadLooper_, messagePipe_[0], ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT, &OMXVideoCodec::looperCallback, this); - jbyte *bufferData = (jbyte *) env->GetDirectBufferAddress(buf); - memcpy(tmp, bufferData, len); + Log_v("start alooper polling"); + while (ALooper_pollOnce(0,nullptr, nullptr, nullptr) && !decoderThreadQuitFlag_) { +// Log_v("pollOnce"); + } - omxCodec->setSps(tmp, len); + Log_v("init_feedBufferThread finished"); } diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.h b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.h index 9ef41a87..32a93a17 100644 --- a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.h +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/OMXVideoCodec.h @@ -1,10 +1,8 @@ #pragma once -#include #include #include "OMXSource.h" #include "OMXDecoder.h" -#include #include #include @@ -13,11 +11,11 @@ struct ScreenSize { int width = 0; }; -class OMXVideoCodec : JNIBase { +class OMXVideoCodec { public: typedef OMXVideoCodec* Pointer; - OMXVideoCodec(JNIEnv *env, jobject androidApp); + OMXVideoCodec(); status_t init(int fps); void shutdown(); @@ -25,20 +23,23 @@ class OMXVideoCodec : JNIBase { OMXSource::Pointer source(); OMXDecoder::Pointer decoder(); + void queueBuffer(common::DataConstBuffer& b, int64_t timestamp); - void setSps(unsigned char* buf, int len); - - ~OMXVideoCodec(); - -protected: - void initJavaMethods() { }; + void setSps(common::DataConstBuffer &b); +// ~OMXVideoCodec(); private: void init_omxDecoderThread(); + void init_feedBufferThread(); + static int looperCallback(int fd, int events, void* data); + + ALooper* bufferThreadLooper_; + int messagePipe_[2]; OMXSource::Pointer omxSource_; OMXDecoder::Pointer omxDecoder_; + std::thread feedBufferThread_; std::thread omxDecoderThread_; std::mutex codecMutex_; std::condition_variable omxDecoderCond_; @@ -49,4 +50,6 @@ class OMXVideoCodec : JNIBase { sp nativeWindow_; ScreenSize screenSize_; int fps_; + + Packet::Pointer tmpPacket_; }; diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Packet.h b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Packet.h new file mode 100644 index 00000000..2ea28902 --- /dev/null +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/Packet.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +class Packet { +public: + typedef Packet* Pointer; + + Packet(common::Data buf, int64_t ts, size_t size) : buffer(std::move(buf)), timestamp(ts), size(size) { + } + + static common::Data toData(common::DataConstBuffer& buffer, int64_t timestamp){ + common::Data data; + + const common::DataConstBuffer ts(×tamp, sizeof(timestamp)); + common::copy(data, ts); + + const common::DataConstBuffer s(&buffer.size, sizeof(size)); + common::copy(data, s); + + common::copy(data, buffer); + + return data; + } + + static Packet::Pointer fromData(common::Data data, int offset){ + int64_t timestamp = reinterpret_cast(data[offset]); + size_t size = reinterpret_cast(data[offset + 8]); + if (Log::isVerbose()) Log_v("readed buffer size %d", size); + size_t currentSize = size; + if (size > (data.size()-offset-12) ){ + Log_w("Not full data available"); + currentSize = data.size()-offset-12; + } + common::DataConstBuffer b(&data[offset], currentSize + 12, 12); + common::Data d; + common::copy(d, b); + + return new Packet(d, timestamp, size); + } + + size_t packetSize(){ + return sizeof(int64_t) + sizeof(size_t) + size; + } + + common::Data buffer; + const size_t size; + const int64_t timestamp; + + + + + + +}; \ No newline at end of file diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.cpp b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.cpp new file mode 100644 index 00000000..1089aaf5 --- /dev/null +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.cpp @@ -0,0 +1,111 @@ +#include "it_smg_libs_videocodec_OMXVideoCodec.h" + +jfieldID JOMXVideoCodec::handleId = nullptr; + +JOMXVideoCodec::JOMXVideoCodec(JNIEnv *env, jobject jvideocodec) : + JNIBase(env, jvideocodec, "JOMXVideoCodec"), omxVideoCodec_(new OMXVideoCodec()){ + + initJavaMethods(); +} + +void JOMXVideoCodec::initJavaMethods() { +} + +JOMXVideoCodec::Pointer JOMXVideoCodec::getJOMXVideoCodec(JNIEnv *env, jobject jvideocodec) { + return (JOMXVideoCodec::Pointer)env->GetLongField(jvideocodec, JOMXVideoCodec::handleId); +} + +void JOMXVideoCodec::setNativeWindow(ANativeWindow* nativeWindow, int height, int width){ + omxVideoCodec_->setNativeWindow(nativeWindow, height, width); +} + +status_t JOMXVideoCodec::init(int fps){ + return omxVideoCodec_->init(fps); +} + +void JOMXVideoCodec::shutdown(){ + omxVideoCodec_->shutdown(); +} + +void JOMXVideoCodec::queueBuffer(common::DataConstBuffer &b, int64_t timestamp) { + omxVideoCodec_->queueBuffer(b, timestamp); +} + +void JOMXVideoCodec::setSps(common::DataConstBuffer &b){ + omxVideoCodec_->setSps(b); +} + +JOMXVideoCodec::~JOMXVideoCodec() { + delete omxVideoCodec_; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +extern "C" +JNIEXPORT void JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeInit(JNIEnv *env, jclass clazz) { + jclass _class = env->FindClass("it/smg/libs/omxvideocodec/OMXVideoCodec"); + JOMXVideoCodec::handleId = env->GetFieldID(_class, "handle_", "J"); + + env->DeleteLocalRef(_class); + _class = nullptr; +} + +extern "C" +JNIEXPORT jlong JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeSetup(JNIEnv* env, jobject thiz) { + JOMXVideoCodec::Pointer jOMXVideoCodec = new JOMXVideoCodec(env, thiz); + return (jlong)((size_t)jOMXVideoCodec); +} + +extern "C" +JNIEXPORT void JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeSurfaceInit(JNIEnv *env, jobject thiz, jobject surface, jint width, jint height) { + JOMXVideoCodec::Pointer jOMXVideoCodec = JOMXVideoCodec::getJOMXVideoCodec(env, thiz); + + ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface); + jOMXVideoCodec->setNativeWindow(nativeWindow, height, width); +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeDecoderInit(JNIEnv *env, jobject thiz, jint fps) { + status_t ret = 1; + + JOMXVideoCodec::Pointer jOMXVideoCodec = JOMXVideoCodec::getJOMXVideoCodec(env, thiz); + ret = jOMXVideoCodec->init(fps); + + return ret == 0 ? JNI_TRUE : JNI_FALSE; +} + +extern "C" +JNIEXPORT void JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeDelete(JNIEnv *env, jobject thiz) { + JOMXVideoCodec::Pointer jOMXVideoCodec = JOMXVideoCodec::getJOMXVideoCodec(env, thiz); + jOMXVideoCodec->shutdown(); + delete jOMXVideoCodec; +} + + +extern "C" +JNIEXPORT void JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeConsume(JNIEnv *env, jobject thiz, jobject buf, int len, jlong t) { + JOMXVideoCodec::Pointer jOMXVideoCodec = JOMXVideoCodec::getJOMXVideoCodec(env, thiz); + + jbyte *bufferData = (jbyte *) env->GetDirectBufferAddress(buf); + common::DataConstBuffer buffer(bufferData, len); + int64_t timestamp = static_cast(t); + + jOMXVideoCodec->queueBuffer(buffer, timestamp); +} + +extern "C" +JNIEXPORT void JNICALL +Java_it_smg_libs_omxvideocodec_OMXVideoCodec_nativeSetSps(JNIEnv *env, jobject thiz, jobject buf, jint len) { + JOMXVideoCodec::Pointer jOMXVideoCodec = JOMXVideoCodec::getJOMXVideoCodec(env, thiz); + + jbyte *bufferData = (jbyte *) env->GetDirectBufferAddress(buf); + common::DataConstBuffer buffer(bufferData, len); + + jOMXVideoCodec->setSps(buffer); +} diff --git a/omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.h b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.h new file mode 100644 index 00000000..ceebc0cf --- /dev/null +++ b/omxvideocodec/src/main/cpp/libomxvideocodec-jni/it_smg_libs_videocodec_OMXVideoCodec.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include "OMXVideoCodec.h" + +class JOMXVideoCodec : JNIBase { +public: + typedef JOMXVideoCodec* Pointer; + + JOMXVideoCodec(JNIEnv *env, jobject jvideocodec); + + static jfieldID handleId; + static JOMXVideoCodec::Pointer getJOMXVideoCodec(JNIEnv* env, jobject jvideocodec); + + void setNativeWindow(ANativeWindow* nativeWindow, int height, int width); + status_t init(int fps); + void shutdown(); + void queueBuffer(common::DataConstBuffer &b, int64_t timestamp); + void setSps(common::DataConstBuffer &b); + + ~JOMXVideoCodec(); +protected: + void initJavaMethods() override; + +private: + OMXVideoCodec::Pointer omxVideoCodec_; +}; + diff --git a/omxvideocodec/src/main/java/it/smg/libs/omxvideocodec/OMXVideoCodec.java b/omxvideocodec/src/main/java/it/smg/libs/omxvideocodec/OMXVideoCodec.java index 92f090f2..06c62957 100644 --- a/omxvideocodec/src/main/java/it/smg/libs/omxvideocodec/OMXVideoCodec.java +++ b/omxvideocodec/src/main/java/it/smg/libs/omxvideocodec/OMXVideoCodec.java @@ -9,12 +9,14 @@ public class OMXVideoCodec { private static final String TAG = "OMXVideoCodec"; - private native void nativeSurfaceInit(long mNativeHandle, Object surface, int width, int height); - private native long createNativeApp(); - private native boolean nativeInit(long mNativeHandle, int fps); - private native void nativeFinalize(long mNativeHandle); - private native void nativeConsume(long mNativeHandle, ByteBuffer buf, int len, long t); - private native void nativeSetSps(long mNativeHandle, ByteBuffer buf, int len); + + private static native void nativeInit(); + private native long nativeSetup(); + private native void nativeSurfaceInit(Object surface, int width, int height); + private native boolean nativeDecoderInit(int fps); + private native void nativeDelete(); + private native void nativeConsume(ByteBuffer buf, int len, long t); + private native void nativeSetSps(ByteBuffer buf, int len); private long handle_ = 0; @@ -27,11 +29,12 @@ public class OMXVideoCodec { System.loadLibrary("c++_shared"); System.loadLibrary("common"); System.loadLibrary("omxvideocodec-jni"); + + nativeInit(); } public OMXVideoCodec(int fps){ - handle_ = createNativeApp(); - + handle_ = nativeSetup(); fps_ = fps; } @@ -39,23 +42,24 @@ public void setSurface(Surface surface, int width, int height){ surfaceView_ = surface; width_ = width; height_ = height; - nativeSurfaceInit (handle_, surface, height_, width_); + nativeSurfaceInit (surface, height_, width_); } public boolean init() { - return nativeInit(handle_, fps_); + return nativeDecoderInit(fps_); } public void shutdown() { - nativeFinalize(handle_); + nativeDelete(); handle_ = 0; } public void mediaDecode(long timestamp, ByteBuffer buf, int len) { + if (Log.isVerbose()) Log.v(TAG, "mediaDecode"); if (isSps(buf)) { - nativeSetSps(handle_, buf, len); + nativeSetSps(buf, len); } - nativeConsume(handle_, buf, len, timestamp); + nativeConsume(buf, len, timestamp); } private boolean isSps(ByteBuffer buf) { From 52f56d6e08bd0f11ae1598b0e033441f68426dd3 Mon Sep 17 00:00:00 2001 From: MaKi983 Date: Fri, 12 Jul 2024 11:58:49 +0200 Subject: [PATCH 3/4] Experimental opensles audio codec --- app/build.gradle | 1 + .../main/java/it/smg/hu/config/Settings.java | 11 + .../java/it/smg/hu/projection/AudioCodec.java | 133 ++++ .../it/smg/hu/projection/AudioOutput.java | 95 +-- .../it/smg/hu/projection/IAudioCodec.java | 9 + .../it/smg/hu/projection/SLESAudioCodec.java | 55 ++ .../java/it/smg/hu/ui/SettingsActivity.java | 17 +- .../it/smg/hu/ui/settings/AudioFragment.java | 271 ++++---- app/src/main/res/layout/activity_settings.xml | 13 +- app/src/main/res/layout/audio_fragment.xml | 492 +-------------- app/src/main/res/values/array.xml | 10 + app/src/main/res/values/strings.xml | 1 + settings.gradle | 3 +- slesaudiocodec/.gitignore | 1 + slesaudiocodec/build.gradle | 64 ++ slesaudiocodec/consumer-rules.pro | 0 slesaudiocodec/proguard-rules.pro | 21 + slesaudiocodec/src/main/AndroidManifest.xml | 5 + slesaudiocodec/src/main/cpp/Android.mk | 1 + slesaudiocodec/src/main/cpp/Application.mk | 6 + .../main/cpp/libslesaudiocodec-jni/Android.mk | 28 + .../libslesaudiocodec-jni/SLESAudioCodec.cpp | 593 ++++++++++++++++++ .../libslesaudiocodec-jni/SLESAudioCodec.h | 81 +++ .../cpp/libslesaudiocodec-jni/SLESStream.cpp | 2 + .../cpp/libslesaudiocodec-jni/SLESStream.h | 103 +++ .../it_smg_libs_audiocodec_SLESAudioCodec.cpp | 69 ++ .../it_smg_libs_audiocodec_SLESAudioCodec.h | 34 + .../libs/slesaudiocodec/SLESAudioCodec.java | 54 ++ .../libs/omxvideocodec/ExampleUnitTest.java | 17 + 29 files changed, 1481 insertions(+), 709 deletions(-) create mode 100644 app/src/main/java/it/smg/hu/projection/AudioCodec.java create mode 100644 app/src/main/java/it/smg/hu/projection/IAudioCodec.java create mode 100644 app/src/main/java/it/smg/hu/projection/SLESAudioCodec.java create mode 100644 slesaudiocodec/.gitignore create mode 100644 slesaudiocodec/build.gradle create mode 100644 slesaudiocodec/consumer-rules.pro create mode 100644 slesaudiocodec/proguard-rules.pro create mode 100644 slesaudiocodec/src/main/AndroidManifest.xml create mode 100644 slesaudiocodec/src/main/cpp/Android.mk create mode 100644 slesaudiocodec/src/main/cpp/Application.mk create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/Android.mk create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/SLESAudioCodec.cpp create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/SLESAudioCodec.h create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/SLESStream.cpp create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/SLESStream.h create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/it_smg_libs_audiocodec_SLESAudioCodec.cpp create mode 100644 slesaudiocodec/src/main/cpp/libslesaudiocodec-jni/it_smg_libs_audiocodec_SLESAudioCodec.h create mode 100644 slesaudiocodec/src/main/java/it/smg/libs/slesaudiocodec/SLESAudioCodec.java create mode 100644 slesaudiocodec/src/test/java/it/smg/libs/omxvideocodec/ExampleUnitTest.java diff --git a/app/build.gradle b/app/build.gradle index 42901046..73dcf9c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,6 +63,7 @@ dependencies { implementation project(path: ':common') implementation project(path: ':aasdk') implementation project(path: ':omxvideocodec') + implementation project(path: ':slesaudiocodec') implementation 'androidx.multidex:multidex:2.0.1' testImplementation 'junit:junit:4.+' diff --git a/app/src/main/java/it/smg/hu/config/Settings.java b/app/src/main/java/it/smg/hu/config/Settings.java index 0db79fcc..d9d880ab 100644 --- a/app/src/main/java/it/smg/hu/config/Settings.java +++ b/app/src/main/java/it/smg/hu/config/Settings.java @@ -240,6 +240,8 @@ public void showAppBadge(boolean value){ } public class Audio extends Base { + public final static String AUDIO_CODEC = "audio_codec"; + public final static String MEDIA_ENABLE_CHANNEL = "media_enable_channel"; public final static String MEDIA_SAMPLERATE = "media_samplerate"; public final static String MEDIA_SAMPLESIZE = "media_samplesize"; @@ -260,6 +262,8 @@ public class Audio extends Base { public final static String MIC_CHANNELCOUNT = "mic_channelcount"; public final static String MIC_SOURCE = "mic_source"; + public final static int AUDIO_CODEC_DEFAULT_VALUE = 1; //Android AudioTrack + public final static boolean MEDIA_ENABLE_CHANNEL_DEFAULT_VALUE = true; public final static int MEDIA_SAMPLERATE_DEFAULT_VALUE = 48000; public final static int MEDIA_SAMPLESIZE_DEFAULT_VALUE = 16; // 16bit @@ -280,6 +284,13 @@ public class Audio extends Base { public final static int MIC_CHANNELCOUNT_DEFAULT_VALUE = 1; //AudioFormat.CHANNEL_OUT_MONO; public final static int MIC_SOURCE_DEFAULT_VALUE = 1; // 1 = MIC + public int audioCodec(){ + return get(AUDIO_CODEC,AUDIO_CODEC_DEFAULT_VALUE); + } + public void audioCodec(int value){ + set(AUDIO_CODEC, value); + } + public boolean musicChannelEnabled(){ return SP.getBoolean(MEDIA_ENABLE_CHANNEL, MEDIA_ENABLE_CHANNEL_DEFAULT_VALUE); } diff --git a/app/src/main/java/it/smg/hu/projection/AudioCodec.java b/app/src/main/java/it/smg/hu/projection/AudioCodec.java new file mode 100644 index 00000000..c490ecf5 --- /dev/null +++ b/app/src/main/java/it/smg/hu/projection/AudioCodec.java @@ -0,0 +1,133 @@ +package it.smg.hu.projection; + +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.Handler; +import android.os.HandlerThread; + +import java.nio.ByteBuffer; + +import it.smg.hu.config.Settings; +import it.smg.libs.common.Log; + +public class AudioCodec implements IAudioCodec { + private static final String TAG = "AudioCodec"; + + private AudioTrack audioTrack_; + private int sampleRate_; + private int channelConfig_; + private int sampleSize_; + protected boolean running_; + private HandlerThread codecThread_; + private Handler codecHandler_; + + public AudioCodec(int sampleRate, int channelConfig, int sampleSize){ + sampleRate_ = sampleRate; + channelConfig_ = channelConfig; + sampleSize_ = sampleSize; + } + + private static int channels2num(int channels){ + switch (channels){ + case 1: + return AudioFormat.CHANNEL_OUT_MONO; + case 2: + return AudioFormat.CHANNEL_OUT_STEREO; + case 4: + return AudioFormat.CHANNEL_OUT_QUAD; + case 6: + return AudioFormat.CHANNEL_OUT_5POINT1; + case 8: + return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; + default: + return -1; + } + } + + public static int sampleSizeFromInt(int sampleSize){ + switch (sampleSize){ + case 16: + return AudioFormat.ENCODING_PCM_16BIT; + case 8: + return AudioFormat.ENCODING_PCM_8BIT; + default: + return -1; + } + } + + @Override + public void write(ByteBuffer buffer, long timestamp) { + if (running_) { + if (Log.isVerbose()) Log.v(TAG, "buffer size: " + buffer.limit()); +// if (Log.isVerbose()) Log.v(TAG, buffer); + final int size = buffer.limit(); + final byte[] data = new byte[size]; + buffer.get(data); +// if (Log.isVerbose()) Log.v(TAG, data); + + codecHandler_.post(() -> { +// if (Log.isVerbose()) Log.v(TAG, "in thread"); +// if (Log.isVerbose()) Log.v(TAG, data); + audioTrack_.write(data, 0, size); + }); + } + } + + @Override + public void start() { + if (Log.isInfo()) Log.i(TAG, "Start"); + + codecThread_ = new HandlerThread("AudioCodec-thread"); + codecThread_.start(); + codecHandler_ = new Handler(codecThread_.getLooper()); + + if (audioTrack_ == null) { + try { + int bufferSize_ = AudioTrack.getMinBufferSize(sampleRate_, channels2num(channelConfig_), sampleSizeFromInt(sampleSize_)); + if (Log.isInfo()) Log.i(TAG, "Buffer size " + bufferSize_ + "*2"); + audioTrack_ = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate_, channels2num(channelConfig_), sampleSizeFromInt(sampleSize_), bufferSize_, AudioTrack.MODE_STREAM); + } catch (Exception e) { + Log.e(TAG, "error in audiotrack creation", e); + return; + } + + if (Log.isInfo()) Log.i(TAG, "initialized"); + } + + if (audioTrack_ != null) { + audioTrack_.play(); + } + + running_ = true; + } + + @Override + public void stop() { + if (Log.isInfo()) Log.i(TAG, "Stop"); + if (running_) { + running_ = false; + + if (audioTrack_ != null) { + if (audioTrack_.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { + audioTrack_.flush(); + audioTrack_.stop(); + } + audioTrack_.release(); + audioTrack_ = null; + } + + if (Log.isInfo()) Log.i(TAG, "audtiotrack released"); + +// codecHandler_.getLooper().quit(); + + if (codecThread_ != null) { + if (Log.isDebug()) Log.d(TAG, "interrupt codecThread_"); + codecThread_.interrupt(); + codecThread_ = null; + } + codecHandler_ = null; + } + } + +} diff --git a/app/src/main/java/it/smg/hu/projection/AudioOutput.java b/app/src/main/java/it/smg/hu/projection/AudioOutput.java index 9530f0dd..a7e1ee92 100644 --- a/app/src/main/java/it/smg/hu/projection/AudioOutput.java +++ b/app/src/main/java/it/smg/hu/projection/AudioOutput.java @@ -1,52 +1,21 @@ package it.smg.hu.projection; -import android.media.AudioFormat; -import android.media.AudioManager; -import android.media.AudioTrack; - import java.nio.ByteBuffer; import it.smg.hu.config.Settings; import it.smg.libs.common.Log; -public abstract class AudioOutput extends it.smg.libs.aasdk.projection.AudioOutput /*implements Runnable*/ { - private AudioTrack audioTrack_; + +public abstract class AudioOutput extends it.smg.libs.aasdk.projection.AudioOutput { protected Settings settings_; - protected boolean running_; + + private IAudioCodec audioCodec_; public AudioOutput(){ settings_ = Settings.instance(); } - private static int channels2num(int channels){ - switch (channels){ - case 1: - return AudioFormat.CHANNEL_OUT_MONO; - case 2: - return AudioFormat.CHANNEL_OUT_STEREO; - case 4: - return AudioFormat.CHANNEL_OUT_QUAD; - case 6: - return AudioFormat.CHANNEL_OUT_5POINT1; - case 8: - return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; - default: - return -1; - } - } - - public static int sampleSizeFromInt(int sampleSize){ - switch (sampleSize){ - case 16: - return AudioFormat.ENCODING_PCM_16BIT; - case 8: - return AudioFormat.ENCODING_PCM_8BIT; - default: - return -1; - } - } - @Override public boolean open() { return true; @@ -54,62 +23,34 @@ public boolean open() { @Override public void write(long timestamp, ByteBuffer buffer) { - if (running_) { - int size = buffer.limit(); - byte[] data = new byte[size]; - buffer.get(data); - audioTrack_.write(data, 0, size); - } + audioCodec_.write(buffer, timestamp); } @Override public void start() { - if (audioTrack_ == null) { - try { - int bufferSize_ = AudioTrack.getMinBufferSize(sampleRate_, channels2num(channelConfig_), sampleSizeFromInt(sampleSize_)); - if (Log.isInfo()) Log.i(tag(), "Buffer size " + bufferSize_ + "*2"); - audioTrack_ = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate_, channels2num(channelConfig_), sampleSizeFromInt(sampleSize_), bufferSize_ * 2, AudioTrack.MODE_STREAM); - } catch (Exception e) { - Log.e(tag(), "error in audiotrack creation", e); - return; - } - - if (Log.isInfo()) Log.i(tag(), "initialized"); - } - - if (audioTrack_ != null) { - audioTrack_.play(); + if (settings_.audio.audioCodec() == 2){ + if (Log.isInfo()) Log.v(tag(), "Create SLESAudio codec"); + audioCodec_ = new SLESAudioCodec(getSampleRate(), getChannelCount(), getSampleSize()); + } else { + if (Log.isInfo()) Log.v(tag(), "Create Android Audio codec"); + audioCodec_ = new AudioCodec(getSampleRate(), getChannelCount(), getSampleSize()); } - - running_ = true; + audioCodec_.start(); } @Override public void stop() { - if (Log.isInfo()) Log.i(tag(), "Stopping"); - suspend(); - - if (Log.isInfo()) Log.i(tag(), "Stop"); + if (audioCodec_ != null) { + audioCodec_.stop(); + audioCodec_ = null; + } } @Override public void suspend() { - if (Log.isInfo()) Log.i(tag(), "Suspend"); - if (running_) { - running_ = false; - - if (audioTrack_ != null) { - if (audioTrack_.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { - audioTrack_.flush(); - audioTrack_.stop(); - } - audioTrack_.release(); - audioTrack_ = null; - } - - if (Log.isInfo()) Log.i(tag(), "audtiotrack released"); + if (audioCodec_ != null) { + audioCodec_.stop(); } - } public abstract String tag(); diff --git a/app/src/main/java/it/smg/hu/projection/IAudioCodec.java b/app/src/main/java/it/smg/hu/projection/IAudioCodec.java new file mode 100644 index 00000000..286f718d --- /dev/null +++ b/app/src/main/java/it/smg/hu/projection/IAudioCodec.java @@ -0,0 +1,9 @@ +package it.smg.hu.projection; + +import java.nio.ByteBuffer; + +public interface IAudioCodec { + void write(ByteBuffer buffer, long timestamp); + void start(); + void stop(); +} diff --git a/app/src/main/java/it/smg/hu/projection/SLESAudioCodec.java b/app/src/main/java/it/smg/hu/projection/SLESAudioCodec.java new file mode 100644 index 00000000..7e747364 --- /dev/null +++ b/app/src/main/java/it/smg/hu/projection/SLESAudioCodec.java @@ -0,0 +1,55 @@ +package it.smg.hu.projection; + +import java.nio.ByteBuffer; + +import it.smg.libs.common.Log; + +public class SLESAudioCodec implements IAudioCodec { + private static final String TAG = "SLESAudioCodec"; + + private it.smg.libs.slesaudiocodec.SLESAudioCodec audioCodec_; + + private int sampleRate_; + private int channelConfig_; + private int sampleSize_; + protected boolean running_; + + public SLESAudioCodec(int sampleRate, int channelConfig, int sampleSize){ + sampleRate_ = sampleRate; + channelConfig_ = channelConfig; + sampleSize_ = sampleSize; + } + + @Override + public void write(ByteBuffer buffer, long timestamp) { + if (running_) { + if (Log.isVerbose()) Log.v(TAG, "write buffer size: " + buffer.limit()); +// if (Log.isVerbose()) Log.v(tag(), buffer); + audioCodec_.write(timestamp, buffer, buffer.limit()); + } + } + + @Override + public void start() { + if (audioCodec_ == null) { + audioCodec_ = new it.smg.libs.slesaudiocodec.SLESAudioCodec(sampleRate_, channelConfig_, sampleSize_); + running_ = true; + } + } + + @Override + public void stop() { + if (Log.isInfo()) Log.i(TAG, "Suspend"); + if (running_) { + running_ = false; + + if (audioCodec_ != null) { + audioCodec_.shutdown(); + audioCodec_ = null; + } + + if (Log.isInfo()) Log.i(TAG, "audioCodec_ destroyed"); + } + + } +} diff --git a/app/src/main/java/it/smg/hu/ui/SettingsActivity.java b/app/src/main/java/it/smg/hu/ui/SettingsActivity.java index fe48c92f..c6dbba11 100644 --- a/app/src/main/java/it/smg/hu/ui/SettingsActivity.java +++ b/app/src/main/java/it/smg/hu/ui/SettingsActivity.java @@ -9,6 +9,7 @@ import it.smg.hu.R; import it.smg.hu.ui.settings.AdvancedFragment; +import it.smg.hu.ui.settings.AudioFragment; import it.smg.hu.ui.settings.CarFragment; import it.smg.hu.ui.settings.VideoFragment; @@ -18,7 +19,7 @@ public class SettingsActivity extends FragmentActivity { private ImageButton carImage; private ImageButton advancedImage; private ImageButton videoImage; -// private ImageButton audioImage; + private ImageButton audioImage; @Override protected void onCreate(Bundle savedInstanceState) { @@ -50,13 +51,13 @@ protected void onCreate(Bundle savedInstanceState) { .commit() ); -// audioImage = findViewById(R.id.audio_settings); -// audioImage.setOnClickListener( -// listener -> getSupportFragmentManager() -// .beginTransaction() -// .replace(R.id.main_content, new AudioFragment()) -// .commit() -// ); + audioImage = findViewById(R.id.audio_settings); + audioImage.setOnClickListener( + listener -> getSupportFragmentManager() + .beginTransaction() + .replace(R.id.main_content, new AudioFragment()) + .commit() + ); getSupportFragmentManager().beginTransaction().replace(R.id.main_content, new CarFragment()).commit(); } diff --git a/app/src/main/java/it/smg/hu/ui/settings/AudioFragment.java b/app/src/main/java/it/smg/hu/ui/settings/AudioFragment.java index 38100e7a..8fb60798 100644 --- a/app/src/main/java/it/smg/hu/ui/settings/AudioFragment.java +++ b/app/src/main/java/it/smg/hu/ui/settings/AudioFragment.java @@ -1,7 +1,10 @@ package it.smg.hu.ui.settings; import android.Manifest; +import android.content.Context; import android.content.pm.PackageManager; +import android.hardware.Sensor; +import android.hardware.SensorManager; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -15,6 +18,8 @@ import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import java.util.concurrent.Callable; + import it.smg.hu.R; import it.smg.hu.config.Settings; import it.smg.hu.projection.AudioInput; @@ -23,6 +28,7 @@ import it.smg.hu.projection.MediaAudioOutput; import it.smg.hu.projection.SpeechAudioOutput; import it.smg.hu.projection.SystemAudioOutput; +import it.smg.libs.aasdk.projection.ISensor; public class AudioFragment extends BaseSettingsFragment { @@ -34,142 +40,145 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa settings = Settings.instance(); - initMediaAudio(view); - initSpeechAudio(view); - initSystemAudio(view); - initMic(view); - - return view; - - } - - private void initMediaAudio(View view){ - - CheckBox enableMediaAudio = view.findViewById(R.id.enable_media_channel); - initCheckBox(enableMediaAudio, settings.audio, Settings.Audio.MEDIA_ENABLE_CHANNEL, Settings.Audio.MEDIA_ENABLE_CHANNEL_DEFAULT_VALUE); - - EditText sampleRate = view.findViewById(R.id.media_samplerate); - initEditText(sampleRate, settings.audio, Settings.Audio.MEDIA_SAMPLERATE, Settings.Audio.MEDIA_SAMPLERATE_DEFAULT_VALUE); - - Spinner sampleSize = view.findViewById(R.id.media_samplesize); - initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.MEDIA_SAMPLESIZE, Settings.Audio.MEDIA_SAMPLESIZE_DEFAULT_VALUE); - - Spinner channelCount = view.findViewById(R.id.media_channel_count); - initSpinner(channelCount, R.array.audio_channels_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.MEDIA_CHANNELCOUNT, Settings.Audio.MEDIA_CHANNELCOUNT_DEFAULT_VALUE); - - Button check = view.findViewById(R.id.media_check_button); - check.setOnClickListener(v -> { - checkMediaAudioOutput(); - }); - } - - private void initSpeechAudio(View view){ - - CheckBox enableSpeechAudio = view.findViewById(R.id.enable_speech_channel); - initCheckBox(enableSpeechAudio, settings.audio, Settings.Audio.SPEECH_ENABLE_CHANNEL, Settings.Audio.SPEECH_ENABLE_CHANNEL_DEFAULT_VALUE); - - EditText sampleRate = view.findViewById(R.id.speech_samplerate); - initEditText(sampleRate, settings.audio, Settings.Audio.SPEECH_SAMPLERATE, Settings.Audio.SPEECH_SAMPLERATE_DEFAULT_VALUE); - - Spinner sampleSize = view.findViewById(R.id.speech_samplesize); - initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.SPEECH_SAMPLESIZE, Settings.Audio.SPEECH_SAMPLESIZE_DEFAULT_VALUE); - - Spinner channelCount = view.findViewById(R.id.speech_channel_count); - initSpinner(channelCount, R.array.audio_channels_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.SPEECH_CHANNELCOUNT, Settings.Audio.SPEECH_CHANNELCOUNT_DEFAULT_VALUE); - - Button check = view.findViewById(R.id.speech_check_button); - check.setOnClickListener(v -> { - checkSpeechAudioOutput(); - }); - - } - - private void initSystemAudio(View view){ - EditText sampleRate = view.findViewById(R.id.system_samplerate); - initEditText(sampleRate, settings.audio, Settings.Audio.SYSTEM_SAMPLERATE, Settings.Audio.SYSTEM_SAMPLERATE_DEFAULT_VALUE); +// initMediaAudio(view); +// initSpeechAudio(view); +// initSystemAudio(view); +// initMic(view); - Spinner sampleSize = view.findViewById(R.id.system_samplesize); - initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.SYSTEM_SAMPLESIZE, Settings.Audio.SYSTEM_SAMPLESIZE_DEFAULT_VALUE); + Spinner audioCodec = view.findViewById(R.id.audio_codec); + initSpinner(audioCodec, R.array.audio_codec_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.AUDIO_CODEC, Settings.Audio.AUDIO_CODEC_DEFAULT_VALUE); - Spinner channelCount = view.findViewById(R.id.system_channel_count); - initSpinner(channelCount, R.array.audio_channels_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.SYSTEM_CHANNELCOUNT, Settings.Audio.SYSTEM_CHANNELCOUNT_DEFAULT_VALUE); - - Button check = view.findViewById(R.id.system_check_button); - check.setOnClickListener(v -> { - checkSystemAudioOutput(); - }); - - } - - private boolean checkMediaAudioOutput(){ - return checkAudioSettings(new MediaAudioOutput(), "Wrong Media Audio Settings"); - } - - private boolean checkSpeechAudioOutput(){ - return checkAudioSettings(new SpeechAudioOutput(), "Wrong Speech Audio Settings"); - } - - private boolean checkSystemAudioOutput(){ - return checkAudioSettings(new SystemAudioOutput(), "Wrong System Audio Settings"); - } - - private boolean checkAudioSettings(IAudioOutput audioOutput, String error){ - try { - if (!audioOutput.open()){ - throw new Exception(); - }; - audioOutput.stop(); - Toast.makeText(getContext(), "Configuration OK", Toast.LENGTH_SHORT).show(); - } catch (Exception e){ - Toast.makeText(getContext(), error + ": " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); - return false; - } - return true; - } - - private void initMic(View view){ - CheckBox enableAudioInput = view.findViewById(R.id.enable_audioinput_channel); - initCheckBox(enableAudioInput, settings.audio, Settings.Audio.MIC_ENABLE_CHANNEL, Settings.Audio.MIC_ENABLE_CHANNEL_DEFAULT_VALUE); - - EditText sampleRate = view.findViewById(R.id.mic_samplerate); - initEditText(sampleRate, settings.audio, Settings.Audio.MIC_SAMPLERATE, Settings.Audio.MIC_SAMPLERATE_DEFAULT_VALUE); - - Spinner channelCount = view.findViewById(R.id.mic_channel_count); - initSpinner(channelCount, R.array.mic_channels_labels, R.array.mic_channels_values, settings.audio, Settings.Audio.MIC_CHANNELCOUNT, Settings.Audio.MIC_CHANNELCOUNT_DEFAULT_VALUE); - - Spinner sampleSize = view.findViewById(R.id.mic_samplesize); - initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.MIC_SAMPLESIZE, Settings.Audio.MIC_SAMPLESIZE_DEFAULT_VALUE); - - Spinner source = view.findViewById(R.id.mic_source); - initSpinner(source, R.array.mic_source_labels, R.array.mic_source_values, settings.audio, Settings.Audio.MIC_SOURCE, Settings.Audio.MIC_SOURCE_DEFAULT_VALUE); - - Button check = view.findViewById(R.id.mic_check_button); - check.setOnClickListener(v -> { - checkMicSettings("Wrong Microphone Settings"); - }); + return view; } - private boolean checkMicSettings(String error){ - try { - if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(getContext(), "Mic permission KO, request it", Toast.LENGTH_SHORT).show(); - ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.RECORD_AUDIO}, 111); - } else { - Toast.makeText(getContext(), "Mic permission OK", Toast.LENGTH_SHORT).show(); - } - - IAudioInput audioInput = new AudioInput(); - if (!audioInput.open()){ - throw new Exception(); - } - Toast.makeText(getContext(), "Configuration OK", Toast.LENGTH_SHORT).show(); - } catch (Exception e){ - Toast.makeText(getContext(), error + ": " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); - return false; - } - return true; - } +// private void initMediaAudio(View view){ +// +// CheckBox enableMediaAudio = view.findViewById(R.id.enable_media_channel); +// initCheckBox(enableMediaAudio, settings.audio, Settings.Audio.MEDIA_ENABLE_CHANNEL, Settings.Audio.MEDIA_ENABLE_CHANNEL_DEFAULT_VALUE); +// +// EditText sampleRate = view.findViewById(R.id.media_samplerate); +// initEditText(sampleRate, settings.audio, Settings.Audio.MEDIA_SAMPLERATE, Settings.Audio.MEDIA_SAMPLERATE_DEFAULT_VALUE); +// +// Spinner sampleSize = view.findViewById(R.id.media_samplesize); +// initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.MEDIA_SAMPLESIZE, Settings.Audio.MEDIA_SAMPLESIZE_DEFAULT_VALUE); +// +// Spinner channelCount = view.findViewById(R.id.media_channel_count); +// initSpinner(channelCount, R.array.audio_channels_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.MEDIA_CHANNELCOUNT, Settings.Audio.MEDIA_CHANNELCOUNT_DEFAULT_VALUE); +// +// Button check = view.findViewById(R.id.media_check_button); +// check.setOnClickListener(v -> { +// checkMediaAudioOutput(); +// }); +// } +// +// private void initSpeechAudio(View view){ +// +// CheckBox enableSpeechAudio = view.findViewById(R.id.enable_speech_channel); +// initCheckBox(enableSpeechAudio, settings.audio, Settings.Audio.SPEECH_ENABLE_CHANNEL, Settings.Audio.SPEECH_ENABLE_CHANNEL_DEFAULT_VALUE); +// +// EditText sampleRate = view.findViewById(R.id.speech_samplerate); +// initEditText(sampleRate, settings.audio, Settings.Audio.SPEECH_SAMPLERATE, Settings.Audio.SPEECH_SAMPLERATE_DEFAULT_VALUE); +// +// Spinner sampleSize = view.findViewById(R.id.speech_samplesize); +// initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.SPEECH_SAMPLESIZE, Settings.Audio.SPEECH_SAMPLESIZE_DEFAULT_VALUE); +// +// Spinner channelCount = view.findViewById(R.id.speech_channel_count); +// initSpinner(channelCount, R.array.audio_channels_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.SPEECH_CHANNELCOUNT, Settings.Audio.SPEECH_CHANNELCOUNT_DEFAULT_VALUE); +// +// Button check = view.findViewById(R.id.speech_check_button); +// check.setOnClickListener(v -> { +// checkSpeechAudioOutput(); +// }); +// +// } +// +// private void initSystemAudio(View view){ +// EditText sampleRate = view.findViewById(R.id.system_samplerate); +// initEditText(sampleRate, settings.audio, Settings.Audio.SYSTEM_SAMPLERATE, Settings.Audio.SYSTEM_SAMPLERATE_DEFAULT_VALUE); +// +// Spinner sampleSize = view.findViewById(R.id.system_samplesize); +// initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.SYSTEM_SAMPLESIZE, Settings.Audio.SYSTEM_SAMPLESIZE_DEFAULT_VALUE); +// +// Spinner channelCount = view.findViewById(R.id.system_channel_count); +// initSpinner(channelCount, R.array.audio_channels_labels, R.array.audio_channels_values, settings.audio, Settings.Audio.SYSTEM_CHANNELCOUNT, Settings.Audio.SYSTEM_CHANNELCOUNT_DEFAULT_VALUE); +// +// Button check = view.findViewById(R.id.system_check_button); +// check.setOnClickListener(v -> { +// checkSystemAudioOutput(); +// }); +// +// } +// +// private boolean checkMediaAudioOutput(){ +// return checkAudioSettings(new MediaAudioOutput(), "Wrong Media Audio Settings"); +// } +// +// private boolean checkSpeechAudioOutput(){ +// return checkAudioSettings(new SpeechAudioOutput(), "Wrong Speech Audio Settings"); +// } +// +// private boolean checkSystemAudioOutput(){ +// return checkAudioSettings(new SystemAudioOutput(), "Wrong System Audio Settings"); +// } +// +// private boolean checkAudioSettings(IAudioOutput audioOutput, String error){ +// try { +// if (!audioOutput.open()){ +// throw new Exception(); +// }; +// audioOutput.stop(); +// Toast.makeText(getContext(), "Configuration OK", Toast.LENGTH_SHORT).show(); +// } catch (Exception e){ +// Toast.makeText(getContext(), error + ": " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); +// return false; +// } +// return true; +// } +// +// private void initMic(View view){ +// CheckBox enableAudioInput = view.findViewById(R.id.enable_audioinput_channel); +// initCheckBox(enableAudioInput, settings.audio, Settings.Audio.MIC_ENABLE_CHANNEL, Settings.Audio.MIC_ENABLE_CHANNEL_DEFAULT_VALUE); +// +// EditText sampleRate = view.findViewById(R.id.mic_samplerate); +// initEditText(sampleRate, settings.audio, Settings.Audio.MIC_SAMPLERATE, Settings.Audio.MIC_SAMPLERATE_DEFAULT_VALUE); +// +// Spinner channelCount = view.findViewById(R.id.mic_channel_count); +// initSpinner(channelCount, R.array.mic_channels_labels, R.array.mic_channels_values, settings.audio, Settings.Audio.MIC_CHANNELCOUNT, Settings.Audio.MIC_CHANNELCOUNT_DEFAULT_VALUE); +// +// Spinner sampleSize = view.findViewById(R.id.mic_samplesize); +// initSpinner(sampleSize, R.array.audio_samplesize_labels, R.array.audio_samplesize_values, settings.audio, Settings.Audio.MIC_SAMPLESIZE, Settings.Audio.MIC_SAMPLESIZE_DEFAULT_VALUE); +// +// Spinner source = view.findViewById(R.id.mic_source); +// initSpinner(source, R.array.mic_source_labels, R.array.mic_source_values, settings.audio, Settings.Audio.MIC_SOURCE, Settings.Audio.MIC_SOURCE_DEFAULT_VALUE); +// +// Button check = view.findViewById(R.id.mic_check_button); +// check.setOnClickListener(v -> { +// checkMicSettings("Wrong Microphone Settings"); +// }); +// +// } +// +// private boolean checkMicSettings(String error){ +// try { +// if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { +// Toast.makeText(getContext(), "Mic permission KO, request it", Toast.LENGTH_SHORT).show(); +// ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.RECORD_AUDIO}, 111); +// } else { +// Toast.makeText(getContext(), "Mic permission OK", Toast.LENGTH_SHORT).show(); +// } +// +// IAudioInput audioInput = new AudioInput(); +// if (!audioInput.open()){ +// throw new Exception(); +// } +// Toast.makeText(getContext(), "Configuration OK", Toast.LENGTH_SHORT).show(); +// } catch (Exception e){ +// Toast.makeText(getContext(), error + ": " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); +// return false; +// } +// return true; +// } @Override protected String tag() { diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 6f94341a..a1fc6d93 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -50,23 +50,24 @@ android:layout_width="128dp" android:layout_height="64dp" android:layout_marginLeft="15dp" - android:layout_marginRight="15dp" android:adjustViewBounds="true" android:background="#039BE5" android:contentDescription="@string/video_settings" android:scaleType="fitCenter" android:src="@drawable/video_settings" /> - + android:background="#039BE5" + android:contentDescription="@string/audio_settings" + android:scaleType="fitCenter" + android:src="@drawable/audio_settings"/> - - - - - - - - - - - - - - + android:text="@string/audio_settings_audiocodec"/> - -