Git Product home page Git Product logo

roc-java's People

Contributors

computerscienceiscool avatar diemass avatar gavv avatar matteoarella avatar ortex avatar poulasthamukherjee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

roc-java's Issues

Whether to support multicast

Is it okay to do that?
Sender :
new Endpoint("rtp+rs8m://239.244.0.100:10001");
Receiver :
new Endpoint("rtp+rs8m://239.244.0.100:10001");

Use standard Java logger by default

Currently, if Logger.setCallback() was never called, or it was called with null argument, we use "default logger".

Currently, default logger is implemented in libroc (native code), and it just writes message to stderr.

It would be more convenient to implement default logger in java and make it writing to standard java logger instead of stderr.

We should make sure than on android, default logger will send logs to android log (which can be received with adb logcat).

Fix android/osx job on ci - Error: reserveCache failed: Cache already exists.

Sometimes we have problem with Install Android SDK components step on CI.

      - name: Install Android SDK components
        uses: maxim-lobanov/setup-android-tools@v1
        with:
          cache: true
          packages: |
            platforms;android-${{ matrix.api }}
            build-tools;${{ matrix.build_tools }}
            ndk;${{ matrix.ndk }}
            cmake;${{ matrix.cmake }}
            system-images;android-${{ matrix.api }};${{ matrix.avd_image }};${{ matrix.avd_arch }}
            emulator

e.g. https://github.com/roc-streaming/roc-java/actions/runs/5083653562 :

Run maxim-lobanov/setup-android-tools@v1
Getting list of available components

Installing 'platforms;android-29'...
  Package is already installed and update is not required

Installing 'build-tools;28.0.3'...
  Package is already installed and update is not required

Installing 'ndk;[21](https://github.com/roc-streaming/roc-java/actions/runs/5083653562/jobs/9144799554#step:3:23).1.635[24](https://github.com/roc-streaming/roc-java/actions/runs/5083653562/jobs/9144799554#step:3:26)62'...
Trying to restore package from cache...
  Package is restored from cache

Installing 'cmake;3.10.2.4988404'...
Trying to restore package from cache...
  Package is restored from cache

Installing 'system-images;android-29;default;x86_64'...
Trying to restore package from cache...
  Package is restored from cache

Installing 'emulator'...
  Package is already installed but update is required
Trying to restore package from cache...
  No cache found
Trying to download package via sdkmanager...
  Package is downloaded and installed
Saving package to cache...
  Error: reserveCache failed: Cache already exists. Scope: refs/pull/115/merge, Key: emulator/32.1.13/macos12, Version: a9f019e19b66fa[27](https://github.com/roc-streaming/roc-java/actions/runs/5083653562/jobs/9144799554#step:3:29)731f9a30544c8c38d8e005fcc1[59](https://github.com/roc-streaming/roc-java/actions/runs/5083653562/jobs/9144799554#step:3:63)c97da1[75](https://github.com/roc-streaming/roc-java/actions/runs/5083653562/jobs/9144799554#step:3:80)fea90accf[79](https://github.com/roc-streaming/roc-java/actions/runs/5083653562/jobs/9144799554#step:3:84)1

I suppose that because we have 2 similar job that saves to cache the same thing

Document version requirements and guidelines

Here are some things we need to document in README.

For user - what are requirements

For developer - what versions to bump

roc-java developers should periodically bump the following versions to the latest available:

  • SDK API level (SDK_LEVEL) (sets compileSdkVersion and targetSdkVersion)
  • Android NDK version (NDK_VERSION)
  • Android build-tools version (BUILD_TOOLS_VERSION)
  • CMake version (CMAKE_VERSION)

All these versions are defined in build.yml as described in detail in this issue: #105. We can include some info and links from that issue to README.

See also #112. ROC_VERSION will also need periodical bump.

I think we should also mention android_docker.sh, which has its own set of defaults. These defaults are used if the user did not specify any variables when building AAR locally.

Eliminate libc++_shared.so dependency on Android?

On Android, if AAR or APK has native libraries depending on libc++_shared.so (C++ STL from Clang), they should ship a copy of the library.

This, theoretically, may lead to problems if the user wants to use more than one native library and they depend on different versions of libc++_shared.so. It seems that the official recommendation is not use more than one native library.

In our case, both libroc.so and libroc_jni.so depend on libc++_shared.so. Here are the dependencies of libroc.so:

$ aarch64-linux-android-readelf -d ./libroc.so | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libc++_shared.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]

Here, libc++_shared.so is the only library needed to be shipped. Other libraries, AFAIK, are guaranteed to be available on every Android system.

But actually, I think we could get rid of the dependency on libc++_shared.so:

  • For libroc.so, we can link it statically into libroc.so or maybe even don't use it on Android at all (Roc does not use much of STL).

  • For libroc_jni.so, we can actually don't use C++. It seems that most files can be just renamed from .cpp to .c. It seems that the only C++ feature we're using is std::mutex. We can replace it with pthread_mutex for now (and add non-unix implementation later when needed), or maybe we can somehow move synchronization from C++ side to Java side.

    #55

@MatteoArella Thoughts?

Add validation for unsigned integer fields in configs

RocContextConfig, RocSenderConfig, RocReceiverConfig have some fields that have int or long types, but actually are not allowed to be negative.

If the user tries to make them negative, they'll get error when opening context, sender, and receiver.

It would be more convenient to catch these errors earlier - immediately when trying to set negative value to config. We already provide type checking for other values - e.g. enums are checked by compiler.

Fields to be checked to be >= 0:

  • RocContextConfig

    • maxPacketSize
    • maxFrameSize
  • RocSenderConfig

    • frameSampleRate
    • packetSampleRate
    • fecBlockSourcePackets
    • fecBlockRepairPackets
  • RocReceiverConfig

    • frameSampleRate

I think we should add a new method to Check class and invoke this method in setters and builder methods for corresponding fields.

Java package rename

As recently posted to the mailing list, I've renamed github org to "roc-streaming" and also renamed the main repo from just "roc" to "roc-toolkit".

So the full name of this roc-java project is now something like "JNI bindings to Roc Toolkit".

I've also registered a domain name, finally: https://roc-streaming.org/

"Roc Toolkit" is considered as a "sub-project" of the Roc Streaming organization.

So now I suggest to rename Java package from com.github.rocproject.roc to something based on the new domain, e.g.:

  • org.rocstreaming.roc
  • org.rocstreaming.roctoolkit
  • org.rocstreaming.rocjava
  • etc

@MatteoArella @ortex Thoughts?

Add version compatibility checks

This should be done after #57

When the library is initialized, we need to retrieve versions of native lib and go bindings, and check the following invariant:

  • major versions are equal
  • minor version of bindings is greater than or equal to minor version of native lib

(See "Versioning" section in Readme for explanation)

If the invariant is not satisfied, we should throw an exception with a message including the retrieved versions and explanation of what is wrong.

We can do this check in RocLibrary.loadLibrary.

Freeze libroc version when building AAR on CI

Currently, when CI builds AAR, it uses libroc from master branch of roc-toolkit. It's not good because this way AAR builds are not reproducible.

What we need to do:

  • add ROC_VERSION parameter to android_docker.sh script; default value should be "master"; when cloning roc, checkout specified version

  • in release job on CI, specify ROC_VERSION explicitly, set it to roc-toolkit tag which is currently the latest

ROC_VERSION should support any git revision notation: tag name, branch name, or commit hash.

Revise Android SDK and NDK versions

There are a few android-related versions that we specify in build scripts and CI:

  • Android NDK version. Does not affect runtime requirements. Generally should be set to latest available version because newer versions have more bug-fixes and optimizations.

  • Android build-tools version and CMake version. Similarly, should be set to latest available version.

  • Android API levels:

    • minSdkVersion. Defines runtime requirement of the app. The app will support only systems with this version and later. Should be set to the lowest possible version.

    • targetSdkVersion. Affects runtime behavior of the app. Should be set to the latest API level on which the app was tested. Android runtime will take this into account and will avoid behavior that was introduced in later versions.

    • compileSdkVersion. Defines compile-time version of Android SDK. Generally should be set to latest available version.

More info: 1, 2.


Currently, minSdkVersion is defined in android/roc-android/build.gradle, and other versions are defined in .github/workflows/build.yml and passed to gradle via environment variables.

What we need to do:

  • in scripts/android_docker.sh:

    • rename API to SDK_LEVEL (corresponds to compileSdkVersion)

      the rename should be also reflected in:

      • scripts/android/build_roc.sh
      • scripts/android/start_emulator.sh
      • README.md
  • in .github/workflows/build.yml:

    • in all jobs:

      • rename API to SDK_LEVEL
    • in android-linux and release jobs:

      • explicitly define BUILD_TOOLS_VERSION and CMAKE_VERSION vars (currently they're missing and we rely on defaults)
    • in android-linux, android-osx, and release jobs:

      • bump SDK_LEVEL (compileSdkVersion) to the latest available version
      • bump NDK_VERSION (Android NDK version) to the latest available version
      • bump BUILD_TOOLS_VERSION (Android build-tools version) to the latest available version
      • bump CMAKE_VERSION to the latest available version
    • in android-linux and android-osx jobs:

      • in addition to bumping versions as described above, keep one step with the currently used, older, versions of sdk, ndk, build-tools, and cmake; it will allow us to keep testing compatibility with older build environments

        in android-linux we'll need to add a new step for older versions; in android-osx we'll need to use the existing last step for that

    • in android-linux job:

      • introduce new step that runs scripts/android_docker.sh build without exporting any environment variables (SDK_LEVEL, NDK_VERSION, etc); this step will allow us to keep testing that defaults defined in android_docker.sh are good and the script works when no configuration is provided
  • In android/roc-android/build.gradle:

    • rename API env var to SDK_LEVEL
    • rename apiLevel var to sdkLevel
    • set compileSdkVersion and targetSdkVersion to sdkLevel (obtained from SDK_LEVEL)

Fix logger on android

Logger doesn't work on android.

A/.rocandroidsin: java_vm_ext.cc:570] JNI DETECTED ERROR IN APPLICATION: JNI GetStaticFieldID called with pending exception java.lang.ClassNotFoundException: Didn't find class "com.github.rocproject.roc.LogLevel" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/product/lib64, /system/lib64, /system/product/lib64]]
    java_vm_ext.cc:570]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:196)
    java_vm_ext.cc:570]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
    java_vm_ext.cc:570]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
    java_vm_ext.cc:570] 
    java_vm_ext.cc:570]     in call to GetStaticFieldID
A/.rocandroidsin: thread.cc:2348] No pending exception expected: java.lang.ClassNotFoundException: Didn't find class "com.github.rocproject.roc.LogLevel" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/product/lib64, /system/lib64, /system/product/lib64]]
    thread.cc:2348]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:196)
    thread.cc:2348]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
    thread.cc:2348]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
    thread.cc:2348] 

This could help: https://developer.android.com/training/articles/perf-jni.html#faq:-why-didnt-findclass-find-my-class

Do your FindClass lookups once, in JNI_OnLoad, and cache the class references for later use. Any FindClass calls made as part of executing JNI_OnLoad will use the class loader associated with the function that called System.loadLibrary (this is a special rule, provided to make library initialization more convenient). If your app code is loading the library, FindClass will use the correct class loader.

Add standalone Java API usage examples

What do we need:

  • We should port sender and receiver examples that we already have for C API to Java.
  • Examples should be buildable and runnable project(s).
  • Examples should be minimal and simple. All steps should be documented, similar to our C examples.
  • Examples should be interoperable with roc command-line tools (e.g. it should be possible to run example sender in Java with roc-recv tool as a receiver).

References:

Think about some finalizer-like feature

Currently we use AutoClosable for Context, Receiver, and Sender.

Probably we could also implement some automatic closing for them to reduce the damage from forgetting to call close() in long-running applications.

As discussed in #2:

Finalizers have been deprecated since Java 9 in favour of PhantomReferences, Cleaners and ReferenceQueues. A better approach should be studied deeply and implemented maybe in a separate issue.

In 0.2 we'll replace roc_address with roc_endpoint, which also has to be deinitialized. Since roc_endpoint does not hold any resources except memory, it would be very convenient to employ something like finalizers for it as well to make it manageable by GC.

Extend README

  • Overview (briefly about project)
  • Features
  • Documentation
  • Installation
  • Versioning (mapping bindings versions to libroc versions)
  • Development
  • Authors
  • License (note on bindings and library)

Revise Android minSdkVersion

Currently, Android minSdkVersion (i.e. Android API level which we support) is set to 26:

We should check whether this value can be lowered or it is indeed minimum version we can work with.

Theoretically it could be lowered because the requirement of the underlying native library (libroc) is 21:

https://github.com/roc-streaming/roc-toolkit/blob/271ddf27eb3fae0273b5f8488a3114e70f1acfdb/SConstruct#LL720C35-L720C35

Chance are that roc-java has higher requirements than 21, but probably still lower than current 26. In this case, we'll need to update it in android/roc-android/build.gradle, scripts/android_docker.sh, and examples in README.md.

See also #105

Improve debug logs

Add debug logs on java side for all non-realtime operations:

  • opening and closing context/sender/receiver
  • bind and connect
  • registering/unregistering/collecting object in NativeObjectCleaner
  • loading jni library first time (RocLibrary)

These operations should log their arguments.

If operation does a call to a native method, it should write to log before and after native call. This is useful when debugging crashes in native code.

Background: roc-streaming/roc-droid#45 (comment)

Missing config field checks

In receiver_config_unmarshal and in sender_config_unmarshal, for some fields we have checks if (tempObj == NULL) return -1, and for some we don't have them.

I've tried to add checks for missing fields, and for every field when I tried to add a check, test started failing, with an exception stating that sender or receiver config is invalid (i.e. the added checks are failing).

Below I list the fields which don't have checks (and I was unable to add them).

Receiver:

  • clock_source
  • resampler_backend
  • resampler_profile

Sender:

  • packet_channels
  • packet_encoding
  • clock_source
  • resampler_backend
  • resampler_profile
  • fec_encoding

Build debug version of libroc when building debug AAR

We build two versions of AAR, debug and release, and both use release version of native libroc.so.

It would be convenient to build debug version of libroc, and use it in debug version of AAR. Debug version of libroc should have better stacktraces.

libroc is built using scripts/android/build_roc.sh. Currently it builds 4 versions of the lib (for 4 android ABIs). Now it'll need to build 8 versions (debug + release for each ABI), and gradle will need to use appropriate version.

To enable debugging, pass --enable-debug option to scons.

Build and publish JAR

Automatically build and publish our library.

Maybe use jitpack.io or Maven Central or JCenter.

Port JNI bindings from C++ to C

Rationale:

  • although files has .cpp extension, most of the code is written in C style, and C++ dependency in redundant
  • more importantly, see #17

API integration tests

We should add at least one integration test in Java that creates a sender, a receiver, transfers samples, and checks that they were transferred correctly.

Such an integration test for the C API can be found here: https://github.com/roc-streaming/roc-toolkit/blob/master/src/tests/public_api/test_sender_receiver.cpp

We can go further and add a few more tests, similar to tests described roc-streaming/roc-toolkit#328. I don't think we need to replicate all of them, but it'd be nice to test at least some of the key features.

See also roc-streaming/roc-go#29 for more hints.

Pass more info from log message to java logger

New libroc API (starting from 0.2), log messages provide more granular information. Instead of three arguments (level, component, message), logging callback in native library now receives a struct roc_log_message, defined here:

https://github.com/roc-streaming/roc-toolkit/blob/271ddf27eb3fae0273b5f8488a3114e70f1acfdb/src/public_api/include/roc/log.h#L58

Consider passing the following fields to jul:

  • file and line (not strictly necessary, generally libroc logs are useful without this information too)
  • time
  • pid and tid (or maybe only tid)

Rename some java classes to more unique names

As discussed in chat:

  • Context -> RocContext
  • Sender -> RocSender
  • Receiver -> RocReceiver
  • ContextConfig -> RocContextConfig
  • SenderConfig -> RocSenderConfig
  • ReceiverConfig -> RocReceiverConfig
  • Logger -> RocLogger
  • LogLevel -> RocLogLevel
  • LogHandler -> RocLogHandler

Cache artifact build for release stage on Travis

According to Travis docs https://docs.travis-ci.com/user/using-workspaces:

Travis workspaces allow jobs within a build to share files. They are useful when you want to use build artifacts from a previous job

In the Travis Release stage the rebuilding of android artifact can be avoided (since it's already done during previous Android build stage) using Travis Workspaces (even though they are currently still in beta).

In particular the steps involved would be:

  1. create a new workspace on Android build stage, caching artifact
  2. use the workspace on android Release stage publishing the previously built artifact.

See #25.

Can't build using OpenJDK 17

Currently, I'm able to build roc-java using OpenJDK 8, but not OpenJDK 17.

OpenJDK 8 is not available in next debian stable candidate, so it would be nice to fix build with recent version. Otherwise you need to install older JDK manually.


When using OpenJDK 17, I get the following error:

Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':roc_jni'.
> Could not open proj remapped class cache for 6ln1p28aqpsv1qjk04pyeijya (/home/victor/.gradle/caches/6.4/scripts-remapped/build_bvwlj1vorvl1q0nbtcfbai48m/6ln1p28aqpsv1qjk04pyeijya/proj68a30bfc7da5ef859cd7b983445462e5).
   > Could not open proj generic class cache for build file '/home/victor/dev/roc-streaming/roc-java/roc_jni/build.gradle' (/home/victor/.gradle/caches/6.4/scripts/6ln1p28aqpsv1qjk04pyeijya/proj/proj68a30bfc7da5ef859cd7b983445462e5).
      > BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 61

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s

If I download JDK 8 from here and added it to PATH:

PATH="/some/path/jdk8u362-b09/bin:$PATH" ./gradlew build

everything works.

Refactor checks for invalid arguments

  • Find all places in java code where we check for invalid arguments and throw IllegalArgumentException.

  • Refactor them: add information to the thrown exception about which exact field is invalid and why (e.g. it's null).

Use Duration class instead of long for time values in configs

Find all fields in RocSenderConfig and RocReceiverConfig that hold durations (in nanoseconds), e.g. targetLatency, and convert them from long to Duration. Adjust JNI side accordingly.

Fields of interest:

SenderConfig:

  • PacketLength

ReceiverConfig

  • TargetLatency
  • MaxLatencyOverrun
  • MaxLatencyUnderrun
  • NoPlaybackTimeout
  • BrokenPlaybackTimeout
  • BreakageDetectionWindow

Fix android aar build

Built aar doesn't work

java.lang.UnsatisfiedLinkError: dlopen failed: library "libroc.so.0.1" not found
    at java.lang.Runtime.loadLibrary0(Runtime.java:1071)
    at java.lang.Runtime.loadLibrary0(Runtime.java:1007)
    at java.lang.System.loadLibrary(System.java:1667)
    at com.github.rocproject.roc.RocLibrary.loadLibrary(RocLibrary.java:5)
    at com.github.rocproject.roc.ChannelSet.<init>(ChannelSet.java:18)
    at com.github.rocproject.roc.ChannelSet.<clinit>(ChannelSet.java:14)

how to build:

export JAVA_VERSION=8 
export ANDROID_API=28 
export ANDROID_BUILD_TOOLS_VERSION=28.0.3 
export ANDROID_NDK_VERSION=21.1.6352462 
export ROC_BASE_DIR=$HOME/roc-build

./scripts/travis/android/install.sh 
./scripts/travis/android/script.sh 

how to reproduce:

As a temporary workaround to build arr I changed in https://github.com/roc-project/roc/blob/master/SConstruct#L1079
from

lib_env['SHLIBSUFFIX'] = '%s.%s' % (lib_env['SHLIBSUFFIX'], abi_version)

to

lib_env['SHLIBSUFFIX'] = '%s' % (lib_env['SHLIBSUFFIX'], abi_version)

Remove getValue from all enums

Numeric value of enum is actually not needed outside of roc-java package.

  • remove getValue method from all enums
  • convert value field of all enums from private to package-private
  • use value instead of getValue everywhere inside roc-java

Add bindings for reuseaddr option

roc-toolkit 0.2.3 added two new functions:

  • roc_sender_set_reuseaddr
  • roc_receiver_set_reuseaddr

See API reference for description.

We should add two corresponding methods to bindings:

  • Sender.setReuseaddr(bool)
  • Receiver.setReuseaddr(bool)

Comments should be copied and adopted from C header.

We also need to add tests for both successful and unsuccessful invocations of the two newly added methods. No need to test how the option itself work, just a simple "smoke" test.

Detach current thread only at its exit

Actually we are calling AttachCurrentThread and DetachCurrentThread inside the logger_handler function (https://github.com/roc-project/roc-java/blob/master/roc_jni/src/main/cpp/logger.cpp);

As it has been discussed at #18 this can slow down performances.

A more efficient solution would involve detaching thread just before its exit, as it's described at https://developer.android.com/training/articles/perf-jni#threads:

you can use pthread_key_create() to define a destructor function that will be called before the thread exits, and call DetachCurrentThread() from there. (Use that key with pthread_setspecific() to store the JNIEnv in thread-local-storage).

Native symbols are not present in backtrace

For some reason, when there is a crash in native code, the backtrace does not show symbols in frames in native codes. Neither in console output, nor in gdb when I open core dump.

I checked that both libroc_jni and libroc have debug symbols, that gdb has correct paths to these libs, and tried to force gdb to load symbols from them (using sharedlibrary command). It did not help.

Without this, it's very hard to debug crashes in native code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.