From 80f39e6b4d4662efced41b09413578e24506fe19 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Thu, 20 Mar 2025 14:08:07 +0100 Subject: [PATCH 01/28] feat!: refactor code to use webrtc branch 6998 --- webrtc-jni/pom.xml | 374 ++--- .../include/api/RTCRtpContributingSource.h | 97 +- .../src/main/cpp/include/api/RTCStats.h | 132 +- .../cpp/include/media/audio/AudioConverter.h | 114 +- .../media/audio/AudioProcessingConfig.h | 255 ++-- .../media/video/VideoTrackDesktopSource.h | 148 +- .../src/main/cpp/src/JNI_AudioConverter.cpp | 129 +- .../main/cpp/src/JNI_AudioDeviceModule.cpp | 996 ++++++------- .../src/main/cpp/src/JNI_AudioProcessing.cpp | 431 +++--- .../src/main/cpp/src/JNI_AudioResampler.cpp | 157 ++- .../src/main/cpp/src/JNI_MediaStream.cpp | 240 ++-- .../src/main/cpp/src/JNI_MediaStreamTrack.cpp | 344 ++--- .../cpp/src/JNI_PeerConnectionFactory.cpp | 533 +++---- .../src/main/cpp/src/JNI_RTCDataChannel.cpp | 402 +++--- .../main/cpp/src/JNI_RTCPeerConnection.cpp | 1226 ++++++++--------- .../src/main/cpp/src/JNI_RefCountedObject.cpp | 82 +- .../main/cpp/src/JNI_VideoDesktopSource.cpp | 226 +-- .../main/cpp/src/JNI_VideoDeviceSource.cpp | 230 ++-- .../src/main/cpp/src/api/AudioOptions.cpp | 106 +- .../src/main/cpp/src/api/RTCConfiguration.cpp | 215 ++- .../cpp/src/api/RTCRtpContributingSource.cpp | 142 +- .../src/api/RTCRtpSynchronizationSource.cpp | 141 +- webrtc-jni/src/main/cpp/src/api/RTCStats.cpp | 430 +++--- .../cpp/src/media/audio/AudioConverter.cpp | 398 +++--- .../src/media/audio/AudioProcessingConfig.cpp | 326 ++--- .../media/video/VideoTrackDesktopSource.cpp | 559 ++++---- .../media/video/desktop/DesktopCapturer.cpp | 201 ++- .../webrtc/RTCRtpContributingSource.java | 140 +- .../webrtc/media/audio/AudioOptions.java | 128 +- .../media/audio/AudioProcessingConfig.java | 228 ++- .../webrtc/media/audio/AudioResampler.java | 202 ++- .../media/audio/AudioProcessingTest.java | 312 +++-- .../media/audio/AudioResamplerTest.java | 278 ++-- 33 files changed, 4894 insertions(+), 5028 deletions(-) diff --git a/webrtc-jni/pom.xml b/webrtc-jni/pom.xml index cc86b5a3..b581893f 100644 --- a/webrtc-jni/pom.xml +++ b/webrtc-jni/pom.xml @@ -1,187 +1,187 @@ - - - 4.0.0 - - - dev.onvoid.webrtc - webrtc-java-parent - 0.11.0-SNAPSHOT - - - webrtc-java-jni - pom - - - branch-heads/4844 - ${user.home}/webrtc - ${user.home}/webrtc/build - Release - - - - - webrtc-java-${project.version} - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-jar-plugin - - - prepare-package - - jar - - - ${platform.classifier} - ${project.build.directory}/lib - - false - - ${platform.module} - - - - - - - - org.apache.maven.plugins - maven-install-plugin - - true - - - - install-classifier - package - - install-file - - - ${project.build.directory}/webrtc-java-${project.version}-${platform.classifier}.jar - ${platform.classifier} - ${project.groupId} - webrtc-java - ${project.version} - jar - false - - - - - - com.googlecode.cmake-maven-project - cmake-maven-plugin - 3.22.1-b1 - - - cmake-generate - generate-resources - - generate - - - src/main/cpp - ${project.build.directory}/${platform.classifier} - - - - - - - - - - - - - cmake-compile - generate-resources - - compile - - - ${cmake.config} - install - ${project.build.directory}/${platform.classifier} - - - - - - - - - - windows-x86_64 - - - windows - amd64 - - - - -Ax64 - ${cmake.build.type} - - - - linux-x86_64 - - - linux - amd64 - - - - toolchain/x86_64-linux-gnu.cmake - - - - linux-aarch32 - - - linux - aarch32 - - - - toolchain/aarch32-linux-gnu.cmake - - - - linux-aarch64 - - - linux - aarch64 - - - - toolchain/aarch64-linux-gnu.cmake - - - - + + + 4.0.0 + + + dev.onvoid.webrtc + webrtc-java-parent + 0.11.0-SNAPSHOT + + + webrtc-java-jni + pom + + + branch-heads/6998 + ${user.home}/webrtc + ${user.home}/webrtc/build + Release + + + + + webrtc-java-${project.version} + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-jar-plugin + + + prepare-package + + jar + + + ${platform.classifier} + ${project.build.directory}/lib + + false + + ${platform.module} + + + + + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + install-classifier + package + + install-file + + + ${project.build.directory}/webrtc-java-${project.version}-${platform.classifier}.jar + ${platform.classifier} + ${project.groupId} + webrtc-java + ${project.version} + jar + false + + + + + + com.googlecode.cmake-maven-project + cmake-maven-plugin + 3.22.1-b1 + + + cmake-generate + generate-resources + + generate + + + src/main/cpp + ${project.build.directory}/${platform.classifier} + + + + + + + + + + + + + cmake-compile + generate-resources + + compile + + + ${cmake.config} + install + ${project.build.directory}/${platform.classifier} + + + + + + + + + + windows-x86_64 + + + windows + amd64 + + + + -Ax64 + ${cmake.build.type} + + + + linux-x86_64 + + + linux + amd64 + + + + toolchain/x86_64-linux-gnu.cmake + + + + linux-aarch32 + + + linux + aarch32 + + + + toolchain/aarch32-linux-gnu.cmake + + + + linux-aarch64 + + + linux + aarch64 + + + + toolchain/aarch64-linux-gnu.cmake + + + + diff --git a/webrtc-jni/src/main/cpp/include/api/RTCRtpContributingSource.h b/webrtc-jni/src/main/cpp/include/api/RTCRtpContributingSource.h index 5014fc3c..07cccd88 100644 --- a/webrtc-jni/src/main/cpp/include/api/RTCRtpContributingSource.h +++ b/webrtc-jni/src/main/cpp/include/api/RTCRtpContributingSource.h @@ -1,49 +1,50 @@ -/* - * Copyright 2019 Alex Andres - * - * 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 JNI_WEBRTC_API_RTC_RTP_CONTRIBUTING_SOURCE_H_ -#define JNI_WEBRTC_API_RTC_RTP_CONTRIBUTING_SOURCE_H_ - -#include "JavaClass.h" -#include "JavaRef.h" - -#include "api/transport/rtp/rtp_source.h" - -#include - -namespace jni -{ - namespace RTCRtpContributingSource - { - class JavaRTCRtpContributingSourceClass : public JavaClass - { - public: - explicit JavaRTCRtpContributingSourceClass(JNIEnv * env); - - jclass cls; - jmethodID ctor; - jfieldID timestamp; - jfieldID source; - jfieldID audioLevel; - jfieldID rtpTimestamp; - }; - - JavaLocalRef toJava(JNIEnv * env, const webrtc::RtpSource & source); - webrtc::RtpSource toNative(JNIEnv * env, const JavaRef & source); - } -} - +/* + * Copyright 2019 Alex Andres + * + * 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 JNI_WEBRTC_API_RTC_RTP_CONTRIBUTING_SOURCE_H_ +#define JNI_WEBRTC_API_RTC_RTP_CONTRIBUTING_SOURCE_H_ + +#include "JavaClass.h" +#include "JavaRef.h" + +#include "api/transport/rtp/rtp_source.h" + +#include + +namespace jni +{ + namespace RTCRtpContributingSource + { + class JavaRTCRtpContributingSourceClass : public JavaClass + { + public: + explicit JavaRTCRtpContributingSourceClass(JNIEnv * env); + + jclass cls; + jmethodID ctor; + jfieldID timestamp; + jfieldID sourceId; + jfieldID sourceType; + jfieldID audioLevel; + jfieldID rtpTimestamp; + }; + + JavaLocalRef toJava(JNIEnv * env, const webrtc::RtpSource & source); + webrtc::RtpSource toNative(JNIEnv * env, const JavaRef & source); + } +} + #endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/include/api/RTCStats.h b/webrtc-jni/src/main/cpp/include/api/RTCStats.h index ad45ccf2..deae15bf 100644 --- a/webrtc-jni/src/main/cpp/include/api/RTCStats.h +++ b/webrtc-jni/src/main/cpp/include/api/RTCStats.h @@ -1,67 +1,67 @@ -/* - * Copyright 2019 Alex Andres - * - * 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 JNI_WEBRTC_API_RTC_STATS_H_ -#define JNI_WEBRTC_API_RTC_STATS_H_ - -#include "JavaClass.h" -#include "JavaRef.h" - -#include "api/stats/rtc_stats_report.h" - -#include - -namespace jni -{ - namespace RTCStats - { - enum class RTCStatsType { - kCodec, - kInboundRtp, - kOutboundRtp, - kRemoteInboundRtp, - kRemoteOutboundRtp, - kMediaSource, - kCsrc, - kPeerConnection, - kDataChannel, - kStream, - kTrack, - kSender, - kReceiver, - kTransport, - kCandidatePair, - kLocalCandidate, - kRemoteCandidate, - kCertificate, - kIceServer - }; - - class JavaRTCStatsClass : public JavaClass - { - public: - explicit JavaRTCStatsClass(JNIEnv * env); - - jclass cls; - jmethodID ctor; - }; - - JavaLocalRef toJava(JNIEnv * env, const webrtc::RTCStats & stats); - JavaLocalRef toJava(JNIEnv * env, const webrtc::RTCStatsMemberInterface & member); - } -} - +/* + * Copyright 2019 Alex Andres + * + * 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 JNI_WEBRTC_API_RTC_STATS_H_ +#define JNI_WEBRTC_API_RTC_STATS_H_ + +#include "JavaClass.h" +#include "JavaRef.h" + +#include "api/stats/rtc_stats_report.h" + +#include + +namespace jni +{ + namespace RTCStats + { + enum class RTCStatsType { + kCodec, + kInboundRtp, + kOutboundRtp, + kRemoteInboundRtp, + kRemoteOutboundRtp, + kMediaSource, + kCsrc, + kPeerConnection, + kDataChannel, + kStream, + kTrack, + kSender, + kReceiver, + kTransport, + kCandidatePair, + kLocalCandidate, + kRemoteCandidate, + kCertificate, + kIceServer + }; + + class JavaRTCStatsClass : public JavaClass + { + public: + explicit JavaRTCStatsClass(JNIEnv * env); + + jclass cls; + jmethodID ctor; + }; + + JavaLocalRef toJava(JNIEnv * env, const webrtc::RTCStats & stats); + JavaLocalRef toJava(JNIEnv * env, const webrtc::Attribute & attribute); + } +} + #endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/include/media/audio/AudioConverter.h b/webrtc-jni/src/main/cpp/include/media/audio/AudioConverter.h index 76f97f5c..fa496ecf 100644 --- a/webrtc-jni/src/main/cpp/include/media/audio/AudioConverter.h +++ b/webrtc-jni/src/main/cpp/include/media/audio/AudioConverter.h @@ -1,59 +1,57 @@ -/* - * Copyright 2021 Alex Andres - * - * 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 JNI_WEBRTC_MEDIA_AUDIO_CONVERTER_H_ -#define JNI_WEBRTC_MEDIA_AUDIO_CONVERTER_H_ - -#include "JavaClass.h" -#include "JavaRef.h" - -#include - -#include "rtc_base/constructor_magic.h" - -namespace jni -{ - class AudioConverter - { - public: - static std::unique_ptr create(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels); - - virtual ~AudioConverter() = default; - - virtual void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) = 0; - - size_t getSrcChannels() const { return srcChannels; } - size_t getSrcFrames() const { return srcFrames; } - size_t getDstChannels() const { return dstChannels; } - size_t getDstFrames() const { return dstFrames; } - - protected: - AudioConverter(); - AudioConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels); - - void checkSizes(size_t srcSize, size_t dstCapacity) const; - - const size_t srcFrames; - const size_t srcChannels; - const size_t dstFrames; - const size_t dstChannels; - - private: - RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter); - }; -} - +/* + * Copyright 2021 Alex Andres + * + * 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 JNI_WEBRTC_MEDIA_AUDIO_CONVERTER_H_ +#define JNI_WEBRTC_MEDIA_AUDIO_CONVERTER_H_ + +#include "JavaClass.h" +#include "JavaRef.h" + +#include + +namespace jni +{ + class AudioConverter + { + public: + AudioConverter(const AudioConverter&) = delete; + AudioConverter& operator=(const AudioConverter&) = delete; + + static std::unique_ptr create(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels); + + virtual ~AudioConverter() = default; + + virtual void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) = 0; + + size_t getSrcChannels() const { return srcChannels; } + size_t getSrcFrames() const { return srcFrames; } + size_t getDstChannels() const { return dstChannels; } + size_t getDstFrames() const { return dstFrames; } + + protected: + AudioConverter(); + AudioConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels); + + void checkSizes(size_t srcSize, size_t dstCapacity) const; + + const size_t srcFrames; + const size_t srcChannels; + const size_t dstFrames; + const size_t dstChannels; + }; +} + #endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h b/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h index ce95ca30..219b6dad 100644 --- a/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h +++ b/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h @@ -1,142 +1,115 @@ -/* - * Copyright 2021 Alex Andres - * - * 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 JNI_WEBRTC_MEDIA_AUDIO_PROCESSING_CONFIG_H_ -#define JNI_WEBRTC_MEDIA_AUDIO_PROCESSING_CONFIG_H_ - -#include "JavaClass.h" -#include "JavaRef.h" - -#include "modules/audio_processing/include/audio_processing.h" - -#include - -namespace jni -{ - namespace AudioProcessingConfig - { - class JavaAudioProcessingConfigClass : public JavaClass - { - public: - explicit JavaAudioProcessingConfigClass(JNIEnv * env); - - jclass cls; - jfieldID echoCanceller; - jfieldID gainControl; - jfieldID highPassFilter; - jfieldID noiseSuppression; - jfieldID residualEchoDetector; - jfieldID transientSuppression; - jfieldID voiceDetection; - }; - - webrtc::AudioProcessing::Config toNative(JNIEnv * env, const JavaRef & javaType); - webrtc::AudioProcessing::Config::GainController2 toGainController2(JNIEnv * env, const JavaLocalRef & javaType); - - - class JavaEchoCancellerClass : public JavaClass - { - public: - explicit JavaEchoCancellerClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - jfieldID enforceHighPassFiltering; - }; - - class JavaGainControlClass : public JavaClass - { - public: - explicit JavaGainControlClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - jfieldID fixedDigital; - jfieldID adaptiveDigital; - }; - - class JavaGainControlFixedDigitalClass : public JavaClass - { - public: - explicit JavaGainControlFixedDigitalClass(JNIEnv * env); - - jclass cls; - jfieldID gainDb; - }; - - class JavaGainControlAdaptiveDigitalClass : public JavaClass - { - public: - explicit JavaGainControlAdaptiveDigitalClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - jfieldID dryRun; - jfieldID vadResetPeriodMs; - jfieldID adjacentSpeechFramesThreshold; - jfieldID maxGainChangeDbPerSecond; - jfieldID maxOutputNoiseLevelDbfs; - }; - - class JavaHighPassFilterClass : public JavaClass - { - public: - explicit JavaHighPassFilterClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - }; - - class JavaNoiseSuppressionClass : public JavaClass - { - public: - explicit JavaNoiseSuppressionClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - jfieldID level; - }; - - class JavaResidualEchoDetectorClass : public JavaClass - { - public: - explicit JavaResidualEchoDetectorClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - }; - - class JavaTransientSuppressionClass : public JavaClass - { - public: - explicit JavaTransientSuppressionClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - }; - - class JavaVoiceDetectionClass : public JavaClass - { - public: - explicit JavaVoiceDetectionClass(JNIEnv * env); - - jclass cls; - jfieldID enabled; - }; - } -} - +/* + * Copyright 2021 Alex Andres + * + * 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 JNI_WEBRTC_MEDIA_AUDIO_PROCESSING_CONFIG_H_ +#define JNI_WEBRTC_MEDIA_AUDIO_PROCESSING_CONFIG_H_ + +#include "JavaClass.h" +#include "JavaRef.h" + +#include "modules/audio_processing/include/audio_processing.h" + +#include + +namespace jni +{ + namespace AudioProcessingConfig + { + class JavaAudioProcessingConfigClass : public JavaClass + { + public: + explicit JavaAudioProcessingConfigClass(JNIEnv * env); + + jclass cls; + jfieldID echoCanceller; + jfieldID gainControl; + jfieldID highPassFilter; + jfieldID noiseSuppression; + jfieldID residualEchoDetector; + jfieldID transientSuppression; + jfieldID voiceDetection; + }; + + webrtc::AudioProcessing::Config toNative(JNIEnv * env, const JavaRef & javaType); + webrtc::AudioProcessing::Config::GainController2 toGainController2(JNIEnv * env, const JavaLocalRef & javaType); + + + class JavaEchoCancellerClass : public JavaClass + { + public: + explicit JavaEchoCancellerClass(JNIEnv * env); + + jclass cls; + jfieldID enabled; + jfieldID enforceHighPassFiltering; + }; + + class JavaGainControlClass : public JavaClass + { + public: + explicit JavaGainControlClass(JNIEnv * env); + + jclass cls; + jfieldID enabled; + jfieldID fixedDigital; + jfieldID adaptiveDigital; + }; + + class JavaGainControlFixedDigitalClass : public JavaClass + { + public: + explicit JavaGainControlFixedDigitalClass(JNIEnv * env); + + jclass cls; + jfieldID gainDb; + }; + + class JavaGainControlAdaptiveDigitalClass : public JavaClass + { + public: + explicit JavaGainControlAdaptiveDigitalClass(JNIEnv * env); + + jclass cls; + jfieldID enabled; + jfieldID headroomDb; + jfieldID maxGainDb; + jfieldID initialGainDb; + jfieldID maxGainChangeDbPerSecond; + jfieldID maxOutputNoiseLevelDbfs; + }; + + class JavaHighPassFilterClass : public JavaClass + { + public: + explicit JavaHighPassFilterClass(JNIEnv * env); + + jclass cls; + jfieldID enabled; + }; + + class JavaNoiseSuppressionClass : public JavaClass + { + public: + explicit JavaNoiseSuppressionClass(JNIEnv * env); + + jclass cls; + jfieldID enabled; + jfieldID level; + }; + } +} + #endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/include/media/video/VideoTrackDesktopSource.h b/webrtc-jni/src/main/cpp/include/media/video/VideoTrackDesktopSource.h index e52fd819..312758cd 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/VideoTrackDesktopSource.h +++ b/webrtc-jni/src/main/cpp/include/media/video/VideoTrackDesktopSource.h @@ -1,75 +1,75 @@ -/* - * Copyright 2019 Alex Andres - * - * 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 JNI_WEBRTC_MEDIA_VIDEO_TRACK_DESKTOP_SOURCE_H_ -#define JNI_WEBRTC_MEDIA_VIDEO_TRACK_DESKTOP_SOURCE_H_ - -#include "api/video/i420_buffer.h" -#include "media/base/adapted_video_track_source.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "rtc_base/thread.h" - -namespace jni -{ - class VideoTrackDesktopSource : public rtc::AdaptedVideoTrackSource, public webrtc::DesktopCapturer::Callback - { - public: - VideoTrackDesktopSource(); - ~VideoTrackDesktopSource(); - - void setSourceId(webrtc::DesktopCapturer::SourceId source, bool isWindow); - void setFrameRate(const uint16_t frameRate); - void setMaxFrameSize(webrtc::DesktopSize size); - void setFocusSelectedSource(bool focus); - - void start(); - void stop(); - void terminate(); - - // AdaptedVideoTrackSource implementation. - virtual bool is_screencast() const override; - virtual absl::optional needs_denoising() const override; - SourceState state() const override; - bool remote() const override; - - // DesktopCapturer::Callback implementation. - void OnCaptureResult(webrtc::DesktopCapturer::Result result, std::unique_ptr frame) override; - - private: - void capture(); - void process(std::unique_ptr & frame); - - private: - uint16_t frameRate; - bool isCapturing; - bool focusSelectedSource; - - webrtc::DesktopSize maxFrameSize; - - webrtc::MediaSourceInterface::SourceState sourceState; - - webrtc::DesktopCapturer::SourceId sourceId; - bool sourceIsWindow; - - std::unique_ptr lastFrame; - - std::unique_ptr captureThread; - - rtc::scoped_refptr buffer; - }; -} - +/* + * Copyright 2019 Alex Andres + * + * 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 JNI_WEBRTC_MEDIA_VIDEO_TRACK_DESKTOP_SOURCE_H_ +#define JNI_WEBRTC_MEDIA_VIDEO_TRACK_DESKTOP_SOURCE_H_ + +#include "api/video/i420_buffer.h" +#include "media/base/adapted_video_track_source.h" +#include "modules/desktop_capture/desktop_capturer.h" +#include "rtc_base/thread.h" + +namespace jni +{ + class VideoTrackDesktopSource : public rtc::AdaptedVideoTrackSource, public webrtc::DesktopCapturer::Callback + { + public: + VideoTrackDesktopSource(); + ~VideoTrackDesktopSource(); + + void setSourceId(webrtc::DesktopCapturer::SourceId source, bool isWindow); + void setFrameRate(const uint16_t frameRate); + void setMaxFrameSize(webrtc::DesktopSize size); + void setFocusSelectedSource(bool focus); + + void start(); + void stop(); + void terminate(); + + // AdaptedVideoTrackSource implementation. + virtual bool is_screencast() const override; + virtual std::optional needs_denoising() const override; + SourceState state() const override; + bool remote() const override; + + // DesktopCapturer::Callback implementation. + void OnCaptureResult(webrtc::DesktopCapturer::Result result, std::unique_ptr frame) override; + + private: + void capture(); + void process(std::unique_ptr & frame); + + private: + uint16_t frameRate; + bool isCapturing; + bool focusSelectedSource; + + webrtc::DesktopSize maxFrameSize; + + webrtc::MediaSourceInterface::SourceState sourceState; + + webrtc::DesktopCapturer::SourceId sourceId; + bool sourceIsWindow; + + std::unique_ptr lastFrame; + + std::unique_ptr captureThread; + + rtc::scoped_refptr buffer; + }; +} + #endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_AudioConverter.cpp b/webrtc-jni/src/main/cpp/src/JNI_AudioConverter.cpp index 0caf4633..47e1a336 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_AudioConverter.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_AudioConverter.cpp @@ -1,65 +1,66 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -#include "JNI_AudioConverter.h" -#include "media/audio/AudioConverter.h" -#include "JavaUtils.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioConverter_convertInternal -(JNIEnv * env, jobject caller, jbyteArray src, jint nSrcSamples, jbyteArray dst, jint nDstSamples) -{ - jni::AudioConverter * converter = GetHandle(env, caller); - CHECK_HANDLE(converter); - - jboolean isDstCopy = JNI_FALSE; - - jbyte * srcPtr = env->GetByteArrayElements(src, nullptr); - jbyte * dstPtr = env->GetByteArrayElements(dst, &isDstCopy); - - converter->convert(reinterpret_cast(srcPtr), nSrcSamples, reinterpret_cast(dstPtr), nDstSamples); - - if (isDstCopy == JNI_TRUE) { - jsize dstLength = env->GetArrayLength(dst); - - env->SetByteArrayRegion(dst, 0, dstLength, dstPtr); - } - - env->ReleaseByteArrayElements(src, srcPtr, JNI_ABORT); - env->ReleaseByteArrayElements(dst, dstPtr, JNI_ABORT); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioConverter_dispose -(JNIEnv * env, jobject caller) -{ - jni::AudioConverter * converter = GetHandle(env, caller); - CHECK_HANDLE(converter); - - SetHandle(env, caller, nullptr); - - delete converter; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioConverter_initialize -(JNIEnv * env, jobject caller, jint srcSampleRate, jint srcChannels, jint dstSampleRate, jint dstChannels) -{ - // 10 ms frames - size_t srcFrames = srcSampleRate / 100; - size_t dstFrames = dstSampleRate / 100; - - jni::AudioConverter * converter = jni::AudioConverter::create(srcFrames, srcChannels, dstFrames, dstChannels).release(); - - SetHandle(env, caller, converter); +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +#include "JNI_AudioConverter.h" +#include "api/audio/audio_processing.h" +#include "media/audio/AudioConverter.h" +#include "JavaUtils.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioConverter_convertInternal +(JNIEnv * env, jobject caller, jbyteArray src, jint nSrcSamples, jbyteArray dst, jint nDstSamples) +{ + jni::AudioConverter * converter = GetHandle(env, caller); + CHECK_HANDLE(converter); + + jboolean isDstCopy = JNI_FALSE; + + jbyte * srcPtr = env->GetByteArrayElements(src, nullptr); + jbyte * dstPtr = env->GetByteArrayElements(dst, &isDstCopy); + + converter->convert(reinterpret_cast(srcPtr), nSrcSamples, reinterpret_cast(dstPtr), nDstSamples); + + if (isDstCopy == JNI_TRUE) { + jsize dstLength = env->GetArrayLength(dst); + + env->SetByteArrayRegion(dst, 0, dstLength, dstPtr); + } + + env->ReleaseByteArrayElements(src, srcPtr, JNI_ABORT); + env->ReleaseByteArrayElements(dst, dstPtr, JNI_ABORT); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioConverter_dispose +(JNIEnv * env, jobject caller) +{ + jni::AudioConverter * converter = GetHandle(env, caller); + CHECK_HANDLE(converter); + + SetHandle(env, caller, nullptr); + + delete converter; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioConverter_initialize +(JNIEnv * env, jobject caller, jint srcSampleRate, jint srcChannels, jint dstSampleRate, jint dstChannels) +{ + // 10 ms frames + size_t srcFrames = webrtc::AudioProcessing::GetFrameSize(srcSampleRate); + size_t dstFrames = webrtc::AudioProcessing::GetFrameSize(dstSampleRate); + + jni::AudioConverter * converter = jni::AudioConverter::create(srcFrames, srcChannels, dstFrames, dstChannels).release(); + + SetHandle(env, caller, converter); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_AudioDeviceModule.cpp b/webrtc-jni/src/main/cpp/src/JNI_AudioDeviceModule.cpp index aebc6656..a9a425f5 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_AudioDeviceModule.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_AudioDeviceModule.cpp @@ -1,498 +1,498 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_AudioDeviceModule.h" -#include "Exception.h" -#include "JavaArrayList.h" -#include "JavaEnums.h" -#include "JavaError.h" -#include "JavaObject.h" -#include "JavaRef.h" -#include "JavaString.h" -#include "JavaUtils.h" -#include "media/audio/AudioDevice.h" -#include "media/audio/AudioTransportSink.h" -#include "media/audio/AudioTransportSource.h" - -#include "api/scoped_refptr.h" -#include "api/task_queue/default_task_queue_factory.h" -#include "modules/audio_device/include/audio_device.h" -#include "rtc_base/logging.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_initPlayout -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->InitPlayout() != 0) { - env->Throw(jni::JavaError(env, "Init playout failed")); - return; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_stopPlayout -(JNIEnv* env, jobject caller) -{ - webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->StopPlayout() != 0) { - env->Throw(jni::JavaError(env, "Stop playout failed")); - return; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_startPlayout -(JNIEnv* env, jobject caller) -{ - webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->StartPlayout() != 0) { - env->Throw(jni::JavaError(env, "Start playout failed")); - return; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_initRecording -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->InitRecording() != 0) { - env->Throw(jni::JavaError(env, "Init recording failed")); - return; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_stopRecording -(JNIEnv* env, jobject caller) -{ - webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->StopRecording() != 0) { - env->Throw(jni::JavaError(env, "Stop recording failed")); - return; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_startRecording -(JNIEnv* env, jobject caller) -{ - webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->StartRecording() != 0) { - env->Throw(jni::JavaError(env, "Start recording failed")); - return; - } -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getPlayoutDevices -(JNIEnv* env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, nullptr); - - char name[webrtc::kAdmMaxDeviceNameSize]; - char guid[webrtc::kAdmMaxGuidSize]; - - int16_t deviceCount = audioModule->PlayoutDevices(); - - jni::JavaArrayList deviceList(env, deviceCount); - - for (int i = 0; i < deviceCount; ++i) { - if (audioModule->PlayoutDeviceName(i, name, guid) == 0) { - auto device = std::make_shared(name, guid); - - deviceList.add(jni::AudioDevice::toJavaAudioDevice(env, device)); - } - } - - return deviceList.listObject().release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getRecordingDevices -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, nullptr); - - char name[webrtc::kAdmMaxDeviceNameSize]; - char guid[webrtc::kAdmMaxGuidSize]; - - int16_t deviceCount = audioModule->RecordingDevices(); - - jni::JavaArrayList deviceList(env, deviceCount); - - for (int i = 0; i < deviceCount; ++i) { - if (audioModule->RecordingDeviceName(i, name, guid) == 0) { - auto device = std::make_shared(name, guid); - - deviceList.add(jni::AudioDevice::toJavaAudioDevice(env, device)); - } - } - - return deviceList.listObject().release(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setPlayoutDevice -(JNIEnv * env, jobject caller, jobject device) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (!device) { - env->Throw(jni::JavaNullPointerException(env, "AudioDevice is null")); - return; - } - - jni::JavaObject obj(env, jni::JavaLocalRef(env, device)); - - const auto javaClass = jni::JavaClasses::get(env); - const std::string devGuid = jni::JavaString::toNative(env, obj.getString(javaClass->descriptor)); - - uint16_t index = 0; - int16_t deviceCount = audioModule->PlayoutDevices(); - - char name[webrtc::kAdmMaxDeviceNameSize]; - char guid[webrtc::kAdmMaxGuidSize]; - - for (int i = 0; i < deviceCount; ++i) { - if ((audioModule->PlayoutDeviceName(i, name, guid) == 0) && devGuid == std::string(guid)) { - index = i; - break; - } - } - - if (audioModule->SetPlayoutDevice(index) != 0) { - env->Throw(jni::JavaError(env, "Set playout device failed")); - return; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setRecordingDevice -(JNIEnv * env, jobject caller, jobject device) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (!device) { - env->Throw(jni::JavaNullPointerException(env, "AudioDevice is null")); - return; - } - - jni::JavaObject obj(env, jni::JavaLocalRef(env, device)); - - const auto javaClass = jni::JavaClasses::get(env); - const std::string devGuid = jni::JavaString::toNative(env, obj.getString(javaClass->descriptor)); - - uint16_t index = 0; - int16_t deviceCount = audioModule->RecordingDevices(); - - char name[webrtc::kAdmMaxDeviceNameSize]; - char guid[webrtc::kAdmMaxGuidSize]; - - for (int i = 0; i < deviceCount; ++i) { - if ((audioModule->RecordingDeviceName(i, name, guid) == 0) && devGuid == std::string(guid)) { - index = i; - break; - } - } - - if (audioModule->SetRecordingDevice(index) != 0) { - env->Throw(jni::JavaError(env, "Set recording device failed")); - return; - } -} - -JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_isSpeakerMuted -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, true); - - bool mute = true; - - audioModule->SpeakerMute(&mute); - - return mute; -} - -JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_isMicrophoneMuted -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, true); - - bool mute = true; - - audioModule->MicrophoneMute(&mute); - - return mute; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getSpeakerVolume -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - uint32_t volume = 0; - - if (audioModule->SpeakerVolume(&volume) != 0) { - env->Throw(jni::JavaError(env, "Get speaker volume failed")); - } - - return volume; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMaxSpeakerVolume -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - uint32_t volume = 0; - - if (audioModule->MaxSpeakerVolume(&volume) != 0) { - env->Throw(jni::JavaError(env, "Get max speaker volume failed")); - } - - return volume; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMinSpeakerVolume -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - uint32_t volume = 0; - - if (audioModule->MinSpeakerVolume(&volume) != 0) { - env->Throw(jni::JavaError(env, "Get min speaker volume failed")); - } - - return volume; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMicrophoneVolume -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - uint32_t volume = 0; - - if (audioModule->MicrophoneVolume(&volume) != 0) { - env->Throw(jni::JavaError(env, "Get microphone volume failed")); - } - - return volume; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMaxMicrophoneVolume -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - uint32_t volume = 0; - - if (audioModule->MaxMicrophoneVolume(&volume) != 0) { - env->Throw(jni::JavaError(env, "Get max microphone volume failed")); - } - - return volume; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMinMicrophoneVolume -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - uint32_t volume = 0; - - if (audioModule->MinMicrophoneVolume(&volume) != 0) { - env->Throw(jni::JavaError(env, "Get min microphone volume failed")); - } - - return volume; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setSpeakerVolume -(JNIEnv * env, jobject caller, jint volume) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->SetSpeakerVolume(static_cast(volume)) != 0) { - env->Throw(jni::JavaError(env, "Set speaker volume failed")); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setSpeakerMute -(JNIEnv * env, jobject caller, jboolean mute) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->SetSpeakerMute(mute) != 0) { - env->Throw(jni::JavaError(env, "Set speaker mute failed")); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setMicrophoneVolume -(JNIEnv * env, jobject caller, jint volume) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->SetMicrophoneVolume(static_cast(volume)) != 0) { - env->Throw(jni::JavaError(env, "Set microphone volume failed")); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setMicrophoneMute -(JNIEnv * env, jobject caller, jboolean mute) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->SetMicrophoneMute(mute) != 0) { - env->Throw(jni::JavaError(env, "Set microphone mute failed")); - } -} - -JNIEXPORT jlong JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_addSinkInternal -(JNIEnv * env, jobject caller, jobject jSink) -{ - if (jSink == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "AudioSink must not be null")); - return 0; - } - - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - auto sink = new jni::AudioTransportSink(env, jni::JavaGlobalRef(env, jSink)); - - audioModule->RegisterAudioCallback(sink); - - return reinterpret_cast(sink); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_removeSinkInternal -(JNIEnv * env, jobject caller, jlong sinkHandle) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - auto sink = reinterpret_cast(sinkHandle); - - if (sink != nullptr) { - audioModule->RegisterAudioCallback(nullptr); - - delete sink; - } -} - -JNIEXPORT jlong JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_addSourceInternal -(JNIEnv * env, jobject caller, jobject jSource) -{ - if (jSource == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "AudioSource must not be null")); - return 0; - } - - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLEV(audioModule, 0); - - auto source = new jni::AudioTransportSource(env, jni::JavaGlobalRef(env, jSource)); - - audioModule->RegisterAudioCallback(source); - - return reinterpret_cast(source); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_removeSourceInternal -(JNIEnv * env, jobject caller, jlong sourceHandle) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - auto source = reinterpret_cast(sourceHandle); - - if (source != nullptr) { - audioModule->RegisterAudioCallback(nullptr); - - delete source; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_disposeInternal -(JNIEnv * env, jobject caller) -{ - webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); - CHECK_HANDLE(audioModule); - - if (audioModule->Initialized()) { - audioModule->Terminate(); - } - - rtc::RefCountReleaseStatus status = audioModule->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; - } - - SetHandle(env, caller, nullptr); - - audioModule = nullptr; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_initialize -(JNIEnv * env, jobject caller, jobject jAudioLayer) -{ - std::unique_ptr taskQueueFactory = webrtc::CreateDefaultTaskQueueFactory(); - - if (!taskQueueFactory) { - env->Throw(jni::JavaError(env, "Create TaskQueueFactory failed")); - return; - } - - auto audioLayer = jni::JavaEnums::toNative(env, jAudioLayer); - - rtc::scoped_refptr audioModule = webrtc::AudioDeviceModule::Create( - audioLayer, taskQueueFactory.release()); - - if (!audioModule) { - env->Throw(jni::JavaError(env, "Create AudioDeviceModule failed")); - return; - } - - if (audioModule->Init() != 0) { - env->Throw(jni::JavaError(env, "Initialize AudioDeviceModule failed")); - return; - } - - SetHandle(env, caller, audioModule.release()); -} +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_AudioDeviceModule.h" +#include "Exception.h" +#include "JavaArrayList.h" +#include "JavaEnums.h" +#include "JavaError.h" +#include "JavaObject.h" +#include "JavaRef.h" +#include "JavaString.h" +#include "JavaUtils.h" +#include "media/audio/AudioDevice.h" +#include "media/audio/AudioTransportSink.h" +#include "media/audio/AudioTransportSource.h" + +#include "api/scoped_refptr.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "modules/audio_device/include/audio_device.h" +#include "rtc_base/logging.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_initPlayout +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->InitPlayout() != 0) { + env->Throw(jni::JavaError(env, "Init playout failed")); + return; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_stopPlayout +(JNIEnv* env, jobject caller) +{ + webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->StopPlayout() != 0) { + env->Throw(jni::JavaError(env, "Stop playout failed")); + return; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_startPlayout +(JNIEnv* env, jobject caller) +{ + webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->StartPlayout() != 0) { + env->Throw(jni::JavaError(env, "Start playout failed")); + return; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_initRecording +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->InitRecording() != 0) { + env->Throw(jni::JavaError(env, "Init recording failed")); + return; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_stopRecording +(JNIEnv* env, jobject caller) +{ + webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->StopRecording() != 0) { + env->Throw(jni::JavaError(env, "Stop recording failed")); + return; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_startRecording +(JNIEnv* env, jobject caller) +{ + webrtc::AudioDeviceModule* audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->StartRecording() != 0) { + env->Throw(jni::JavaError(env, "Start recording failed")); + return; + } +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getPlayoutDevices +(JNIEnv* env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, nullptr); + + char name[webrtc::kAdmMaxDeviceNameSize]; + char guid[webrtc::kAdmMaxGuidSize]; + + int16_t deviceCount = audioModule->PlayoutDevices(); + + jni::JavaArrayList deviceList(env, deviceCount); + + for (int i = 0; i < deviceCount; ++i) { + if (audioModule->PlayoutDeviceName(i, name, guid) == 0) { + auto device = std::make_shared(name, guid); + + deviceList.add(jni::AudioDevice::toJavaAudioDevice(env, device)); + } + } + + return deviceList.listObject().release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getRecordingDevices +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, nullptr); + + char name[webrtc::kAdmMaxDeviceNameSize]; + char guid[webrtc::kAdmMaxGuidSize]; + + int16_t deviceCount = audioModule->RecordingDevices(); + + jni::JavaArrayList deviceList(env, deviceCount); + + for (int i = 0; i < deviceCount; ++i) { + if (audioModule->RecordingDeviceName(i, name, guid) == 0) { + auto device = std::make_shared(name, guid); + + deviceList.add(jni::AudioDevice::toJavaAudioDevice(env, device)); + } + } + + return deviceList.listObject().release(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setPlayoutDevice +(JNIEnv * env, jobject caller, jobject device) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (!device) { + env->Throw(jni::JavaNullPointerException(env, "AudioDevice is null")); + return; + } + + jni::JavaObject obj(env, jni::JavaLocalRef(env, device)); + + const auto javaClass = jni::JavaClasses::get(env); + const std::string devGuid = jni::JavaString::toNative(env, obj.getString(javaClass->descriptor)); + + uint16_t index = 0; + int16_t deviceCount = audioModule->PlayoutDevices(); + + char name[webrtc::kAdmMaxDeviceNameSize]; + char guid[webrtc::kAdmMaxGuidSize]; + + for (int i = 0; i < deviceCount; ++i) { + if ((audioModule->PlayoutDeviceName(i, name, guid) == 0) && devGuid == std::string(guid)) { + index = i; + break; + } + } + + if (audioModule->SetPlayoutDevice(index) != 0) { + env->Throw(jni::JavaError(env, "Set playout device failed")); + return; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setRecordingDevice +(JNIEnv * env, jobject caller, jobject device) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (!device) { + env->Throw(jni::JavaNullPointerException(env, "AudioDevice is null")); + return; + } + + jni::JavaObject obj(env, jni::JavaLocalRef(env, device)); + + const auto javaClass = jni::JavaClasses::get(env); + const std::string devGuid = jni::JavaString::toNative(env, obj.getString(javaClass->descriptor)); + + uint16_t index = 0; + int16_t deviceCount = audioModule->RecordingDevices(); + + char name[webrtc::kAdmMaxDeviceNameSize]; + char guid[webrtc::kAdmMaxGuidSize]; + + for (int i = 0; i < deviceCount; ++i) { + if ((audioModule->RecordingDeviceName(i, name, guid) == 0) && devGuid == std::string(guid)) { + index = i; + break; + } + } + + if (audioModule->SetRecordingDevice(index) != 0) { + env->Throw(jni::JavaError(env, "Set recording device failed")); + return; + } +} + +JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_isSpeakerMuted +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, true); + + bool mute = true; + + audioModule->SpeakerMute(&mute); + + return mute; +} + +JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_isMicrophoneMuted +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, true); + + bool mute = true; + + audioModule->MicrophoneMute(&mute); + + return mute; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getSpeakerVolume +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + uint32_t volume = 0; + + if (audioModule->SpeakerVolume(&volume) != 0) { + env->Throw(jni::JavaError(env, "Get speaker volume failed")); + } + + return volume; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMaxSpeakerVolume +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + uint32_t volume = 0; + + if (audioModule->MaxSpeakerVolume(&volume) != 0) { + env->Throw(jni::JavaError(env, "Get max speaker volume failed")); + } + + return volume; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMinSpeakerVolume +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + uint32_t volume = 0; + + if (audioModule->MinSpeakerVolume(&volume) != 0) { + env->Throw(jni::JavaError(env, "Get min speaker volume failed")); + } + + return volume; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMicrophoneVolume +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + uint32_t volume = 0; + + if (audioModule->MicrophoneVolume(&volume) != 0) { + env->Throw(jni::JavaError(env, "Get microphone volume failed")); + } + + return volume; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMaxMicrophoneVolume +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + uint32_t volume = 0; + + if (audioModule->MaxMicrophoneVolume(&volume) != 0) { + env->Throw(jni::JavaError(env, "Get max microphone volume failed")); + } + + return volume; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_getMinMicrophoneVolume +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + uint32_t volume = 0; + + if (audioModule->MinMicrophoneVolume(&volume) != 0) { + env->Throw(jni::JavaError(env, "Get min microphone volume failed")); + } + + return volume; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setSpeakerVolume +(JNIEnv * env, jobject caller, jint volume) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->SetSpeakerVolume(static_cast(volume)) != 0) { + env->Throw(jni::JavaError(env, "Set speaker volume failed")); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setSpeakerMute +(JNIEnv * env, jobject caller, jboolean mute) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->SetSpeakerMute(mute) != 0) { + env->Throw(jni::JavaError(env, "Set speaker mute failed")); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setMicrophoneVolume +(JNIEnv * env, jobject caller, jint volume) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->SetMicrophoneVolume(static_cast(volume)) != 0) { + env->Throw(jni::JavaError(env, "Set microphone volume failed")); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_setMicrophoneMute +(JNIEnv * env, jobject caller, jboolean mute) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->SetMicrophoneMute(mute) != 0) { + env->Throw(jni::JavaError(env, "Set microphone mute failed")); + } +} + +JNIEXPORT jlong JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_addSinkInternal +(JNIEnv * env, jobject caller, jobject jSink) +{ + if (jSink == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "AudioSink must not be null")); + return 0; + } + + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + auto sink = new jni::AudioTransportSink(env, jni::JavaGlobalRef(env, jSink)); + + audioModule->RegisterAudioCallback(sink); + + return reinterpret_cast(sink); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_removeSinkInternal +(JNIEnv * env, jobject caller, jlong sinkHandle) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + auto sink = reinterpret_cast(sinkHandle); + + if (sink != nullptr) { + audioModule->RegisterAudioCallback(nullptr); + + delete sink; + } +} + +JNIEXPORT jlong JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_addSourceInternal +(JNIEnv * env, jobject caller, jobject jSource) +{ + if (jSource == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "AudioSource must not be null")); + return 0; + } + + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLEV(audioModule, 0); + + auto source = new jni::AudioTransportSource(env, jni::JavaGlobalRef(env, jSource)); + + audioModule->RegisterAudioCallback(source); + + return reinterpret_cast(source); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_removeSourceInternal +(JNIEnv * env, jobject caller, jlong sourceHandle) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + auto source = reinterpret_cast(sourceHandle); + + if (source != nullptr) { + audioModule->RegisterAudioCallback(nullptr); + + delete source; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_disposeInternal +(JNIEnv * env, jobject caller) +{ + webrtc::AudioDeviceModule * audioModule = GetHandle(env, caller); + CHECK_HANDLE(audioModule); + + if (audioModule->Initialized()) { + audioModule->Terminate(); + } + + webrtc::RefCountReleaseStatus status = audioModule->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; + } + + SetHandle(env, caller, nullptr); + + audioModule = nullptr; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioDeviceModule_initialize +(JNIEnv * env, jobject caller, jobject jAudioLayer) +{ + std::unique_ptr taskQueueFactory = webrtc::CreateDefaultTaskQueueFactory(); + + if (!taskQueueFactory) { + env->Throw(jni::JavaError(env, "Create TaskQueueFactory failed")); + return; + } + + auto audioLayer = jni::JavaEnums::toNative(env, jAudioLayer); + + rtc::scoped_refptr audioModule = webrtc::AudioDeviceModule::Create( + audioLayer, taskQueueFactory.release()); + + if (!audioModule) { + env->Throw(jni::JavaError(env, "Create AudioDeviceModule failed")); + return; + } + + if (audioModule->Init() != 0) { + env->Throw(jni::JavaError(env, "Initialize AudioDeviceModule failed")); + return; + } + + SetHandle(env, caller, audioModule.release()); +} diff --git a/webrtc-jni/src/main/cpp/src/JNI_AudioProcessing.cpp b/webrtc-jni/src/main/cpp/src/JNI_AudioProcessing.cpp index aa1985c6..da7feecd 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_AudioProcessing.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_AudioProcessing.cpp @@ -1,215 +1,218 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -#include "JNI_AudioProcessing.h" -#include "Exception.h" -#include "JavaArrayList.h" -#include "JavaEnums.h" -#include "JavaError.h" -#include "JavaObject.h" -#include "JavaRef.h" -#include "JavaString.h" -#include "JavaUtils.h" - -#include "media/audio/AudioProcessing.h" -#include "media/audio/AudioProcessingConfig.h" -#include "media/audio/AudioProcessingStreamConfig.h" -#include "api/audio/audio_frame.h" -#include "api/scoped_refptr.h" -#include "modules/audio_processing/include/audio_processing.h" -#include "rtc_base/logging.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_applyConfig -(JNIEnv * env, jobject caller, jobject config) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLE(apm); - - apm->ApplyConfig(jni::AudioProcessingConfig::toNative(env, jni::JavaLocalRef(env, config))); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_setStreamDelayMs -(JNIEnv * env, jobject caller, jint delayMs) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLE(apm); - - apm->set_stream_delay_ms(delayMs); -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_getStreamDelayMs -(JNIEnv * env, jobject caller) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLEV(apm, 0); - - return apm->stream_delay_ms(); -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_processStream -(JNIEnv * env, jobject caller, jbyteArray src, jobject inputConfig, jobject outputConfig, jbyteArray dest) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLEV(apm, 0); - - webrtc::StreamConfig srcConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, inputConfig)); - webrtc::StreamConfig dstConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, outputConfig)); - - jboolean isDstCopy = JNI_FALSE; - - jbyte * srcPtr = env->GetByteArrayElements(src, NULL); - jbyte * dstPtr = env->GetByteArrayElements(dest, &isDstCopy); - - const int16_t * srcFrame = reinterpret_cast(srcPtr); - int16_t * dstFrame = reinterpret_cast(dstPtr); - - int result; - - if (srcConfig.num_channels() == 1 && dstConfig.num_channels() == 2) { - // Up-mixing, only mono to stereo. - // For complex channel layouts a channel mixer is required. - - const size_t srcNumSamples = srcConfig.num_samples(); - const size_t dstNumChannels = dstConfig.num_channels(); - const size_t frameSize = srcNumSamples * dstNumChannels; - - if (frameSize > webrtc::AudioFrame::kMaxDataSizeSamples) { - return -9; - } - - for (int i = static_cast(srcNumSamples) - 1; i >= 0; i--) { - for (size_t j = 0; j < dstNumChannels; ++j) { - dstFrame[dstNumChannels * i + j] = srcFrame[i]; - } - } - - srcConfig.set_num_channels(dstNumChannels); - - result = apm->ProcessStream(dstFrame, srcConfig, dstConfig, dstFrame); - } - else { - // Will also down-mix if required, e.g. from stereo to mono. - result = apm->ProcessStream(srcFrame, srcConfig, dstConfig, dstFrame); - } - - if (isDstCopy == JNI_TRUE) { - jsize dstLength = env->GetArrayLength(dest); - - env->SetByteArrayRegion(dest, 0, dstLength, dstPtr); - } - - env->ReleaseByteArrayElements(src, srcPtr, JNI_ABORT); - env->ReleaseByteArrayElements(dest, dstPtr, JNI_ABORT); - - return result; -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_processReverseStream -(JNIEnv * env, jobject caller, jbyteArray src, jobject inputConfig, jobject outputConfig, jbyteArray dest) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLEV(apm, 0); - - webrtc::StreamConfig srcConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, inputConfig)); - webrtc::StreamConfig dstConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, outputConfig)); - - jboolean isDstCopy = JNI_FALSE; - - jbyte * srcPtr = env->GetByteArrayElements(src, nullptr); - jbyte * dstPtr = env->GetByteArrayElements(dest, &isDstCopy); - - const int16_t * srcFrame = reinterpret_cast(srcPtr); - int16_t * dstFrame = reinterpret_cast(dstPtr); - - int result; - - if (srcConfig.num_channels() == 1 && dstConfig.num_channels() == 2) { - // Up-mixing, only mono to stereo. - // For complex channel layouts a channel mixer is required. - - const size_t srcNumSamples = srcConfig.num_samples(); - const size_t dstNumChannels = dstConfig.num_channels(); - const size_t frameSize = srcNumSamples * dstNumChannels; - - if (frameSize > webrtc::AudioFrame::kMaxDataSizeSamples) { - return -9; - } - - for (int i = static_cast(srcNumSamples) - 1; i >= 0; i--) { - for (size_t j = 0; j < dstNumChannels; ++j) { - dstFrame[dstNumChannels * i + j] = srcFrame[i]; - } - } - - srcConfig.set_num_channels(dstNumChannels); - - result = apm->ProcessReverseStream(dstFrame, srcConfig, dstConfig, dstFrame); - } - else { - // Will also down-mix if required, e.g. from stereo to mono. - result = apm->ProcessReverseStream(srcFrame, srcConfig, dstConfig, dstFrame); - } - - if (isDstCopy == JNI_TRUE) { - jsize dstLength = env->GetArrayLength(dest); - - env->SetByteArrayRegion(dest, 0, dstLength, dstPtr); - } - - env->ReleaseByteArrayElements(src, srcPtr, JNI_ABORT); - env->ReleaseByteArrayElements(dest, dstPtr, JNI_ABORT); - - return result; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_dispose -(JNIEnv * env, jobject caller) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLE(apm); - - rtc::RefCountReleaseStatus status = apm->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; - } - - SetHandle(env, caller, nullptr); - - apm = nullptr; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_initialize -(JNIEnv * env, jobject caller) -{ - rtc::scoped_refptr apm = webrtc::AudioProcessingBuilder().Create(); - - if (!apm) { - env->Throw(jni::JavaError(env, "Create AudioProcessing failed")); - return; - } - - SetHandle(env, caller, apm.release()); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_updateStats -(JNIEnv* env, jobject caller) -{ - webrtc::AudioProcessing * apm = GetHandle(env, caller); - CHECK_HANDLE(apm); - - jni::AudioProcessing::updateStats(apm->GetStatistics(), env, jni::JavaLocalRef(env, caller)); +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +#include "JNI_AudioProcessing.h" +#include "Exception.h" +#include "JavaArrayList.h" +#include "JavaEnums.h" +#include "JavaError.h" +#include "JavaObject.h" +#include "JavaRef.h" +#include "JavaString.h" +#include "JavaUtils.h" + +#include "media/audio/AudioProcessing.h" +#include "media/audio/AudioProcessingConfig.h" +#include "media/audio/AudioProcessingStreamConfig.h" +#include "api/audio/audio_frame.h" +#include "api/audio/audio_processing.h" +#include "api/audio/builtin_audio_processing_builder.h" +#include "api/environment/environment_factory.h" +#include "api/scoped_refptr.h" +#include "modules/audio_processing/include/audio_processing.h" +#include "rtc_base/logging.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_applyConfig +(JNIEnv * env, jobject caller, jobject config) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLE(apm); + + apm->ApplyConfig(jni::AudioProcessingConfig::toNative(env, jni::JavaLocalRef(env, config))); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_setStreamDelayMs +(JNIEnv * env, jobject caller, jint delayMs) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLE(apm); + + apm->set_stream_delay_ms(delayMs); +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_getStreamDelayMs +(JNIEnv * env, jobject caller) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLEV(apm, 0); + + return apm->stream_delay_ms(); +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_processStream +(JNIEnv * env, jobject caller, jbyteArray src, jobject inputConfig, jobject outputConfig, jbyteArray dest) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLEV(apm, 0); + + webrtc::StreamConfig srcConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, inputConfig)); + webrtc::StreamConfig dstConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, outputConfig)); + + jboolean isDstCopy = JNI_FALSE; + + jbyte * srcPtr = env->GetByteArrayElements(src, NULL); + jbyte * dstPtr = env->GetByteArrayElements(dest, &isDstCopy); + + const int16_t * srcFrame = reinterpret_cast(srcPtr); + int16_t * dstFrame = reinterpret_cast(dstPtr); + + int result; + + if (srcConfig.num_channels() == 1 && dstConfig.num_channels() == 2) { + // Up-mixing, only mono to stereo. + // For complex channel layouts a channel mixer is required. + + const size_t srcNumSamples = srcConfig.num_samples(); + const size_t dstNumChannels = dstConfig.num_channels(); + const size_t frameSize = srcNumSamples * dstNumChannels; + + if (frameSize > webrtc::AudioFrame::kMaxDataSizeSamples) { + return -9; + } + + for (int i = static_cast(srcNumSamples) - 1; i >= 0; i--) { + for (size_t j = 0; j < dstNumChannels; ++j) { + dstFrame[dstNumChannels * i + j] = srcFrame[i]; + } + } + + srcConfig.set_num_channels(dstNumChannels); + + result = apm->ProcessStream(dstFrame, srcConfig, dstConfig, dstFrame); + } + else { + // Will also down-mix if required, e.g. from stereo to mono. + result = apm->ProcessStream(srcFrame, srcConfig, dstConfig, dstFrame); + } + + if (isDstCopy == JNI_TRUE) { + jsize dstLength = env->GetArrayLength(dest); + + env->SetByteArrayRegion(dest, 0, dstLength, dstPtr); + } + + env->ReleaseByteArrayElements(src, srcPtr, JNI_ABORT); + env->ReleaseByteArrayElements(dest, dstPtr, JNI_ABORT); + + return result; +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_processReverseStream +(JNIEnv * env, jobject caller, jbyteArray src, jobject inputConfig, jobject outputConfig, jbyteArray dest) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLEV(apm, 0); + + webrtc::StreamConfig srcConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, inputConfig)); + webrtc::StreamConfig dstConfig = jni::AudioProcessingStreamConfig::toNative(env, jni::JavaLocalRef(env, outputConfig)); + + jboolean isDstCopy = JNI_FALSE; + + jbyte * srcPtr = env->GetByteArrayElements(src, nullptr); + jbyte * dstPtr = env->GetByteArrayElements(dest, &isDstCopy); + + const int16_t * srcFrame = reinterpret_cast(srcPtr); + int16_t * dstFrame = reinterpret_cast(dstPtr); + + int result; + + if (srcConfig.num_channels() == 1 && dstConfig.num_channels() == 2) { + // Up-mixing, only mono to stereo. + // For complex channel layouts a channel mixer is required. + + const size_t srcNumSamples = srcConfig.num_samples(); + const size_t dstNumChannels = dstConfig.num_channels(); + const size_t frameSize = srcNumSamples * dstNumChannels; + + if (frameSize > webrtc::AudioFrame::kMaxDataSizeSamples) { + return -9; + } + + for (int i = static_cast(srcNumSamples) - 1; i >= 0; i--) { + for (size_t j = 0; j < dstNumChannels; ++j) { + dstFrame[dstNumChannels * i + j] = srcFrame[i]; + } + } + + srcConfig.set_num_channels(dstNumChannels); + + result = apm->ProcessReverseStream(dstFrame, srcConfig, dstConfig, dstFrame); + } + else { + // Will also down-mix if required, e.g. from stereo to mono. + result = apm->ProcessReverseStream(srcFrame, srcConfig, dstConfig, dstFrame); + } + + if (isDstCopy == JNI_TRUE) { + jsize dstLength = env->GetArrayLength(dest); + + env->SetByteArrayRegion(dest, 0, dstLength, dstPtr); + } + + env->ReleaseByteArrayElements(src, srcPtr, JNI_ABORT); + env->ReleaseByteArrayElements(dest, dstPtr, JNI_ABORT); + + return result; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLE(apm); + + webrtc::RefCountReleaseStatus status = apm->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; + } + + SetHandle(env, caller, nullptr); + + apm = nullptr; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_initialize +(JNIEnv * env, jobject caller) +{ + rtc::scoped_refptr apm = webrtc::BuiltinAudioProcessingBuilder().Build(webrtc::CreateEnvironment()); + + if (!apm) { + env->Throw(jni::JavaError(env, "Create AudioProcessing failed")); + return; + } + + SetHandle(env, caller, apm.release()); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioProcessing_updateStats +(JNIEnv* env, jobject caller) +{ + webrtc::AudioProcessing * apm = GetHandle(env, caller); + CHECK_HANDLE(apm); + + jni::AudioProcessing::updateStats(apm->GetStatistics(), env, jni::JavaLocalRef(env, caller)); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp b/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp index e5989b05..d5874599 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp @@ -1,76 +1,81 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -#include "JNI_AudioResampler.h" -#include "Exception.h" -#include "JavaObject.h" -#include "JavaRef.h" -#include "JavaUtils.h" - -#include "common_audio/resampler/include/push_resampler.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_dispose -(JNIEnv * env, jobject caller) -{ - webrtc::PushResampler * resampler = GetHandle>(env, caller); - CHECK_HANDLE(resampler); - - delete resampler; - - SetHandle(env, caller, nullptr); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_initialize -(JNIEnv * env, jobject caller) -{ - webrtc::PushResampler * resampler = new webrtc::PushResampler(); - - SetHandle(env, caller, resampler); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resetInternal -(JNIEnv* env, jobject caller, jint sourceRate, jint targetRate, jint channels) -{ - webrtc::PushResampler * resampler = GetHandle>(env, caller); - CHECK_HANDLE(resampler); - - resampler->InitializeIfNeeded(sourceRate, targetRate, channels); -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resampleInternal -(JNIEnv * env, jobject caller, jbyteArray samplesIn, jint nSamplesIn, jbyteArray samplesOut, jint maxSamplesOut) -{ - webrtc::PushResampler * resampler = GetHandle>(env, caller); - CHECK_HANDLEV(resampler, -1); - - jboolean isDstCopy = JNI_FALSE; - - jbyte * srcPtr = env->GetByteArrayElements(samplesIn, nullptr); - jbyte * dstPtr = env->GetByteArrayElements(samplesOut, &isDstCopy); - - size_t result = resampler->Resample(reinterpret_cast(srcPtr), nSamplesIn, reinterpret_cast(dstPtr), maxSamplesOut); - - if (isDstCopy == JNI_TRUE) { - jsize dstLength = env->GetArrayLength(samplesOut); - - env->SetByteArrayRegion(samplesOut, 0, dstLength, dstPtr); - } - - env->ReleaseByteArrayElements(samplesIn, srcPtr, JNI_ABORT); - env->ReleaseByteArrayElements(samplesOut, dstPtr, JNI_ABORT); - - return static_cast(result); -} +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +#include "JNI_AudioResampler.h" +#include "Exception.h" +#include "JavaObject.h" +#include "JavaRef.h" +#include "JavaUtils.h" + +#include "common_audio/resampler/include/push_resampler.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::PushResampler * resampler = GetHandle>(env, caller); + CHECK_HANDLE(resampler); + + delete resampler; + + SetHandle(env, caller, nullptr); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_initialize +(JNIEnv * env, jobject caller) +{ + webrtc::PushResampler * resampler = new webrtc::PushResampler(); + + SetHandle(env, caller, resampler); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_initialize +(JNIEnv* env, jobject caller, jint srcSamplesPerChannel, jint dstSamplesPerChannel, jint channels) +{ + webrtc::PushResampler * resampler = new webrtc::PushResampler(srcSamplesPerChannel, dstSamplesPerChannel, channels); + + SetHandle(env, caller, resampler); +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resample +(JNIEnv * env, jobject caller, jbyteArray samplesIn, jint srcSamplesPerChannel, jbyteArray samplesOut, jint dstSamplesPerChannel, jint channels) +{ + webrtc::PushResampler * resampler = GetHandle>(env, caller); + CHECK_HANDLEV(resampler, -1); + + jboolean isDstCopy = JNI_FALSE; + + jbyte * srcPtr = env->GetByteArrayElements(samplesIn, nullptr); + jbyte * dstPtr = env->GetByteArrayElements(samplesOut, &isDstCopy); + + int16_t * src16Ptr = reinterpret_cast(srcPtr); + int16_t * dst16Ptr = reinterpret_cast(dstPtr); + + webrtc::InterleavedView src(src16Ptr, srcSamplesPerChannel, channels); + webrtc::InterleavedView dst(dst16Ptr, dstSamplesPerChannel, channels); + + size_t result = resampler->Resample(src, dst); + + if (isDstCopy == JNI_TRUE) { + jsize dstLength = env->GetArrayLength(samplesOut); + + env->SetByteArrayRegion(samplesOut, 0, dstLength, dstPtr); + } + + env->ReleaseByteArrayElements(samplesIn, srcPtr, JNI_ABORT); + env->ReleaseByteArrayElements(samplesOut, dstPtr, JNI_ABORT); + + return static_cast(result); +} diff --git a/webrtc-jni/src/main/cpp/src/JNI_MediaStream.cpp b/webrtc-jni/src/main/cpp/src/JNI_MediaStream.cpp index 14c2c909..efd192f9 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_MediaStream.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_MediaStream.cpp @@ -1,121 +1,121 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_MediaStream.h" -#include "api/WebRTCUtils.h" -#include "JavaError.h" -#include "JavaFactories.h" -#include "JavaString.h" -#include "JavaUtils.h" - -#include "api/media_stream_interface.h" -#include "rtc_base/logging.h" - -JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_media_MediaStream_id -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamInterface * stream = GetHandle(env, caller); - CHECK_HANDLEV(stream, nullptr); - - return jni::JavaString::toJava(env, stream->id()); -} - -JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_media_MediaStream_getAudioTracks -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamInterface * stream = GetHandle(env, caller); - CHECK_HANDLEV(stream, nullptr); - - jni::JavaLocalRef objectArray; - - try { - objectArray = jni::createObjectArray(env, stream->GetAudioTracks()); - } - catch (...) { - ThrowCxxJavaException(env); - } - - return objectArray; -} - -JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_media_MediaStream_getVideoTracks -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamInterface * stream = GetHandle(env, caller); - CHECK_HANDLEV(stream, nullptr); - - jni::JavaLocalRef objectArray; - - try { - objectArray = jni::createObjectArray(env, stream->GetVideoTracks()); - } - catch (...) { - ThrowCxxJavaException(env); - } - - return objectArray; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStream_addTrack -(JNIEnv * env, jobject caller, jobject jTrack) -{ - webrtc::MediaStreamInterface * stream = GetHandle(env, caller); - CHECK_HANDLE(stream); - - webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); - CHECK_HANDLE(track); - - if (webrtc::AudioTrackInterface * t = dynamic_cast(track)) { - stream->AddTrack(t); - } - else if (webrtc::VideoTrackInterface * t = dynamic_cast(track)) { - stream->AddTrack(t); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStream_removeTrack -(JNIEnv * env, jobject caller, jobject jTrack) -{ - webrtc::MediaStreamInterface * stream = GetHandle(env, caller); - CHECK_HANDLE(stream); - - webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); - CHECK_HANDLE(track); - - if (webrtc::AudioTrackInterface * t = dynamic_cast(track)) { - stream->RemoveTrack(t); - } - else if (webrtc::VideoTrackInterface * t = dynamic_cast(track)) { - stream->RemoveTrack(t); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStream_dispose -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamInterface * stream = GetHandle(env, caller); - CHECK_HANDLE(stream); - - rtc::RefCountReleaseStatus status = stream->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; - } - - SetHandle(env, caller, nullptr); - - stream = nullptr; +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_MediaStream.h" +#include "api/WebRTCUtils.h" +#include "JavaError.h" +#include "JavaFactories.h" +#include "JavaString.h" +#include "JavaUtils.h" + +#include "api/media_stream_interface.h" +#include "rtc_base/logging.h" + +JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_media_MediaStream_id +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamInterface * stream = GetHandle(env, caller); + CHECK_HANDLEV(stream, nullptr); + + return jni::JavaString::toJava(env, stream->id()); +} + +JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_media_MediaStream_getAudioTracks +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamInterface * stream = GetHandle(env, caller); + CHECK_HANDLEV(stream, nullptr); + + jni::JavaLocalRef objectArray; + + try { + objectArray = jni::createObjectArray(env, stream->GetAudioTracks()); + } + catch (...) { + ThrowCxxJavaException(env); + } + + return objectArray; +} + +JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_media_MediaStream_getVideoTracks +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamInterface * stream = GetHandle(env, caller); + CHECK_HANDLEV(stream, nullptr); + + jni::JavaLocalRef objectArray; + + try { + objectArray = jni::createObjectArray(env, stream->GetVideoTracks()); + } + catch (...) { + ThrowCxxJavaException(env); + } + + return objectArray; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStream_addTrack +(JNIEnv * env, jobject caller, jobject jTrack) +{ + webrtc::MediaStreamInterface * stream = GetHandle(env, caller); + CHECK_HANDLE(stream); + + webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); + CHECK_HANDLE(track); + + if (webrtc::AudioTrackInterface * t = dynamic_cast(track)) { + stream->AddTrack(rtc::scoped_refptr(t)); + } + else if (webrtc::VideoTrackInterface * t = dynamic_cast(track)) { + stream->AddTrack(rtc::scoped_refptr(t)); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStream_removeTrack +(JNIEnv * env, jobject caller, jobject jTrack) +{ + webrtc::MediaStreamInterface * stream = GetHandle(env, caller); + CHECK_HANDLE(stream); + + webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); + CHECK_HANDLE(track); + + if (webrtc::AudioTrackInterface * t = dynamic_cast(track)) { + stream->RemoveTrack(rtc::scoped_refptr(t)); + } + else if (webrtc::VideoTrackInterface * t = dynamic_cast(track)) { + stream->RemoveTrack(rtc::scoped_refptr(t)); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStream_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamInterface * stream = GetHandle(env, caller); + CHECK_HANDLE(stream); + + webrtc::RefCountReleaseStatus status = stream->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; + } + + SetHandle(env, caller, nullptr); + + stream = nullptr; } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp b/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp index a668e674..b6ad5be2 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp @@ -1,172 +1,172 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_MediaStreamTrack.h" -#include "JavaContext.h" -#include "JavaEnums.h" -#include "JavaError.h" -#include "JavaFactories.h" -#include "JavaString.h" -#include "WebRTCContext.h" - -#include "media/MediaStreamTrackObserver.h" - -#include "api/media_stream_interface.h" -#include "rtc_base/logging.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_dispose -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLE(track); - - rtc::RefCountReleaseStatus status = track->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - env->Throw(jni::JavaError(env, "Native object was not deleted. A reference is still around somewhere.")); - } - else { - SetHandle(env, caller, nullptr); - track = nullptr; - } -} - -JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_getKind -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLEV(track, nullptr); - - return jni::JavaString::toJava(env, track->kind()).release(); -} - -JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_getId -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLEV(track, nullptr); - - return jni::JavaString::toJava(env, track->id()).release(); -} - -JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_isEnabled -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLEV(track, false); - - return static_cast(track->enabled()); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_setEnabled -(JNIEnv * env, jobject caller, jboolean enabled) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLE(track); - - track->set_enabled(static_cast(enabled)); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_getState -(JNIEnv * env, jobject caller) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLEV(track, nullptr); - - return jni::JavaEnums::toJava(env, track->state()).release(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_addEndedEventListener -(JNIEnv * env, jobject caller, jobject jListener) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLE(track); - - jni::WebRTCContext * context = static_cast(javaContext); - - try { - jni::MediaStreamTrackObserver * observer = new jni::MediaStreamTrackObserver(env, jni::JavaGlobalRef(env, jListener), track, jni::MediaStreamTrackEvent::ended); - auto observerPtr = std::shared_ptr(observer); - - track->RegisterObserver(observer); - - javaContext->addNativeRef(env, jni::JavaLocalRef(env, jListener), observerPtr); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_removeEndedEventListener -(JNIEnv * env, jobject caller, jobject jListener) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLE(track); - - jni::WebRTCContext * context = static_cast(javaContext); - - try { - auto observerPtr = javaContext->removeNativeRef(env, jni::JavaLocalRef(env, jListener)); - - if (observerPtr) { - track->UnregisterObserver(observerPtr.get()); - } - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_addMuteEventListener -(JNIEnv * env, jobject caller, jobject jListener) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLE(track); - - jni::WebRTCContext * context = static_cast(javaContext); - - try { - jni::MediaStreamTrackObserver * observer = new jni::MediaStreamTrackObserver(env, jni::JavaGlobalRef(env, jListener), track, jni::MediaStreamTrackEvent::mute); - auto observerPtr = std::shared_ptr(observer); - - track->RegisterObserver(observer); - - javaContext->addNativeRef(env, jni::JavaLocalRef(env, jListener), observerPtr); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_removeMuteEventListener -(JNIEnv * env, jobject caller, jobject jListener) -{ - webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); - CHECK_HANDLE(track); - - jni::WebRTCContext * context = static_cast(javaContext); - - try { - auto observerPtr = javaContext->removeNativeRef(env, jni::JavaLocalRef(env, jListener)); - - if (observerPtr) { - track->UnregisterObserver(observerPtr.get()); - } - } - catch (...) { - ThrowCxxJavaException(env); - } -} +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_MediaStreamTrack.h" +#include "JavaContext.h" +#include "JavaEnums.h" +#include "JavaError.h" +#include "JavaFactories.h" +#include "JavaString.h" +#include "WebRTCContext.h" + +#include "media/MediaStreamTrackObserver.h" + +#include "api/media_stream_interface.h" +#include "rtc_base/logging.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLE(track); + + webrtc::RefCountReleaseStatus status = track->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + env->Throw(jni::JavaError(env, "Native object was not deleted. A reference is still around somewhere.")); + } + else { + SetHandle(env, caller, nullptr); + track = nullptr; + } +} + +JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_getKind +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLEV(track, nullptr); + + return jni::JavaString::toJava(env, track->kind()).release(); +} + +JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_getId +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLEV(track, nullptr); + + return jni::JavaString::toJava(env, track->id()).release(); +} + +JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_isEnabled +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLEV(track, false); + + return static_cast(track->enabled()); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_setEnabled +(JNIEnv * env, jobject caller, jboolean enabled) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLE(track); + + track->set_enabled(static_cast(enabled)); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_getState +(JNIEnv * env, jobject caller) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLEV(track, nullptr); + + return jni::JavaEnums::toJava(env, track->state()).release(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_addEndedEventListener +(JNIEnv * env, jobject caller, jobject jListener) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLE(track); + + jni::WebRTCContext * context = static_cast(javaContext); + + try { + jni::MediaStreamTrackObserver * observer = new jni::MediaStreamTrackObserver(env, jni::JavaGlobalRef(env, jListener), track, jni::MediaStreamTrackEvent::ended); + auto observerPtr = std::shared_ptr(observer); + + track->RegisterObserver(observer); + + javaContext->addNativeRef(env, jni::JavaLocalRef(env, jListener), observerPtr); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_removeEndedEventListener +(JNIEnv * env, jobject caller, jobject jListener) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLE(track); + + jni::WebRTCContext * context = static_cast(javaContext); + + try { + auto observerPtr = javaContext->removeNativeRef(env, jni::JavaLocalRef(env, jListener)); + + if (observerPtr) { + track->UnregisterObserver(observerPtr.get()); + } + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_addMuteEventListener +(JNIEnv * env, jobject caller, jobject jListener) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLE(track); + + jni::WebRTCContext * context = static_cast(javaContext); + + try { + jni::MediaStreamTrackObserver * observer = new jni::MediaStreamTrackObserver(env, jni::JavaGlobalRef(env, jListener), track, jni::MediaStreamTrackEvent::mute); + auto observerPtr = std::shared_ptr(observer); + + track->RegisterObserver(observer); + + javaContext->addNativeRef(env, jni::JavaLocalRef(env, jListener), observerPtr); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_removeMuteEventListener +(JNIEnv * env, jobject caller, jobject jListener) +{ + webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); + CHECK_HANDLE(track); + + jni::WebRTCContext * context = static_cast(javaContext); + + try { + auto observerPtr = javaContext->removeNativeRef(env, jni::JavaLocalRef(env, jListener)); + + if (observerPtr) { + track->UnregisterObserver(observerPtr.get()); + } + } + catch (...) { + ThrowCxxJavaException(env); + } +} diff --git a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp index df038f9e..52a48df7 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp @@ -1,267 +1,268 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_PeerConnectionFactory.h" -#include "api/AudioOptions.h" -#include "api/CreateSessionDescriptionObserver.h" -#include "api/PeerConnectionObserver.h" -#include "api/RTCConfiguration.h" -#include "api/RTCRtpCapabilities.h" -#include "JavaEnums.h" -#include "JavaError.h" -#include "JavaFactories.h" -#include "JavaNullPointerException.h" -#include "JavaRuntimeException.h" -#include "JavaRef.h" -#include "JavaString.h" -#include "JavaUtils.h" - -#include "api/create_peerconnection_factory.h" -#include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "api/audio_codecs/builtin_audio_encoder_factory.h" -#include "api/video_codecs/builtin_video_decoder_factory.h" -#include "api/video_codecs/builtin_video_encoder_factory.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_initialize -(JNIEnv * env, jobject caller, jobject audioModule, jobject audioProcessing) -{ - webrtc::AudioDeviceModule * audioDevModule = (audioModule != nullptr) - ? GetHandle(env, audioModule) - : nullptr; - - try { - auto networkThread = rtc::Thread::CreateWithSocketServer(); - auto signalingThread = rtc::Thread::Create(); - auto workerThread = rtc::Thread::Create(); - - if (!networkThread->Start()) { - throw jni::Exception("Start network thread failed"); - } - if (!signalingThread->Start()) { - throw jni::Exception("Start signaling thread failed"); - } - if (!workerThread->Start()) { - throw jni::Exception("Start worker thread failed"); - } - - webrtc::AudioProcessing * processing = (audioProcessing != nullptr) - ? GetHandle(env, audioProcessing) - : nullptr; - rtc::scoped_refptr apm(processing); - - auto factory = webrtc::CreatePeerConnectionFactory( - networkThread.get(), - workerThread.get(), - signalingThread.get(), - audioDevModule, - webrtc::CreateBuiltinAudioEncoderFactory(), - webrtc::CreateBuiltinAudioDecoderFactory(), - webrtc::CreateBuiltinVideoEncoderFactory(), - webrtc::CreateBuiltinVideoDecoderFactory(), - nullptr, - apm); - - if (factory != nullptr) { - SetHandle(env, caller, factory.release()); - SetHandle(env, caller, "networkThreadHandle", networkThread.release()); - SetHandle(env, caller, "signalingThreadHandle", signalingThread.release()); - SetHandle(env, caller, "workerThreadHandle", workerThread.release()); - } - else { - throw jni::Exception("Create PeerConnectionFactory failed"); - } - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_dispose -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLE(factory); - - rtc::Thread * networkThread = GetHandle(env, caller, "networkThreadHandle"); - rtc::Thread * signalingThread = GetHandle(env, caller, "signalingThreadHandle"); - rtc::Thread * workerThread = GetHandle(env, caller, "workerThreadHandle"); - - rtc::RefCountReleaseStatus status = factory->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - env->Throw(jni::JavaError(env, "Native object was not deleted. A reference is still around somewhere.")); - } - - SetHandle(env, caller, nullptr); - - factory = nullptr; - - try { - if (networkThread) { - networkThread->Stop(); - delete networkThread; - } - if (signalingThread) { - signalingThread->Stop(); - delete signalingThread; - } - if (workerThread) { - workerThread->Stop(); - delete workerThread; - } - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createAudioSource -(JNIEnv * env, jobject caller, jobject jAudioOptions) -{ - if (jAudioOptions == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "AudioOptions is null")); - return nullptr; - } - - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLEV(factory, nullptr); - - auto audioOptions = jni::AudioOptions::toNative(env, jni::JavaLocalRef(env, jAudioOptions)); - - rtc::scoped_refptr audioSource = factory->CreateAudioSource(audioOptions); - - if (audioSource == nullptr) { - env->Throw(jni::JavaError(env, "Create audio-track source failed")); - return nullptr; - } - - return jni::JavaFactories::create(env, audioSource.release()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createAudioTrack -(JNIEnv * env, jobject caller, jstring jlabel, jobject jsource) -{ - if (jlabel == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "Audio track label is null")); - return nullptr; - } - if (jsource == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "AudioTrackSource is null")); - return nullptr; - } - - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLEV(factory, nullptr); - - webrtc::AudioSourceInterface * source = GetHandle(env, jsource); - CHECK_HANDLEV(source, nullptr); - - std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jlabel)); - - rtc::scoped_refptr audioTrack = factory->CreateAudioTrack(label, source); - - return jni::JavaFactories::create(env, audioTrack.release()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createVideoTrack -(JNIEnv * env, jobject caller, jstring jlabel, jobject jsource) -{ - if (jlabel == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "Video track label is null")); - return nullptr; - } - if (jsource == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "VideoTrackSource is null")); - return nullptr; - } - - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLEV(factory, nullptr); - - webrtc::VideoTrackSourceInterface * source = GetHandle(env, jsource); - CHECK_HANDLEV(source, nullptr); - - std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jlabel)); - - rtc::scoped_refptr videoTrack = factory->CreateVideoTrack(label, source); - - return jni::JavaFactories::create(env, videoTrack.release()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createPeerConnection -(JNIEnv * env, jobject caller, jobject jConfig, jobject jobserver) -{ - if (jConfig == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCConfiguration is null")); - return nullptr; - } - if (jobserver == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "PeerConnectionObserver is null")); - return nullptr; - } - - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLEV(factory, nullptr); - - webrtc::PeerConnectionInterface::RTCConfiguration configuration = jni::RTCConfiguration::toNative(env, jni::JavaLocalRef(env, jConfig)); - webrtc::PeerConnectionObserver * observer = new jni::PeerConnectionObserver(env, jni::JavaGlobalRef(env, jobserver)); - webrtc::PeerConnectionDependencies dependencies(observer); - - auto result = factory->CreatePeerConnectionOrError(configuration, std::move(dependencies)); - - if (!result.ok()) { - env->Throw(jni::JavaRuntimeException(env, "Create PeerConnection failed: %s %s", - ToString(result.error().type()), result.error().message())); - - return nullptr; - } - - auto pc = result.MoveValue(); - - if (pc != nullptr) { - auto javaPeerConnection = jni::JavaFactories::create(env, pc.release()); - - SetHandle(env, javaPeerConnection.get(), "observerHandle", observer); - - return javaPeerConnection.release(); - } - - return nullptr; -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_getRtpReceiverCapabilities -(JNIEnv * env, jobject caller, jobject mediaType) -{ - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLEV(factory, nullptr); - - auto type = jni::JavaEnums::toNative(env, mediaType); - auto capabilities = factory->GetRtpReceiverCapabilities(type); - - return jni::RTCRtpCapabilities::toJava(env, capabilities).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_getRtpSenderCapabilities -(JNIEnv * env, jobject caller, jobject mediaType) -{ - webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); - CHECK_HANDLEV(factory, nullptr); - - auto type = jni::JavaEnums::toNative(env, mediaType); - auto capabilities = factory->GetRtpSenderCapabilities(type); - - return jni::RTCRtpCapabilities::toJava(env, capabilities).release(); +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_PeerConnectionFactory.h" +#include "api/AudioOptions.h" +#include "api/CreateSessionDescriptionObserver.h" +#include "api/PeerConnectionObserver.h" +#include "api/RTCConfiguration.h" +#include "api/RTCRtpCapabilities.h" +#include "JavaEnums.h" +#include "JavaError.h" +#include "JavaFactories.h" +#include "JavaNullPointerException.h" +#include "JavaRuntimeException.h" +#include "JavaRef.h" +#include "JavaString.h" +#include "JavaUtils.h" + +#include "api/create_peerconnection_factory.h" +#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "api/video_codecs/builtin_video_decoder_factory.h" +#include "api/video_codecs/builtin_video_encoder_factory.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_initialize +(JNIEnv * env, jobject caller, jobject audioModule, jobject audioProcessing) +{ + webrtc::AudioDeviceModule * audioDevModule = (audioModule != nullptr) + ? GetHandle(env, audioModule) + : nullptr; + + try { + auto networkThread = rtc::Thread::CreateWithSocketServer(); + auto signalingThread = rtc::Thread::Create(); + auto workerThread = rtc::Thread::Create(); + + if (!networkThread->Start()) { + throw jni::Exception("Start network thread failed"); + } + if (!signalingThread->Start()) { + throw jni::Exception("Start signaling thread failed"); + } + if (!workerThread->Start()) { + throw jni::Exception("Start worker thread failed"); + } + + webrtc::AudioProcessing * processing = (audioProcessing != nullptr) + ? GetHandle(env, audioProcessing) + : nullptr; + rtc::scoped_refptr apm(processing); + rtc::scoped_refptr adm(audioDevModule); + + auto factory = webrtc::CreatePeerConnectionFactory( + networkThread.get(), + workerThread.get(), + signalingThread.get(), + adm, + webrtc::CreateBuiltinAudioEncoderFactory(), + webrtc::CreateBuiltinAudioDecoderFactory(), + webrtc::CreateBuiltinVideoEncoderFactory(), + webrtc::CreateBuiltinVideoDecoderFactory(), + nullptr, + apm); + + if (factory != nullptr) { + SetHandle(env, caller, factory.release()); + SetHandle(env, caller, "networkThreadHandle", networkThread.release()); + SetHandle(env, caller, "signalingThreadHandle", signalingThread.release()); + SetHandle(env, caller, "workerThreadHandle", workerThread.release()); + } + else { + throw jni::Exception("Create PeerConnectionFactory failed"); + } + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLE(factory); + + rtc::Thread * networkThread = GetHandle(env, caller, "networkThreadHandle"); + rtc::Thread * signalingThread = GetHandle(env, caller, "signalingThreadHandle"); + rtc::Thread * workerThread = GetHandle(env, caller, "workerThreadHandle"); + + webrtc::RefCountReleaseStatus status = factory->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + env->Throw(jni::JavaError(env, "Native object was not deleted. A reference is still around somewhere.")); + } + + SetHandle(env, caller, nullptr); + + factory = nullptr; + + try { + if (networkThread) { + networkThread->Stop(); + delete networkThread; + } + if (signalingThread) { + signalingThread->Stop(); + delete signalingThread; + } + if (workerThread) { + workerThread->Stop(); + delete workerThread; + } + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createAudioSource +(JNIEnv * env, jobject caller, jobject jAudioOptions) +{ + if (jAudioOptions == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "AudioOptions is null")); + return nullptr; + } + + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLEV(factory, nullptr); + + auto audioOptions = jni::AudioOptions::toNative(env, jni::JavaLocalRef(env, jAudioOptions)); + + rtc::scoped_refptr audioSource = factory->CreateAudioSource(audioOptions); + + if (audioSource == nullptr) { + env->Throw(jni::JavaError(env, "Create audio-track source failed")); + return nullptr; + } + + return jni::JavaFactories::create(env, audioSource.release()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createAudioTrack +(JNIEnv * env, jobject caller, jstring jlabel, jobject jsource) +{ + if (jlabel == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "Audio track label is null")); + return nullptr; + } + if (jsource == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "AudioTrackSource is null")); + return nullptr; + } + + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLEV(factory, nullptr); + + webrtc::AudioSourceInterface * source = GetHandle(env, jsource); + CHECK_HANDLEV(source, nullptr); + + std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jlabel)); + + rtc::scoped_refptr audioTrack = factory->CreateAudioTrack(label, source); + + return jni::JavaFactories::create(env, audioTrack.release()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createVideoTrack +(JNIEnv * env, jobject caller, jstring jlabel, jobject jsource) +{ + if (jlabel == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "Video track label is null")); + return nullptr; + } + if (jsource == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "VideoTrackSource is null")); + return nullptr; + } + + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLEV(factory, nullptr); + + webrtc::VideoTrackSourceInterface * source = GetHandle(env, jsource); + CHECK_HANDLEV(source, nullptr); + + std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jlabel)); + + rtc::scoped_refptr videoTrack = factory->CreateVideoTrack(label, source); + + return jni::JavaFactories::create(env, videoTrack.release()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createPeerConnection +(JNIEnv * env, jobject caller, jobject jConfig, jobject jobserver) +{ + if (jConfig == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCConfiguration is null")); + return nullptr; + } + if (jobserver == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "PeerConnectionObserver is null")); + return nullptr; + } + + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLEV(factory, nullptr); + + webrtc::PeerConnectionInterface::RTCConfiguration configuration = jni::RTCConfiguration::toNative(env, jni::JavaLocalRef(env, jConfig)); + webrtc::PeerConnectionObserver * observer = new jni::PeerConnectionObserver(env, jni::JavaGlobalRef(env, jobserver)); + webrtc::PeerConnectionDependencies dependencies(observer); + + auto result = factory->CreatePeerConnectionOrError(configuration, std::move(dependencies)); + + if (!result.ok()) { + env->Throw(jni::JavaRuntimeException(env, "Create PeerConnection failed: %s %s", + ToString(result.error().type()), result.error().message())); + + return nullptr; + } + + auto pc = result.MoveValue(); + + if (pc != nullptr) { + auto javaPeerConnection = jni::JavaFactories::create(env, pc.release()); + + SetHandle(env, javaPeerConnection.get(), "observerHandle", observer); + + return javaPeerConnection.release(); + } + + return nullptr; +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_getRtpReceiverCapabilities +(JNIEnv * env, jobject caller, jobject mediaType) +{ + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLEV(factory, nullptr); + + auto type = jni::JavaEnums::toNative(env, mediaType); + auto capabilities = factory->GetRtpReceiverCapabilities(type); + + return jni::RTCRtpCapabilities::toJava(env, capabilities).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_getRtpSenderCapabilities +(JNIEnv * env, jobject caller, jobject mediaType) +{ + webrtc::PeerConnectionFactoryInterface * factory = GetHandle(env, caller); + CHECK_HANDLEV(factory, nullptr); + + auto type = jni::JavaEnums::toNative(env, mediaType); + auto capabilities = factory->GetRtpSenderCapabilities(type); + + return jni::RTCRtpCapabilities::toJava(env, capabilities).release(); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_RTCDataChannel.cpp b/webrtc-jni/src/main/cpp/src/JNI_RTCDataChannel.cpp index 97602a7b..a08cfe79 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_RTCDataChannel.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_RTCDataChannel.cpp @@ -1,202 +1,202 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_RTCDataChannel.h" -#include "api/RTCDataChannelObserver.h" -#include "JavaEnums.h" -#include "JavaError.h" -#include "JavaRef.h" -#include "JavaString.h" -#include "JavaUtils.h" - -#include "api/data_channel_interface.h" - -#include - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_registerObserver -(JNIEnv * env, jobject caller, jobject jObserver) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLE(channel); - - channel->RegisterObserver(new jni::RTCDataChannelObserver(env, jni::JavaGlobalRef(env, jObserver))); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_unregisterObserver -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLE(channel); - - channel->UnregisterObserver(); -} - -JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getLabel -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, nullptr); - - return jni::JavaString::toJava(env, channel->label()).release(); -} - -JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_isReliable -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, false); - - return static_cast(channel->reliable()); -} - -JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_isOrdered -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, false); - - return static_cast(channel->ordered()); -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getMaxPacketLifeTime -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, 0); - - return static_cast(channel->maxRetransmitTime()); -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getMaxRetransmits -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, 0); - - return static_cast(channel->maxRetransmits()); -} - -JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getProtocol -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, nullptr); - - return jni::JavaString::toJava(env, channel->protocol()).release(); -} - -JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_isNegotiated -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, false); - - return static_cast(channel->negotiated()); -} - -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getId -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, 0); - - return static_cast(channel->id()); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getState -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, nullptr); - - return jni::JavaEnums::toJava(env, channel->state()).release(); -} - -JNIEXPORT jlong JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getBufferedAmount -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLEV(channel, 0); - - return static_cast(channel->buffered_amount()); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_close -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLE(channel); - - channel->Close(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_dispose -(JNIEnv * env, jobject caller) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLE(channel); - - rtc::RefCountReleaseStatus status = channel->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - env->Throw(jni::JavaError(env, "Native object was not deleted. A reference is still around somewhere.")); - } - - SetHandle(env, caller, nullptr); - - channel = nullptr; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendDirectBuffer -(JNIEnv * env, jobject caller, jobject jBuffer, jboolean isBinary) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLE(channel); - - uint8_t * address = static_cast(env->GetDirectBufferAddress(jBuffer)); - - if (address != NULL) { - jlong bufferLength = env->GetDirectBufferCapacity(jBuffer); - - rtc::CopyOnWriteBuffer data(address, static_cast(bufferLength)); - - channel->Send(webrtc::DataBuffer(data, static_cast(isBinary))); - } - else { - env->Throw(jni::JavaError(env, "Non-direct buffer provided")); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendByteArrayBuffer -(JNIEnv * env, jobject caller, jbyteArray jBufferArray, jboolean isBinary) -{ - webrtc::DataChannelInterface * channel = GetHandle(env, caller); - CHECK_HANDLE(channel); - - int8_t * arrayPtr = env->GetByteArrayElements(jBufferArray, nullptr); - size_t arrayLength = env->GetArrayLength(jBufferArray); - - rtc::CopyOnWriteBuffer data(arrayPtr, arrayLength); - - env->ReleaseByteArrayElements(jBufferArray, arrayPtr, JNI_ABORT); - - try { - channel->Send(webrtc::DataBuffer(data, static_cast(isBinary))); - } - catch (...) { - ThrowCxxJavaException(env); - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_RTCDataChannel.h" +#include "api/RTCDataChannelObserver.h" +#include "JavaEnums.h" +#include "JavaError.h" +#include "JavaRef.h" +#include "JavaString.h" +#include "JavaUtils.h" + +#include "api/data_channel_interface.h" + +#include + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_registerObserver +(JNIEnv * env, jobject caller, jobject jObserver) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLE(channel); + + channel->RegisterObserver(new jni::RTCDataChannelObserver(env, jni::JavaGlobalRef(env, jObserver))); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_unregisterObserver +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLE(channel); + + channel->UnregisterObserver(); +} + +JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getLabel +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, nullptr); + + return jni::JavaString::toJava(env, channel->label()).release(); +} + +JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_isReliable +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, false); + + return static_cast(channel->reliable()); +} + +JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_isOrdered +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, false); + + return static_cast(channel->ordered()); +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getMaxPacketLifeTime +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, 0); + + return static_cast(channel->maxPacketLifeTime().value_or(0)); +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getMaxRetransmits +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, 0); + + return static_cast(channel->maxRetransmitsOpt().value_or(0)); +} + +JNIEXPORT jstring JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getProtocol +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, nullptr); + + return jni::JavaString::toJava(env, channel->protocol()).release(); +} + +JNIEXPORT jboolean JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_isNegotiated +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, false); + + return static_cast(channel->negotiated()); +} + +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getId +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, 0); + + return static_cast(channel->id()); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getState +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, nullptr); + + return jni::JavaEnums::toJava(env, channel->state()).release(); +} + +JNIEXPORT jlong JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_getBufferedAmount +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLEV(channel, 0); + + return static_cast(channel->buffered_amount()); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_close +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLE(channel); + + channel->Close(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLE(channel); + + webrtc::RefCountReleaseStatus status = channel->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + env->Throw(jni::JavaError(env, "Native object was not deleted. A reference is still around somewhere.")); + } + + SetHandle(env, caller, nullptr); + + channel = nullptr; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendDirectBuffer +(JNIEnv * env, jobject caller, jobject jBuffer, jboolean isBinary) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLE(channel); + + uint8_t * address = static_cast(env->GetDirectBufferAddress(jBuffer)); + + if (address != NULL) { + jlong bufferLength = env->GetDirectBufferCapacity(jBuffer); + + rtc::CopyOnWriteBuffer data(address, static_cast(bufferLength)); + + channel->Send(webrtc::DataBuffer(data, static_cast(isBinary))); + } + else { + env->Throw(jni::JavaError(env, "Non-direct buffer provided")); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendByteArrayBuffer +(JNIEnv * env, jobject caller, jbyteArray jBufferArray, jboolean isBinary) +{ + webrtc::DataChannelInterface * channel = GetHandle(env, caller); + CHECK_HANDLE(channel); + + int8_t * arrayPtr = env->GetByteArrayElements(jBufferArray, nullptr); + size_t arrayLength = env->GetArrayLength(jBufferArray); + + rtc::CopyOnWriteBuffer data(arrayPtr, arrayLength); + + env->ReleaseByteArrayElements(jBufferArray, arrayPtr, JNI_ABORT); + + try { + channel->Send(webrtc::DataBuffer(data, static_cast(isBinary))); + } + catch (...) { + ThrowCxxJavaException(env); + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_RTCPeerConnection.cpp b/webrtc-jni/src/main/cpp/src/JNI_RTCPeerConnection.cpp index ba8445a1..2244c28c 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_RTCPeerConnection.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_RTCPeerConnection.cpp @@ -1,614 +1,614 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_RTCPeerConnection.h" -#include "api/CreateSessionDescriptionObserver.h" -#include "api/SetSessionDescriptionObserver.h" -#include "api/RTCAnswerOptions.h" -#include "api/RTCConfiguration.h" -#include "api/RTCDataChannelInit.h" -#include "api/RTCIceCandidate.h" -#include "api/RTCOfferOptions.h" -#include "api/RTCRtpTransceiverInit.h" -#include "api/RTCSessionDescription.h" -#include "api/RTCStatsCollectorCallback.h" -#include "api/WebRTCUtils.h" -#include "JavaArray.h" -#include "JavaEnums.h" -#include "JavaError.h" -#include "JavaFactories.h" -#include "JavaIterable.h" -#include "JavaList.h" -#include "JavaNullPointerException.h" -#include "JavaRef.h" -#include "JavaRuntimeException.h" -#include "JavaString.h" -#include "JavaUtils.h" - -#include "api/peer_connection_interface.h" -#include "api/rtp_receiver_interface.h" -#include "api/rtp_sender_interface.h" - -#include -#include - -JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getSenders -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - jni::JavaLocalRef objectArray; - - try { - objectArray = jni::createObjectArray(env, pc->GetSenders()); - } - catch (...) { - ThrowCxxJavaException(env); - } - - return objectArray.release(); -} - -JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getReceivers -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - jni::JavaLocalRef objectArray; - - try { - objectArray = jni::createObjectArray(env, pc->GetReceivers()); - } - catch (...) { - ThrowCxxJavaException(env); - } - - return objectArray.release(); -} - -JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getTransceivers -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - jni::JavaLocalRef objectArray; - - try { - objectArray = jni::createObjectArray(env, pc->GetTransceivers()); - } - catch (...) { - ThrowCxxJavaException(env); - } - - return objectArray.release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_addTrack -(JNIEnv * env, jobject caller, jobject jTrack, jobject jStreamIds) -{ - if (jTrack == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "MediaStreamTrack must not be null")); - return nullptr; - } - if (jStreamIds == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "Stream IDs must not be null")); - return nullptr; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); - CHECK_HANDLEV(track, nullptr); - - std::vector streamIDs = jni::JavaList::toStringVector(env, jni::JavaLocalRef(env, jStreamIds)); - - auto result = pc->AddTrack(track, streamIDs); - - if (result.ok()) { - auto sender = result.MoveValue(); - - return jni::JavaFactories::create(env, sender.release()).release(); - } - - env->Throw(jni::JavaRuntimeException(env, jni::RTCErrorToString(result.error()).c_str())); - - return nullptr; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_removeTrack -(JNIEnv * env, jobject caller, jobject jSender) -{ - if (jSender == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCRtpSender must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - webrtc::RtpSenderInterface * sender = GetHandle(env, jSender); - CHECK_HANDLE(sender); - - auto result = pc->RemoveTrackOrError(sender); - - if (!result.ok()) { - env->Throw(jni::JavaRuntimeException(env, "Remove track (RTCRtpSender) failed: %s %s", - ToString(result.type()), result.message())); - } -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_addTransceiver -(JNIEnv * env, jobject caller, jobject jTrack, jobject jTransceiverInit) -{ - if (jTrack == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "MediaStreamTrack must not be null")); - return nullptr; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); - CHECK_HANDLEV(track, nullptr); - - webrtc::RTCErrorOr> result; - - if (jTransceiverInit != nullptr) { - auto init = jni::RTCRtpTransceiverInit::toNative(env, jni::JavaLocalRef(env, jTransceiverInit)); - - result = pc->AddTransceiver(track, init); - } - else { - result = pc->AddTransceiver(track); - } - - if (result.ok()) { - auto transceiver = result.MoveValue(); - - return jni::JavaFactories::create(env, transceiver.release()).release(); - } - - env->Throw(jni::JavaRuntimeException(env, jni::RTCErrorToString(result.error()).c_str())); - - return nullptr; -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_createDataChannel -(JNIEnv * env, jobject caller, jstring jLabel, jobject jDict) -{ - if (jLabel == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "Label must not be null")); - return nullptr; - } - if (jDict == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCDataChannelInit must not be null")); - return nullptr; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jLabel)); - webrtc::DataChannelInit dict = jni::RTCDataChannelInit::toNative(env, jni::JavaLocalRef(env, jDict)); - - try { - auto result = pc->CreateDataChannelOrError(label, &dict); - - if (!result.ok()) { - env->Throw(jni::JavaRuntimeException(env, "Create DataChannel failed: %s %s", - ToString(result.error().type()), result.error().message())); - - return nullptr; - } - - auto dataChannel = result.MoveValue(); - - return jni::JavaFactories::create(env, dataChannel.release()).release(); - } - catch (...) { - ThrowCxxJavaException(env); - return nullptr; - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_createOffer -(JNIEnv * env, jobject caller, jobject jOptions, jobject jObserver) -{ - if (jOptions == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCOfferOptions must not be null")); - return; - } - if (jObserver == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "CreateSessionDescriptionObserver must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - auto options = jni::RTCOfferOptions::toNative(env, jni::JavaLocalRef(env, jOptions)); - auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jObserver)); - - pc->CreateOffer(observer, options); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_createAnswer -(JNIEnv * env, jobject caller, jobject jOptions, jobject jObserver) -{ - if (jOptions == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCAnswerOptions must not be null")); - return; - } - if (jObserver == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "CreateSessionDescriptionObserver must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - auto options = jni::RTCAnswerOptions::toNative(env, jni::JavaLocalRef(env, jOptions)); - auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jObserver)); - - pc->CreateAnswer(observer, options); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getCurrentLocalDescription -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - if (!pc->current_local_description()) { - return nullptr; - } - - return jni::RTCSessionDescription::toJava(env, pc->current_local_description()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getLocalDescription -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - if (!pc->local_description()) { - return nullptr; - } - - return jni::RTCSessionDescription::toJava(env, pc->local_description()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getPendingLocalDescription -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - if (!pc->pending_local_description()) { - return nullptr; - } - - return jni::RTCSessionDescription::toJava(env, pc->pending_local_description()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getCurrentRemoteDescription -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - if (!pc->current_remote_description()) { - return nullptr; - } - - return jni::RTCSessionDescription::toJava(env, pc->current_remote_description()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getRemoteDescription -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - if (!pc->remote_description()) { - return nullptr; - } - - return jni::RTCSessionDescription::toJava(env, pc->remote_description()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getPendingRemoteDescription -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - if (!pc->pending_remote_description()) { - return nullptr; - } - - return jni::RTCSessionDescription::toJava(env, pc->pending_remote_description()).release(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_setLocalDescription -(JNIEnv * env, jobject caller, jobject jSessionDesc, jobject jobserver) -{ - if (jSessionDesc == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCSessionDescription must not be null")); - return; - } - if (jobserver == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "SetSessionDescriptionObserver must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - auto desc = jni::RTCSessionDescription::toNative(env, jni::JavaLocalRef(env, jSessionDesc)); - auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jobserver)); - - pc->SetLocalDescription(observer, desc.release()); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_setRemoteDescription -(JNIEnv * env, jobject caller, jobject jSessionDesc, jobject jobserver) -{ - if (jSessionDesc == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCSessionDescription must not be null")); - return; - } - if (jobserver == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "SetSessionDescriptionObserver must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - auto desc = jni::RTCSessionDescription::toNative(env, jni::JavaLocalRef(env, jSessionDesc)); - auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jobserver)); - - pc->SetRemoteDescription(observer, desc.release()); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_addIceCandidate -(JNIEnv * env, jobject caller, jobject jCandidate) -{ - if (jCandidate == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCIceCandidate must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - auto candidate = jni::RTCIceCandidate::toNative(env, jni::JavaLocalRef(env, jCandidate)); - - pc->AddIceCandidate(candidate.get()); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_removeIceCandidates -(JNIEnv * env, jobject caller, jobject jCandidates) -{ - if (jCandidates == nullptr) { - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - auto candidates = jni::JavaArray::toNativeVector(env, - jni::static_java_ref_cast(env, jni::JavaLocalRef(env, jCandidates)), - &jni::RTCIceCandidate::toNativeCricket); - - if (!pc->RemoveIceCandidates(candidates)) { - env->Throw(jni::JavaRuntimeException(env, "Remove ICE candidates from the peer connection failed")); - } - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getSignalingState -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::SignalingState::kClosed).release()); - - return jni::JavaEnums::toJava(env, pc->signaling_state()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getIceGatheringState -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringNew).release()); - - return jni::JavaEnums::toJava(env, pc->ice_gathering_state()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getIceConnectionState -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::IceConnectionState::kIceConnectionClosed).release()); - - return jni::JavaEnums::toJava(env, pc->ice_connection_state()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getConnectionState -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::PeerConnectionState::kClosed).release()); - - return jni::JavaEnums::toJava(env, pc->peer_connection_state()).release(); -} - -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getConfiguration -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLEV(pc, nullptr); - - return jni::RTCConfiguration::toJava(env, pc->GetConfiguration()).release(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_setConfiguration -(JNIEnv * env, jobject caller, jobject jConfig) -{ - if (jConfig == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCConfiguration must not be null")); - return; - } - - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - auto config = jni::RTCConfiguration::toNative(env, jni::JavaLocalRef(env, jConfig)); - - webrtc::RTCError error = pc->SetConfiguration(config); - - if (!error.ok()) { - env->Throw(jni::JavaRuntimeException(env, jni::RTCErrorToString(error).c_str())); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getStats__Ldev_onvoid_webrtc_RTCStatsCollectorCallback_2 -(JNIEnv * env, jobject caller, jobject jcallback) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - if (jcallback == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCStatsCollectorCallback is null")); - return; - } - - auto callback = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jcallback)); - - pc->GetStats(callback); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getStats__Ldev_onvoid_webrtc_RTCRtpReceiver_2Ldev_onvoid_webrtc_RTCStatsCollectorCallback_2 -(JNIEnv * env, jobject caller, jobject jreceiver, jobject jcallback) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - if (jreceiver == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCRtpReceiver is null")); - return; - } - if (jcallback == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCStatsCollectorCallback is null")); - return; - } - - webrtc::RtpReceiverInterface * receiver = GetHandle(env, jreceiver); - CHECK_HANDLE(receiver); - - auto callback = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jcallback)); - - pc->GetStats(receiver, callback); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getStats__Ldev_onvoid_webrtc_RTCRtpSender_2Ldev_onvoid_webrtc_RTCStatsCollectorCallback_2 -(JNIEnv * env, jobject caller, jobject jsender, jobject jcallback) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - if (jsender == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCRtpSender is null")); - return; - } - if (jcallback == nullptr) { - env->Throw(jni::JavaNullPointerException(env, "RTCStatsCollectorCallback is null")); - return; - } - - webrtc::RtpReceiverInterface * sender = GetHandle(env, jsender); - CHECK_HANDLE(sender); - - auto callback = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jcallback)); - - pc->GetStats(sender, callback); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_restartIce -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - pc->RestartIce(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_close -(JNIEnv * env, jobject caller) -{ - webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); - CHECK_HANDLE(pc); - - try { - pc->Close(); - - SetHandle(env, caller, nullptr); - - auto observer = GetHandle(env, caller, "observerHandle"); - - if (observer) { - delete observer; - } - } - catch (...) { - ThrowCxxJavaException(env); - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_RTCPeerConnection.h" +#include "api/CreateSessionDescriptionObserver.h" +#include "api/SetSessionDescriptionObserver.h" +#include "api/RTCAnswerOptions.h" +#include "api/RTCConfiguration.h" +#include "api/RTCDataChannelInit.h" +#include "api/RTCIceCandidate.h" +#include "api/RTCOfferOptions.h" +#include "api/RTCRtpTransceiverInit.h" +#include "api/RTCSessionDescription.h" +#include "api/RTCStatsCollectorCallback.h" +#include "api/WebRTCUtils.h" +#include "JavaArray.h" +#include "JavaEnums.h" +#include "JavaError.h" +#include "JavaFactories.h" +#include "JavaIterable.h" +#include "JavaList.h" +#include "JavaNullPointerException.h" +#include "JavaRef.h" +#include "JavaRuntimeException.h" +#include "JavaString.h" +#include "JavaUtils.h" + +#include "api/peer_connection_interface.h" +#include "api/rtp_receiver_interface.h" +#include "api/rtp_sender_interface.h" + +#include +#include + +JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getSenders +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + jni::JavaLocalRef objectArray; + + try { + objectArray = jni::createObjectArray(env, pc->GetSenders()); + } + catch (...) { + ThrowCxxJavaException(env); + } + + return objectArray.release(); +} + +JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getReceivers +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + jni::JavaLocalRef objectArray; + + try { + objectArray = jni::createObjectArray(env, pc->GetReceivers()); + } + catch (...) { + ThrowCxxJavaException(env); + } + + return objectArray.release(); +} + +JNIEXPORT jobjectArray JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getTransceivers +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + jni::JavaLocalRef objectArray; + + try { + objectArray = jni::createObjectArray(env, pc->GetTransceivers()); + } + catch (...) { + ThrowCxxJavaException(env); + } + + return objectArray.release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_addTrack +(JNIEnv * env, jobject caller, jobject jTrack, jobject jStreamIds) +{ + if (jTrack == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "MediaStreamTrack must not be null")); + return nullptr; + } + if (jStreamIds == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "Stream IDs must not be null")); + return nullptr; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); + CHECK_HANDLEV(track, nullptr); + + std::vector streamIDs = jni::JavaList::toStringVector(env, jni::JavaLocalRef(env, jStreamIds)); + + auto result = pc->AddTrack(rtc::scoped_refptr(track), streamIDs); + + if (result.ok()) { + auto sender = result.MoveValue(); + + return jni::JavaFactories::create(env, sender.release()).release(); + } + + env->Throw(jni::JavaRuntimeException(env, jni::RTCErrorToString(result.error()).c_str())); + + return nullptr; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_removeTrack +(JNIEnv * env, jobject caller, jobject jSender) +{ + if (jSender == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCRtpSender must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + webrtc::RtpSenderInterface * sender = GetHandle(env, jSender); + CHECK_HANDLE(sender); + + auto result = pc->RemoveTrackOrError(rtc::scoped_refptr(sender)); + + if (!result.ok()) { + env->Throw(jni::JavaRuntimeException(env, "Remove track (RTCRtpSender) failed: %s %s", + ToString(result.type()), result.message())); + } +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_addTransceiver +(JNIEnv * env, jobject caller, jobject jTrack, jobject jTransceiverInit) +{ + if (jTrack == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "MediaStreamTrack must not be null")); + return nullptr; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + webrtc::MediaStreamTrackInterface * track = GetHandle(env, jTrack); + CHECK_HANDLEV(track, nullptr); + + webrtc::RTCErrorOr> result; + + if (jTransceiverInit != nullptr) { + auto init = jni::RTCRtpTransceiverInit::toNative(env, jni::JavaLocalRef(env, jTransceiverInit)); + + result = pc->AddTransceiver(rtc::scoped_refptr(track), init); + } + else { + result = pc->AddTransceiver(rtc::scoped_refptr(track)); + } + + if (result.ok()) { + auto transceiver = result.MoveValue(); + + return jni::JavaFactories::create(env, transceiver.release()).release(); + } + + env->Throw(jni::JavaRuntimeException(env, jni::RTCErrorToString(result.error()).c_str())); + + return nullptr; +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_createDataChannel +(JNIEnv * env, jobject caller, jstring jLabel, jobject jDict) +{ + if (jLabel == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "Label must not be null")); + return nullptr; + } + if (jDict == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCDataChannelInit must not be null")); + return nullptr; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jLabel)); + webrtc::DataChannelInit dict = jni::RTCDataChannelInit::toNative(env, jni::JavaLocalRef(env, jDict)); + + try { + auto result = pc->CreateDataChannelOrError(label, &dict); + + if (!result.ok()) { + env->Throw(jni::JavaRuntimeException(env, "Create DataChannel failed: %s %s", + ToString(result.error().type()), result.error().message())); + + return nullptr; + } + + auto dataChannel = result.MoveValue(); + + return jni::JavaFactories::create(env, dataChannel.release()).release(); + } + catch (...) { + ThrowCxxJavaException(env); + return nullptr; + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_createOffer +(JNIEnv * env, jobject caller, jobject jOptions, jobject jObserver) +{ + if (jOptions == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCOfferOptions must not be null")); + return; + } + if (jObserver == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "CreateSessionDescriptionObserver must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + auto options = jni::RTCOfferOptions::toNative(env, jni::JavaLocalRef(env, jOptions)); + auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jObserver)); + + pc->CreateOffer(observer, options); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_createAnswer +(JNIEnv * env, jobject caller, jobject jOptions, jobject jObserver) +{ + if (jOptions == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCAnswerOptions must not be null")); + return; + } + if (jObserver == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "CreateSessionDescriptionObserver must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + auto options = jni::RTCAnswerOptions::toNative(env, jni::JavaLocalRef(env, jOptions)); + auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jObserver)); + + pc->CreateAnswer(observer, options); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getCurrentLocalDescription +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + if (!pc->current_local_description()) { + return nullptr; + } + + return jni::RTCSessionDescription::toJava(env, pc->current_local_description()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getLocalDescription +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + if (!pc->local_description()) { + return nullptr; + } + + return jni::RTCSessionDescription::toJava(env, pc->local_description()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getPendingLocalDescription +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + if (!pc->pending_local_description()) { + return nullptr; + } + + return jni::RTCSessionDescription::toJava(env, pc->pending_local_description()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getCurrentRemoteDescription +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + if (!pc->current_remote_description()) { + return nullptr; + } + + return jni::RTCSessionDescription::toJava(env, pc->current_remote_description()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getRemoteDescription +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + if (!pc->remote_description()) { + return nullptr; + } + + return jni::RTCSessionDescription::toJava(env, pc->remote_description()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getPendingRemoteDescription +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + if (!pc->pending_remote_description()) { + return nullptr; + } + + return jni::RTCSessionDescription::toJava(env, pc->pending_remote_description()).release(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_setLocalDescription +(JNIEnv * env, jobject caller, jobject jSessionDesc, jobject jobserver) +{ + if (jSessionDesc == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCSessionDescription must not be null")); + return; + } + if (jobserver == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "SetSessionDescriptionObserver must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + auto desc = jni::RTCSessionDescription::toNative(env, jni::JavaLocalRef(env, jSessionDesc)); + auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jobserver)); + + pc->SetLocalDescription(observer, desc.release()); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_setRemoteDescription +(JNIEnv * env, jobject caller, jobject jSessionDesc, jobject jobserver) +{ + if (jSessionDesc == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCSessionDescription must not be null")); + return; + } + if (jobserver == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "SetSessionDescriptionObserver must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + auto desc = jni::RTCSessionDescription::toNative(env, jni::JavaLocalRef(env, jSessionDesc)); + auto observer = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jobserver)); + + pc->SetRemoteDescription(observer, desc.release()); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_addIceCandidate +(JNIEnv * env, jobject caller, jobject jCandidate) +{ + if (jCandidate == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCIceCandidate must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + auto candidate = jni::RTCIceCandidate::toNative(env, jni::JavaLocalRef(env, jCandidate)); + + pc->AddIceCandidate(candidate.get()); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_removeIceCandidates +(JNIEnv * env, jobject caller, jobject jCandidates) +{ + if (jCandidates == nullptr) { + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + auto candidates = jni::JavaArray::toNativeVector(env, + jni::static_java_ref_cast(env, jni::JavaLocalRef(env, jCandidates)), + &jni::RTCIceCandidate::toNativeCricket); + + if (!pc->RemoveIceCandidates(candidates)) { + env->Throw(jni::JavaRuntimeException(env, "Remove ICE candidates from the peer connection failed")); + } + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getSignalingState +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::SignalingState::kClosed).release()); + + return jni::JavaEnums::toJava(env, pc->signaling_state()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getIceGatheringState +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::IceGatheringState::kIceGatheringNew).release()); + + return jni::JavaEnums::toJava(env, pc->ice_gathering_state()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getIceConnectionState +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::IceConnectionState::kIceConnectionClosed).release()); + + return jni::JavaEnums::toJava(env, pc->ice_connection_state()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getConnectionState +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE_DEFAULT(pc, jni::JavaEnums::toJava(env, webrtc::PeerConnectionInterface::PeerConnectionState::kClosed).release()); + + return jni::JavaEnums::toJava(env, pc->peer_connection_state()).release(); +} + +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getConfiguration +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLEV(pc, nullptr); + + return jni::RTCConfiguration::toJava(env, pc->GetConfiguration()).release(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_setConfiguration +(JNIEnv * env, jobject caller, jobject jConfig) +{ + if (jConfig == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCConfiguration must not be null")); + return; + } + + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + auto config = jni::RTCConfiguration::toNative(env, jni::JavaLocalRef(env, jConfig)); + + webrtc::RTCError error = pc->SetConfiguration(config); + + if (!error.ok()) { + env->Throw(jni::JavaRuntimeException(env, jni::RTCErrorToString(error).c_str())); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getStats__Ldev_onvoid_webrtc_RTCStatsCollectorCallback_2 +(JNIEnv * env, jobject caller, jobject jcallback) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + if (jcallback == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCStatsCollectorCallback is null")); + return; + } + + auto callback = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jcallback)); + + pc->GetStats(callback); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getStats__Ldev_onvoid_webrtc_RTCRtpReceiver_2Ldev_onvoid_webrtc_RTCStatsCollectorCallback_2 +(JNIEnv * env, jobject caller, jobject jreceiver, jobject jcallback) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + if (jreceiver == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCRtpReceiver is null")); + return; + } + if (jcallback == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCStatsCollectorCallback is null")); + return; + } + + webrtc::RtpReceiverInterface * receiver = GetHandle(env, jreceiver); + CHECK_HANDLE(receiver); + + auto callback = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jcallback)); + + pc->GetStats(rtc::scoped_refptr(receiver), rtc::scoped_refptr(callback)); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_getStats__Ldev_onvoid_webrtc_RTCRtpSender_2Ldev_onvoid_webrtc_RTCStatsCollectorCallback_2 +(JNIEnv * env, jobject caller, jobject jsender, jobject jcallback) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + if (jsender == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCRtpSender is null")); + return; + } + if (jcallback == nullptr) { + env->Throw(jni::JavaNullPointerException(env, "RTCStatsCollectorCallback is null")); + return; + } + + webrtc::RtpSenderInterface * sender = GetHandle(env, jsender); + CHECK_HANDLE(sender); + + auto callback = new rtc::RefCountedObject(env, jni::JavaGlobalRef(env, jcallback)); + + pc->GetStats(rtc::scoped_refptr(sender), rtc::scoped_refptr(callback)); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_restartIce +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + pc->RestartIce(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCPeerConnection_close +(JNIEnv * env, jobject caller) +{ + webrtc::PeerConnectionInterface * pc = GetHandle(env, caller); + CHECK_HANDLE(pc); + + try { + pc->Close(); + + SetHandle(env, caller, nullptr); + + auto observer = GetHandle(env, caller, "observerHandle"); + + if (observer) { + delete observer; + } + } + catch (...) { + ThrowCxxJavaException(env); + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp b/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp index 79282f21..74791248 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp @@ -1,42 +1,42 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_RefCountedObject.h" -#include "JavaUtils.h" - -#include "rtc_base/ref_count.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_internal_RefCountedObject_retain -(JNIEnv * env, jobject caller) -{ - rtc::RefCountInterface * ref = GetHandle(env, caller); - CHECK_HANDLE(ref); - - ref->AddRef(); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_internal_RefCountedObject_release -(JNIEnv * env, jobject caller) -{ - rtc::RefCountInterface * ref = GetHandle(env, caller); - CHECK_HANDLE(ref); - - const auto status = ref->Release(); - - if (status == rtc::RefCountReleaseStatus::kDroppedLastRef) { - SetHandle(env, caller, nullptr); - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_RefCountedObject.h" +#include "JavaUtils.h" + +#include "rtc_base/ref_count.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_internal_RefCountedObject_retain +(JNIEnv * env, jobject caller) +{ + webrtc::RefCountInterface * ref = GetHandle(env, caller); + CHECK_HANDLE(ref); + + ref->AddRef(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_internal_RefCountedObject_release +(JNIEnv * env, jobject caller) +{ + webrtc::RefCountInterface * ref = GetHandle(env, caller); + CHECK_HANDLE(ref); + + const auto status = ref->Release(); + + if (status == webrtc::RefCountReleaseStatus::kDroppedLastRef) { + SetHandle(env, caller, nullptr); + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_VideoDesktopSource.cpp b/webrtc-jni/src/main/cpp/src/JNI_VideoDesktopSource.cpp index 971d3da4..3d15ee36 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_VideoDesktopSource.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_VideoDesktopSource.cpp @@ -1,114 +1,114 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_VideoDesktopSource.h" -#include "api/VideoTrackSink.h" -#include "media/video/VideoTrackDesktopSource.h" -#include "JavaRef.h" -#include "JavaObject.h" -#include "JavaString.h" -#include "JavaUtils.h" -#include "rtc_base/logging.h" -#include "rtc_base/ref_counted_object.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setSourceId -(JNIEnv * env, jobject caller, jlong sourceId, jboolean isWindow) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - videoSource->setSourceId(static_cast(sourceId), static_cast(isWindow)); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setFrameRate -(JNIEnv * env, jobject caller, jint frameRate) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - videoSource->setFrameRate(static_cast(frameRate)); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setMaxFrameSize -(JNIEnv* env, jobject caller, jint width, jint height) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - videoSource->setMaxFrameSize(webrtc::DesktopSize(width, height)); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setFocusSelectedSource -(JNIEnv * env, jobject caller, jboolean focus) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - videoSource->setFocusSelectedSource(focus); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_start -(JNIEnv * env, jobject caller) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - try { - videoSource->start(); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_stop -(JNIEnv * env, jobject caller) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - try { - videoSource->stop(); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_dispose -(JNIEnv * env, jobject caller) -{ - jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - rtc::RefCountReleaseStatus status = videoSource->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; - } - - SetHandle(env, caller, nullptr); - - videoSource = nullptr; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_initialize -(JNIEnv * env, jobject caller) -{ - rtc::scoped_refptr videoSource = new rtc::RefCountedObject(); - - SetHandle(env, caller, videoSource.release()); +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_VideoDesktopSource.h" +#include "api/VideoTrackSink.h" +#include "media/video/VideoTrackDesktopSource.h" +#include "JavaRef.h" +#include "JavaObject.h" +#include "JavaString.h" +#include "JavaUtils.h" +#include "rtc_base/logging.h" +#include "rtc_base/ref_counted_object.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setSourceId +(JNIEnv * env, jobject caller, jlong sourceId, jboolean isWindow) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + videoSource->setSourceId(static_cast(sourceId), static_cast(isWindow)); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setFrameRate +(JNIEnv * env, jobject caller, jint frameRate) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + videoSource->setFrameRate(static_cast(frameRate)); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setMaxFrameSize +(JNIEnv* env, jobject caller, jint width, jint height) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + videoSource->setMaxFrameSize(webrtc::DesktopSize(width, height)); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_setFocusSelectedSource +(JNIEnv * env, jobject caller, jboolean focus) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + videoSource->setFocusSelectedSource(focus); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_start +(JNIEnv * env, jobject caller) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + try { + videoSource->start(); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_stop +(JNIEnv * env, jobject caller) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + try { + videoSource->stop(); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_dispose +(JNIEnv * env, jobject caller) +{ + jni::VideoTrackDesktopSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + webrtc::RefCountReleaseStatus status = videoSource->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; + } + + SetHandle(env, caller, nullptr); + + videoSource = nullptr; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDesktopSource_initialize +(JNIEnv * env, jobject caller) +{ + rtc::scoped_refptr videoSource = webrtc::make_ref_counted(); + + SetHandle(env, caller, videoSource.release()); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_VideoDeviceSource.cpp b/webrtc-jni/src/main/cpp/src/JNI_VideoDeviceSource.cpp index 56345972..d64bc900 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_VideoDeviceSource.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_VideoDeviceSource.cpp @@ -1,116 +1,116 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "JNI_VideoDeviceSource.h" -#include "api/VideoTrackSink.h" -#include "media/video/VideoDevice.h" -#include "media/video/VideoTrackDeviceSource.h" -#include "JavaRef.h" -#include "JavaObject.h" -#include "JavaString.h" -#include "JavaUtils.h" - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_setVideoCaptureDevice -(JNIEnv * env, jobject caller, jobject device) -{ - if (!device) { - env->Throw(jni::JavaNullPointerException(env, "VideoDevice is null")); - return; - } - - jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - const auto dev = jni::VideoDevice::toNativeVideoDevice(env, jni::JavaLocalRef(env, device)); - - videoSource->setVideoDevice(std::make_shared(dev.getName(), dev.getDescriptor())); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_setVideoCaptureCapability -(JNIEnv * env, jobject caller, jobject jcapability) -{ - jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - if (!jcapability) { - env->Throw(jni::JavaNullPointerException(env, "VideoCaptureCapability is null")); - return; - } - - jint width = env->GetIntField(jcapability, GetFieldID(env, jcapability, "width", "I")); - jint height = env->GetIntField(jcapability, GetFieldID(env, jcapability, "height", "I")); - jint frameRate = env->GetIntField(jcapability, GetFieldID(env, jcapability, "frameRate", "I")); - - webrtc::VideoCaptureCapability capability; - capability.width = static_cast(width); - capability.height = static_cast(height); - capability.maxFPS = static_cast(frameRate); - - videoSource->setVideoCaptureCapability(capability); -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_start -(JNIEnv * env, jobject caller) -{ - jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - try { - videoSource->start(); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_stop -(JNIEnv * env, jobject caller) -{ - jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - try { - videoSource->stop(); - } - catch (...) { - ThrowCxxJavaException(env); - } -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_dispose -(JNIEnv * env, jobject caller) -{ - jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); - CHECK_HANDLE(videoSource); - - rtc::RefCountReleaseStatus status = videoSource->Release(); - - if (status != rtc::RefCountReleaseStatus::kDroppedLastRef) { - RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; - } - - SetHandle(env, caller, nullptr); - - videoSource = nullptr; -} - -JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_initialize -(JNIEnv * env, jobject caller) -{ - rtc::scoped_refptr videoSource = new rtc::RefCountedObject(); - - SetHandle(env, caller, videoSource.release()); +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "JNI_VideoDeviceSource.h" +#include "api/VideoTrackSink.h" +#include "media/video/VideoDevice.h" +#include "media/video/VideoTrackDeviceSource.h" +#include "JavaRef.h" +#include "JavaObject.h" +#include "JavaString.h" +#include "JavaUtils.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_setVideoCaptureDevice +(JNIEnv * env, jobject caller, jobject device) +{ + if (!device) { + env->Throw(jni::JavaNullPointerException(env, "VideoDevice is null")); + return; + } + + jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + const auto dev = jni::VideoDevice::toNativeVideoDevice(env, jni::JavaLocalRef(env, device)); + + videoSource->setVideoDevice(std::make_shared(dev.getName(), dev.getDescriptor())); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_setVideoCaptureCapability +(JNIEnv * env, jobject caller, jobject jcapability) +{ + jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + if (!jcapability) { + env->Throw(jni::JavaNullPointerException(env, "VideoCaptureCapability is null")); + return; + } + + jint width = env->GetIntField(jcapability, GetFieldID(env, jcapability, "width", "I")); + jint height = env->GetIntField(jcapability, GetFieldID(env, jcapability, "height", "I")); + jint frameRate = env->GetIntField(jcapability, GetFieldID(env, jcapability, "frameRate", "I")); + + webrtc::VideoCaptureCapability capability; + capability.width = static_cast(width); + capability.height = static_cast(height); + capability.maxFPS = static_cast(frameRate); + + videoSource->setVideoCaptureCapability(capability); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_start +(JNIEnv * env, jobject caller) +{ + jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + try { + videoSource->start(); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_stop +(JNIEnv * env, jobject caller) +{ + jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + try { + videoSource->stop(); + } + catch (...) { + ThrowCxxJavaException(env); + } +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_dispose +(JNIEnv * env, jobject caller) +{ + jni::VideoTrackDeviceSource * videoSource = GetHandle(env, caller); + CHECK_HANDLE(videoSource); + + webrtc::RefCountReleaseStatus status = videoSource->Release(); + + if (status != webrtc::RefCountReleaseStatus::kDroppedLastRef) { + RTC_LOG(LS_WARNING) << "Native object was not deleted. A reference is still around somewhere."; + } + + SetHandle(env, caller, nullptr); + + videoSource = nullptr; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoDeviceSource_initialize +(JNIEnv * env, jobject caller) +{ + rtc::scoped_refptr videoSource = webrtc::make_ref_counted(); + + SetHandle(env, caller, videoSource.release()); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/api/AudioOptions.cpp b/webrtc-jni/src/main/cpp/src/api/AudioOptions.cpp index d1224243..4b9f69b6 100644 --- a/webrtc-jni/src/main/cpp/src/api/AudioOptions.cpp +++ b/webrtc-jni/src/main/cpp/src/api/AudioOptions.cpp @@ -1,56 +1,52 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "api/AudioOptions.h" -#include "JavaClasses.h" -#include "JavaObject.h" -#include "JavaUtils.h" -#include "JNI_WebRTC.h" - -namespace jni -{ - namespace AudioOptions - { - cricket::AudioOptions toNative(JNIEnv * env, const JavaRef& javaType) - { - const auto javaClass = JavaClasses::get(env); - - JavaObject obj(env, javaType); - - auto options = cricket::AudioOptions(); - options.echo_cancellation = obj.getBoolean(javaClass->echoCancellation); - options.auto_gain_control = obj.getBoolean(javaClass->autoGainControl); - options.noise_suppression = obj.getBoolean(javaClass->noiseSuppression); - options.highpass_filter = obj.getBoolean(javaClass->highpassFilter); - options.typing_detection = obj.getBoolean(javaClass->typingDetection); - options.residual_echo_detector = obj.getBoolean(javaClass->residualEchoDetector); - - return options; - } - - JavaAudioOptionsClass::JavaAudioOptionsClass(JNIEnv * env) - { - cls = FindClass(env, PKG_AUDIO"AudioOptions"); - - echoCancellation = GetFieldID(env, cls, "echoCancellation", "Z"); - autoGainControl = GetFieldID(env, cls, "autoGainControl", "Z"); - noiseSuppression = GetFieldID(env, cls, "noiseSuppression", "Z"); - highpassFilter = GetFieldID(env, cls, "highpassFilter", "Z"); - typingDetection = GetFieldID(env, cls, "typingDetection", "Z"); - residualEchoDetector = GetFieldID(env, cls, "residualEchoDetector", "Z"); - } - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "api/AudioOptions.h" +#include "JavaClasses.h" +#include "JavaObject.h" +#include "JavaUtils.h" +#include "JNI_WebRTC.h" + +namespace jni +{ + namespace AudioOptions + { + cricket::AudioOptions toNative(JNIEnv * env, const JavaRef& javaType) + { + const auto javaClass = JavaClasses::get(env); + + JavaObject obj(env, javaType); + + auto options = cricket::AudioOptions(); + options.echo_cancellation = obj.getBoolean(javaClass->echoCancellation); + options.auto_gain_control = obj.getBoolean(javaClass->autoGainControl); + options.noise_suppression = obj.getBoolean(javaClass->noiseSuppression); + options.highpass_filter = obj.getBoolean(javaClass->highpassFilter); + + return options; + } + + JavaAudioOptionsClass::JavaAudioOptionsClass(JNIEnv * env) + { + cls = FindClass(env, PKG_AUDIO"AudioOptions"); + + echoCancellation = GetFieldID(env, cls, "echoCancellation", "Z"); + autoGainControl = GetFieldID(env, cls, "autoGainControl", "Z"); + noiseSuppression = GetFieldID(env, cls, "noiseSuppression", "Z"); + highpassFilter = GetFieldID(env, cls, "highpassFilter", "Z"); + } + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/api/RTCConfiguration.cpp b/webrtc-jni/src/main/cpp/src/api/RTCConfiguration.cpp index b4193ffa..33b1c72c 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCConfiguration.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCConfiguration.cpp @@ -1,109 +1,108 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "api/RTCConfiguration.h" -#include "api/RTCIceServer.h" -#include "rtc/RTCCertificatePEM.h" -#include "JavaArrayList.h" -#include "JavaClasses.h" -#include "JavaEnums.h" -#include "JavaIterable.h" -#include "JavaList.h" -#include "JavaRef.h" -#include "JavaObject.h" -#include "JavaUtils.h" -#include "JNI_WebRTC.h" - -namespace jni -{ - namespace RTCConfiguration - { - JavaLocalRef toJava(JNIEnv * env, const webrtc::PeerConnectionInterface::RTCConfiguration & nativeType) - { - const auto javaClass = JavaClasses::get(env); - - auto certificates = nativeType.certificates; - - auto serverList = JavaList::toArrayList(env, nativeType.servers, &RTCIceServer::toJava); - JavaArrayList certificateList(env, certificates.size()); - - for (auto & certificate : certificates) { - certificateList.add(jni::RTCCertificatePEM::toJava(env, certificate->ToPEM())); - } - - auto type = JavaEnums::toJava(env, nativeType.type); - auto bundlePolicy = JavaEnums::toJava(env, nativeType.bundle_policy); - auto rtcpMuxPolicy = JavaEnums::toJava(env, nativeType.rtcp_mux_policy); - - jobject config = env->NewObject(javaClass->cls, javaClass->ctor); - - env->SetObjectField(config, javaClass->iceServers, serverList.get()); - env->SetObjectField(config, javaClass->iceTransportPolicy, type.get()); - env->SetObjectField(config, javaClass->bundlePolicy, bundlePolicy.get()); - env->SetObjectField(config, javaClass->rtcpMuxPolicy, rtcpMuxPolicy.get()); - env->SetObjectField(config, javaClass->certificates, certificateList.listObject()); - - return JavaLocalRef(env, config); - } - - webrtc::PeerConnectionInterface::RTCConfiguration toNative(JNIEnv * env, const JavaRef & javaType) - { - const auto javaClass = JavaClasses::get(env); - - JavaObject obj(env, javaType); - - JavaLocalRef is = obj.getObject(javaClass->iceServers); - JavaLocalRef tp = obj.getObject(javaClass->iceTransportPolicy); - JavaLocalRef bp = obj.getObject(javaClass->bundlePolicy); - JavaLocalRef mp = obj.getObject(javaClass->rtcpMuxPolicy); - JavaLocalRef cr = obj.getObject(javaClass->certificates); - - webrtc::PeerConnectionInterface::RTCConfiguration configuration; - - configuration.servers = JavaList::toVector(env, is, &RTCIceServer::toNative); - configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; - configuration.enable_dtls_srtp = true; - configuration.type = JavaEnums::toNative(env, tp); - configuration.bundle_policy = JavaEnums::toNative(env, bp); - configuration.rtcp_mux_policy = JavaEnums::toNative(env, mp); - - for (auto & item : JavaIterable(env, cr)) { - auto certificate = rtc::RTCCertificate::FromPEM(jni::RTCCertificatePEM::toNative(env, item)); - - RTC_CHECK(certificate != nullptr) << "Supplied certificate is malformed"; - - if (certificate != nullptr) { - configuration.certificates.push_back(certificate); - } - } - - return configuration; - } - - JavaRTCConfigurationClass::JavaRTCConfigurationClass(JNIEnv * env) - { - cls = FindClass(env, PKG"RTCConfiguration"); - - ctor = GetMethod(env, cls, "", "()V"); - - iceServers = GetFieldID(env, cls, "iceServers", LIST_SIG); - iceTransportPolicy = GetFieldID(env, cls, "iceTransportPolicy", "L" PKG "RTCIceTransportPolicy;"); - bundlePolicy = GetFieldID(env, cls, "bundlePolicy", "L" PKG "RTCBundlePolicy;"); - rtcpMuxPolicy = GetFieldID(env, cls, "rtcpMuxPolicy", "L" PKG "RTCRtcpMuxPolicy;"); - certificates = GetFieldID(env, cls, "certificates", LIST_SIG); - } - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "api/RTCConfiguration.h" +#include "api/RTCIceServer.h" +#include "rtc/RTCCertificatePEM.h" +#include "JavaArrayList.h" +#include "JavaClasses.h" +#include "JavaEnums.h" +#include "JavaIterable.h" +#include "JavaList.h" +#include "JavaRef.h" +#include "JavaObject.h" +#include "JavaUtils.h" +#include "JNI_WebRTC.h" + +namespace jni +{ + namespace RTCConfiguration + { + JavaLocalRef toJava(JNIEnv * env, const webrtc::PeerConnectionInterface::RTCConfiguration & nativeType) + { + const auto javaClass = JavaClasses::get(env); + + auto certificates = nativeType.certificates; + + auto serverList = JavaList::toArrayList(env, nativeType.servers, &RTCIceServer::toJava); + JavaArrayList certificateList(env, certificates.size()); + + for (auto & certificate : certificates) { + certificateList.add(jni::RTCCertificatePEM::toJava(env, certificate->ToPEM())); + } + + auto type = JavaEnums::toJava(env, nativeType.type); + auto bundlePolicy = JavaEnums::toJava(env, nativeType.bundle_policy); + auto rtcpMuxPolicy = JavaEnums::toJava(env, nativeType.rtcp_mux_policy); + + jobject config = env->NewObject(javaClass->cls, javaClass->ctor); + + env->SetObjectField(config, javaClass->iceServers, serverList.get()); + env->SetObjectField(config, javaClass->iceTransportPolicy, type.get()); + env->SetObjectField(config, javaClass->bundlePolicy, bundlePolicy.get()); + env->SetObjectField(config, javaClass->rtcpMuxPolicy, rtcpMuxPolicy.get()); + env->SetObjectField(config, javaClass->certificates, certificateList.listObject()); + + return JavaLocalRef(env, config); + } + + webrtc::PeerConnectionInterface::RTCConfiguration toNative(JNIEnv * env, const JavaRef & javaType) + { + const auto javaClass = JavaClasses::get(env); + + JavaObject obj(env, javaType); + + JavaLocalRef is = obj.getObject(javaClass->iceServers); + JavaLocalRef tp = obj.getObject(javaClass->iceTransportPolicy); + JavaLocalRef bp = obj.getObject(javaClass->bundlePolicy); + JavaLocalRef mp = obj.getObject(javaClass->rtcpMuxPolicy); + JavaLocalRef cr = obj.getObject(javaClass->certificates); + + webrtc::PeerConnectionInterface::RTCConfiguration configuration; + + configuration.servers = JavaList::toVector(env, is, &RTCIceServer::toNative); + configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; + configuration.type = JavaEnums::toNative(env, tp); + configuration.bundle_policy = JavaEnums::toNative(env, bp); + configuration.rtcp_mux_policy = JavaEnums::toNative(env, mp); + + for (auto & item : JavaIterable(env, cr)) { + auto certificate = rtc::RTCCertificate::FromPEM(jni::RTCCertificatePEM::toNative(env, item)); + + RTC_CHECK(certificate != nullptr) << "Supplied certificate is malformed"; + + if (certificate != nullptr) { + configuration.certificates.push_back(certificate); + } + } + + return configuration; + } + + JavaRTCConfigurationClass::JavaRTCConfigurationClass(JNIEnv * env) + { + cls = FindClass(env, PKG"RTCConfiguration"); + + ctor = GetMethod(env, cls, "", "()V"); + + iceServers = GetFieldID(env, cls, "iceServers", LIST_SIG); + iceTransportPolicy = GetFieldID(env, cls, "iceTransportPolicy", "L" PKG "RTCIceTransportPolicy;"); + bundlePolicy = GetFieldID(env, cls, "bundlePolicy", "L" PKG "RTCBundlePolicy;"); + rtcpMuxPolicy = GetFieldID(env, cls, "rtcpMuxPolicy", "L" PKG "RTCRtcpMuxPolicy;"); + certificates = GetFieldID(env, cls, "certificates", LIST_SIG); + } + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/api/RTCRtpContributingSource.cpp b/webrtc-jni/src/main/cpp/src/api/RTCRtpContributingSource.cpp index bddd467a..47316216 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCRtpContributingSource.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCRtpContributingSource.cpp @@ -1,69 +1,73 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "api/RTCRtpContributingSource.h" -#include "JavaObject.h" -#include "JavaRef.h" -#include "JavaUtils.h" -#include "JNI_WebRTC.h" - -namespace jni -{ - namespace RTCRtpContributingSource - { - JavaLocalRef toJava(JNIEnv * env, const webrtc::RtpSource & source) - { - const auto javaClass = JavaClasses::get(env); - - jlong timestamp = static_cast(source.timestamp_ms()); - jlong sourceId = static_cast(source.source_id()); - jdouble audioLevel = static_cast(source.audio_level().value_or(0)); - jlong rtpTimestamp = static_cast(source.rtp_timestamp()); - - jobject object = env->NewObject(javaClass->cls, javaClass->ctor, - timestamp, sourceId, audioLevel, rtpTimestamp); - - return JavaLocalRef(env, object); - } - - webrtc::RtpSource toNative(JNIEnv * env, const JavaRef & source) - { - const auto javaClass = JavaClasses::get(env); - - JavaObject obj(env, source); - - return webrtc::RtpSource( - static_cast(obj.getLong(javaClass->timestamp)), - static_cast(obj.getLong(javaClass->source)), - webrtc::RtpSourceType::CSRC, - static_cast(obj.getDouble(javaClass->audioLevel)), - static_cast(obj.getLong(javaClass->rtpTimestamp)) - ); - } - - JavaRTCRtpContributingSourceClass::JavaRTCRtpContributingSourceClass(JNIEnv * env) - { - cls = FindClass(env, PKG"RTCRtpContributingSource"); - - ctor = GetMethod(env, cls, "", "(JJDJ)V"); - - timestamp = GetFieldID(env, cls, "timestamp", "J"); - source = GetFieldID(env, cls, "source", "J"); - audioLevel = GetFieldID(env, cls, "audioLevel", "D"); - rtpTimestamp = GetFieldID(env, cls, "rtpTimestamp", "J"); - } - } -} +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "api/RTCRtpContributingSource.h" +#include "JavaObject.h" +#include "JavaRef.h" +#include "JavaUtils.h" +#include "JNI_WebRTC.h" + +namespace jni +{ + namespace RTCRtpContributingSource + { + JavaLocalRef toJava(JNIEnv * env, const webrtc::RtpSource & source) + { + const auto javaClass = JavaClasses::get(env); + + jlong timestamp = static_cast(source.timestamp().us()); + jlong sourceId = static_cast(source.source_id()); + jdouble audioLevel = static_cast(source.audio_level().value_or(0)); + jlong rtpTimestamp = static_cast(source.rtp_timestamp()); + + jobject object = env->NewObject(javaClass->cls, javaClass->ctor, + timestamp, sourceId, audioLevel, rtpTimestamp); + + return JavaLocalRef(env, object); + } + + webrtc::RtpSource toNative(JNIEnv * env, const JavaRef & source) + { + const auto javaClass = JavaClasses::get(env); + + JavaObject obj(env, source); + + webrtc::RtpSource::Extensions extensions; + extensions.audio_level = static_cast(obj.getDouble(javaClass->audioLevel)); + + return webrtc::RtpSource( + webrtc::Timestamp::Micros(static_cast(obj.getLong(javaClass->timestamp))), + static_cast(obj.getLong(javaClass->sourceId)), + webrtc::RtpSourceType::CSRC, + static_cast(obj.getLong(javaClass->rtpTimestamp)), + extensions + ); + } + + JavaRTCRtpContributingSourceClass::JavaRTCRtpContributingSourceClass(JNIEnv * env) + { + cls = FindClass(env, PKG"RTCRtpContributingSource"); + + ctor = GetMethod(env, cls, "", "(JJDJ)V"); + + timestamp = GetFieldID(env, cls, "timestamp", "J"); + sourceId = GetFieldID(env, cls, "sourceId", "J"); + sourceType = GetFieldID(env, cls, "sourceType", "J"); + audioLevel = GetFieldID(env, cls, "audioLevel", "D"); + rtpTimestamp = GetFieldID(env, cls, "rtpTimestamp", "J"); + } + } +} diff --git a/webrtc-jni/src/main/cpp/src/api/RTCRtpSynchronizationSource.cpp b/webrtc-jni/src/main/cpp/src/api/RTCRtpSynchronizationSource.cpp index 326ebb5f..fc9621b7 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCRtpSynchronizationSource.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCRtpSynchronizationSource.cpp @@ -1,69 +1,72 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "api/RTCRtpSynchronizationSource.h" -#include "api/RTCRtpContributingSource.h" -#include "JavaObject.h" -#include "JavaRef.h" -#include "JavaUtils.h" -#include "JNI_WebRTC.h" - -namespace jni -{ - namespace RTCRtpSynchronizationSource - { - JavaLocalRef toJava(JNIEnv * env, const webrtc::RtpSource & source) - { - const auto javaClass = JavaClasses::get(env); - - jlong timestamp = static_cast(source.timestamp_ms()); - jlong sourceId = static_cast(source.source_id()); - jdouble audioLevel = static_cast(source.audio_level().value_or(0)); - jlong rtpTimestamp = static_cast(source.rtp_timestamp()); - jboolean voiceActivityFlag = false; - - jobject object = env->NewObject(javaClass->cls, javaClass->ctor, - timestamp, sourceId, audioLevel, rtpTimestamp, voiceActivityFlag); - - return JavaLocalRef(env, object); - } - - webrtc::RtpSource toNative(JNIEnv * env, const JavaRef & source) - { - const auto javaClass = JavaClasses::get(env); - const auto parentClass = JavaClasses::get(env); - - JavaObject obj(env, source); - - return webrtc::RtpSource( - static_cast(obj.getLong(parentClass->timestamp)), - static_cast(obj.getLong(parentClass->source)), - webrtc::RtpSourceType::SSRC, - static_cast(obj.getDouble(parentClass->audioLevel)), - static_cast(obj.getLong(parentClass->rtpTimestamp)) - ); - } - - JavaRTCRtpSynchronizationSourceClass::JavaRTCRtpSynchronizationSourceClass(JNIEnv * env) - { - cls = FindClass(env, PKG"RTCRtpSynchronizationSource"); - - ctor = GetMethod(env, cls, "", "(JJDJZ)V"); - - voiceActivityFlag = GetFieldID(env, cls, "voiceActivityFlag", "Z"); - } - } -} +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "api/RTCRtpSynchronizationSource.h" +#include "api/RTCRtpContributingSource.h" +#include "JavaObject.h" +#include "JavaRef.h" +#include "JavaUtils.h" +#include "JNI_WebRTC.h" + +namespace jni +{ + namespace RTCRtpSynchronizationSource + { + JavaLocalRef toJava(JNIEnv * env, const webrtc::RtpSource & source) + { + const auto javaClass = JavaClasses::get(env); + + jlong timestamp = static_cast(source.timestamp().us()); + jlong sourceId = static_cast(source.source_id()); + jdouble audioLevel = static_cast(source.audio_level().value_or(0)); + jlong rtpTimestamp = static_cast(source.rtp_timestamp()); + jboolean voiceActivityFlag = false; + + jobject object = env->NewObject(javaClass->cls, javaClass->ctor, + timestamp, sourceId, audioLevel, rtpTimestamp, voiceActivityFlag); + + return JavaLocalRef(env, object); + } + + webrtc::RtpSource toNative(JNIEnv * env, const JavaRef & source) + { + const auto javaClass = JavaClasses::get(env); + const auto parentClass = JavaClasses::get(env); + + JavaObject obj(env, source); + + webrtc::RtpSource::Extensions extensions; + extensions.audio_level = static_cast(obj.getDouble(parentClass->audioLevel)); + + return webrtc::RtpSource( + webrtc::Timestamp::Micros(static_cast(obj.getLong(parentClass->timestamp))), + static_cast(obj.getLong(parentClass->sourceId)), + webrtc::RtpSourceType::SSRC, + static_cast(obj.getLong(parentClass->rtpTimestamp)), + extensions + ); + } + + JavaRTCRtpSynchronizationSourceClass::JavaRTCRtpSynchronizationSourceClass(JNIEnv * env) + { + cls = FindClass(env, PKG"RTCRtpSynchronizationSource"); + + ctor = GetMethod(env, cls, "", "(JJDJZ)V"); + + voiceActivityFlag = GetFieldID(env, cls, "voiceActivityFlag", "Z"); + } + } +} diff --git a/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp b/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp index 5525f7f7..f0c9b55d 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp @@ -1,211 +1,221 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "api/RTCStats.h" -#include "JavaBigInteger.h" -#include "JavaClasses.h" -#include "JavaEnums.h" -#include "JavaHashMap.h" -#include "JavaPrimitive.h" -#include "JavaString.h" -#include "JNI_WebRTC.h" - -#include "rtc_base/logging.h" -#include "rtc_base/string_encode.h" - -#include -#include - -namespace jni -{ - namespace RTCStats - { - std::map initTypeMap() - { - std::string typeNames[] = { - "codec", - "inbound-rtp", - "outbound-rtp", - "remote-inbound-rtp", - "remote-outbound-rtp", - "media-source", - "csrc", - "peer-connection", - "data-channel", - "stream", - "track", - "sender", - "receiver", - "transport", - "candidate-pair", - "local-candidate", - "remote-candidate", - "certificate", - "ice-server" - }; - - std::map map; - uint8_t index = 0; - - for (const auto & name : typeNames) { - map[name] = index++; - } - - return map; - } - - const std::map typeMap = initTypeMap(); - - - JavaLocalRef toJava(JNIEnv * env, const webrtc::RTCStats & stats) - { - const auto javaClass = JavaClasses::get(env); - - JavaHashMap memberMap(env); - - for (const auto * member : stats.Members()) { - if (!member->is_defined()) { - continue; - } - - JavaLocalRef key = JavaString::toJava(env, member->name()); - JavaLocalRef value = toJava(env, *member); - - memberMap.put(key, value); - } - - JavaLocalRef type = nullptr; - - auto result = typeMap.find(stats.type()); - if (result != typeMap.end()) { - type = jni::JavaEnums::toJava(env, static_cast(result->second)); - } - else { - RTC_LOG(LS_WARNING) << "No Java Enum for '" << stats.type() << "' found"; - } - - jobject obj = env->NewObject(javaClass->cls, javaClass->ctor, - stats.timestamp_us(), - type ? type.get() : type, - JavaString::toJava(env, stats.id()).get(), - ((JavaLocalRef)memberMap).get()); - - return JavaLocalRef(env, obj); - } - - JavaLocalRef toJava(JNIEnv * env, const webrtc::RTCStatsMemberInterface & member) - { - switch (member.type()) { - case webrtc::RTCStatsMemberInterface::kBool: - return Boolean::create(env, *member.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kInt32: - return Integer::create(env, *member.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kUint32: - return Long::create(env, *member.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kInt64: - return Long::create(env, *member.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kUint64: - return JavaBigInteger::toJava(env, rtc::ToString(*member.cast_to>())); - - case webrtc::RTCStatsMemberInterface::kDouble: - return Double::create(env, *member.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kString: - return jni::static_java_ref_cast(env, - JavaString::toJava(env, *member.cast_to>())); - - case webrtc::RTCStatsMemberInterface::kSequenceBool: - return jni::static_java_ref_cast(env, - Boolean::createArray(env, *member.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceInt32: - return jni::static_java_ref_cast(env, - Integer::createArray(env, *member.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceUint32: - { - const std::vector & v = *member.cast_to>>(); - return jni::static_java_ref_cast(env, - Long::createArray(env, std::vector(v.begin(), v.end()))); - } - - case webrtc::RTCStatsMemberInterface::kSequenceInt64: - return jni::static_java_ref_cast(env, - Long::createArray(env, *member.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceUint64: - { - const std::vector & v = *member.cast_to>>(); - std::vector r; - - std::transform(v.begin(), v.end(), std::back_inserter(r), - [](uint64_t n) { return rtc::ToString(n); }); - - return jni::static_java_ref_cast(env, JavaBigInteger::createArray(env, r)); - } - - case webrtc::RTCStatsMemberInterface::kSequenceDouble: - return jni::static_java_ref_cast(env, - Double::createArray(env, *member.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceString: - return jni::static_java_ref_cast(env, - JavaString::createArray(env, *member.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kMapStringDouble: - { - std::map map = *member.cast_to>>(); - - JavaHashMap memberMap(env); - - for (const auto& item : map) { - memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), - Double::create(env, item.second)); - } - - return jni::static_java_ref_cast(env, memberMap); - } - - case webrtc::RTCStatsMemberInterface::kMapStringUint64: - { - std::map map = *member.cast_to>>(); - - JavaHashMap memberMap(env); - - for (const auto& item : map) { - memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), - JavaBigInteger::toJava(env, rtc::ToString(item.second))); - } - - return jni::static_java_ref_cast(env, memberMap); - } - } - - return nullptr; - } - - JavaRTCStatsClass::JavaRTCStatsClass(JNIEnv * env) - { - cls = FindClass(env, PKG"RTCStats"); - - ctor = GetMethod(env, cls, "", "(JL" PKG "RTCStatsType;" STRING_SIG MAP_SIG ")V"); - } - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "api/RTCStats.h" +#include "JavaBigInteger.h" +#include "JavaClasses.h" +#include "JavaEnums.h" +#include "JavaHashMap.h" +#include "JavaPrimitive.h" +#include "JavaString.h" +#include "JNI_WebRTC.h" + +#include "api/stats/attribute.h" +#include "rtc_base/logging.h" +#include "rtc_base/string_encode.h" + +#include +#include + +namespace jni +{ + namespace RTCStats + { + std::map initTypeMap() + { + std::string typeNames[] = { + "codec", + "inbound-rtp", + "outbound-rtp", + "remote-inbound-rtp", + "remote-outbound-rtp", + "media-source", + "csrc", + "peer-connection", + "data-channel", + "stream", + "track", + "sender", + "receiver", + "transport", + "candidate-pair", + "local-candidate", + "remote-candidate", + "certificate", + "ice-server" + }; + + std::map map; + uint8_t index = 0; + + for (const auto & name : typeNames) { + map[name] = index++; + } + + return map; + } + + const std::map typeMap = initTypeMap(); + + + JavaLocalRef toJava(JNIEnv * env, const webrtc::RTCStats & stats) + { + const auto javaClass = JavaClasses::get(env); + + JavaHashMap attributeMap(env); + + for (const auto & attribute : stats.Attributes()) { + if (!attribute.has_value()) { + continue; + } + + JavaLocalRef key = JavaString::toJava(env, attribute.name()); + JavaLocalRef value = toJava(env, attribute); + + attributeMap.put(key, value); + } + + JavaLocalRef type = nullptr; + + auto result = typeMap.find(stats.type()); + if (result != typeMap.end()) { + type = jni::JavaEnums::toJava(env, static_cast(result->second)); + } + else { + RTC_LOG(LS_WARNING) << "No Java Enum for '" << stats.type() << "' found"; + } + + jobject obj = env->NewObject(javaClass->cls, javaClass->ctor, + stats.timestamp(), + type ? type.get() : type, + JavaString::toJava(env, stats.id()).get(), + ((JavaLocalRef)attributeMap).get()); + + return JavaLocalRef(env, obj); + } + + JavaLocalRef toJava(JNIEnv * env, const webrtc::Attribute & attribute) + { + if (attribute.has_value()) { + auto value = attribute.as_variant(); + + + } + + + /* + switch (attribute.type()) { + case webrtc::RTCStatsMemberInterface::kBool: + return Boolean::create(env, *attribute.cast_to>()); + + case webrtc::RTCStatsMemberInterface::kInt32: + return Integer::create(env, *attribute.cast_to>()); + + case webrtc::RTCStatsMemberInterface::kUint32: + return Long::create(env, *attribute.cast_to>()); + + case webrtc::RTCStatsMemberInterface::kInt64: + return Long::create(env, *attribute.cast_to>()); + + case webrtc::RTCStatsMemberInterface::kUint64: + return JavaBigInteger::toJava(env, rtc::ToString(*attribute.cast_to>())); + + case webrtc::RTCStatsMemberInterface::kDouble: + return Double::create(env, *attribute.cast_to>()); + + case webrtc::RTCStatsMemberInterface::kString: + return jni::static_java_ref_cast(env, + JavaString::toJava(env, *attribute.cast_to>())); + + case webrtc::RTCStatsMemberInterface::kSequenceBool: + return jni::static_java_ref_cast(env, + Boolean::createArray(env, *attribute.cast_to>>())); + + case webrtc::RTCStatsMemberInterface::kSequenceInt32: + return jni::static_java_ref_cast(env, + Integer::createArray(env, *attribute.cast_to>>())); + + case webrtc::RTCStatsMemberInterface::kSequenceUint32: + { + const std::vector & v = *attribute.cast_to>>(); + return jni::static_java_ref_cast(env, + Long::createArray(env, std::vector(v.begin(), v.end()))); + } + + case webrtc::RTCStatsMemberInterface::kSequenceInt64: + return jni::static_java_ref_cast(env, + Long::createArray(env, *attribute.cast_to>>())); + + case webrtc::RTCStatsMemberInterface::kSequenceUint64: + { + const std::vector & v = *attribute.cast_to>>(); + std::vector r; + + std::transform(v.begin(), v.end(), std::back_inserter(r), + [](uint64_t n) { return rtc::ToString(n); }); + + return jni::static_java_ref_cast(env, JavaBigInteger::createArray(env, r)); + } + + case webrtc::RTCStatsMemberInterface::kSequenceDouble: + return jni::static_java_ref_cast(env, + Double::createArray(env, *attribute.cast_to>>())); + + case webrtc::RTCStatsMemberInterface::kSequenceString: + return jni::static_java_ref_cast(env, + JavaString::createArray(env, *attribute.cast_to>>())); + + case webrtc::RTCStatsMemberInterface::kMapStringDouble: + { + std::map map = *attribute.cast_to>>(); + + JavaHashMap memberMap(env); + + for (const auto& item : map) { + memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), + Double::create(env, item.second)); + } + + return jni::static_java_ref_cast(env, memberMap); + } + + case webrtc::RTCStatsMemberInterface::kMapStringUint64: + { + std::map map = *attribute.cast_to>>(); + + JavaHashMap memberMap(env); + + for (const auto& item : map) { + memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), + JavaBigInteger::toJava(env, rtc::ToString(item.second))); + } + + return jni::static_java_ref_cast(env, memberMap); + } + } + */ + + return nullptr; + } + + JavaRTCStatsClass::JavaRTCStatsClass(JNIEnv * env) + { + cls = FindClass(env, PKG"RTCStats"); + + ctor = GetMethod(env, cls, "", "(JL" PKG "RTCStatsType;" STRING_SIG MAP_SIG ")V"); + } + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/media/audio/AudioConverter.cpp b/webrtc-jni/src/main/cpp/src/media/audio/AudioConverter.cpp index 19f6d487..7014a44b 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/AudioConverter.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/AudioConverter.cpp @@ -1,200 +1,200 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -#include "media/audio/AudioConverter.h" - -#include - -#include "audio/utility/channel_mixer.h" -#include "common_audio/resampler/include/push_resampler.h" - -namespace jni -{ - class CopyConverter : public AudioConverter { - public: - CopyConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) - : AudioConverter(srcFrames, srcChannels, dstFrames, dstChannels) - { - } - - ~CopyConverter() override - { - } - - void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { - checkSizes(srcSize, dstSize); - - if (src != dst) { - std::memcpy(dst, src, dstFrames * dstChannels * sizeof(int16_t)); - } - } - }; - - - class ChannelConverter : public AudioConverter { - public: - ChannelConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) - : AudioConverter(srcFrames, srcChannels, dstFrames, dstChannels) - { - webrtc::ChannelLayout srcLayout = webrtc::GuessChannelLayout(static_cast(srcChannels)); - webrtc::ChannelLayout dstLayout = webrtc::GuessChannelLayout(static_cast(dstChannels)); - - mixer = std::make_unique(srcLayout, dstLayout); - frame = std::make_unique(); - - frame->samples_per_channel_ = srcFrames; - frame->num_channels_ = srcChannels; - } - - ~ChannelConverter() override - { - } - - void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { - checkSizes(srcSize, dstSize); - - std::memcpy(frame->mutable_data(), src, srcFrames * srcChannels * sizeof(int16_t)); - - mixer->Transform(frame.get()); - - std::memcpy(dst, frame->data(), dstFrames * dstChannels * sizeof(int16_t)); - } - - private: - std::unique_ptr mixer; - std::unique_ptr frame; - }; - - - class ResampleConverter : public AudioConverter { - public: - ResampleConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) - : AudioConverter(srcFrames, srcChannels, dstFrames, dstChannels) - { - resampler = std::make_unique>(); - resampler->InitializeIfNeeded(static_cast(srcFrames * 100), static_cast(dstFrames * 100), srcChannels); - } - - ~ResampleConverter() override - { - } - - void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { - checkSizes(srcSize, dstSize); - - resampler->Resample(src, srcSize, dst, dstSize); - } - - private: - std::unique_ptr> resampler; - }; - - - class CompositionConverter : public AudioConverter { - public: - explicit CompositionConverter(std::vector> converters_) - : converters(std::move(converters_)) - { - RTC_CHECK_GE(converters.size(), 2); - - // We need an intermediate buffer after every converter. - for (auto it = converters.begin(); it != converters.end() - 1; ++it) { - buffers.push_back(std::vector((*it)->getDstFrames() * (*it)->getDstChannels(), 0)); - } - } - - ~CompositionConverter() override - { - } - - void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { - converters.front()->convert(src, srcSize, buffers.front().data(), buffers.front().size()); - - for (size_t i = 2; i < converters.size(); ++i) { - auto & src_buffer = buffers[i - 2]; - auto & dst_buffer = buffers[i - 1]; - - converters[i]->convert(src_buffer.data(), src_buffer.size(), dst_buffer.data(), dst_buffer.size()); - } - - converters.back()->convert(buffers.back().data(), buffers.back().size(), dst, dstSize); - } - - private: - std::vector> converters; - std::vector> buffers; - }; - - - std::unique_ptr AudioConverter::create(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) - { - std::unique_ptr converter; - - if (srcChannels > dstChannels) { - if (srcFrames != dstFrames) { - std::vector> converters; - converters.push_back(std::unique_ptr(new ChannelConverter(srcFrames, srcChannels, srcFrames, dstChannels))); - converters.push_back(std::unique_ptr(new ResampleConverter(srcFrames, dstChannels, dstFrames, dstChannels))); - - converter.reset(new CompositionConverter(std::move(converters))); - } - else { - converter.reset(new ChannelConverter(srcFrames, srcChannels, dstFrames, dstChannels)); - } - } - else if (srcChannels < dstChannels) { - if (srcFrames != dstFrames) { - std::vector> converters; - converters.push_back(std::unique_ptr(new ResampleConverter(srcFrames, srcChannels, dstFrames, srcChannels))); - converters.push_back(std::unique_ptr(new ChannelConverter(dstFrames, srcChannels, dstFrames, dstChannels))); - - converter.reset(new CompositionConverter(std::move(converters))); - } - else { - converter.reset(new ChannelConverter(srcFrames, srcChannels, dstFrames, dstChannels)); - } - } - else if (srcFrames != dstFrames) { - converter.reset(new ResampleConverter(srcFrames, srcChannels, dstFrames, dstChannels)); - } - else { - converter.reset(new CopyConverter(srcFrames, srcChannels, dstFrames, dstChannels)); - } - - return converter; - } - - AudioConverter::AudioConverter() : - srcFrames(0), - srcChannels(0), - dstFrames(0), - dstChannels(0) - { - } - - AudioConverter::AudioConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) : - srcFrames(srcFrames), - srcChannels(srcChannels), - dstFrames(dstFrames), - dstChannels(dstChannels) - { - } - - void AudioConverter::checkSizes(size_t srcSize, size_t dstCapacity) const { - RTC_CHECK_EQ(srcSize, srcChannels * srcFrames); - RTC_CHECK_GE(dstCapacity, dstChannels * dstFrames); - } +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +#include "media/audio/AudioConverter.h" + +#include + +#include "audio/utility/channel_mixer.h" +#include "common_audio/resampler/include/push_resampler.h" + +namespace jni +{ + class CopyConverter : public AudioConverter { + public: + CopyConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) + : AudioConverter(srcFrames, srcChannels, dstFrames, dstChannels) + { + } + + ~CopyConverter() override + { + } + + void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { + checkSizes(srcSize, dstSize); + + if (src != dst) { + std::memcpy(dst, src, dstFrames * dstChannels * sizeof(int16_t)); + } + } + }; + + + class ChannelConverter : public AudioConverter { + public: + ChannelConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) + : AudioConverter(srcFrames, srcChannels, dstFrames, dstChannels) + { + webrtc::ChannelLayout srcLayout = webrtc::GuessChannelLayout(static_cast(srcChannels)); + webrtc::ChannelLayout dstLayout = webrtc::GuessChannelLayout(static_cast(dstChannels)); + + mixer = std::make_unique(srcLayout, dstLayout); + frame = std::make_unique(); + + frame->samples_per_channel_ = srcFrames; + frame->num_channels_ = srcChannels; + } + + ~ChannelConverter() override + { + } + + void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { + checkSizes(srcSize, dstSize); + + std::memcpy(frame->mutable_data(), src, srcFrames * srcChannels * sizeof(int16_t)); + + mixer->Transform(frame.get()); + + std::memcpy(dst, frame->data(), dstFrames * dstChannels * sizeof(int16_t)); + } + + private: + std::unique_ptr mixer; + std::unique_ptr frame; + }; + + + class ResampleConverter : public AudioConverter { + public: + ResampleConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) + : AudioConverter(srcFrames, srcChannels, dstFrames, dstChannels) + { + resampler = std::make_unique>(srcFrames, dstFrames, srcChannels); + } + + ~ResampleConverter() override + { + } + + void convert(const int16_t * src, size_t srcSamplesPerChannel, int16_t * dst, size_t dstSamplesPerChannel) override { + webrtc::InterleavedView srcView(src, srcSamplesPerChannel, srcChannels); + webrtc::InterleavedView dstView(dst, dstSamplesPerChannel, srcChannels); + + resampler->Resample(srcView, dstView); + } + + private: + std::unique_ptr> resampler; + }; + + + class CompositionConverter : public AudioConverter { + public: + explicit CompositionConverter(std::vector> converters_) + : converters(std::move(converters_)) + { + RTC_CHECK_GE(converters.size(), 2); + + // We need an intermediate buffer after every converter. + for (auto it = converters.begin(); it != converters.end() - 1; ++it) { + buffers.push_back(std::vector((*it)->getDstFrames() * (*it)->getDstChannels(), 0)); + } + } + + ~CompositionConverter() override + { + } + + void convert(const int16_t * src, size_t srcSize, int16_t * dst, size_t dstSize) override { + converters.front()->convert(src, srcSize, buffers.front().data(), buffers.front().size()); + + for (size_t i = 2; i < converters.size(); ++i) { + auto & src_buffer = buffers[i - 2]; + auto & dst_buffer = buffers[i - 1]; + + converters[i]->convert(src_buffer.data(), src_buffer.size(), dst_buffer.data(), dst_buffer.size()); + } + + converters.back()->convert(buffers.back().data(), buffers.back().size(), dst, dstSize); + } + + private: + std::vector> converters; + std::vector> buffers; + }; + + + std::unique_ptr AudioConverter::create(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) + { + std::unique_ptr converter; + + if (srcChannels > dstChannels) { + if (srcFrames != dstFrames) { + std::vector> converters; + converters.push_back(std::unique_ptr(new ChannelConverter(srcFrames, srcChannels, srcFrames, dstChannels))); + converters.push_back(std::unique_ptr(new ResampleConverter(srcFrames, dstChannels, dstFrames, dstChannels))); + + converter.reset(new CompositionConverter(std::move(converters))); + } + else { + converter.reset(new ChannelConverter(srcFrames, srcChannels, dstFrames, dstChannels)); + } + } + else if (srcChannels < dstChannels) { + if (srcFrames != dstFrames) { + std::vector> converters; + converters.push_back(std::unique_ptr(new ResampleConverter(srcFrames, srcChannels, dstFrames, srcChannels))); + converters.push_back(std::unique_ptr(new ChannelConverter(dstFrames, srcChannels, dstFrames, dstChannels))); + + converter.reset(new CompositionConverter(std::move(converters))); + } + else { + converter.reset(new ChannelConverter(srcFrames, srcChannels, dstFrames, dstChannels)); + } + } + else if (srcFrames != dstFrames) { + converter.reset(new ResampleConverter(srcFrames, srcChannels, dstFrames, dstChannels)); + } + else { + converter.reset(new CopyConverter(srcFrames, srcChannels, dstFrames, dstChannels)); + } + + return converter; + } + + AudioConverter::AudioConverter() : + srcFrames(0), + srcChannels(0), + dstFrames(0), + dstChannels(0) + { + } + + AudioConverter::AudioConverter(size_t srcFrames, size_t srcChannels, size_t dstFrames, size_t dstChannels) : + srcFrames(srcFrames), + srcChannels(srcChannels), + dstFrames(dstFrames), + dstChannels(dstChannels) + { + } + + void AudioConverter::checkSizes(size_t srcSize, size_t dstCapacity) const { + RTC_CHECK_EQ(srcSize, srcChannels * srcFrames); + RTC_CHECK_GE(dstCapacity, dstChannels * dstFrames); + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp index a14188cd..d807aab6 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp @@ -1,183 +1,145 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -#include "media/audio/AudioProcessingConfig.h" - -#include "JavaClasses.h" -#include "JavaEnums.h" -#include "JavaObject.h" -#include "JavaRef.h" -#include "JavaUtils.h" -#include "JNI_WebRTC.h" - -namespace jni -{ - namespace AudioProcessingConfig - { - webrtc::AudioProcessing::Config toNative(JNIEnv * env, const JavaRef & javaType) - { - const auto javaClass = JavaClasses::get(env); - const auto javaEchoCancellerClass = JavaClasses::get(env); - const auto javaHighPassFilterClass = JavaClasses::get(env); - const auto javaNoiseSuppressionClass = JavaClasses::get(env); - const auto javaResidualEchoDetectorClass = JavaClasses::get(env); - const auto javaTransientSuppressionClass = JavaClasses::get(env); - const auto javaVoiceDetectionClass = JavaClasses::get(env); - - JavaObject obj(env, javaType); - JavaObject echoCanceller(env, obj.getObject(javaClass->echoCanceller)); - JavaObject highPassFilter(env, obj.getObject(javaClass->highPassFilter)); - JavaObject noiseSuppression(env, obj.getObject(javaClass->noiseSuppression)); - JavaObject residualEchoDetector(env, obj.getObject(javaClass->residualEchoDetector)); - JavaObject transientSuppression(env, obj.getObject(javaClass->transientSuppression)); - JavaObject voiceDetection(env, obj.getObject(javaClass->voiceDetection)); - - webrtc::AudioProcessing::Config config; - - config.echo_canceller.enabled = echoCanceller.getBoolean(javaEchoCancellerClass->enabled); - config.echo_canceller.enforce_high_pass_filtering = echoCanceller.getBoolean(javaEchoCancellerClass->enforceHighPassFiltering); - - config.gain_controller2 = toGainController2(env, obj.getObject(javaClass->gainControl)); - - config.high_pass_filter.enabled = highPassFilter.getBoolean(javaHighPassFilterClass->enabled); - - config.noise_suppression.enabled = noiseSuppression.getBoolean(javaNoiseSuppressionClass->enabled); - - JavaLocalRef nsLevel = noiseSuppression.getObject(javaNoiseSuppressionClass->level); - - if (nsLevel.get()) { - config.noise_suppression.level = jni::JavaEnums::toNative(env, nsLevel); - } - - config.residual_echo_detector.enabled = residualEchoDetector.getBoolean(javaResidualEchoDetectorClass->enabled); - - config.transient_suppression.enabled = transientSuppression.getBoolean(javaTransientSuppressionClass->enabled); - - config.voice_detection.enabled = voiceDetection.getBoolean(javaVoiceDetectionClass->enabled); - - return config; - } - - webrtc::AudioProcessing::Config::GainController2 toGainController2(JNIEnv * env, const JavaLocalRef & javaType) - { - const auto javaGainControlClass = JavaClasses::get(env); - const auto javaGainControlFixedDigitalClass = JavaClasses::get(env); - const auto javaGainControlAdaptiveDigitalClass = JavaClasses::get(env); - - JavaObject gainControl(env, javaType); - JavaObject gainControlFixedDigital(env, gainControl.getObject(javaGainControlClass->fixedDigital)); - JavaObject gainControlAdaptiveDigital(env, gainControl.getObject(javaGainControlClass->adaptiveDigital)); - - webrtc::AudioProcessing::Config::GainController2 gainController; - - gainController.enabled = gainControl.getBoolean(javaGainControlClass->enabled); - gainController.fixed_digital.gain_db = gainControlFixedDigital.getFloat(javaGainControlFixedDigitalClass->gainDb); - gainController.adaptive_digital.enabled = gainControlAdaptiveDigital.getBoolean(javaGainControlAdaptiveDigitalClass->enabled); - gainController.adaptive_digital.dry_run = gainControlAdaptiveDigital.getBoolean(javaGainControlAdaptiveDigitalClass->dryRun); - gainController.adaptive_digital.vad_reset_period_ms = gainControlAdaptiveDigital.getInt(javaGainControlAdaptiveDigitalClass->vadResetPeriodMs); - gainController.adaptive_digital.adjacent_speech_frames_threshold = gainControlAdaptiveDigital.getInt(javaGainControlAdaptiveDigitalClass->adjacentSpeechFramesThreshold); - gainController.adaptive_digital.max_gain_change_db_per_second = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->maxGainChangeDbPerSecond); - gainController.adaptive_digital.max_output_noise_level_dbfs = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->maxOutputNoiseLevelDbfs); - - return gainController; - } - - JavaAudioProcessingConfigClass::JavaAudioProcessingConfigClass(JNIEnv * env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig"); - - echoCanceller = GetFieldID(env, cls, "echoCanceller", "L" PKG_AUDIO "AudioProcessingConfig$EchoCanceller;"); - gainControl = GetFieldID(env, cls, "gainControl", "L" PKG_AUDIO "AudioProcessingConfig$GainControl;"); - highPassFilter = GetFieldID(env, cls, "highPassFilter", "L" PKG_AUDIO "AudioProcessingConfig$HighPassFilter;"); - noiseSuppression = GetFieldID(env, cls, "noiseSuppression", "L" PKG_AUDIO "AudioProcessingConfig$NoiseSuppression;"); - residualEchoDetector = GetFieldID(env, cls, "residualEchoDetector", "L" PKG_AUDIO "AudioProcessingConfig$ResidualEchoDetector;"); - transientSuppression = GetFieldID(env, cls, "transientSuppression", "L" PKG_AUDIO "AudioProcessingConfig$TransientSuppression;"); - voiceDetection = GetFieldID(env, cls, "voiceDetection", "L" PKG_AUDIO "AudioProcessingConfig$VoiceDetection;"); - } - - JavaEchoCancellerClass::JavaEchoCancellerClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$EchoCanceller"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - enforceHighPassFiltering = GetFieldID(env, cls, "enforceHighPassFiltering", "Z"); - } - - JavaGainControlClass::JavaGainControlClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$GainControl"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - fixedDigital = GetFieldID(env, cls, "fixedDigital", "L" PKG_AUDIO "AudioProcessingConfig$GainControl$FixedDigital;"); - adaptiveDigital = GetFieldID(env, cls, "adaptiveDigital", "L" PKG_AUDIO "AudioProcessingConfig$GainControl$AdaptiveDigital;"); - } - - JavaGainControlFixedDigitalClass::JavaGainControlFixedDigitalClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$GainControl$FixedDigital"); - - gainDb = GetFieldID(env, cls, "gainDb", "F"); - } - - JavaGainControlAdaptiveDigitalClass::JavaGainControlAdaptiveDigitalClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$GainControl$AdaptiveDigital"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - dryRun = GetFieldID(env, cls, "dryRun", "Z"); - vadResetPeriodMs = GetFieldID(env, cls, "vadResetPeriodMs", "I"); - adjacentSpeechFramesThreshold = GetFieldID(env, cls, "adjacentSpeechFramesThreshold", "I"); - maxGainChangeDbPerSecond = GetFieldID(env, cls, "maxGainChangeDbPerSecond", "F"); - maxOutputNoiseLevelDbfs = GetFieldID(env, cls, "maxOutputNoiseLevelDbfs", "F"); - } - - JavaHighPassFilterClass::JavaHighPassFilterClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$HighPassFilter"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - } - - JavaNoiseSuppressionClass::JavaNoiseSuppressionClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$NoiseSuppression"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - level = GetFieldID(env, cls, "level", "L" PKG_AUDIO "AudioProcessingConfig$NoiseSuppression$Level;"); - } - - JavaResidualEchoDetectorClass::JavaResidualEchoDetectorClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$ResidualEchoDetector"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - } - - JavaTransientSuppressionClass::JavaTransientSuppressionClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$TransientSuppression"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - } - - JavaVoiceDetectionClass::JavaVoiceDetectionClass(JNIEnv* env) - { - cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$VoiceDetection"); - - enabled = GetFieldID(env, cls, "enabled", "Z"); - } - } +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +#include "media/audio/AudioProcessingConfig.h" + +#include "JavaClasses.h" +#include "JavaEnums.h" +#include "JavaObject.h" +#include "JavaRef.h" +#include "JavaUtils.h" +#include "JNI_WebRTC.h" + +namespace jni +{ + namespace AudioProcessingConfig + { + webrtc::AudioProcessing::Config toNative(JNIEnv * env, const JavaRef & javaType) + { + const auto javaClass = JavaClasses::get(env); + const auto javaEchoCancellerClass = JavaClasses::get(env); + const auto javaHighPassFilterClass = JavaClasses::get(env); + const auto javaNoiseSuppressionClass = JavaClasses::get(env); + + JavaObject obj(env, javaType); + JavaObject echoCanceller(env, obj.getObject(javaClass->echoCanceller)); + JavaObject highPassFilter(env, obj.getObject(javaClass->highPassFilter)); + JavaObject noiseSuppression(env, obj.getObject(javaClass->noiseSuppression)); + + webrtc::AudioProcessing::Config config; + + config.echo_canceller.enabled = echoCanceller.getBoolean(javaEchoCancellerClass->enabled); + config.echo_canceller.enforce_high_pass_filtering = echoCanceller.getBoolean(javaEchoCancellerClass->enforceHighPassFiltering); + config.gain_controller2 = toGainController2(env, obj.getObject(javaClass->gainControl)); + config.high_pass_filter.enabled = highPassFilter.getBoolean(javaHighPassFilterClass->enabled); + config.noise_suppression.enabled = noiseSuppression.getBoolean(javaNoiseSuppressionClass->enabled); + + JavaLocalRef nsLevel = noiseSuppression.getObject(javaNoiseSuppressionClass->level); + + if (nsLevel.get()) { + config.noise_suppression.level = jni::JavaEnums::toNative(env, nsLevel); + } + + return config; + } + + webrtc::AudioProcessing::Config::GainController2 toGainController2(JNIEnv * env, const JavaLocalRef & javaType) + { + const auto javaGainControlClass = JavaClasses::get(env); + const auto javaGainControlFixedDigitalClass = JavaClasses::get(env); + const auto javaGainControlAdaptiveDigitalClass = JavaClasses::get(env); + + JavaObject gainControl(env, javaType); + JavaObject gainControlFixedDigital(env, gainControl.getObject(javaGainControlClass->fixedDigital)); + JavaObject gainControlAdaptiveDigital(env, gainControl.getObject(javaGainControlClass->adaptiveDigital)); + + webrtc::AudioProcessing::Config::GainController2 gainController; + + gainController.enabled = gainControl.getBoolean(javaGainControlClass->enabled); + gainController.fixed_digital.gain_db = gainControlFixedDigital.getFloat(javaGainControlFixedDigitalClass->gainDb); + gainController.adaptive_digital.enabled = gainControlAdaptiveDigital.getBoolean(javaGainControlAdaptiveDigitalClass->enabled); + gainController.adaptive_digital.headroom_db = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->headroomDb); + gainController.adaptive_digital.initial_gain_db = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->initialGainDb); + gainController.adaptive_digital.max_gain_db = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->maxGainDb); + gainController.adaptive_digital.max_gain_change_db_per_second = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->maxGainChangeDbPerSecond); + gainController.adaptive_digital.max_output_noise_level_dbfs = gainControlAdaptiveDigital.getFloat(javaGainControlAdaptiveDigitalClass->maxOutputNoiseLevelDbfs); + + return gainController; + } + + JavaAudioProcessingConfigClass::JavaAudioProcessingConfigClass(JNIEnv * env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig"); + + echoCanceller = GetFieldID(env, cls, "echoCanceller", "L" PKG_AUDIO "AudioProcessingConfig$EchoCanceller;"); + gainControl = GetFieldID(env, cls, "gainControl", "L" PKG_AUDIO "AudioProcessingConfig$GainControl;"); + highPassFilter = GetFieldID(env, cls, "highPassFilter", "L" PKG_AUDIO "AudioProcessingConfig$HighPassFilter;"); + noiseSuppression = GetFieldID(env, cls, "noiseSuppression", "L" PKG_AUDIO "AudioProcessingConfig$NoiseSuppression;"); + transientSuppression = GetFieldID(env, cls, "transientSuppression", "L" PKG_AUDIO "AudioProcessingConfig$TransientSuppression;"); + } + + JavaEchoCancellerClass::JavaEchoCancellerClass(JNIEnv* env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$EchoCanceller"); + + enabled = GetFieldID(env, cls, "enabled", "Z"); + enforceHighPassFiltering = GetFieldID(env, cls, "enforceHighPassFiltering", "Z"); + } + + JavaGainControlClass::JavaGainControlClass(JNIEnv* env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$GainControl"); + + enabled = GetFieldID(env, cls, "enabled", "Z"); + fixedDigital = GetFieldID(env, cls, "fixedDigital", "L" PKG_AUDIO "AudioProcessingConfig$GainControl$FixedDigital;"); + adaptiveDigital = GetFieldID(env, cls, "adaptiveDigital", "L" PKG_AUDIO "AudioProcessingConfig$GainControl$AdaptiveDigital;"); + } + + JavaGainControlFixedDigitalClass::JavaGainControlFixedDigitalClass(JNIEnv* env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$GainControl$FixedDigital"); + + gainDb = GetFieldID(env, cls, "gainDb", "F"); + } + + JavaGainControlAdaptiveDigitalClass::JavaGainControlAdaptiveDigitalClass(JNIEnv* env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$GainControl$AdaptiveDigital"); + + enabled = GetFieldID(env, cls, "enabled", "Z"); + headroomDb = GetFieldID(env, cls, "headroomDb", "F"); + maxGainDb = GetFieldID(env, cls, "maxGainDb", "F"); + initialGainDb = GetFieldID(env, cls, "initialGainDb", "F"); + maxGainChangeDbPerSecond = GetFieldID(env, cls, "maxGainChangeDbPerSecond", "F"); + maxOutputNoiseLevelDbfs = GetFieldID(env, cls, "maxOutputNoiseLevelDbfs", "F"); + } + + JavaHighPassFilterClass::JavaHighPassFilterClass(JNIEnv* env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$HighPassFilter"); + + enabled = GetFieldID(env, cls, "enabled", "Z"); + } + + JavaNoiseSuppressionClass::JavaNoiseSuppressionClass(JNIEnv* env) + { + cls = FindClass(env, PKG_AUDIO"AudioProcessingConfig$NoiseSuppression"); + + enabled = GetFieldID(env, cls, "enabled", "Z"); + level = GetFieldID(env, cls, "level", "L" PKG_AUDIO "AudioProcessingConfig$NoiseSuppression$Level;"); + } + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp b/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp index c7f19b05..cfed798e 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp @@ -1,281 +1,280 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "media/video/VideoTrackDesktopSource.h" -#include "Exception.h" - -#include "api/video/i420_buffer.h" -#include "libyuv/convert.h" -#include "modules/desktop_capture/cropping_window_capturer.h" -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/video_capture/video_capture_factory.h" -#include "third_party/libyuv/include/libyuv/video_common.h" -#include "rtc_base/logging.h" -#include "system_wrappers/include/sleep.h" - -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/desktop_and_cursor_composer.h" -#include "modules/desktop_capture/mouse_cursor_monitor.h" - -namespace jni -{ - VideoTrackDesktopSource::VideoTrackDesktopSource() : - AdaptedVideoTrackSource(), - frameRate(20), - isCapturing(false), - focusSelectedSource(true), - sourceState(kInitializing), - sourceId(-1), - sourceIsWindow(false) - { - } - - VideoTrackDesktopSource::~VideoTrackDesktopSource() - { - stop(); - } - - void VideoTrackDesktopSource::setSourceId(webrtc::DesktopCapturer::SourceId source, bool isWindow) - { - this->sourceId = source; - this->sourceIsWindow = isWindow; - } - - void VideoTrackDesktopSource::setFrameRate(const uint16_t frameRate) - { - this->frameRate = frameRate; - } - - void VideoTrackDesktopSource::setMaxFrameSize(webrtc::DesktopSize size) - { - this->maxFrameSize = size; - } - - void VideoTrackDesktopSource::setFocusSelectedSource(bool focus) - { - this->focusSelectedSource = focus; - } - - void VideoTrackDesktopSource::start() - { - isCapturing = true; - - captureThread = rtc::Thread::Create(); - captureThread->Start(); - captureThread->PostTask(RTC_FROM_HERE, [&] { capture(); }); - } - - void VideoTrackDesktopSource::stop() - { - if (isCapturing) { - isCapturing = false; - - captureThread->Stop(); - captureThread.reset(); - } - } - - void VideoTrackDesktopSource::terminate() - { - // Notify the track that we are permanently done. - sourceState = kEnded; - FireOnChanged(); - } - - bool VideoTrackDesktopSource::is_screencast() const { - return true; - } - - absl::optional VideoTrackDesktopSource::needs_denoising() const { - return false; - } - - webrtc::MediaSourceInterface::SourceState VideoTrackDesktopSource::state() const { - return sourceState; - } - - bool VideoTrackDesktopSource::remote() const { - return false; - } - - void VideoTrackDesktopSource::OnCaptureResult(webrtc::DesktopCapturer::Result result, std::unique_ptr frame) - { - if (result != webrtc::DesktopCapturer::Result::SUCCESS) { - if (result == webrtc::DesktopCapturer::Result::ERROR_PERMANENT) { - RTC_LOG(LS_ERROR) << "Permanent error capturing desktop frame. Stopping track."; - - terminate(); - stop(); - } - - return; - } - - int width = frame->size().width(); - int height = frame->size().height(); - - if (width == 1 && height == 1) { - // Window has been minimized (hidden). - if (lastFrame != nullptr) { - process(lastFrame); - } - } - else { - // Copy current frame as backup, in order to show it when the window is minimized. - lastFrame.reset(new webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height))); - lastFrame->CopyPixelsFrom(frame->data(), frame->stride(), webrtc::DesktopRect::MakeWH(width, height)); - - process(frame); - } - } - - void VideoTrackDesktopSource::process(std::unique_ptr & frame) - { - int64_t time = rtc::TimeMicros(); - - int width = frame->size().width(); - int height = frame->size().height(); - - int adapted_width; - int adapted_height; - - int crop_x = 0; - int crop_y = 0; - int crop_w = width; - int crop_h = height; - - if (!AdaptFrame(width, height, time, &adapted_width, &adapted_height, &crop_w, &crop_h, &crop_x, &crop_y)) { - // Drop frame in order to respect frame rate constraint. - return; - } - -#if defined(WEBRTC_WIN) - // Crop black window borders. - bool fullscreen = frame->stride() == (frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel); - - if (!fullscreen) { - const webrtc::DesktopVector& top_left = frame->top_left(); - const int32_t border = GetSystemMetrics(SM_CXPADDEDBORDER); - - crop_x = border; - crop_y = top_left.y() < 0 ? -top_left.y() : 0; - crop_w = width - crop_x * 2; - crop_h = height - (crop_y + border); - } -#endif - - if (!buffer || buffer->width() != crop_w || buffer->height() != crop_h) { - buffer = webrtc::I420Buffer::Create(crop_w, crop_h); - } - - const int conversionResult = libyuv::ConvertToI420( - frame->data(), - 0, - buffer->MutableDataY(), buffer->StrideY(), - buffer->MutableDataU(), buffer->StrideU(), - buffer->MutableDataV(), buffer->StrideV(), - crop_x, crop_y, - frame->stride() / webrtc::DesktopFrame::kBytesPerPixel, buffer->height(), crop_w, crop_h, - libyuv::kRotate0, - libyuv::FOURCC_ARGB); - - if (conversionResult >= 0) { - if (!maxFrameSize.is_empty()) { - // Adapt frame size to contraints. - int max_width = maxFrameSize.width(); - int max_height = maxFrameSize.height(); - - if (adapted_width > max_width) { - double scale = max_width / (double)adapted_width; - adapted_width = max_width; - adapted_height = (int)(adapted_height * scale); - } - else if (adapted_height > max_height) { - double scale = max_height / (double)adapted_height; - adapted_width = (int)(adapted_width * scale); - adapted_height = max_height; - } - } - - if (adapted_width != width || adapted_height != height) { - // Video adapter has requested a down-scale. Allocate a new buffer and return scaled version. - rtc::scoped_refptr scaled_buffer = webrtc::I420Buffer::Create(adapted_width, adapted_height); - - scaled_buffer->ScaleFrom(*buffer); - - OnFrame(webrtc::VideoFrame::Builder() - .set_video_frame_buffer(scaled_buffer) - .set_rotation(webrtc::kVideoRotation_0) - .set_timestamp_us(time) - .build()); - } - else { - // No adaptations needed, just return the frame as is. - OnFrame(webrtc::VideoFrame::Builder() - .set_video_frame_buffer(buffer) - .set_rotation(webrtc::kVideoRotation_0) - .set_timestamp_us(time) - .build()); - } - } - } - - void VideoTrackDesktopSource::capture() - { - auto options = webrtc::DesktopCaptureOptions::CreateDefault(); - // Enable desktop effects. - options.set_disable_effects(false); - -#if defined(WEBRTC_WIN) - options.set_allow_directx_capturer(true); - options.set_allow_use_magnification_api(true); -#endif - - std::unique_ptr capturer; - - if (sourceIsWindow) { - capturer.reset(new webrtc::DesktopAndCursorComposer( - webrtc::DesktopCapturer::CreateWindowCapturer(options), - options)); - } - else { - capturer.reset(new webrtc::DesktopAndCursorComposer( - webrtc::DesktopCapturer::CreateScreenCapturer(options), - options)); - } - - if (!capturer->SelectSource(sourceId)) { - terminate(); - return; - } - - capturer->Start(this); - - if (focusSelectedSource) { - capturer->FocusOnSelectedSource(); - } - - sourceState = kLive; - - int msPerFrame = 1000 / frameRate; - - while (isCapturing) { - capturer->CaptureFrame(); - - webrtc::SleepMs(msPerFrame); - } - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "media/video/VideoTrackDesktopSource.h" +#include "Exception.h" + +#include "api/video/i420_buffer.h" +#include "libyuv/convert.h" +#include "modules/desktop_capture/cropping_window_capturer.h" +#include "modules/desktop_capture/desktop_capture_options.h" +#include "modules/video_capture/video_capture_factory.h" +#include "third_party/libyuv/include/libyuv/video_common.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/sleep.h" + +#include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/desktop_and_cursor_composer.h" +#include "modules/desktop_capture/mouse_cursor_monitor.h" + +namespace jni +{ + VideoTrackDesktopSource::VideoTrackDesktopSource() : + AdaptedVideoTrackSource(), + frameRate(20), + isCapturing(false), + focusSelectedSource(true), + sourceState(kInitializing), + sourceId(-1), + sourceIsWindow(false) + { + } + + VideoTrackDesktopSource::~VideoTrackDesktopSource() + { + stop(); + } + + void VideoTrackDesktopSource::setSourceId(webrtc::DesktopCapturer::SourceId source, bool isWindow) + { + this->sourceId = source; + this->sourceIsWindow = isWindow; + } + + void VideoTrackDesktopSource::setFrameRate(const uint16_t frameRate) + { + this->frameRate = frameRate; + } + + void VideoTrackDesktopSource::setMaxFrameSize(webrtc::DesktopSize size) + { + this->maxFrameSize = size; + } + + void VideoTrackDesktopSource::setFocusSelectedSource(bool focus) + { + this->focusSelectedSource = focus; + } + + void VideoTrackDesktopSource::start() + { + isCapturing = true; + + captureThread = rtc::Thread::Create(); + captureThread->Start(); + captureThread->PostTask([&] { capture(); }); + } + + void VideoTrackDesktopSource::stop() + { + if (isCapturing) { + isCapturing = false; + + captureThread->Stop(); + captureThread.reset(); + } + } + + void VideoTrackDesktopSource::terminate() + { + // Notify the track that we are permanently done. + sourceState = kEnded; + FireOnChanged(); + } + + bool VideoTrackDesktopSource::is_screencast() const { + return true; + } + + std::optional VideoTrackDesktopSource::needs_denoising() const { + return false; + } + + webrtc::MediaSourceInterface::SourceState VideoTrackDesktopSource::state() const { + return sourceState; + } + + bool VideoTrackDesktopSource::remote() const { + return false; + } + + void VideoTrackDesktopSource::OnCaptureResult(webrtc::DesktopCapturer::Result result, std::unique_ptr frame) + { + if (result != webrtc::DesktopCapturer::Result::SUCCESS) { + if (result == webrtc::DesktopCapturer::Result::ERROR_PERMANENT) { + RTC_LOG(LS_ERROR) << "Permanent error capturing desktop frame. Stopping track."; + + terminate(); + stop(); + } + + return; + } + + int width = frame->size().width(); + int height = frame->size().height(); + + if (width == 1 && height == 1) { + // Window has been minimized (hidden). + if (lastFrame != nullptr) { + process(lastFrame); + } + } + else { + // Copy current frame as backup, in order to show it when the window is minimized. + lastFrame.reset(new webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height))); + lastFrame->CopyPixelsFrom(frame->data(), frame->stride(), webrtc::DesktopRect::MakeWH(width, height)); + + process(frame); + } + } + + void VideoTrackDesktopSource::process(std::unique_ptr & frame) + { + int64_t time = rtc::TimeMicros(); + + int width = frame->size().width(); + int height = frame->size().height(); + + int adapted_width; + int adapted_height; + + int crop_x = 0; + int crop_y = 0; + int crop_w = width; + int crop_h = height; + + if (!AdaptFrame(width, height, time, &adapted_width, &adapted_height, &crop_w, &crop_h, &crop_x, &crop_y)) { + // Drop frame in order to respect frame rate constraint. + return; + } + +#if defined(WEBRTC_WIN) + // Crop black window borders. + bool fullscreen = frame->stride() == (frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel); + + if (!fullscreen) { + const webrtc::DesktopVector& top_left = frame->top_left(); + const int32_t border = GetSystemMetrics(SM_CXPADDEDBORDER); + + crop_x = border; + crop_y = top_left.y() < 0 ? -top_left.y() : 0; + crop_w = width - crop_x * 2; + crop_h = height - (crop_y + border); + } +#endif + + if (!buffer || buffer->width() != crop_w || buffer->height() != crop_h) { + buffer = webrtc::I420Buffer::Create(crop_w, crop_h); + } + + const int conversionResult = libyuv::ConvertToI420( + frame->data(), + 0, + buffer->MutableDataY(), buffer->StrideY(), + buffer->MutableDataU(), buffer->StrideU(), + buffer->MutableDataV(), buffer->StrideV(), + crop_x, crop_y, + frame->stride() / webrtc::DesktopFrame::kBytesPerPixel, buffer->height(), crop_w, crop_h, + libyuv::kRotate0, + libyuv::FOURCC_ARGB); + + if (conversionResult >= 0) { + if (!maxFrameSize.is_empty()) { + // Adapt frame size to contraints. + int max_width = maxFrameSize.width(); + int max_height = maxFrameSize.height(); + + if (adapted_width > max_width) { + double scale = max_width / (double)adapted_width; + adapted_width = max_width; + adapted_height = (int)(adapted_height * scale); + } + else if (adapted_height > max_height) { + double scale = max_height / (double)adapted_height; + adapted_width = (int)(adapted_width * scale); + adapted_height = max_height; + } + } + + if (adapted_width != width || adapted_height != height) { + // Video adapter has requested a down-scale. Allocate a new buffer and return scaled version. + rtc::scoped_refptr scaled_buffer = webrtc::I420Buffer::Create(adapted_width, adapted_height); + + scaled_buffer->ScaleFrom(*buffer); + + OnFrame(webrtc::VideoFrame::Builder() + .set_video_frame_buffer(scaled_buffer) + .set_rotation(webrtc::kVideoRotation_0) + .set_timestamp_us(time) + .build()); + } + else { + // No adaptations needed, just return the frame as is. + OnFrame(webrtc::VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rotation(webrtc::kVideoRotation_0) + .set_timestamp_us(time) + .build()); + } + } + } + + void VideoTrackDesktopSource::capture() + { + auto options = webrtc::DesktopCaptureOptions::CreateDefault(); + // Enable desktop effects. + options.set_disable_effects(false); + +#if defined(WEBRTC_WIN) + options.set_allow_directx_capturer(true); +#endif + + std::unique_ptr capturer; + + if (sourceIsWindow) { + capturer.reset(new webrtc::DesktopAndCursorComposer( + webrtc::DesktopCapturer::CreateWindowCapturer(options), + options)); + } + else { + capturer.reset(new webrtc::DesktopAndCursorComposer( + webrtc::DesktopCapturer::CreateScreenCapturer(options), + options)); + } + + if (!capturer->SelectSource(sourceId)) { + terminate(); + return; + } + + capturer->Start(this); + + if (focusSelectedSource) { + capturer->FocusOnSelectedSource(); + } + + sourceState = kLive; + + int msPerFrame = 1000 / frameRate; + + while (isCapturing) { + capturer->CaptureFrame(); + + webrtc::SleepMs(msPerFrame); + } + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp index 0ac19c2d..c82c9e2d 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp @@ -1,102 +1,101 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "media/video/desktop/DesktopCapturer.h" - -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/desktop_and_cursor_composer.h" - -namespace jni -{ - DesktopCapturer::DesktopCapturer(bool screenCapturer) : - focusSelectedSource(false) - { - auto options = webrtc::DesktopCaptureOptions::CreateDefault(); - // Enable desktop effects. - options.set_disable_effects(false); - -#if defined(WEBRTC_WIN) - options.set_allow_directx_capturer(true); - options.set_allow_use_magnification_api(true); -#endif - - if (screenCapturer) { - capturer.reset(new webrtc::DesktopAndCursorComposer( - webrtc::DesktopCapturer::CreateScreenCapturer(options), - options)); - } - else { - capturer.reset(new webrtc::DesktopAndCursorComposer( - webrtc::DesktopCapturer::CreateWindowCapturer(options), - options)); - } - } - - DesktopCapturer::~DesktopCapturer() - { - capturer.reset(); - } - - void DesktopCapturer::Start(Callback * callback) - { - capturer->Start(callback); - - if (focusSelectedSource) { - capturer->FocusOnSelectedSource(); - } - } - - void DesktopCapturer::SetSharedMemoryFactory(std::unique_ptr factory) - { - capturer->SetSharedMemoryFactory(std::move(factory)); - } - - void DesktopCapturer::CaptureFrame() - { - capturer->CaptureFrame(); - } - - void DesktopCapturer::SetExcludedWindow(webrtc::WindowId window) - { - capturer->SetExcludedWindow(window); - } - - bool DesktopCapturer::GetSourceList(SourceList * sources) - { - return capturer->GetSourceList(sources); - } - - bool DesktopCapturer::SelectSource(SourceId id) - { - return capturer->SelectSource(id); - } - - bool DesktopCapturer::FocusOnSelectedSource() - { - return capturer->FocusOnSelectedSource(); - } - - void DesktopCapturer::setFocusSelectedSource(bool focus) - { - this->focusSelectedSource = focus; - } - - bool DesktopCapturer::IsOccluded(const webrtc::DesktopVector & pos) - { - return capturer->IsOccluded(pos); - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "media/video/desktop/DesktopCapturer.h" + +#include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/desktop_capture_options.h" +#include "modules/desktop_capture/desktop_and_cursor_composer.h" + +namespace jni +{ + DesktopCapturer::DesktopCapturer(bool screenCapturer) : + focusSelectedSource(false) + { + auto options = webrtc::DesktopCaptureOptions::CreateDefault(); + // Enable desktop effects. + options.set_disable_effects(false); + +#if defined(WEBRTC_WIN) + options.set_allow_directx_capturer(true); +#endif + + if (screenCapturer) { + capturer.reset(new webrtc::DesktopAndCursorComposer( + webrtc::DesktopCapturer::CreateScreenCapturer(options), + options)); + } + else { + capturer.reset(new webrtc::DesktopAndCursorComposer( + webrtc::DesktopCapturer::CreateWindowCapturer(options), + options)); + } + } + + DesktopCapturer::~DesktopCapturer() + { + capturer.reset(); + } + + void DesktopCapturer::Start(Callback * callback) + { + capturer->Start(callback); + + if (focusSelectedSource) { + capturer->FocusOnSelectedSource(); + } + } + + void DesktopCapturer::SetSharedMemoryFactory(std::unique_ptr factory) + { + capturer->SetSharedMemoryFactory(std::move(factory)); + } + + void DesktopCapturer::CaptureFrame() + { + capturer->CaptureFrame(); + } + + void DesktopCapturer::SetExcludedWindow(webrtc::WindowId window) + { + capturer->SetExcludedWindow(window); + } + + bool DesktopCapturer::GetSourceList(SourceList * sources) + { + return capturer->GetSourceList(sources); + } + + bool DesktopCapturer::SelectSource(SourceId id) + { + return capturer->SelectSource(id); + } + + bool DesktopCapturer::FocusOnSelectedSource() + { + return capturer->FocusOnSelectedSource(); + } + + void DesktopCapturer::setFocusSelectedSource(bool focus) + { + this->focusSelectedSource = focus; + } + + bool DesktopCapturer::IsOccluded(const webrtc::DesktopVector & pos) + { + return capturer->IsOccluded(pos); + } } \ No newline at end of file diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/RTCRtpContributingSource.java b/webrtc/src/main/java/dev/onvoid/webrtc/RTCRtpContributingSource.java index 3d11dec8..b3395d76 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/RTCRtpContributingSource.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/RTCRtpContributingSource.java @@ -1,70 +1,70 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -package dev.onvoid.webrtc; - -/** - * Contains information about a given contributing source (CSRC). - * - * @author Alex Andres - */ -public class RTCRtpContributingSource { - - /** - * Indicating the most recent time a frame from an RTP packet, originating - * from this source, was delivered to the RTCRtpReceiver's MediaStreamTrack. - */ - public final long timestamp; - - /** - * The CSRC or SSRC identifier of the contributing or synchronization - * source. - */ - public final long source; - - /** - * Only present for audio receivers. This is a value between 0..1 (linear), - * where 1.0 represents 0 dBov, 0 represents silence, and 0.5 represents - * approximately 6 dBSPL change in the sound pressure level from 0 dBov. - */ - public final double audioLevel; - - /** - * The last RTP timestamp, as defined in [RFC3550] Section 5.1, of the media - * played out at timestamp. - */ - public final long rtpTimestamp; - - - /** - * Creates an instance of RTCRtpContributingSource with the specified - * contributing source information. - * - * @param timestamp The most recent time a frame from an RTP packet. - * @param source The CSRC or SSRC identifier of the contributing or - * synchronization source. - * @param audioLevel The sound pressure level. Only present for audio - * receivers. - * @param rtpTimestamp The last RTP timestamp. - */ - protected RTCRtpContributingSource(long timestamp, long source, - double audioLevel, long rtpTimestamp) { - this.timestamp = timestamp; - this.source = source; - this.audioLevel = audioLevel; - this.rtpTimestamp = rtpTimestamp; - } -} +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc; + +/** + * Contains information about a given contributing source (CSRC). + * + * @author Alex Andres + */ +public class RTCRtpContributingSource { + + /** + * Indicating the most recent time a frame from an RTP packet, originating + * from this source, was delivered to the RTCRtpReceiver's MediaStreamTrack. + */ + public final long timestamp; + + /** + * The CSRC or SSRC identifier of the contributing or synchronization + * source. + */ + public final long sourceId; + + /** + * Only present for audio receivers. This is a value between 0..1 (linear), + * where 1.0 represents 0 dBov, 0 represents silence, and 0.5 represents + * approximately 6 dBSPL change in the sound pressure level from 0 dBov. + */ + public final double audioLevel; + + /** + * The last RTP timestamp, as defined in [RFC3550] Section 5.1, of the media + * played out at timestamp. + */ + public final long rtpTimestamp; + + + /** + * Creates an instance of RTCRtpContributingSource with the specified + * contributing source information. + * + * @param timestamp The most recent time a frame from an RTP packet. + * @param sourceId The CSRC or SSRC identifier of the contributing or + * synchronization source. + * @param audioLevel The sound pressure level. Only present for audio + * receivers. + * @param rtpTimestamp The last RTP timestamp. + */ + protected RTCRtpContributingSource(long timestamp, long sourceId, + double audioLevel, long rtpTimestamp) { + this.timestamp = timestamp; + this.sourceId = sourceId; + this.audioLevel = audioLevel; + this.rtpTimestamp = rtpTimestamp; + } +} diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioOptions.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioOptions.java index da410499..8808965a 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioOptions.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioOptions.java @@ -1,69 +1,59 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -package dev.onvoid.webrtc.media.audio; - -/** - * Audio options to control AudioTracks. - * - * @link https://www.w3.org/TR/mediacapture-streams/ - * - * @author Alex Andres - */ -public class AudioOptions { - - /** - * When one or more audio streams is being played in the processes of - * various microphones, it is often desirable to attempt to remove the sound - * being played from the input signals recorded by the microphones. This is - * referred to as echo cancellation. There are cases where it is not needed - * and it is desirable to turn it off so that no audio artifacts are - * introduced. This allows applications to control this behavior. - */ - public boolean echoCancellation; - - /** - * Automatic gain control is often desirable on the input signal recorded by - * the microphone. There are cases where it is not needed and it is - * desirable to turn it off so that the audio is not altered. This allows - * applications to control this behavior. - */ - public boolean autoGainControl; - - /** - * Noise suppression is often desirable on the input signal recorded by the - * microphone. There are cases where it is not needed and it is desirable to - * turn it off so that the audio is not altered. This allows applications to - * control this behavior. - */ - public boolean noiseSuppression; - - /** - * Audio processing to remove background noise of lower frequencies. - */ - public boolean highpassFilter; - - /** - * Audio processing to detect typing. - */ - public boolean typingDetection; - - /** - * Audio processing to detect residual echoes. - */ - public boolean residualEchoDetector; - -} +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +/** + * Audio options to control AudioTracks. + * + * @link https://www.w3.org/TR/mediacapture-streams/ + * + * @author Alex Andres + */ +public class AudioOptions { + + /** + * When one or more audio streams is being played in the processes of + * various microphones, it is often desirable to attempt to remove the sound + * being played from the input signals recorded by the microphones. This is + * referred to as echo cancellation. There are cases where it is not needed + * and it is desirable to turn it off so that no audio artifacts are + * introduced. This allows applications to control this behavior. + */ + public boolean echoCancellation; + + /** + * Automatic gain control is often desirable on the input signal recorded by + * the microphone. There are cases where it is not needed and it is + * desirable to turn it off so that the audio is not altered. This allows + * applications to control this behavior. + */ + public boolean autoGainControl; + + /** + * Noise suppression is often desirable on the input signal recorded by the + * microphone. There are cases where it is not needed and it is desirable to + * turn it off so that the audio is not altered. This allows applications to + * control this behavior. + */ + public boolean noiseSuppression; + + /** + * Audio processing to remove background noise of lower frequencies. + */ + public boolean highpassFilter; + +} diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingConfig.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingConfig.java index e1fc70f4..5631a3c1 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingConfig.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingConfig.java @@ -1,127 +1,101 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -package dev.onvoid.webrtc.media.audio; - -/** - * This config is intended to be used during setup of {@link AudioProcessing} to - * enable/disable audio processing effects. - * - * @author Alex Andres - */ -public class AudioProcessingConfig { - - public final EchoCanceller echoCanceller = new EchoCanceller(); - - public final GainControl gainControl = new GainControl(); - - public final HighPassFilter highPassFilter = new HighPassFilter(); - - public final NoiseSuppression noiseSuppression = new NoiseSuppression(); - - public final ResidualEchoDetector residualEchoDetector = new ResidualEchoDetector(); - - public final TransientSuppression transientSuppression = new TransientSuppression(); - - public final VoiceDetection voiceDetection = new VoiceDetection(); - - - - public static class EchoCanceller { - - public boolean enabled; - - public boolean enforceHighPassFiltering; - - } - - public static class GainControl { - - public static class FixedDigital { - - public float gainDb = 0.0f; - - } - - public static class AdaptiveDigital { - - public boolean enabled; - - /** Run the adaptive digital controller but the signal is not modified. */ - public boolean dryRun = false; - - public int vadResetPeriodMs = 1500; - public int adjacentSpeechFramesThreshold = 12; - public float maxGainChangeDbPerSecond = 3.0f; - public float maxOutputNoiseLevelDbfs = -50.0f; - - } - - - public final FixedDigital fixedDigital = new FixedDigital(); - - public final AdaptiveDigital adaptiveDigital = new AdaptiveDigital(); - - public boolean enabled; - - } - - public static class HighPassFilter { - - public boolean enabled; - - } - - public static class LevelEstimation { - - public boolean enabled; - - } - - public static class NoiseSuppression { - - public enum Level { - LOW, - MODERATE, - HIGH, - VERY_HIGH - } - - - public boolean enabled; - - public Level level; - - } - - public static class ResidualEchoDetector { - - public boolean enabled; - - } - - public static class TransientSuppression { - - public boolean enabled; - - } - - public static class VoiceDetection { - - public boolean enabled; - - } -} +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +/** + * This config is intended to be used during setup of {@link AudioProcessing} to + * enable/disable audio processing effects. + * + * @author Alex Andres + */ +public class AudioProcessingConfig { + + public final EchoCanceller echoCanceller = new EchoCanceller(); + + public final GainControl gainControl = new GainControl(); + + public final HighPassFilter highPassFilter = new HighPassFilter(); + + public final NoiseSuppression noiseSuppression = new NoiseSuppression(); + + + + public static class EchoCanceller { + + public boolean enabled; + + public boolean enforceHighPassFiltering; + + } + + public static class GainControl { + + public static class FixedDigital { + + public float gainDb = 0.0f; + + } + + public static class AdaptiveDigital { + + public boolean enabled; + + public float headroomDb = 5.0f; + public float maxGainDb = 50.0f; + public float initialGainDb = 15.0f; + public float maxGainChangeDbPerSecond = 6.0f; + public float maxOutputNoiseLevelDbfs = -50.0f; + + } + + + public final FixedDigital fixedDigital = new FixedDigital(); + + public final AdaptiveDigital adaptiveDigital = new AdaptiveDigital(); + + public boolean enabled; + + } + + public static class HighPassFilter { + + public boolean enabled; + + } + + public static class LevelEstimation { + + public boolean enabled; + + } + + public static class NoiseSuppression { + + public enum Level { + LOW, + MODERATE, + HIGH, + VERY_HIGH + } + + + public boolean enabled; + + public Level level; + + } +} diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java index 88be7d08..a14675ad 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java @@ -1,120 +1,82 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -package dev.onvoid.webrtc.media.audio; - -import static java.util.Objects.requireNonNull; - -import dev.onvoid.webrtc.internal.DisposableNativeObject; - -/** - * Audio sampling rate converter. This resampler operates on audio frames of 10 - * milliseconds. Each sample is assumed to be a 16-bit PCM sample. - * - * @author Alex Andres - */ -public class AudioResampler extends DisposableNativeObject { - - private int targetFrames; - - private boolean initialized; - - - /** - * Creates a new {@code AudioResampler} without sampling parameters. Make - * sure to call {@link #reset(int, int, int)} afterwards. - */ - public AudioResampler() { - initialize(); - } - - /** - * Creates a new {@code AudioResampler} with specified sampling frequency - * parameters. - * - * @param sourceSampleRate The sampling frequency of the input signal. - * @param targetSampleRate The sampling frequency of the output signal. - * @param channels The number of audio channels to resample. - */ - public AudioResampler(int sourceSampleRate, int targetSampleRate, int channels) { - initialize(); - reset(sourceSampleRate, targetSampleRate, channels); - } - - /** - * Must be called when created with default constructor or whenever the - * sampling parameters change. Can be called at any time as it is a no-op if - * parameters have not changed since the last call. - * - * @param sourceSampleRate The sampling frequency of the input signal. - * @param targetSampleRate The sampling frequency of the output signal. - * @param channels The number of audio channels to resample. - */ - public void reset(int sourceSampleRate, int targetSampleRate, int channels) { - initialized = false; - - resetInternal(sourceSampleRate, targetSampleRate, channels); - - targetFrames = targetSampleRate / 100 * channels; // 10 ms frame - - initialized = true; - } - - /** - * Converts the input samples into the output samples with the sampling - * frequency specified in the constructor. The audio input must be of the - * length of 10 milliseconds. Accordingly, the output has the length of 10 - * milliseconds. - * - * @param samplesIn The audio samples to convert. - * @param nSamplesIn The number of audio samples to consider from {@code - * samplesIn}. - * @param samplesOut The converted audio samples. - * - * @return The number of converted audio samples. - */ - public int resample(byte[] samplesIn, int nSamplesIn, byte[] samplesOut) { - requireNonNull(samplesIn); - requireNonNull(samplesOut); - - if (!initialized) { - throw new IllegalStateException("Not initialized: Use reset() to set parameters"); - } - - final int arraySamplesIn = samplesIn.length / 2; // 16-bit PCM sample - final int maxSamplesOut = samplesOut.length / 2; - - nSamplesIn = Math.min(arraySamplesIn, Math.max(0, nSamplesIn)); - - if (targetFrames > maxSamplesOut) { - throw new IllegalArgumentException("Insufficient samples output length"); - } - - return resampleInternal(samplesIn, nSamplesIn, samplesOut, maxSamplesOut); - } - - @Override - public native void dispose(); - - private native void initialize(); - - private native void resetInternal(int sourceSampleRate, int targetSampleRate, - int channels); - - private native int resampleInternal(byte[] samplesIn, int nSamplesIn, - byte[] samplesOut, int maxSamplesOut); - -} +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +import dev.onvoid.webrtc.internal.DisposableNativeObject; + +/** + * Audio sampling rate converter. This resampler operates on audio frames of 10 + * milliseconds. Each sample is assumed to be a 16-bit PCM sample. + * + * @author Alex Andres + */ +public class AudioResampler extends DisposableNativeObject { + + /** + * Creates a new {@code AudioResampler} without sampling parameters. + */ + public AudioResampler() { + initialize(); + } + + /** + * Creates a new {@code AudioResampler} with specified sampling frequency + * parameters. + * + * @param sourceSampleRate The sampling frequency of the input signal. + * @param targetSampleRate The sampling frequency of the output signal. + * @param channels The number of audio channels to resample. + */ + public AudioResampler(int sourceSampleRate, int targetSampleRate, int channels) { + initialize(getSamplesPerChannel(sourceSampleRate), getSamplesPerChannel(targetSampleRate), channels); + } + + /** + * Converts the input samples into the output samples with the sampling + * frequency specified in the constructor. The audio input must be of the + * length of 10 milliseconds. Accordingly, the output has the length of 10 + * milliseconds. + * + * @param samplesIn The audio samples to convert. + * @param srcSamplesPerChannel The number of samples per source channel. + * @param samplesOut The converted audio samples. + * @param dstSamplesPerChannel The number of samples per destination channel. + * @param channels The number of audio channels to resample. + * + * @return The number of converted audio samples. + */ + public native int resample(byte[] samplesIn, int srcSamplesPerChannel, byte[] samplesOut, int dstSamplesPerChannel, + int channels); + + @Override + public native void dispose(); + + private native void initialize(); + + private native void initialize(int srcSamplesPerChannel, int dstSamplesPerChannel, int channels); + + /** + * Returns the number of samples a buffer needs to hold for ~10ms of a single audio channel at a given sample rate. + * + * @param sampleRate The sample rate. + * + * @return The number of samples per channel. + */ + public static int getSamplesPerChannel(int sampleRate) { + return sampleRate / 100; + } +} diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioProcessingTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioProcessingTest.java index 49ca5298..25ba3c86 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioProcessingTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioProcessingTest.java @@ -1,158 +1,154 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -package dev.onvoid.webrtc.media.audio; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import dev.onvoid.webrtc.media.audio.AudioProcessingConfig.NoiseSuppression; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class AudioProcessingTest { - - private AudioProcessing audioProcessing; - - - @BeforeEach - void init() { - audioProcessing = new AudioProcessing(); - } - - @AfterEach - void dispose() { - audioProcessing.dispose(); - } - - @Test - void applyConfig() { - AudioProcessingConfig config = new AudioProcessingConfig(); - config.echoCanceller.enabled = true; - config.echoCanceller.enforceHighPassFiltering = true; - - config.gainControl.enabled = true; - - config.highPassFilter.enabled = true; - - config.noiseSuppression.enabled = true; - config.noiseSuppression.level = NoiseSuppression.Level.HIGH; - - config.residualEchoDetector.enabled = true; - config.transientSuppression.enabled = true; - config.voiceDetection.enabled = true; - - audioProcessing.applyConfig(config); - } - - @Test - void getStats() { - assertNotNull(audioProcessing.getStatistics()); - } - - @Test - void processByteStream() { - ProcessBuffer buffer = new ProcessBuffer(48000, 48000, 1, 1); - - assertEquals(0, process(audioProcessing, buffer)); - } - - @Test - void processByteStreamDownMix() { - ProcessBuffer buffer = new ProcessBuffer(48000, 44100, 2, 1); - - assertEquals(0, process(audioProcessing, buffer)); - } - - @Test - void processByteStreamUpMix() { - ProcessBuffer buffer = new ProcessBuffer(48000, 44100, 1, 2); - - assertEquals(0, process(audioProcessing, buffer)); - } - - @Test - void processReverseStream() { - ProcessBuffer buffer = new ProcessBuffer(48000, 48000, 1, 1); - - assertEquals(0, processReverse(audioProcessing, buffer)); - } - - @Test - void streamDelay() { - int delay = 70; - - audioProcessing.setStreamDelayMs(delay); - - assertEquals(delay, audioProcessing.getStreamDelayMs()); - } - - private static int process(AudioProcessing audioProcessing, ProcessBuffer buffer) { - return audioProcessing.processStream(buffer.src, buffer.streamConfigIn, - buffer.streamConfigOut, buffer.dst); - } - - private static int processReverse(AudioProcessing audioProcessing, ProcessBuffer buffer) { - return audioProcessing.processReverseStream(buffer.src, buffer.streamConfigIn, - buffer.streamConfigOut, buffer.dst); - } - - - - private static class ProcessBuffer { - - final int bytesPerFrame = 2; - - final int channelsIn; - final int channelsOut; - - final int sampleRateIn; - final int sampleRateOut; - - final int nSamplesIn; - final int nSamplesOut; - - final int frameSizeIn; - final int frameSizeOut; - - byte[] src; - byte[] dst; - - AudioProcessingStreamConfig streamConfigIn; - AudioProcessingStreamConfig streamConfigOut; - - - ProcessBuffer(int sampleRateIn, int sampleRateOut, int channelsIn, int channelsOut) { - this.sampleRateIn = sampleRateIn; - this.sampleRateOut = sampleRateOut; - this.channelsIn = channelsIn; - this.channelsOut = channelsOut; - - nSamplesIn = sampleRateIn / 100; // 10 ms frame - nSamplesOut = sampleRateOut / 100; - frameSizeIn = nSamplesIn * bytesPerFrame * channelsIn; - frameSizeOut = Math.max(nSamplesIn, nSamplesOut) * bytesPerFrame * channelsOut; - - src = new byte[frameSizeIn]; - dst = new byte[frameSizeOut]; - - streamConfigIn = new AudioProcessingStreamConfig(sampleRateIn, channelsIn); - streamConfigOut = new AudioProcessingStreamConfig(sampleRateOut, channelsOut); - } - } -} +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import dev.onvoid.webrtc.media.audio.AudioProcessingConfig.NoiseSuppression; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class AudioProcessingTest { + + private AudioProcessing audioProcessing; + + + @BeforeEach + void init() { + audioProcessing = new AudioProcessing(); + } + + @AfterEach + void dispose() { + audioProcessing.dispose(); + } + + @Test + void applyConfig() { + AudioProcessingConfig config = new AudioProcessingConfig(); + config.echoCanceller.enabled = true; + config.echoCanceller.enforceHighPassFiltering = true; + + config.gainControl.enabled = true; + + config.highPassFilter.enabled = true; + + config.noiseSuppression.enabled = true; + config.noiseSuppression.level = NoiseSuppression.Level.HIGH; + + audioProcessing.applyConfig(config); + } + + @Test + void getStats() { + assertNotNull(audioProcessing.getStatistics()); + } + + @Test + void processByteStream() { + ProcessBuffer buffer = new ProcessBuffer(48000, 48000, 1, 1); + + assertEquals(0, process(audioProcessing, buffer)); + } + + @Test + void processByteStreamDownMix() { + ProcessBuffer buffer = new ProcessBuffer(48000, 44100, 2, 1); + + assertEquals(0, process(audioProcessing, buffer)); + } + + @Test + void processByteStreamUpMix() { + ProcessBuffer buffer = new ProcessBuffer(48000, 44100, 1, 2); + + assertEquals(0, process(audioProcessing, buffer)); + } + + @Test + void processReverseStream() { + ProcessBuffer buffer = new ProcessBuffer(48000, 48000, 1, 1); + + assertEquals(0, processReverse(audioProcessing, buffer)); + } + + @Test + void streamDelay() { + int delay = 70; + + audioProcessing.setStreamDelayMs(delay); + + assertEquals(delay, audioProcessing.getStreamDelayMs()); + } + + private static int process(AudioProcessing audioProcessing, ProcessBuffer buffer) { + return audioProcessing.processStream(buffer.src, buffer.streamConfigIn, + buffer.streamConfigOut, buffer.dst); + } + + private static int processReverse(AudioProcessing audioProcessing, ProcessBuffer buffer) { + return audioProcessing.processReverseStream(buffer.src, buffer.streamConfigIn, + buffer.streamConfigOut, buffer.dst); + } + + + + private static class ProcessBuffer { + + final int bytesPerFrame = 2; + + final int channelsIn; + final int channelsOut; + + final int sampleRateIn; + final int sampleRateOut; + + final int nSamplesIn; + final int nSamplesOut; + + final int frameSizeIn; + final int frameSizeOut; + + byte[] src; + byte[] dst; + + AudioProcessingStreamConfig streamConfigIn; + AudioProcessingStreamConfig streamConfigOut; + + + ProcessBuffer(int sampleRateIn, int sampleRateOut, int channelsIn, int channelsOut) { + this.sampleRateIn = sampleRateIn; + this.sampleRateOut = sampleRateOut; + this.channelsIn = channelsIn; + this.channelsOut = channelsOut; + + nSamplesIn = sampleRateIn / 100; // 10 ms frame + nSamplesOut = sampleRateOut / 100; + frameSizeIn = nSamplesIn * bytesPerFrame * channelsIn; + frameSizeOut = Math.max(nSamplesIn, nSamplesOut) * bytesPerFrame * channelsOut; + + src = new byte[frameSizeIn]; + dst = new byte[frameSizeOut]; + + streamConfigIn = new AudioProcessingStreamConfig(sampleRateIn, channelsIn); + streamConfigOut = new AudioProcessingStreamConfig(sampleRateOut, channelsOut); + } + } +} diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java index 216f9394..92e72956 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java @@ -1,144 +1,134 @@ -/* - * Copyright 2021 Alex Andres - * - * 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. - */ - -package dev.onvoid.webrtc.media.audio; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class AudioResamplerTest { - - private AudioResampler resampler; - - - @BeforeEach - void init() { - resampler = new AudioResampler(); - } - - @AfterEach - void dispose() { - resampler.dispose(); - } - - @Test - void notInitialized() { - SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); - - assertThrows(IllegalStateException.class, () -> { - resampler.resample(buffer.src, buffer.nSamplesIn, buffer.dst); - }); - } - - @Test - void targetBufferUnderflow() { - SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); - buffer.setTargetBufferSize(buffer.frameSizeOut / 2); - - reset(resampler, buffer); - - assertThrows(IllegalArgumentException.class, () -> { - resample(resampler, buffer); - }); - } - - @Test - void constructorParameters() { - SampleBuffer buffer = new SampleBuffer(48000, 44100, 2); - - AudioResampler resampler = new AudioResampler(48000, 44100, 2); - - int result = resample(resampler, buffer); - - resampler.dispose(); - - assertEquals(buffer.nSamplesOut, result); - } - - @Test - void downSample() { - SampleBuffer buffer = new SampleBuffer(48000, 44100, 1); - - reset(resampler, buffer); - - int result = resample(resampler, buffer); - - assertEquals(buffer.nSamplesOut, result); - } - - @Test - void upSample() { - SampleBuffer buffer = new SampleBuffer(32000, 48000, 1); - - reset(resampler, buffer); - - int result = resample(resampler, buffer); - - assertEquals(buffer.nSamplesOut, result); - } - - private static void reset(AudioResampler resampler, SampleBuffer buffer) { - resampler.reset(buffer.sampleRateIn, buffer.sampleRateOut, 1); - } - - private static int resample(AudioResampler resampler, SampleBuffer buffer) { - return resampler.resample(buffer.src, buffer.nSamplesIn, buffer.dst); - } - - - - private static class SampleBuffer { - - final int bytesPerFrame = 2; - - final int channels; - - final int sampleRateIn; - final int sampleRateOut; - - final int nSamplesIn; - final int nSamplesOut; - - final int frameSizeIn; - final int frameSizeOut; - - byte[] src; - byte[] dst; - - - SampleBuffer(int sampleRateIn, int sampleRateOut, int channels) { - this.channels = channels; - this.sampleRateIn = sampleRateIn; - this.sampleRateOut = sampleRateOut; - - nSamplesIn = sampleRateIn / 100 * channels; // 10 ms frame - nSamplesOut = sampleRateOut / 100 * channels; - frameSizeIn = nSamplesIn * bytesPerFrame; - frameSizeOut = nSamplesOut * bytesPerFrame; - - src = new byte[frameSizeIn]; - dst = new byte[frameSizeOut]; - } - - void setTargetBufferSize(int size) { - dst = new byte[size]; - } - } -} +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class AudioResamplerTest { + + private AudioResampler resampler; + + + @BeforeEach + void init() { + resampler = new AudioResampler(); + } + + @AfterEach + void dispose() { + resampler.dispose(); + } + + @Test + void notInitialized() { + SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); + + assertThrows(IllegalStateException.class, () -> { + resampler.resample(buffer.src, buffer.nSamplesIn, buffer.dst, buffer.nSamplesOut, 1); + }); + } + + @Test + void targetBufferUnderflow() { + SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); + buffer.setTargetBufferSize(buffer.frameSizeOut / 2); + + assertThrows(IllegalArgumentException.class, () -> { + resample(resampler, buffer); + }); + } + + @Test + void constructorParameters() { + SampleBuffer buffer = new SampleBuffer(48000, 44100, 2); + + AudioResampler resampler = new AudioResampler(48000, 44100, 2); + + int result = resample(resampler, buffer); + + resampler.dispose(); + + assertEquals(buffer.nSamplesOut, result); + } + + @Test + void downSample() { + SampleBuffer buffer = new SampleBuffer(48000, 44100, 1); + + int result = resample(resampler, buffer); + + assertEquals(buffer.nSamplesOut, result); + } + + @Test + void upSample() { + SampleBuffer buffer = new SampleBuffer(32000, 48000, 1); + + int result = resample(resampler, buffer); + + assertEquals(buffer.nSamplesOut, result); + } + + private static int resample(AudioResampler resampler, SampleBuffer buffer) { + return resampler.resample(buffer.src, buffer.nSamplesIn, buffer.dst, buffer.nSamplesOut, 1); + } + + + + private static class SampleBuffer { + + final int bytesPerFrame = 2; + + final int channels; + + final int sampleRateIn; + final int sampleRateOut; + + final int nSamplesIn; + final int nSamplesOut; + + final int frameSizeIn; + final int frameSizeOut; + + byte[] src; + byte[] dst; + + + SampleBuffer(int sampleRateIn, int sampleRateOut, int channels) { + this.channels = channels; + this.sampleRateIn = sampleRateIn; + this.sampleRateOut = sampleRateOut; + + nSamplesIn = AudioResampler.getSamplesPerChannel(sampleRateIn); // 10 ms frame + nSamplesOut = AudioResampler.getSamplesPerChannel(sampleRateOut);; + frameSizeIn = nSamplesIn * bytesPerFrame; + frameSizeOut = nSamplesOut * bytesPerFrame; + + src = new byte[frameSizeIn]; + dst = new byte[frameSizeOut]; + } + + void setTargetBufferSize(int size) { + dst = new byte[size]; + } + } +} From 40a0482f6cc805dbe39f75b7f076810a0ee110f4 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 21 Mar 2025 11:48:18 +0100 Subject: [PATCH 02/28] fix: unresolved symbols and audio processing classes --- webrtc-jni/src/main/cpp/CMakeLists.txt | 4 +-- .../cpp/dependencies/webrtc/CMakeLists.txt | 6 ++--- .../src/main/cpp/include/JNI_AudioResampler.h | 14 +++------- .../media/audio/AudioProcessingConfig.h | 3 --- .../src/main/cpp/src/JNI_AudioResampler.cpp | 2 +- .../cpp/src/JNI_PeerConnectionFactory.cpp | 26 +++++++++++++++++-- .../src/media/audio/AudioProcessingConfig.cpp | 1 - .../webrtc/media/audio/AudioResampler.java | 20 ++++++++++++-- .../media/audio/AudioResamplerTest.java | 10 ------- 9 files changed, 51 insertions(+), 35 deletions(-) diff --git a/webrtc-jni/src/main/cpp/CMakeLists.txt b/webrtc-jni/src/main/cpp/CMakeLists.txt index 6529fa13..38a35040 100644 --- a/webrtc-jni/src/main/cpp/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/CMakeLists.txt @@ -65,7 +65,7 @@ target_include_directories(${PROJECT_NAME} ) set_target_properties(${PROJECT_NAME} PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF ) @@ -79,7 +79,7 @@ if(APPLE) elseif(LINUX) target_link_libraries(${PROJECT_NAME} -static-libgcc -static-libstdc++ pulse udev) elseif(WIN32) - target_link_libraries(${PROJECT_NAME} mf.lib mfreadwrite.lib mfplat.lib mfuuid.lib) + target_link_libraries(${PROJECT_NAME} dwmapi.lib mf.lib mfreadwrite.lib mfplat.lib mfuuid.lib shcore.lib) endif() install(TARGETS ${PROJECT_NAME} diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index d7353f09..1d7be6f9 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -150,7 +150,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} ${TARGET_LINK_LIB}) if(APPLE) - target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_MAC WEBRTC_POSIX) + target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_MAC WEBRTC_POSIX NDEBUG) target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreAudio" "-framework AudioToolbox" "-framework IOSurface" "-framework ApplicationServices" "-framework AppKit") elseif(LINUX) # Find DBus @@ -158,10 +158,10 @@ elseif(LINUX) pkg_check_modules(DBUS REQUIRED dbus-1) target_include_directories(${PROJECT_NAME} PUBLIC ${DBUS_INCLUDE_DIRS}) - target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_LINUX WEBRTC_POSIX) + target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_LINUX WEBRTC_POSIX NDEBUG) target_link_libraries(${PROJECT_NAME} X11 Xfixes Xrandr Xcomposite dbus-1) elseif(WIN32) - target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_WIN NOMINMAX WIN32_LEAN_AND_MEAN) + target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_WIN NOMINMAX WIN32_LEAN_AND_MEAN NDEBUG) target_link_libraries(${PROJECT_NAME} D3D11 DXGI user32 gdi32 iphlpapi dmoguids msdmo secur32 strmiids winmm wmcodecdspuuid ws2_32) endif() diff --git a/webrtc-jni/src/main/cpp/include/JNI_AudioResampler.h b/webrtc-jni/src/main/cpp/include/JNI_AudioResampler.h index 6f61f414..d667248e 100644 --- a/webrtc-jni/src/main/cpp/include/JNI_AudioResampler.h +++ b/webrtc-jni/src/main/cpp/include/JNI_AudioResampler.h @@ -25,19 +25,11 @@ extern "C" { /* * Class: dev_onvoid_webrtc_media_audio_AudioResampler - * Method: resetInternal - * Signature: (III)V - */ - JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resetInternal - (JNIEnv*, jobject, jint, jint, jint); - - /* - * Class: dev_onvoid_webrtc_media_audio_AudioResampler - * Method: resampleInternal - * Signature: ([BI[BI)I + * Method: resample + * Signature: ([BI[BII)I */ JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resampleInternal - (JNIEnv*, jobject, jbyteArray, jint, jbyteArray, jint); + (JNIEnv*, jobject, jbyteArray, jint, jbyteArray, jint, jint); #ifdef __cplusplus } diff --git a/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h b/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h index 219b6dad..5c96f4c3 100644 --- a/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h +++ b/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingConfig.h @@ -38,9 +38,6 @@ namespace jni jfieldID gainControl; jfieldID highPassFilter; jfieldID noiseSuppression; - jfieldID residualEchoDetector; - jfieldID transientSuppression; - jfieldID voiceDetection; }; webrtc::AudioProcessing::Config toNative(JNIEnv * env, const JavaRef & javaType); diff --git a/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp b/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp index d5874599..e8de6f3e 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_AudioResampler.cpp @@ -49,7 +49,7 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_initial SetHandle(env, caller, resampler); } -JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resample +JNIEXPORT jint JNICALL Java_dev_onvoid_webrtc_media_audio_AudioResampler_resampleInternal (JNIEnv * env, jobject caller, jbyteArray samplesIn, jint srcSamplesPerChannel, jbyteArray samplesOut, jint dstSamplesPerChannel, jint channels) { webrtc::PushResampler * resampler = GetHandle>(env, caller); diff --git a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp index 52a48df7..b5c9c4fd 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp @@ -35,6 +35,20 @@ #include "api/video_codecs/builtin_video_decoder_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h" +#include "api/video_codecs/video_decoder_factory.h" +#include "api/video_codecs/video_decoder_factory_template.h" +#include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h" +#include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h" +#include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h" +#include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h" +#include "api/video_codecs/video_encoder.h" +#include "api/video_codecs/video_encoder_factory.h" +#include "api/video_codecs/video_encoder_factory_template.h" +#include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h" +#include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h" +#include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h" +#include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h" + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_initialize (JNIEnv * env, jobject caller, jobject audioModule, jobject audioProcessing) { @@ -70,8 +84,16 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_initialize adm, webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), - webrtc::CreateBuiltinVideoEncoderFactory(), - webrtc::CreateBuiltinVideoDecoderFactory(), + std::make_unique>(), + std::make_unique>(), nullptr, apm); diff --git a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp index d807aab6..66026969 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingConfig.cpp @@ -88,7 +88,6 @@ namespace jni gainControl = GetFieldID(env, cls, "gainControl", "L" PKG_AUDIO "AudioProcessingConfig$GainControl;"); highPassFilter = GetFieldID(env, cls, "highPassFilter", "L" PKG_AUDIO "AudioProcessingConfig$HighPassFilter;"); noiseSuppression = GetFieldID(env, cls, "noiseSuppression", "L" PKG_AUDIO "AudioProcessingConfig$NoiseSuppression;"); - transientSuppression = GetFieldID(env, cls, "transientSuppression", "L" PKG_AUDIO "AudioProcessingConfig$TransientSuppression;"); } JavaEchoCancellerClass::JavaEchoCancellerClass(JNIEnv* env) diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java index a14675ad..192f9eb6 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioResampler.java @@ -16,6 +16,8 @@ package dev.onvoid.webrtc.media.audio; +import static java.util.Objects.requireNonNull; + import dev.onvoid.webrtc.internal.DisposableNativeObject; /** @@ -59,8 +61,19 @@ public AudioResampler(int sourceSampleRate, int targetSampleRate, int channels) * * @return The number of converted audio samples. */ - public native int resample(byte[] samplesIn, int srcSamplesPerChannel, byte[] samplesOut, int dstSamplesPerChannel, - int channels); + public int resample(byte[] samplesIn, int srcSamplesPerChannel, byte[] samplesOut, int dstSamplesPerChannel, + int channels) { + requireNonNull(samplesIn); + requireNonNull(samplesOut); + + final int maxSamplesOut = samplesOut.length / 2; // 16-bit PCM sample + + if (dstSamplesPerChannel > maxSamplesOut) { + throw new IllegalArgumentException("Insufficient samples output length"); + } + + return resampleInternal(samplesIn, srcSamplesPerChannel, samplesOut, maxSamplesOut, channels); + } @Override public native void dispose(); @@ -69,6 +82,9 @@ public native int resample(byte[] samplesIn, int srcSamplesPerChannel, byte[] sa private native void initialize(int srcSamplesPerChannel, int dstSamplesPerChannel, int channels); + private native int resampleInternal(byte[] samplesIn, int srcSamplesPerChannel, + byte[] samplesOut, int dstSamplesPerChannel, int channels); + /** * Returns the number of samples a buffer needs to hold for ~10ms of a single audio channel at a given sample rate. * diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java index 92e72956..6d6f34d6 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java @@ -38,15 +38,6 @@ void dispose() { resampler.dispose(); } - @Test - void notInitialized() { - SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); - - assertThrows(IllegalStateException.class, () -> { - resampler.resample(buffer.src, buffer.nSamplesIn, buffer.dst, buffer.nSamplesOut, 1); - }); - } - @Test void targetBufferUnderflow() { SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); @@ -60,7 +51,6 @@ void targetBufferUnderflow() { @Test void constructorParameters() { SampleBuffer buffer = new SampleBuffer(48000, 44100, 2); - AudioResampler resampler = new AudioResampler(48000, 44100, 2); int result = resample(resampler, buffer); From af18102cd1b8dafacb75d0433fabc1a4c4940765 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 21 Mar 2025 16:01:08 +0100 Subject: [PATCH 03/28] fix: DesktopCaptureCallback using copy frames for now --- .../cpp/src/media/video/desktop/DesktopCaptureCallback.cpp | 5 ++++- .../dev/onvoid/webrtc/media/audio/AudioResamplerTest.java | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCaptureCallback.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCaptureCallback.cpp index aa2aead0..aca320ff 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCaptureCallback.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCaptureCallback.cpp @@ -95,7 +95,10 @@ namespace jni jint rotation = static_cast(webrtc::kVideoRotation_0); jlong timestamp = rtc::TimeMicros() * rtc::kNumNanosecsPerMicrosec; - JavaLocalRef jBuffer = I420Buffer::toJava(env, i420Buffer); + rtc::scoped_refptr i420BufferCopy = webrtc::I420Buffer::Copy(*i420Buffer); + i420BufferCopy->AddRef(); + + JavaLocalRef jBuffer = I420Buffer::toJava(env, i420BufferCopy); jobject jFrame = env->NewObject(javaFrameClass->cls, javaFrameClass->ctor, jBuffer.get(), rotation, timestamp); env->CallVoidMethod(callback, javaClass->onCaptureResult, jresult.get(), jFrame); diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java index 6d6f34d6..29e1131a 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/AudioResamplerTest.java @@ -43,9 +43,7 @@ void targetBufferUnderflow() { SampleBuffer buffer = new SampleBuffer(48000, 24000, 1); buffer.setTargetBufferSize(buffer.frameSizeOut / 2); - assertThrows(IllegalArgumentException.class, () -> { - resample(resampler, buffer); - }); + assertThrows(IllegalArgumentException.class, () -> resample(resampler, buffer)); } @Test @@ -109,7 +107,7 @@ private static class SampleBuffer { this.sampleRateOut = sampleRateOut; nSamplesIn = AudioResampler.getSamplesPerChannel(sampleRateIn); // 10 ms frame - nSamplesOut = AudioResampler.getSamplesPerChannel(sampleRateOut);; + nSamplesOut = AudioResampler.getSamplesPerChannel(sampleRateOut); frameSizeIn = nSamplesIn * bytesPerFrame; frameSizeOut = nSamplesOut * bytesPerFrame; From 5d12289a6ffae2b0fcaf51c952d747b97f94cc7d Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 21 Mar 2025 17:03:02 +0100 Subject: [PATCH 04/28] fix: missing symbols on macOS --- webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index 1d7be6f9..00699f37 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -151,7 +151,7 @@ target_link_libraries(${PROJECT_NAME} ${TARGET_LINK_LIB}) if(APPLE) target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_MAC WEBRTC_POSIX NDEBUG) - target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreAudio" "-framework AudioToolbox" "-framework IOSurface" "-framework ApplicationServices" "-framework AppKit") + target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreAudio" "-framework CoreVideo" "-framework ScreenCaptureKit" "-framework AudioToolbox" "-framework IOSurface" "-framework ApplicationServices" "-framework AppKit") elseif(LINUX) # Find DBus find_package(PkgConfig QUIET REQUIRED) # Include functions provided by PkgConfig module. From 88940d80d15fb762708b5a90163b998533073708 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 21 Mar 2025 17:03:42 +0100 Subject: [PATCH 05/28] fix: new webrtc branch number in readme and workflows --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- README.md | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 15a26104..6760c571 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ on: workflow_dispatch: env: - WEBRTC_CACHE_BRANCH: 4844 + WEBRTC_CACHE_BRANCH: 6998 WEBRTC_CHECKOUT_FOLDER: webrtc WEBRTC_INSTALL_FOLDER: webrtc/build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ceee83a6..f2fdad3d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ on: default: "X.Y.Z-SNAPSHOT" env: - WEBRTC_CACHE_BRANCH: 4844 + WEBRTC_CACHE_BRANCH: 6998 WEBRTC_CHECKOUT_FOLDER: webrtc WEBRTC_INSTALL_FOLDER: webrtc/build diff --git a/README.md b/README.md index c63f85dd..f1dd2db0 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,11 @@ Maven Central artifacts contain native libraries that can be loaded on the follo -The native libraries were build with WebRTC branch M99/4844. +The native libraries were built with WebRTC branch M134/6998. ### Build Notes -In order to build the native code, be sure to install the prerequisite software (follow the links): +To build the native code, be sure to install the prerequisite software (follow the links): **Note**: You don't have to install the Depot Tools, the build script will do that for you. @@ -80,6 +80,6 @@ On the first run, the WebRTC source tree will be loaded into the `//w | Parameter | Description | Default Value | | ------------------ | ------------------------------------------------------ |-----------------------------| -| webrtc.branch | The WebRTC branch to checkout. | branch-heads/4844 | +| webrtc.branch | The WebRTC branch to checkout. | branch-heads/6997 | | webrtc.src.dir | The absolute checkout path for the WebRTC source tree. | /\/webrtc | | webrtc.install.dir | The install path for the compiled WebRTC library. Is also used to link against a pre-compiled WebRTC library to reduce build time. | /\/webrtc/build | From 98b04f80dc524e2a040ebc7b4ccc9f8df553b9c2 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 21 Mar 2025 17:09:11 +0100 Subject: [PATCH 06/28] fix: compile on Windows 2022 with Visual Studio 2022 --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6760c571..8f2aa2ac 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: matrix: platform: - name: windows_x86_64 - runs-on: windows-2019 + runs-on: windows-2022 java: [17] runs-on: ${{ matrix.platform.runs-on }} steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2fdad3d..5bbc8b3c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,7 +79,7 @@ jobs: matrix: platform: - name: windows_x86_64 - runs-on: windows-2019 + runs-on: windows-2022 java: [17] runs-on: ${{ matrix.platform.runs-on }} steps: From b7174a0772dd705af8da42aa4f66f20265bbb04b Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 21 Mar 2025 19:15:19 +0100 Subject: [PATCH 07/28] fix: add '*.inc' pattern for installation as abseil requires those files --- webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index 00699f37..61c87f12 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -259,6 +259,7 @@ install( DESTINATION "${WEBRTC_INSTALL_DIR}/include" FILES_MATCHING PATTERN "*.h" + PATTERN "*.inc" REGEX /src/base/ EXCLUDE REGEX /src/build/ EXCLUDE REGEX /src/build_overrides/ EXCLUDE From 9cc21fc4202d017d9bc28db98f8c90abcfd16aa3 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Sat, 22 Mar 2025 12:32:38 +0100 Subject: [PATCH 08/28] fix: workflows to run on ubuntu-22.04 --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f2aa2ac..750313fc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -81,7 +81,7 @@ jobs: matrix: platform: - name: linux_x86-64 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 java: [17] runs-on: ${{ matrix.platform.runs-on }} steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5bbc8b3c..cf842fec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ env: jobs: prepare-release: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Disk cleanup run: | @@ -147,7 +147,7 @@ jobs: matrix: platform: - name: linux_x86-64 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 java: [17] runs-on: ${{ matrix.platform.runs-on }} steps: From da240c0db0fb4e622d4a3efc61097d15683e2f83 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Mon, 24 Mar 2025 19:21:38 +0100 Subject: [PATCH 09/28] fix: linux and macOS builds --- README.md | 30 +++++++++++++------ .../cpp/dependencies/webrtc/CMakeLists.txt | 11 +++++-- .../onvoid/webrtc/RTCDataChannelTests.java | 2 ++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f1dd2db0..7e934629 100644 --- a/README.md +++ b/README.md @@ -32,16 +32,28 @@ Maven Central artifacts contain native libraries that can be loaded on the follo - - + + + + - - - + + + + + - - - + + + + + + + + + + +
Linuxx86_64, arm64, arm32x64armarm64
macOSx86_64, arm64
Linux--
Windowsx86_64
macOS-
Windows--
@@ -74,7 +86,7 @@ Assuming you have all the prerequisites installed for your OS, run: mvn install ``` -On the first run, the WebRTC source tree will be loaded into the `//webrtc` directory. This will take a while and require about 18 GB of disk space. +On the first run, the WebRTC source tree will be loaded into the `//webrtc` directory. This will take a while and require about 20 GB of disk space. #### Build Parameters diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index 61c87f12..d92c932b 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -122,6 +122,8 @@ set(WEBRTC_BUILD out/${TARGET_CPU}) set(WEBRTC_LIB_PATH ${WEBRTC_SRC}/${WEBRTC_BUILD}/obj/${WEBRTC_LIB}) set(WEBRTC_LIB_PATH_INSTALLED ${WEBRTC_INSTALL_DIR}/lib/${WEBRTC_LIB}) +set(WEBRTC_CLANG "true") + file(TO_CMAKE_PATH "${WEBRTC_DIR}" WEBRTC_DIR) file(TO_CMAKE_PATH "${WEBRTC_INSTALL_DIR}" WEBRTC_INSTALL_DIR) file(TO_CMAKE_PATH "${WEBRTC_LIB_PATH}" WEBRTC_LIB_PATH) @@ -150,15 +152,18 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} ${TARGET_LINK_LIB}) if(APPLE) - target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_MAC WEBRTC_POSIX NDEBUG) + target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_MAC WEBRTC_POSIX) target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreAudio" "-framework CoreVideo" "-framework ScreenCaptureKit" "-framework AudioToolbox" "-framework IOSurface" "-framework ApplicationServices" "-framework AppKit") elseif(LINUX) + # Due to branch 6998 (m134) build with gcc. Linking webrtc built with clang causes errors. + set(WEBRTC_CLANG "false") + # Find DBus find_package(PkgConfig QUIET REQUIRED) # Include functions provided by PkgConfig module. pkg_check_modules(DBUS REQUIRED dbus-1) target_include_directories(${PROJECT_NAME} PUBLIC ${DBUS_INCLUDE_DIRS}) - target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_LINUX WEBRTC_POSIX NDEBUG) + target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_LINUX WEBRTC_POSIX) target_link_libraries(${PROJECT_NAME} X11 Xfixes Xrandr Xcomposite dbus-1) elseif(WIN32) target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_WIN NOMINMAX WIN32_LEAN_AND_MEAN NDEBUG) @@ -237,7 +242,7 @@ if (PATCHES) endif() message(STATUS "WebRTC: generate") -set(COMPILE_ARGS "is_debug=false target_cpu=\"${TARGET_CPU}\" treat_warnings_as_errors=false rtc_build_examples=false rtc_include_tests=false use_rtti=true use_custom_libcxx=false symbol_level=0 rtc_use_h264=true") +set(COMPILE_ARGS "target_cpu=\"${TARGET_CPU}\" is_clang=${WEBRTC_CLANG} is_debug=false is_component_build=false treat_warnings_as_errors=false rtc_enable_protobuf=false rtc_build_examples=false rtc_include_tests=false use_rtti=true rtc_use_h264=true use_custom_libcxx=false symbol_level=0") execute_command( COMMAND gn gen ${WEBRTC_BUILD} --args=${COMPILE_ARGS} WORKING_DIRECTORY "${WEBRTC_SRC}" diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/RTCDataChannelTests.java b/webrtc/src/test/java/dev/onvoid/webrtc/RTCDataChannelTests.java index 3cfb0ec2..eea8ffd7 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/RTCDataChannelTests.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/RTCDataChannelTests.java @@ -38,6 +38,8 @@ void textMessage() throws Exception { caller.waitUntilConnected(); callee.waitUntilConnected(); + Thread.sleep(500); + caller.sendTextMessage("Hello world"); callee.sendTextMessage("Hi :)"); From 5a462f9e73bf2cbae43fecb2f68c0918af76a073 Mon Sep 17 00:00:00 2001 From: Alex Andres <58339654+devopvoid@users.noreply.github.com> Date: Mon, 24 Mar 2025 22:19:47 +0100 Subject: [PATCH 10/28] build.yml Linux pipewire activation --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 750313fc..2e4a4371 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -115,10 +115,10 @@ jobs: sudo apt-get update sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils # Required for testing - pulseaudio --start - #sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries - #systemctl --user daemon-reload - #systemctl --user --now enable pipewire{,-pulse}.{socket,service} + #pulseaudio --start + sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries + systemctl --user daemon-reload + systemctl --user --now enable pipewire{,-pulse}.{socket,service} - id: maven-build name: Maven build From a6c6a1b403639f99f7814334857702f85defec96 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Tue, 25 Mar 2025 16:52:15 +0100 Subject: [PATCH 11/28] feat: added the utility class VoiceActivityDetector --- .../cpp/include/JNI_VoiceActivityDetector.h | 45 +++++++++++ .../cpp/src/JNI_VoiceActivityDetector.cpp | 64 +++++++++++++++ .../media/audio/VoiceActivityDetector.java | 66 ++++++++++++++++ .../audio/VoiceActivityDetectorTest.java | 79 +++++++++++++++++++ 4 files changed, 254 insertions(+) create mode 100644 webrtc-jni/src/main/cpp/include/JNI_VoiceActivityDetector.h create mode 100644 webrtc-jni/src/main/cpp/src/JNI_VoiceActivityDetector.cpp create mode 100644 webrtc/src/main/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetector.java create mode 100644 webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java diff --git a/webrtc-jni/src/main/cpp/include/JNI_VoiceActivityDetector.h b/webrtc-jni/src/main/cpp/include/JNI_VoiceActivityDetector.h new file mode 100644 index 00000000..ccda4ddd --- /dev/null +++ b/webrtc-jni/src/main/cpp/include/JNI_VoiceActivityDetector.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class dev_onvoid_webrtc_media_audio_VoiceActivityDetector */ + +#ifndef _Included_dev_onvoid_webrtc_media_audio_VoiceActivityDetector +#define _Included_dev_onvoid_webrtc_media_audio_VoiceActivityDetector +#ifdef __cplusplus +extern "C" { +#endif + /* + * Class: dev_onvoid_webrtc_media_audio_VoiceActivityDetector + * Method: process + * Signature: ([BII)V + */ + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_process + (JNIEnv *, jobject, jbyteArray, jint, jint); + + /* + * Class: dev_onvoid_webrtc_media_audio_VoiceActivityDetector + * Method: getLastVoiceProbability + * Signature: ()F + */ + JNIEXPORT jfloat JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_getLastVoiceProbability + (JNIEnv *, jobject); + + /* + * Class: dev_onvoid_webrtc_media_audio_VoiceActivityDetector + * Method: dispose + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_dispose + (JNIEnv *, jobject); + + /* + * Class: dev_onvoid_webrtc_media_audio_VoiceActivityDetector + * Method: initialize + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_initialize + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_VoiceActivityDetector.cpp b/webrtc-jni/src/main/cpp/src/JNI_VoiceActivityDetector.cpp new file mode 100644 index 00000000..c62b594c --- /dev/null +++ b/webrtc-jni/src/main/cpp/src/JNI_VoiceActivityDetector.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +#include "JNI_VoiceActivityDetector.h" + +#include "JavaObject.h" +#include "JavaUtils.h" + +#include "modules/audio_processing/vad/voice_activity_detector.h" + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_process +(JNIEnv * env, jobject caller, jbyteArray data, jint sampleCount, jint sampleRate) +{ + webrtc::VoiceActivityDetector * activityDetector = GetHandle(env, caller); + CHECK_HANDLE(activityDetector); + + jbyte * dataPtr = env->GetByteArrayElements(data, nullptr); + const int16_t * data16Ptr = reinterpret_cast(dataPtr); + + activityDetector->ProcessChunk(data16Ptr, sampleCount, sampleRate); + + env->ReleaseByteArrayElements(data, dataPtr, JNI_ABORT); +} + +JNIEXPORT jfloat JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_getLastVoiceProbability +(JNIEnv * env, jobject caller) +{ + webrtc::VoiceActivityDetector * activityDetector = GetHandle(env, caller); + CHECK_HANDLEV(activityDetector, 0); + + return activityDetector->last_voice_probability(); +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_dispose +(JNIEnv * env, jobject caller) +{ + webrtc::VoiceActivityDetector * activityDetector = GetHandle(env, caller); + CHECK_HANDLE(activityDetector); + + SetHandle(env, caller, nullptr); + + delete activityDetector; +} + +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_audio_VoiceActivityDetector_initialize +(JNIEnv * env, jobject caller) +{ + webrtc::VoiceActivityDetector * activityDetector = new webrtc::VoiceActivityDetector(); + + SetHandle(env, caller, activityDetector); +} \ No newline at end of file diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetector.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetector.java new file mode 100644 index 00000000..08dfe68d --- /dev/null +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetector.java @@ -0,0 +1,66 @@ +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +import dev.onvoid.webrtc.internal.DisposableNativeObject; + +/** + * A voice activity detector that analyzes audio data chunks to determine the probability of voice presence in the + * audio stream. + *

+ * This class provides native methods to process audio and retrieve the probability of voice activity. + * + * @author Alex Andres + */ +public class VoiceActivityDetector extends DisposableNativeObject { + + /** + * Constructs a new {@code VoiceActivityDetector} instance. + */ + public VoiceActivityDetector() { + initialize(); + } + + /** + * Processes audio data to detect voice activity. + * + * @param audio The audio data to process. + * @param samplesPerChannel The number of samples in the audio chunk. + * @param sampleRate The sample rate of the audio data in Hz. + */ + public native void process(byte[] audio, int samplesPerChannel, int sampleRate); + + /** + * Gets the probability of voice presence from the last processed audio data. + * + * @return A value between 0.0 and 1.0 representing the probability of voice presence. + */ + public native float getLastVoiceProbability(); + + /** + * Releases native resources held by this object. + */ + @Override + public native void dispose(); + + /** + * Initializes the native resources for the voice activity detector. This method is called during construction and + * sets up the underlying native implementation. + */ + private native void initialize(); + +} diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java new file mode 100644 index 00000000..4efb4cfd --- /dev/null +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2021 Alex Andres + * + * 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. + */ + +package dev.onvoid.webrtc.media.audio; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class VoiceActivityDetectorTest { + + private VoiceActivityDetector detector; + + + @BeforeEach + void setUp() { + detector = new VoiceActivityDetector(); + } + + @AfterEach + void tearDown() { + if (detector != null) { + detector.dispose(); + } + } + + @Test + void testInitialization() { + assertNotNull(detector, "Detector should be initialized"); + } + + @Test + void testProcessAndGetProbability() { + // Create sample audio data (silence - all zeros). + byte[] silenceData = new byte[320]; // 10ms at 16kHz mono with 16-bit samples + int samplesPerChannel = 160; + int sampleRate = 16000; + + // Process silent audio. + detector.process(silenceData, samplesPerChannel, sampleRate); + + float probability = detector.getLastVoiceProbability(); + + assertTrue(probability >= 0.0f && probability <= 1.0f, + "Probability should be between 0.0 and 1.0"); + } + + @Test + void testDispose() { + // First operation should work. + detector.process(new byte[320], 160, 16000); + + // Dispose resources. + detector.dispose(); + + // After disposal, operations should either throw an exception or be safe to call. + assertThrows(Exception.class, () -> { + detector.process(new byte[320], 160, 16000); + }); + + detector = null; + } + +} From f8462b532b960d8c21b353f95635b4e784869880 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 26 Mar 2025 11:27:54 +0100 Subject: [PATCH 12/28] feat: add maven profile to compile with clang in windows --- webrtc-jni/pom.xml | 10 ++++++++++ webrtc-jni/src/main/cpp/CMakeLists.txt | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/webrtc-jni/pom.xml b/webrtc-jni/pom.xml index b581893f..76f4a01c 100644 --- a/webrtc-jni/pom.xml +++ b/webrtc-jni/pom.xml @@ -17,6 +17,7 @@ ${user.home}/webrtc/build Release + @@ -95,6 +96,9 @@ + @@ -147,6 +151,12 @@ ${cmake.build.type} + + windows-clang-x86_64 + + -T ClangCL + + linux-x86_64 diff --git a/webrtc-jni/src/main/cpp/CMakeLists.txt b/webrtc-jni/src/main/cpp/CMakeLists.txt index 38a35040..0f950c4b 100644 --- a/webrtc-jni/src/main/cpp/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/CMakeLists.txt @@ -25,6 +25,10 @@ elseif(WIN32) set(SOURCE_TARGET windows) endif() +if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /showFilenames") +endif() + add_subdirectory(dependencies/webrtc) add_subdirectory(dependencies/jni-voithos) From 968165f494505aedf20765041d31b13022032701 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 26 Mar 2025 15:31:11 +0100 Subject: [PATCH 13/28] fix: refactored RTCStats to match new API --- .../jni-voithos/include/JavaDimension.h | 2 - .../jni-voithos/include/JavaRectangle.h | 4 - .../include/media/MediaStreamTrackObserver.h | 6 +- .../media/video/VideoCaptureCapability.h | 2 +- .../video/windows/WindowsVideoDeviceManager.h | 4 +- .../src/main/cpp/src/JNI_MediaStreamTrack.cpp | 8 - .../cpp/src/JNI_PeerConnectionFactory.cpp | 3 +- .../cpp/src/api/RTCRtpCodecCapability.cpp | 6 +- .../cpp/src/api/RTCRtpCodecParameters.cpp | 6 +- webrtc-jni/src/main/cpp/src/api/RTCStats.cpp | 147 ++++++++---------- .../src/main/cpp/src/api/RTCStatsReport.cpp | 4 +- .../main/java/dev/onvoid/webrtc/RTCStats.java | 16 +- .../webrtc/RTCStatsCollectorCallback.java | 2 +- .../dev/onvoid/webrtc/RTCStatsReport.java | 19 ++- 14 files changed, 103 insertions(+), 126 deletions(-) diff --git a/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaDimension.h b/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaDimension.h index 43f5d440..d8b73e55 100644 --- a/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaDimension.h +++ b/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaDimension.h @@ -25,8 +25,6 @@ namespace jni private: jclass cls; jmethodID ctor; - jfieldID width; - jfieldID height; }; } diff --git a/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaRectangle.h b/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaRectangle.h index 95216e9f..fd059c7d 100644 --- a/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaRectangle.h +++ b/webrtc-jni/src/main/cpp/dependencies/jni-voithos/include/JavaRectangle.h @@ -25,10 +25,6 @@ namespace jni private: jclass cls; jmethodID ctor; - jfieldID x; - jfieldID y; - jfieldID width; - jfieldID height; }; } diff --git a/webrtc-jni/src/main/cpp/include/media/MediaStreamTrackObserver.h b/webrtc-jni/src/main/cpp/include/media/MediaStreamTrackObserver.h index 5e80f9e6..041fde28 100644 --- a/webrtc-jni/src/main/cpp/include/media/MediaStreamTrackObserver.h +++ b/webrtc-jni/src/main/cpp/include/media/MediaStreamTrackObserver.h @@ -54,14 +54,10 @@ namespace jni JavaLocalRef createJavaTrack(JNIEnv * env); private: + const JavaGlobalRef javaTrack; const webrtc::MediaStreamTrackInterface * track; - const MediaStreamTrackEvent eventType; - - const JavaGlobalRef javaTrack; - const std::shared_ptr javaClass; - webrtc::MediaStreamTrackInterface::TrackState trackState; bool trackEnabled; }; diff --git a/webrtc-jni/src/main/cpp/include/media/video/VideoCaptureCapability.h b/webrtc-jni/src/main/cpp/include/media/video/VideoCaptureCapability.h index e9aefa47..2c17332c 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/VideoCaptureCapability.h +++ b/webrtc-jni/src/main/cpp/include/media/video/VideoCaptureCapability.h @@ -31,7 +31,7 @@ namespace jni class VideoCaptureCapability : public webrtc::VideoCaptureCapability { public: - virtual bool operator<(const VideoCaptureCapability & other) const; + bool operator<(const VideoCaptureCapability & other) const; }; } diff --git a/webrtc-jni/src/main/cpp/include/media/video/windows/WindowsVideoDeviceManager.h b/webrtc-jni/src/main/cpp/include/media/video/windows/WindowsVideoDeviceManager.h index be7590d8..f195fd76 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/windows/WindowsVideoDeviceManager.h +++ b/webrtc-jni/src/main/cpp/include/media/video/windows/WindowsVideoDeviceManager.h @@ -34,8 +34,8 @@ namespace jni std::set getVideoCaptureCapabilities(const VideoDevice & device) override; protected: - void onDeviceConnected(std::wstring symLink); - void onDeviceDisconnected(std::wstring symLink); + void onDeviceConnected(std::wstring symLink) override; + void onDeviceDisconnected(std::wstring symLink) override; private: void enumerateDevices(std::wstring * symLink); diff --git a/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp b/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp index b6ad5be2..011e6ac0 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_MediaStreamTrack.cpp @@ -95,8 +95,6 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_addEndedEve webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); CHECK_HANDLE(track); - jni::WebRTCContext * context = static_cast(javaContext); - try { jni::MediaStreamTrackObserver * observer = new jni::MediaStreamTrackObserver(env, jni::JavaGlobalRef(env, jListener), track, jni::MediaStreamTrackEvent::ended); auto observerPtr = std::shared_ptr(observer); @@ -116,8 +114,6 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_removeEnded webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); CHECK_HANDLE(track); - jni::WebRTCContext * context = static_cast(javaContext); - try { auto observerPtr = javaContext->removeNativeRef(env, jni::JavaLocalRef(env, jListener)); @@ -136,8 +132,6 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_addMuteEven webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); CHECK_HANDLE(track); - jni::WebRTCContext * context = static_cast(javaContext); - try { jni::MediaStreamTrackObserver * observer = new jni::MediaStreamTrackObserver(env, jni::JavaGlobalRef(env, jListener), track, jni::MediaStreamTrackEvent::mute); auto observerPtr = std::shared_ptr(observer); @@ -157,8 +151,6 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_MediaStreamTrack_removeMuteE webrtc::MediaStreamTrackInterface * track = GetHandle(env, caller); CHECK_HANDLE(track); - jni::WebRTCContext * context = static_cast(javaContext); - try { auto observerPtr = javaContext->removeNativeRef(env, jni::JavaLocalRef(env, jListener)); diff --git a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp index b5c9c4fd..382b91a5 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_PeerConnectionFactory.cpp @@ -219,7 +219,8 @@ JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_PeerConnectionFactory_createVid std::string label = jni::JavaString::toNative(env, jni::JavaLocalRef(env, jlabel)); - rtc::scoped_refptr videoTrack = factory->CreateVideoTrack(label, source); + rtc::scoped_refptr videoTrack = factory->CreateVideoTrack( + rtc::scoped_refptr(source), label); return jni::JavaFactories::create(env, videoTrack.release()).release(); } diff --git a/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecCapability.cpp b/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecCapability.cpp index 539deaf8..5e05603b 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecCapability.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecCapability.cpp @@ -35,9 +35,9 @@ namespace jni JavaHashMap paramMap(env); - for (const std::pair & param : capability.parameters) { - JavaLocalRef key = JavaString::toJava(env, param.first); - JavaLocalRef value = JavaString::toJava(env, param.second); + for (const auto & [p_key, p_value] : capability.parameters) { + JavaLocalRef key = JavaString::toJava(env, p_key); + JavaLocalRef value = JavaString::toJava(env, p_value); paramMap.put(key, value); } diff --git a/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecParameters.cpp b/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecParameters.cpp index cec63f38..8259004d 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecParameters.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCRtpCodecParameters.cpp @@ -37,9 +37,9 @@ namespace jni JavaLocalRef channels = nullptr; JavaHashMap paramMap(env); - for (const std::pair & param : parameters.parameters) { - JavaLocalRef key = JavaString::toJava(env, param.first); - JavaLocalRef value = JavaString::toJava(env, param.second); + for (const auto & [p_key, p_value] : parameters.parameters) { + JavaLocalRef key = JavaString::toJava(env, p_key); + JavaLocalRef value = JavaString::toJava(env, p_value); paramMap.put(key, value); } diff --git a/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp b/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp index f0c9b55d..f2f53de9 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp @@ -109,104 +109,81 @@ namespace jni JavaLocalRef toJava(JNIEnv * env, const webrtc::Attribute & attribute) { - if (attribute.has_value()) { - auto value = attribute.as_variant(); + auto value = attribute.as_variant(); - + if (attribute.holds_alternative()) { + return Boolean::create(env, attribute.get()); } + else if (attribute.holds_alternative()) { + return Integer::create(env, attribute.get()); + } + else if (attribute.holds_alternative()) { + return Long::create(env, attribute.get()); + } + else if (attribute.holds_alternative()) { + return Long::create(env, attribute.get()); + } + else if (attribute.holds_alternative()) { + return JavaBigInteger::toJava(env, rtc::ToString(attribute.get())); + } + else if (attribute.holds_alternative()) { + return Double::create(env, attribute.get()); + } + else if (attribute.holds_alternative()) { + return jni::static_java_ref_cast(env, JavaString::toJava(env, attribute.get())); + } + else if (attribute.holds_alternative>()) { + return jni::static_java_ref_cast(env, Boolean::createArray(env, attribute.get>())); + } + else if (attribute.holds_alternative>()) { + return jni::static_java_ref_cast(env, Integer::createArray(env, attribute.get>())); + } + else if (attribute.holds_alternative>()) { + const std::vector & v = attribute.get>(); + return jni::static_java_ref_cast(env, Long::createArray(env, std::vector(v.begin(), v.end()))); + } + else if (attribute.holds_alternative>()) { + return jni::static_java_ref_cast(env, Long::createArray(env, attribute.get>())); + } + else if (attribute.holds_alternative>()) { + const std::vector & v = attribute.get>(); + std::vector r; + std::transform(v.begin(), v.end(), std::back_inserter(r), + [](uint64_t n) { return rtc::ToString(n); }); - /* - switch (attribute.type()) { - case webrtc::RTCStatsMemberInterface::kBool: - return Boolean::create(env, *attribute.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kInt32: - return Integer::create(env, *attribute.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kUint32: - return Long::create(env, *attribute.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kInt64: - return Long::create(env, *attribute.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kUint64: - return JavaBigInteger::toJava(env, rtc::ToString(*attribute.cast_to>())); - - case webrtc::RTCStatsMemberInterface::kDouble: - return Double::create(env, *attribute.cast_to>()); - - case webrtc::RTCStatsMemberInterface::kString: - return jni::static_java_ref_cast(env, - JavaString::toJava(env, *attribute.cast_to>())); - - case webrtc::RTCStatsMemberInterface::kSequenceBool: - return jni::static_java_ref_cast(env, - Boolean::createArray(env, *attribute.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceInt32: - return jni::static_java_ref_cast(env, - Integer::createArray(env, *attribute.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceUint32: - { - const std::vector & v = *attribute.cast_to>>(); - return jni::static_java_ref_cast(env, - Long::createArray(env, std::vector(v.begin(), v.end()))); - } - - case webrtc::RTCStatsMemberInterface::kSequenceInt64: - return jni::static_java_ref_cast(env, - Long::createArray(env, *attribute.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceUint64: - { - const std::vector & v = *attribute.cast_to>>(); - std::vector r; + return jni::static_java_ref_cast(env, JavaBigInteger::createArray(env, r)); + } + else if (attribute.holds_alternative>()) { + return jni::static_java_ref_cast(env, Double::createArray(env, attribute.get>())); + } + else if (attribute.holds_alternative>()) { + return jni::static_java_ref_cast(env, JavaString::createArray(env, attribute.get>())); + } + else if (attribute.holds_alternative>()) { + std::map map = attribute.get>(); - std::transform(v.begin(), v.end(), std::back_inserter(r), - [](uint64_t n) { return rtc::ToString(n); }); + JavaHashMap memberMap(env); - return jni::static_java_ref_cast(env, JavaBigInteger::createArray(env, r)); + for (const auto & item : map) { + memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), + JavaBigInteger::toJava(env, rtc::ToString(item.second))); } - case webrtc::RTCStatsMemberInterface::kSequenceDouble: - return jni::static_java_ref_cast(env, - Double::createArray(env, *attribute.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kSequenceString: - return jni::static_java_ref_cast(env, - JavaString::createArray(env, *attribute.cast_to>>())); - - case webrtc::RTCStatsMemberInterface::kMapStringDouble: - { - std::map map = *attribute.cast_to>>(); - - JavaHashMap memberMap(env); + return jni::static_java_ref_cast(env, memberMap); + } + else if (attribute.holds_alternative>()) { + std::map map = attribute.get>(); - for (const auto& item : map) { - memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), - Double::create(env, item.second)); - } + JavaHashMap memberMap(env); - return jni::static_java_ref_cast(env, memberMap); + for (const auto& item : map) { + memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), + Double::create(env, item.second)); } - case webrtc::RTCStatsMemberInterface::kMapStringUint64: - { - std::map map = *attribute.cast_to>>(); - - JavaHashMap memberMap(env); - - for (const auto& item : map) { - memberMap.put(jni::static_java_ref_cast(env, JavaString::toJava(env, item.first)), - JavaBigInteger::toJava(env, rtc::ToString(item.second))); - } - - return jni::static_java_ref_cast(env, memberMap); - } + return jni::static_java_ref_cast(env, memberMap); } - */ return nullptr; } diff --git a/webrtc-jni/src/main/cpp/src/api/RTCStatsReport.cpp b/webrtc-jni/src/main/cpp/src/api/RTCStatsReport.cpp index 9f3bef37..4025051c 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCStatsReport.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCStatsReport.cpp @@ -38,7 +38,7 @@ namespace jni statsMap.put(key, value); } - jobject obj = env->NewObject(javaClass->cls, javaClass->ctor, ((JavaLocalRef)statsMap).get()); + jobject obj = env->NewObject(javaClass->cls, javaClass->ctor, ((JavaLocalRef)statsMap).get(), report->timestamp().us()); return JavaLocalRef(env, obj); } @@ -47,7 +47,7 @@ namespace jni { cls = FindClass(env, PKG"RTCStatsReport"); - ctor = GetMethod(env, cls, "", "(" MAP_SIG ")V"); + ctor = GetMethod(env, cls, "", "(" MAP_SIG "J)V"); } } } \ No newline at end of file diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/RTCStats.java b/webrtc/src/main/java/dev/onvoid/webrtc/RTCStats.java index b819e15f..fc827ef8 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/RTCStats.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/RTCStats.java @@ -48,14 +48,14 @@ public class RTCStats { /** * The stats data. */ - private final Map members; + private final Map attributes; - protected RTCStats(long timestamp, RTCStatsType type, String id, Map members) { + protected RTCStats(long timestamp, RTCStatsType type, String id, Map attributes) { this.timestamp = timestamp; this.type = type; this.id = id; - this.members = members; + this.attributes = attributes; } /** @@ -89,7 +89,7 @@ public String getId() { } /** - * Returns map of member names to values. Returns as an ordered map so that + * Returns map of attributes names to values. Returns as an ordered map so that * the stats object can be serialized with a consistent ordering. *

* Values will be one of the following objects: @@ -99,12 +99,12 @@ public String getId() { * - BigInteger (for 64-bit unsigned integers) * - Double * - String - * - The array form of any of the above (e.g., Integer[]) + * - The array form of the above (e.g., Integer[]) * * @return the stats map. */ - public Map getMembers() { - return members; + public Map getAttributes() { + return attributes; } @Override @@ -115,7 +115,7 @@ public String toString() { .append(", type: ").append(type) .append(", id: ").append(id); - for (Map.Entry entry : members.entrySet()) { + for (Map.Entry entry : attributes.entrySet()) { builder.append(", ").append(entry.getKey()).append(": "); appendValue(builder, entry.getValue()); } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsCollectorCallback.java b/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsCollectorCallback.java index 921c900b..4025a81b 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsCollectorCallback.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsCollectorCallback.java @@ -25,7 +25,7 @@ public interface RTCStatsCollectorCallback { /** - * All necessary statistics have been gathered and an stats report has been + * All necessary statistics have been gathered and a stats report has been * generated. * * @param report The stats report with updated statistics. diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsReport.java b/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsReport.java index 2054f327..86aeb031 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsReport.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/RTCStatsReport.java @@ -30,15 +30,32 @@ public class RTCStatsReport { private final Map stats; + private final long timestamp; - protected RTCStatsReport(Map stats) { + + protected RTCStatsReport(Map stats, long timestamp) { this.stats = stats; + this.timestamp = timestamp; } + /** + * Returns the map of RTCStats objects. + * + * @return a map where the key is a string identifier and the value is an RTCStats object. + */ public Map getStats() { return stats; } + /** + * Get the timestamp in microseconds. + * + * @return the timestamp in microseconds relative to the UNIX epoch. + */ + public long getTimestamp() { + return timestamp; + } + @Override public String toString() { return String.format("%s@%d [stats=%s]", From d5fa302d93dff09a3312bc35abbc84e9b1777a63 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 26 Mar 2025 15:54:30 +0100 Subject: [PATCH 14/28] fix: refactored AudioProcessingStats to match new API --- .../media/audio/AudioProcessingStats.h | 1 - webrtc-jni/src/main/cpp/src/api/RTCStats.cpp | 2 -- .../cpp/src/media/audio/AudioProcessing.cpp | 1 - .../src/media/audio/AudioProcessingStats.cpp | 1 - .../media/audio/AudioProcessingStats.java | 19 +++++++++---------- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingStats.h b/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingStats.h index a25313b3..6b277aa3 100644 --- a/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingStats.h +++ b/webrtc-jni/src/main/cpp/include/media/audio/AudioProcessingStats.h @@ -34,7 +34,6 @@ namespace jni explicit JavaAudioProcessingStatsClass(JNIEnv * env); jclass cls; - jfieldID voiceDetected; jfieldID echoReturnLoss; jfieldID echoReturnLossEnhancement; jfieldID divergentFilterFraction; diff --git a/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp b/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp index f2f53de9..8146f3c7 100644 --- a/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp +++ b/webrtc-jni/src/main/cpp/src/api/RTCStats.cpp @@ -109,8 +109,6 @@ namespace jni JavaLocalRef toJava(JNIEnv * env, const webrtc::Attribute & attribute) { - auto value = attribute.as_variant(); - if (attribute.holds_alternative()) { return Boolean::create(env, attribute.get()); } diff --git a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessing.cpp b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessing.cpp index c4803c30..9fc06095 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessing.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessing.cpp @@ -34,7 +34,6 @@ namespace jni JavaObject obj(env, javaType); JavaObject statsObj(env, obj.getObject(javaClass->stats)); - statsObj.setBoolean(javaStatsClass->voiceDetected, stats.voice_detected.value_or(false)); statsObj.setDouble(javaStatsClass->echoReturnLoss, stats.echo_return_loss.value_or(0)); statsObj.setDouble(javaStatsClass->echoReturnLossEnhancement, stats.echo_return_loss_enhancement.value_or(0)); statsObj.setDouble(javaStatsClass->divergentFilterFraction, stats.divergent_filter_fraction.value_or(0)); diff --git a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingStats.cpp b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingStats.cpp index 032f82f4..ca1d1d9b 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingStats.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/AudioProcessingStats.cpp @@ -29,7 +29,6 @@ namespace jni { cls = FindClass(env, PKG_AUDIO"AudioProcessingStats"); - voiceDetected = GetFieldID(env, cls, "voiceDetected", "Z"); echoReturnLoss = GetFieldID(env, cls, "echoReturnLoss", "D"); echoReturnLossEnhancement = GetFieldID(env, cls, "echoReturnLossEnhancement", "D"); divergentFilterFraction = GetFieldID(env, cls, "divergentFilterFraction", "D"); diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingStats.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingStats.java index c06cec57..9bbf474d 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingStats.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioProcessingStats.java @@ -16,17 +16,13 @@ package dev.onvoid.webrtc.media.audio; +/** + * This class holds various statistics related to audio processing. + * + * @author Alex Andres + */ public class AudioProcessingStats { - /** - * True if voice is detected in the last capture frame, after processing. - *

- * It is conservative in flagging audio as speech, with low likelihood of - * incorrectly flagging a frame as voice. Only reported if voice detection - * is enabled via {@code AudioProcessingConfig}. - */ - public boolean voiceDetected; - /** * AEC Statistic: ERL = 10log_10(P_far / P_echo) */ @@ -56,11 +52,14 @@ public class AudioProcessingStats { * cancellation perform poorly. The values are aggregated until the first * call to getStatistics() and afterwards aggregated and updated every * second. Note that if there are several clients pulling metrics from - * getStatistics() during a session the first call from any of them will + * getStatistics() during a session, the first call from any of them will * change to one-second aggregation window for all. */ public int delayMedianMs; + /** + * The standard deviation of the delay, in milliseconds. + */ public int delayStandardDeviationMs; /** From 96d6990c901b20a61ce322e668fd735c598fdcfb Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 26 Mar 2025 17:54:46 +0100 Subject: [PATCH 15/28] refactor: prefer and set clang as the default compiler on linux and windows --- .github/workflows/build.yml | 7 ++++ .github/workflows/release.yml | 32 ++++++++++++++----- webrtc-jni/pom.xml | 10 ++++-- webrtc-jni/src/main/cpp/CMakeLists.txt | 2 +- .../cpp/toolchain/x86_64-linux-clang.cmake | 6 ++++ 5 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 webrtc-jni/src/main/cpp/toolchain/x86_64-linux-clang.cmake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e4a4371..51a1a442 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,6 +83,7 @@ jobs: - name: linux_x86-64 runs-on: ubuntu-22.04 java: [17] + llvm: [21] runs-on: ${{ matrix.platform.runs-on }} steps: - name: Checkout code @@ -114,6 +115,12 @@ jobs: run: | sudo apt-get update sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils + + # More recent LLVM and Clang. + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{ matrix.llvm }} all + # Required for testing #pulseaudio --start sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf842fec..39863fff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,6 +18,9 @@ env: jobs: prepare-release: + strategy: + matrix: + llvm: [ 21 ] runs-on: ubuntu-22.04 steps: - name: Disk cleanup @@ -42,11 +45,17 @@ jobs: run: | sudo apt-get update sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils + + # More recent LLVM and Clang. + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{ matrix.llvm }} all + # Required for testing - pulseaudio --start - #sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries - #systemctl --user daemon-reload - #systemctl --user --now enable pipewire{,-pulse}.{socket,service} + #pulseaudio --start + sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries + systemctl --user daemon-reload + systemctl --user --now enable pipewire{,-pulse}.{socket,service} - name: Set up Java uses: actions/setup-java@v4 @@ -149,6 +158,7 @@ jobs: - name: linux_x86-64 runs-on: ubuntu-22.04 java: [17] + llvm: [21] runs-on: ${{ matrix.platform.runs-on }} steps: - name: Checkout code @@ -190,11 +200,17 @@ jobs: run: | sudo apt-get update sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils + + # More recent LLVM and Clang. + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{ matrix.llvm }} all + # Required for testing - pulseaudio --start - #sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries - #systemctl --user daemon-reload - #systemctl --user --now enable pipewire{,-pulse}.{socket,service} + #pulseaudio --start + sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries + systemctl --user daemon-reload + systemctl --user --now enable pipewire{,-pulse}.{socket,service} - name: Create Release # Create the release only once on Linux uses: actions/create-release@v1 diff --git a/webrtc-jni/pom.xml b/webrtc-jni/pom.xml index 76f4a01c..ec7b0d6c 100644 --- a/webrtc-jni/pom.xml +++ b/webrtc-jni/pom.xml @@ -152,7 +152,13 @@ - windows-clang-x86_64 + windows-clang + + + windows + amd64 + + -T ClangCL @@ -166,7 +172,7 @@ - toolchain/x86_64-linux-gnu.cmake + toolchain/x86_64-linux-clang.cmake diff --git a/webrtc-jni/src/main/cpp/CMakeLists.txt b/webrtc-jni/src/main/cpp/CMakeLists.txt index 0f950c4b..38de4dec 100644 --- a/webrtc-jni/src/main/cpp/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/CMakeLists.txt @@ -25,7 +25,7 @@ elseif(WIN32) set(SOURCE_TARGET windows) endif() -if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) +if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /showFilenames") endif() diff --git a/webrtc-jni/src/main/cpp/toolchain/x86_64-linux-clang.cmake b/webrtc-jni/src/main/cpp/toolchain/x86_64-linux-clang.cmake new file mode 100644 index 00000000..4874614a --- /dev/null +++ b/webrtc-jni/src/main/cpp/toolchain/x86_64-linux-clang.cmake @@ -0,0 +1,6 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +set(CMAKE_C_COMPILER /usr/bin/clang-21) +set(CMAKE_CXX_COMPILER /usr/bin/clang++-21) + +set(TARGET_CPU "x64") From 2e8f8aa72907556a8d2e7176cadb5fa9bbf92c67 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 26 Mar 2025 18:55:20 +0100 Subject: [PATCH 16/28] refactor: refined GitHub actions --- .github/actions/prepare-linux/action.yml | 46 ++++++++ .github/actions/prepare-macos/action.yml | 19 ++++ .github/actions/prepare-windows/action.yml | 40 +++++++ .github/workflows/build.yml | 87 ++------------- .github/workflows/release.yml | 123 ++------------------- 5 files changed, 126 insertions(+), 189 deletions(-) create mode 100644 .github/actions/prepare-linux/action.yml create mode 100644 .github/actions/prepare-macos/action.yml create mode 100644 .github/actions/prepare-windows/action.yml diff --git a/.github/actions/prepare-linux/action.yml b/.github/actions/prepare-linux/action.yml new file mode 100644 index 00000000..f4faa49a --- /dev/null +++ b/.github/actions/prepare-linux/action.yml @@ -0,0 +1,46 @@ +name: 'Prepare Linux Build' + +description: 'Frees up disk space and installs required packages for Linux builds.' + +runs: + using: "composite" + steps: + - name: Disk cleanup + run: | + set -x + df -h + #sudo du -h -d1 /usr/local + #sudo du -h -d1 /usr/local/share + #sudo du -h -d1 /usr/local/lib + #sudo du -h -d1 /usr/share + RMI=`docker images -q -a` + if [ -n "$RMI" ]; then + docker rmi $RMI + fi + # 4.6G + sudo rm -rf /usr/local/.ghcup + # 1.7G + sudo rm -rf /usr/share/swift + # 1.4G + sudo rm -rf /usr/share/dotnet + # 13G + sudo rm -rf /usr/local/lib/android + df -h + shell: bash + + - name: Install required packages + run: | + sudo apt-get update + sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils + + # More recent LLVM and Clang. + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{ matrix.llvm }} all + + # Required for testing + #pulseaudio --start + sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries + systemctl --user daemon-reload + systemctl --user --now enable pipewire{,-pulse}.{socket,service} + shell: bash diff --git a/.github/actions/prepare-macos/action.yml b/.github/actions/prepare-macos/action.yml new file mode 100644 index 00000000..11db8c49 --- /dev/null +++ b/.github/actions/prepare-macos/action.yml @@ -0,0 +1,19 @@ +name: 'Prepare macOS Build' + +description: 'Installs required packages for macOS builds.' + +runs: + using: "composite" + steps: + - name: Install required packages + run: | + brew install ninja + # Required for macos-13 + pip install setuptools + # Required for macos-14 + brew install python-setuptools + shell: bash + + - name: Select Xcode version + run: sudo xcode-select -s /Applications/Xcode_15.0.1.app/Contents/Developer + shell: bash diff --git a/.github/actions/prepare-windows/action.yml b/.github/actions/prepare-windows/action.yml new file mode 100644 index 00000000..ff9b023a --- /dev/null +++ b/.github/actions/prepare-windows/action.yml @@ -0,0 +1,40 @@ +name: 'Prepare Windows Build' + +description: 'Frees up disk space and installs required packages for Windows builds.' + +runs: + using: "composite" + steps: + - name: Set up Python 3.11 + if: false + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Disk cleanup + if: false + run: | + Get-PSDrive + # Docker Images + docker rmi $(docker images -q -a) + # Android SDK + if ($Env:ANDROID_HOME) { + Remove-Item -Recurse -Force $Env:ANDROID_HOME -ErrorAction Ignore + } + if ($Env:ANDROID_NDK_HOME) { + Remove-Item -Recurse -Force $Env:ANDROID_NDK_HOME -ErrorAction Ignore + } + # JVM + if ($Env:JAVA_HOME_11_X64) { + Remove-Item -Recurse -Force $Env:JAVA_HOME_11_X64 -ErrorAction Ignore + } + if ($Env:JAVA_HOME_8_X64) { + Remove-Item -Recurse -Force $Env:JAVA_HOME_8_X64 -ErrorAction Ignore + } + Get-PSDrive + shell: powershell + + - name: Install required packages + run: | + choco install ninja + shell: powershell diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51a1a442..5dc0a5d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,37 +34,9 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Python 3.11 - if: false - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Disk cleanup - if: false - run: | - Get-PSDrive - # Docker Images - docker rmi $(docker images -q -a) - # Android SDK - if ($Env:ANDROID_HOME) { - Remove-Item -Recurse -Force $Env:ANDROID_HOME -ErrorAction Ignore - } - if ($Env:ANDROID_NDK_HOME) { - Remove-Item -Recurse -Force $Env:ANDROID_NDK_HOME -ErrorAction Ignore - } - # JVM - if ($Env:JAVA_HOME_11_X64) { - Remove-Item -Recurse -Force $Env:JAVA_HOME_11_X64 -ErrorAction Ignore - } - if ($Env:JAVA_HOME_8_X64) { - Remove-Item -Recurse -Force $Env:JAVA_HOME_8_X64 -ErrorAction Ignore - } - Get-PSDrive - - - name: Install required packages - run: | - choco install ninja + - id: prepare + name: Prepare build + uses: ./.github/actions/prepare-windows - id: maven-build name: Maven build @@ -89,43 +61,9 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Disk cleanup - run: | - set -x - df -h - #sudo du -h -d1 /usr/local - #sudo du -h -d1 /usr/local/share - #sudo du -h -d1 /usr/local/lib - #sudo du -h -d1 /usr/share - RMI=`docker images -q -a` - if [ -n "$RMI" ]; then - docker rmi $RMI - fi - # 4.6G - sudo rm -rf /usr/local/.ghcup - # 1.7G - sudo rm -rf /usr/share/swift - # 1.4G - sudo rm -rf /usr/share/dotnet - # 13G - sudo rm -rf /usr/local/lib/android - df -h - - - name: Install required packages - run: | - sudo apt-get update - sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils - - # More recent LLVM and Clang. - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.llvm }} all - - # Required for testing - #pulseaudio --start - sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries - systemctl --user daemon-reload - systemctl --user --now enable pipewire{,-pulse}.{socket,service} + - id: prepare + name: Prepare build + uses: ./.github/actions/prepare-linux - id: maven-build name: Maven build @@ -151,16 +89,9 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install required packages - run: | - brew install ninja - # Required for macos-13 - pip install setuptools - # Required for macos-14 - brew install python-setuptools - - - name: Select Xcode version - run: sudo xcode-select -s /Applications/Xcode_15.0.1.app/Contents/Developer + - id: prepare-build + name: Prepare release build + uses: ./.github/actions/prepare-macos - id: maven-build name: Maven build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 39863fff..bd656a86 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,39 +23,9 @@ jobs: llvm: [ 21 ] runs-on: ubuntu-22.04 steps: - - name: Disk cleanup - run: | - set -x - df -h - #sudo du -h -d1 /usr/local - #sudo du -h -d1 /usr/local/share - #sudo du -h -d1 /usr/local/lib - #sudo du -h -d1 /usr/share - # 4.6G - sudo rm -rf /usr/local/.ghcup - # 1.7G - sudo rm -rf /usr/share/swift - # 1.4G - sudo rm -rf /usr/share/dotnet - # 13G - sudo rm -rf /usr/local/lib/android - df -h - - - name: Install required packages - run: | - sudo apt-get update - sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils - - # More recent LLVM and Clang. - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.llvm }} all - - # Required for testing - #pulseaudio --start - sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries - systemctl --user daemon-reload - systemctl --user --now enable pipewire{,-pulse}.{socket,service} + - id: prepare + name: Prepare release build + uses: ./.github/actions/prepare-linux - name: Set up Java uses: actions/setup-java@v4 @@ -106,37 +76,9 @@ jobs: echo "tag=$tag" >> "$GITHUB_OUTPUT" git checkout $tag - - name: Set up Python 3.11 - if: false - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Disk cleanup - if: false - run: | - Get-PSDrive - # Docker Images - docker rmi $(docker images -q -a) - # Android SDK - if ($Env:ANDROID_HOME) { - Remove-Item -Recurse -Force $Env:ANDROID_HOME -ErrorAction Ignore - } - if ($Env:ANDROID_NDK_HOME) { - Remove-Item -Recurse -Force $Env:ANDROID_NDK_HOME -ErrorAction Ignore - } - # JVM - if ($Env:JAVA_HOME_11_X64) { - Remove-Item -Recurse -Force $Env:JAVA_HOME_11_X64 -ErrorAction Ignore - } - if ($Env:JAVA_HOME_8_X64) { - Remove-Item -Recurse -Force $Env:JAVA_HOME_8_X64 -ErrorAction Ignore - } - Get-PSDrive - - - name: Install required packages - run: | - choco install ninja + - id: prepare + name: Prepare build + uses: ./.github/actions/prepare-windows - id: maven-build name: Maven build @@ -174,43 +116,9 @@ jobs: echo "tag=$tag" >> "$GITHUB_OUTPUT" git checkout $tag - - name: Disk cleanup - run: | - set -x - df -h - #sudo du -h -d1 /usr/local - #sudo du -h -d1 /usr/local/share - #sudo du -h -d1 /usr/local/lib - #sudo du -h -d1 /usr/share - RMI=`docker images -q -a` - if [ -n "$RMI" ]; then - docker rmi $RMI - fi - # 4.6G - sudo rm -rf /usr/local/.ghcup - # 1.7G - sudo rm -rf /usr/share/swift - # 1.4G - sudo rm -rf /usr/share/dotnet - # 13G - sudo rm -rf /usr/local/lib/android - df -h - - - name: Install required packages - run: | - sudo apt-get update - sudo apt-get install -y pulseaudio libpulse-dev libasound2-dev libdbus-1-dev libudev-dev libv4l-dev libx11-dev libxcomposite-dev libxrandr-dev libxfixes-dev binutils cmake git locales lsb-release ninja-build pkg-config python3 python3-setuptools rsync unzip wget xz-utils - - # More recent LLVM and Clang. - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.llvm }} all - - # Required for testing - #pulseaudio --start - sudo apt-get install -y pipewire pipewire-pulse gstreamer1.0-pipewire libspa-0.2-bluetooth libspa-0.2-jack pipewire-audio-client-libraries - systemctl --user daemon-reload - systemctl --user --now enable pipewire{,-pulse}.{socket,service} + - id: prepare-build + name: Prepare release build + uses: ./.github/actions/prepare-linux - name: Create Release # Create the release only once on Linux uses: actions/create-release@v1 @@ -259,16 +167,9 @@ jobs: echo "tag=$tag" >> "$GITHUB_OUTPUT" git checkout $tag - - name: Install required packages - run: | - brew install ninja - # Required for macos-13 - pip install setuptools - # Required for macos-14 - brew install python-setuptools - - - name: Select Xcode version - run: sudo xcode-select -s /Applications/Xcode_15.0.1.app/Contents/Developer + - id: prepare-build + name: Prepare release build + uses: ./.github/actions/prepare-macos - id: maven-build name: Maven build From df9b49bee2986db3721b792250e3b9850f3008a7 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 26 Mar 2025 18:58:02 +0100 Subject: [PATCH 17/28] fix: GitHub actions step names --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5dc0a5d1..c812d903 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -90,7 +90,7 @@ jobs: uses: actions/checkout@v4 - id: prepare-build - name: Prepare release build + name: Prepare build uses: ./.github/actions/prepare-macos - id: maven-build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd656a86..32ffa3bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,7 +77,7 @@ jobs: git checkout $tag - id: prepare - name: Prepare build + name: Prepare release build uses: ./.github/actions/prepare-windows - id: maven-build From 4b8b4df9a9435aef083bdc1b3530b2f8fe28672e Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Thu, 27 Mar 2025 15:16:53 +0100 Subject: [PATCH 18/28] fix: macOS deprecation warnings --- .../media/audio/macos/CoreAudioDeviceManager.cpp | 14 +++++++++----- .../media/video/macos/AVFVideoDeviceManager.cpp | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp b/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp index ef34d535..607fd259 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp @@ -21,6 +21,10 @@ #include +#if !defined(MAC_OS_VERSION_12_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0 + #define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster +#endif + namespace jni { namespace avdev @@ -80,7 +84,7 @@ namespace jni AudioObjectPropertyAddress pa; pa.mSelector = kAudioHardwarePropertyDevices; pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; + pa.mElement = kAudioObjectPropertyElementMain; UInt32 dataSize; @@ -122,7 +126,7 @@ namespace jni AudioObjectPropertyAddress pa; pa.mSelector = kAudioHardwarePropertyDevices; pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; + pa.mElement = kAudioObjectPropertyElementMain; UInt32 dataSize; @@ -281,7 +285,7 @@ namespace jni AudioObjectPropertyAddress pa; pa.mSelector = kAudioObjectPropertyName; pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; + pa.mElement = kAudioObjectPropertyElementMain; OSStatus status = AudioObjectGetPropertyData(deviceID, &pa, 0, nullptr, &dataSize, &devNameRef); ThrowIfFailed(status, "CoreAudio: Get device name failed"); @@ -324,7 +328,7 @@ namespace jni int CoreAudioDeviceManager::getChannelCount(const AudioDeviceID & deviceID, const AudioObjectPropertyScope & scope) { AudioObjectPropertyAddress pa; pa.mSelector = kAudioDevicePropertyStreamConfiguration; - pa.mElement = kAudioObjectPropertyElementMaster; + pa.mElement = kAudioObjectPropertyElementMain; pa.mScope = scope; int channels = 0; @@ -348,7 +352,7 @@ namespace jni AudioDeviceID CoreAudioDeviceManager::getDefaultDeviceID(const AudioObjectPropertyScope & scope) { AudioObjectPropertyAddress pa; pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; + pa.mElement = kAudioObjectPropertyElementMain; switch (scope) { case kAudioObjectPropertyScopeInput: diff --git a/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp b/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp index db208c3e..69a9656d 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp @@ -59,7 +59,21 @@ namespace jni std::set AVFVideoDeviceManager::getVideoCaptureDevices() { if (captureDevices.empty()) { - NSArray * devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; + AVCaptureDeviceDiscoverySession * discoverySession = [AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:@[ + AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeExternal, + AVCaptureDeviceTypeDeskViewCamera, + #if (MAC_OS_X_VERSION_MIN_REQUIRED >= 140000) + AVCaptureDeviceTypeExternal + #else + AVCaptureDeviceTypeExternalUnknown + #endif + ] + mediaType: AVMediaTypeVideo + position: AVCaptureDevicePositionUnspecified]; + + NSArray * devices = discoverySession.devices; for (AVCaptureDevice * device in devices) { insertDevice(device, false); From 2fa44ff340145e7ffee6f130ee8efb9d77d2a1a9 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Thu, 27 Mar 2025 15:35:04 +0100 Subject: [PATCH 19/28] fix: macOS deprecation warnings --- .../src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp b/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp index 69a9656d..82621fd0 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/macos/AVFVideoDeviceManager.cpp @@ -62,7 +62,6 @@ namespace jni AVCaptureDeviceDiscoverySession * discoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[ AVCaptureDeviceTypeBuiltInWideAngleCamera, - AVCaptureDeviceTypeExternal, AVCaptureDeviceTypeDeskViewCamera, #if (MAC_OS_X_VERSION_MIN_REQUIRED >= 140000) AVCaptureDeviceTypeExternal From 7233fec097d5bd52f3ab987257a0190c7ee2a930 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Thu, 3 Apr 2025 19:42:23 +0200 Subject: [PATCH 20/28] feat: macOS screen inhibition --- .gitignore | 2 +- webrtc-jni/src/main/cpp/CMakeLists.txt | 2 +- .../desktop/macos/MacOSPowerManagement.h | 43 ++++++++++++++++++ webrtc-jni/src/main/cpp/src/WebRTCContext.cpp | 3 +- .../desktop/macos/MacOSPowerManagement.cpp | 45 +++++++++++++++++++ 5 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 webrtc-jni/src/main/cpp/include/media/video/desktop/macos/MacOSPowerManagement.h create mode 100644 webrtc-jni/src/main/cpp/src/media/video/desktop/macos/MacOSPowerManagement.cpp diff --git a/.gitignore b/.gitignore index a2306aad..624afc12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Eclipse Core +# Eclipse Core **/.classpath **/.project **/.settings/ diff --git a/webrtc-jni/src/main/cpp/CMakeLists.txt b/webrtc-jni/src/main/cpp/CMakeLists.txt index 38de4dec..7b2d0a7b 100644 --- a/webrtc-jni/src/main/cpp/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/CMakeLists.txt @@ -79,7 +79,7 @@ target_link_libraries(${PROJECT_NAME} webrtc) if(APPLE) set_source_files_properties(${SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c++") - target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreMedia" "-framework CoreAudio") + target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreMedia" "-framework CoreAudio" "-framework IOKit") elseif(LINUX) target_link_libraries(${PROJECT_NAME} -static-libgcc -static-libstdc++ pulse udev) elseif(WIN32) diff --git a/webrtc-jni/src/main/cpp/include/media/video/desktop/macos/MacOSPowerManagement.h b/webrtc-jni/src/main/cpp/include/media/video/desktop/macos/MacOSPowerManagement.h new file mode 100644 index 00000000..87b69ea2 --- /dev/null +++ b/webrtc-jni/src/main/cpp/include/media/video/desktop/macos/MacOSPowerManagement.h @@ -0,0 +1,43 @@ +/* + * Copyright 2019 Alex Andres + * + * 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 JNI_WEBRTC_MEDIA_DESKTOP_MACOS_POWER_MANAGEMENT_H_ +#define JNI_WEBRTC_MEDIA_DESKTOP_MACOS_POWER_MANAGEMENT_H_ + +#include "media/video/desktop/PowerManagement.h" + +#include + +namespace jni +{ + namespace avdev + { + class MacOSPowerManagement : public PowerManagement + { + public: + MacOSPowerManagement(); + ~MacOSPowerManagement() = default; + + void enableUserActivity(); + void disableUserActivity(); + + private: + IOPMAssertionID powerAssertion; + }; + } +} + +#endif \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/WebRTCContext.cpp b/webrtc-jni/src/main/cpp/src/WebRTCContext.cpp index fd3ae445..bd80f0f7 100644 --- a/webrtc-jni/src/main/cpp/src/WebRTCContext.cpp +++ b/webrtc-jni/src/main/cpp/src/WebRTCContext.cpp @@ -43,6 +43,7 @@ #ifdef __APPLE__ #include "media/audio/macos/CoreAudioDeviceManager.h" #include "media/video/macos/AVFVideoDeviceManager.h" +#include "media/video/desktop/macos/MacOSPowerManagement.h" #endif #include @@ -193,7 +194,7 @@ namespace jni powerManagement = std::make_unique(); #endif #ifdef __APPLE__ - //powerManagement = std::make_unique(); + powerManagement = std::make_unique(); #endif } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/macos/MacOSPowerManagement.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/macos/MacOSPowerManagement.cpp new file mode 100644 index 00000000..426fb934 --- /dev/null +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/macos/MacOSPowerManagement.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "media/video/desktop/macos/MacOSPowerManagement.h" + +namespace jni +{ + namespace avdev + { + MacOSPowerManagement::MacOSPowerManagement() : + powerAssertion(kIOPMNullAssertionID) + { + } + + void MacOSPowerManagement::enableUserActivity() + { + CFStringRef name = CFSTR("WebRTC-Java processing"); + + if (IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, name, &powerAssertion) != kIOReturnSuccess) { + powerAssertion = kIOPMNullAssertionID; + } + } + + void MacOSPowerManagement::disableUserActivity() + { + if (powerAssertion != kIOPMNullAssertionID) { + IOPMAssertionRelease(powerAssertion); + powerAssertion = kIOPMNullAssertionID; + } + } + } +} \ No newline at end of file From 9875faf1ab09ebc24623aca271fb239d7160d2e9 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 4 Apr 2025 01:12:37 +0200 Subject: [PATCH 21/28] chore: migrate ossrh to maven central deployment --- .github/actions/build/action.yml | 2 +- .github/actions/release/action.yml | 2 +- .github/workflows/release.yml | 2 +- pom.xml | 29 +++++++++++++++++------------ webrtc-jni/pom.xml | 7 ------- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index abaeb602..31f1decf 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -42,7 +42,7 @@ runs: with: java-version: ${{ inputs.java-version }} distribution: 'temurin' - server-id: ossrh + server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_TOKEN diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml index 399ecb5f..aa5a83fc 100644 --- a/.github/actions/release/action.yml +++ b/.github/actions/release/action.yml @@ -50,7 +50,7 @@ runs: with: java-version: ${{ inputs.java-version }} distribution: 'temurin' - server-id: ossrh + server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_TOKEN gpg-private-key: ${{ inputs.maven-gpg-private-key }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 32ffa3bb..834393f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: with: java-version: '21' distribution: 'temurin' - server-id: ossrh + server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_TOKEN gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} diff --git a/pom.xml b/pom.xml index 03ef0e9f..1a70d805 100644 --- a/pom.xml +++ b/pom.xml @@ -43,17 +43,6 @@ HEAD - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ${maven.build.timestamp} UTF-8 @@ -111,10 +100,22 @@ true + + org.sonatype.central + central-publishing-maven-plugin + 0.7.0 + true + + central + + webrtc-java-jni + + + org.apache.maven.plugins maven-deploy-plugin - 3.0.0-M1 + 3.1.4 org.apache.maven.plugins @@ -238,6 +239,10 @@ org.apache.maven.plugins maven-compiler-plugin + + org.sonatype.central + central-publishing-maven-plugin + diff --git a/webrtc-jni/pom.xml b/webrtc-jni/pom.xml index ec7b0d6c..88370114 100644 --- a/webrtc-jni/pom.xml +++ b/webrtc-jni/pom.xml @@ -24,13 +24,6 @@ webrtc-java-${project.version} - - org.apache.maven.plugins - maven-deploy-plugin - - true - - org.apache.maven.plugins maven-jar-plugin From 25afe528ff60834e5900e2d30b2b673736984328 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 4 Apr 2025 15:25:49 +0200 Subject: [PATCH 22/28] fix: minor desktop capture fixes --- .../cpp/include/media/video/desktop/DesktopCaptureCallback.h | 2 +- .../src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCaptureCallback.h b/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCaptureCallback.h index 911f2fad..b6863349 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCaptureCallback.h +++ b/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCaptureCallback.h @@ -32,7 +32,7 @@ namespace jni { public: DesktopCaptureCallback(JNIEnv * env, const JavaGlobalRef & callback); - ~DesktopCaptureCallback() = default; + ~DesktopCaptureCallback() override = default; // DesktopCapturer::Callback implementation. void OnCaptureResult(webrtc::DesktopCapturer::Result result, std::unique_ptr frame) override; diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp index c82c9e2d..850881cf 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp @@ -39,9 +39,8 @@ namespace jni options)); } else { - capturer.reset(new webrtc::DesktopAndCursorComposer( - webrtc::DesktopCapturer::CreateWindowCapturer(options), - options)); + capturer = std::make_unique( + webrtc::DesktopCapturer::CreateWindowCapturer(options), options); } } From ca09a433e20517d0a782c3291a6e9f036404ccee Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Mon, 7 Apr 2025 14:51:52 +0200 Subject: [PATCH 23/28] fix: crash with desktop capture with pipewire enabled and clang build --- webrtc-jni/pom.xml | 2 +- webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webrtc-jni/pom.xml b/webrtc-jni/pom.xml index 88370114..ea99ed9e 100644 --- a/webrtc-jni/pom.xml +++ b/webrtc-jni/pom.xml @@ -165,7 +165,7 @@ - toolchain/x86_64-linux-clang.cmake + toolchain/x86_64-linux-gnu.cmake diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index d92c932b..e55d62aa 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -242,7 +242,7 @@ if (PATCHES) endif() message(STATUS "WebRTC: generate") -set(COMPILE_ARGS "target_cpu=\"${TARGET_CPU}\" is_clang=${WEBRTC_CLANG} is_debug=false is_component_build=false treat_warnings_as_errors=false rtc_enable_protobuf=false rtc_build_examples=false rtc_include_tests=false use_rtti=true rtc_use_h264=true use_custom_libcxx=false symbol_level=0") +set(COMPILE_ARGS "target_cpu=\"${TARGET_CPU}\" is_clang=${WEBRTC_CLANG} is_debug=false is_component_build=false treat_warnings_as_errors=false rtc_use_pipewire=false rtc_enable_protobuf=false rtc_build_examples=false rtc_include_tests=false use_rtti=true rtc_use_h264=true use_custom_libcxx=false symbol_level=0") execute_command( COMMAND gn gen ${WEBRTC_BUILD} --args=${COMPILE_ARGS} WORKING_DIRECTORY "${WEBRTC_SRC}" From 255c2a3bed55edd8f4c1b59c72e58230842bc949 Mon Sep 17 00:00:00 2001 From: Alex Andres <58339654+devopvoid@users.noreply.github.com> Date: Tue, 8 Apr 2025 12:11:21 +0200 Subject: [PATCH 24/28] Update CMakeLists.txt Disable rtc_build_tools and rtc_use_perfetto --- webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index e55d62aa..06d95c01 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -242,7 +242,7 @@ if (PATCHES) endif() message(STATUS "WebRTC: generate") -set(COMPILE_ARGS "target_cpu=\"${TARGET_CPU}\" is_clang=${WEBRTC_CLANG} is_debug=false is_component_build=false treat_warnings_as_errors=false rtc_use_pipewire=false rtc_enable_protobuf=false rtc_build_examples=false rtc_include_tests=false use_rtti=true rtc_use_h264=true use_custom_libcxx=false symbol_level=0") +set(COMPILE_ARGS "target_cpu=\"${TARGET_CPU}\" is_clang=${WEBRTC_CLANG} is_debug=false is_component_build=false treat_warnings_as_errors=false rtc_build_tools=false rtc_use_perfetto=false rtc_use_pipewire=false rtc_enable_protobuf=false rtc_build_examples=false rtc_include_tests=false use_rtti=true rtc_use_h264=true use_custom_libcxx=false symbol_level=0") execute_command( COMMAND gn gen ${WEBRTC_BUILD} --args=${COMPILE_ARGS} WORKING_DIRECTORY "${WEBRTC_SRC}" From c23271c117799fc86c92875f320e66c13bb8fe86 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Mon, 14 Apr 2025 10:46:17 +0200 Subject: [PATCH 25/28] refactor: DesktopCapturer initialization --- webrtc-jni/pom.xml | 6 - .../main/cpp/include/JNI_DesktopCapturer.h | 8 + .../media/video/desktop/DesktopCapturer.h | 31 +-- .../src/main/cpp/src/JNI_DesktopCapturer.cpp | 9 + .../src/main/cpp/src/JNI_RefCountedObject.cpp | 2 +- .../src/main/cpp/src/JNI_ScreenCapturer.cpp | 18 +- .../src/main/cpp/src/JNI_WindowCapturer.cpp | 18 +- .../src/main/cpp/src/api/VideoFrame.cpp | 2 +- .../media/video/desktop/DesktopCapturer.cpp | 187 +++++++++--------- .../src/media/video/desktop/DesktopSource.cpp | 4 +- .../video/desktop/DesktopCaptureCallback.java | 12 ++ .../media/video/desktop/DesktopCapturer.java | 55 +++++- .../media/video/desktop/DesktopFrame.java | 34 ++-- .../media/video/desktop/DesktopSource.java | 15 +- .../video/desktop/DesktopSourceType.java | 8 + .../media/video/desktop/ScreenCapturer.java | 11 ++ .../media/video/desktop/WindowCapturer.java | 12 ++ .../audio/VoiceActivityDetectorTest.java | 2 +- 18 files changed, 292 insertions(+), 142 deletions(-) diff --git a/webrtc-jni/pom.xml b/webrtc-jni/pom.xml index ea99ed9e..9918ff96 100644 --- a/webrtc-jni/pom.xml +++ b/webrtc-jni/pom.xml @@ -146,12 +146,6 @@ windows-clang - - - windows - amd64 - - -T ClangCL diff --git a/webrtc-jni/src/main/cpp/include/JNI_DesktopCapturer.h b/webrtc-jni/src/main/cpp/include/JNI_DesktopCapturer.h index eae2112a..a9e46aeb 100644 --- a/webrtc-jni/src/main/cpp/include/JNI_DesktopCapturer.h +++ b/webrtc-jni/src/main/cpp/include/JNI_DesktopCapturer.h @@ -39,6 +39,14 @@ extern "C" { JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapturer_setFocusSelectedSource (JNIEnv*, jobject, jboolean); + /* + * Class: dev_onvoid_webrtc_media_video_desktop_DesktopCapturer + * Method: setMaxFrameRate + * Signature: (I)V + */ + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapturer_setMaxFrameRate + (JNIEnv*, jobject, jint); + /* * Class: dev_onvoid_webrtc_media_video_desktop_DesktopCapturer * Method: start diff --git a/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCapturer.h b/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCapturer.h index 927afdc8..5f5dc000 100644 --- a/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCapturer.h +++ b/webrtc-jni/src/main/cpp/include/media/video/desktop/DesktopCapturer.h @@ -14,36 +14,41 @@ * limitations under the License. */ -#ifndef JNI_WEBRTC_MEDIA_DESKTOP_CAPTURER_H_ -#define JNI_WEBRTC_MEDIA_DESKTOP_CAPTURER_H_ +#ifndef JNI_WEBRTC_MEDIA_VIDEO_DESKTOP_CAPTURER_H_ +#define JNI_WEBRTC_MEDIA_VIDEO_DESKTOP_CAPTURER_H_ #if defined(WEBRTC_WIN) #include "platform/windows/ComInitializer.h" #endif #include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/desktop_and_cursor_composer.h" #include #include namespace jni { - class DesktopCapturer : public webrtc::DesktopCapturer + class DesktopCapturer { public: - explicit DesktopCapturer(bool screenCapturer); - ~DesktopCapturer() override; + DesktopCapturer(webrtc::DesktopCapturer * capturer); + ~DesktopCapturer(); + + DesktopCapturer(const DesktopCapturer &) = delete; + DesktopCapturer & operator=(const DesktopCapturer &) = delete; // webrtc::DesktopCapturer implementations. - void Start(Callback * callback) override; - void SetSharedMemoryFactory(std::unique_ptr factory) override; - void CaptureFrame() override; - void SetExcludedWindow(webrtc::WindowId window) override; - bool GetSourceList(SourceList * sources) override; - bool SelectSource(SourceId id) override; - bool FocusOnSelectedSource() override; + void Start(webrtc::DesktopCapturer::Callback * callback); + void SetSharedMemoryFactory(std::unique_ptr factory); + void SetMaxFrameRate(uint32_t max_frame_rate); + void CaptureFrame(); + void SetExcludedWindow(webrtc::WindowId window); + bool GetSourceList(webrtc::DesktopCapturer::SourceList * sources); + bool SelectSource(webrtc::DesktopCapturer::SourceId id); + bool FocusOnSelectedSource(); void setFocusSelectedSource(bool focus); - bool IsOccluded(const webrtc::DesktopVector & pos) override; + bool IsOccluded(const webrtc::DesktopVector & pos); protected: std::unique_ptr capturer; diff --git a/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp b/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp index 94e3f2c7..4bc3f999 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp @@ -85,6 +85,15 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapture capturer->setFocusSelectedSource(focus); } +JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapturer_setMaxFrameRate +(JNIEnv * env, jobject caller, jint maxFrameRate) +{ + jni::DesktopCapturer * capturer = GetHandle(env, caller); + CHECK_HANDLE(capturer); + + capturer->setMaxFrameRate(maxFrameRate); +} + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapturer_start (JNIEnv * env, jobject caller, jobject jcallback) { diff --git a/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp b/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp index 74791248..3623032c 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_RefCountedObject.cpp @@ -34,7 +34,7 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_internal_RefCountedObject_release webrtc::RefCountInterface * ref = GetHandle(env, caller); CHECK_HANDLE(ref); - const auto status = ref->Release(); + const webrtc::RefCountReleaseStatus status = ref->Release(); if (status == webrtc::RefCountReleaseStatus::kDroppedLastRef) { SetHandle(env, caller, nullptr); diff --git a/webrtc-jni/src/main/cpp/src/JNI_ScreenCapturer.cpp b/webrtc-jni/src/main/cpp/src/JNI_ScreenCapturer.cpp index 16b2a62a..185cfc10 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_ScreenCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_ScreenCapturer.cpp @@ -18,8 +18,24 @@ #include "JavaUtils.h" #include "media/video/desktop/DesktopCapturer.h" +#include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/desktop_capture_options.h" +#include "modules/desktop_capture/desktop_and_cursor_composer.h" + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_ScreenCapturer_initialize (JNIEnv * env, jobject caller) { - SetHandle(env, caller, new jni::DesktopCapturer(true)); + auto options = webrtc::DesktopCaptureOptions::CreateDefault(); + // Enable desktop effects. + options.set_disable_effects(false); + +#if defined(WEBRTC_WIN) + options.set_allow_directx_capturer(true); +#endif + + auto capturer = new webrtc::DesktopAndCursorComposer( + webrtc::DesktopCapturer::CreateScreenCapturer(options), + options); + + SetHandle(env, caller, new jni::DesktopCapturer(capturer)); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/JNI_WindowCapturer.cpp b/webrtc-jni/src/main/cpp/src/JNI_WindowCapturer.cpp index 157b6893..b5be4004 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_WindowCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_WindowCapturer.cpp @@ -18,8 +18,24 @@ #include "JavaUtils.h" #include "media/video/desktop/DesktopCapturer.h" +#include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/desktop_capture_options.h" +#include "modules/desktop_capture/desktop_and_cursor_composer.h" + JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_WindowCapturer_initialize (JNIEnv * env, jobject caller) { - SetHandle(env, caller, new jni::DesktopCapturer(false)); + auto options = webrtc::DesktopCaptureOptions::CreateDefault(); + // Enable desktop effects. + options.set_disable_effects(false); + +#if defined(WEBRTC_WIN) + options.set_allow_directx_capturer(true); +#endif + + auto capturer = new webrtc::DesktopAndCursorComposer( + webrtc::DesktopCapturer::CreateWindowCapturer(options), + options); + + SetHandle(env, caller, new jni::DesktopCapturer(capturer)); } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/api/VideoFrame.cpp b/webrtc-jni/src/main/cpp/src/api/VideoFrame.cpp index cd826102..457fd4a8 100644 --- a/webrtc-jni/src/main/cpp/src/api/VideoFrame.cpp +++ b/webrtc-jni/src/main/cpp/src/api/VideoFrame.cpp @@ -27,7 +27,7 @@ namespace jni { webrtc::VideoFrame toNative(JNIEnv * env, const JavaRef & javaFrame) { - const auto javaClass = JavaClasses::get(env); + const std::shared_ptr javaClass = JavaClasses::get(env); JavaObject obj(env, javaFrame); int rotation = obj.getInt(javaClass->rotation); diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp index 850881cf..57158a96 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp @@ -1,100 +1,89 @@ -/* - * Copyright 2019 Alex Andres - * - * 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. - */ - -#include "media/video/desktop/DesktopCapturer.h" - -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/desktop_and_cursor_composer.h" - -namespace jni -{ - DesktopCapturer::DesktopCapturer(bool screenCapturer) : - focusSelectedSource(false) - { - auto options = webrtc::DesktopCaptureOptions::CreateDefault(); - // Enable desktop effects. - options.set_disable_effects(false); - -#if defined(WEBRTC_WIN) - options.set_allow_directx_capturer(true); -#endif - - if (screenCapturer) { - capturer.reset(new webrtc::DesktopAndCursorComposer( - webrtc::DesktopCapturer::CreateScreenCapturer(options), - options)); - } - else { - capturer = std::make_unique( - webrtc::DesktopCapturer::CreateWindowCapturer(options), options); - } - } - - DesktopCapturer::~DesktopCapturer() - { - capturer.reset(); - } - - void DesktopCapturer::Start(Callback * callback) - { - capturer->Start(callback); - - if (focusSelectedSource) { - capturer->FocusOnSelectedSource(); - } - } - - void DesktopCapturer::SetSharedMemoryFactory(std::unique_ptr factory) - { - capturer->SetSharedMemoryFactory(std::move(factory)); - } - - void DesktopCapturer::CaptureFrame() - { - capturer->CaptureFrame(); - } - - void DesktopCapturer::SetExcludedWindow(webrtc::WindowId window) - { - capturer->SetExcludedWindow(window); - } - - bool DesktopCapturer::GetSourceList(SourceList * sources) - { - return capturer->GetSourceList(sources); - } - - bool DesktopCapturer::SelectSource(SourceId id) - { - return capturer->SelectSource(id); - } - - bool DesktopCapturer::FocusOnSelectedSource() - { - return capturer->FocusOnSelectedSource(); - } - - void DesktopCapturer::setFocusSelectedSource(bool focus) - { - this->focusSelectedSource = focus; - } - - bool DesktopCapturer::IsOccluded(const webrtc::DesktopVector & pos) - { - return capturer->IsOccluded(pos); - } +/* + * Copyright 2019 Alex Andres + * + * 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. + */ + +#include "media/video/desktop/DesktopCapturer.h" + +#include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/desktop_capture_options.h" +#include "modules/desktop_capture/desktop_and_cursor_composer.h" + +namespace jni +{ + DesktopCapturer::DesktopCapturer(webrtc::DesktopCapturer * capturer) : + focusSelectedSource(false) + { + this->capturer.reset(capturer); + } + + DesktopCapturer::~DesktopCapturer() + { + capturer.reset(); + } + + void DesktopCapturer::Start(webrtc::DesktopCapturer::Callback * callback) + { + capturer->Start(callback); + + if (focusSelectedSource) { + capturer->FocusOnSelectedSource(); + } + } + + void DesktopCapturer::SetSharedMemoryFactory(std::unique_ptr factory) + { + capturer->SetSharedMemoryFactory(std::move(factory)); + } + + void DesktopCapturer::SetMaxFrameRate(uint32_t max_frame_rate) + { + capturer->SetMaxFrameRate(max_frame_rate); + } + + void DesktopCapturer::CaptureFrame() + { + capturer->CaptureFrame(); + } + + void DesktopCapturer::SetExcludedWindow(webrtc::WindowId window) + { + capturer->SetExcludedWindow(window); + } + + bool DesktopCapturer::GetSourceList(webrtc::DesktopCapturer::SourceList * sources) + { + return capturer->GetSourceList(sources); + } + + bool DesktopCapturer::SelectSource(webrtc::DesktopCapturer::SourceId id) + { + return capturer->SelectSource(id); + } + + bool DesktopCapturer::FocusOnSelectedSource() + { + return capturer->FocusOnSelectedSource(); + } + + void DesktopCapturer::setFocusSelectedSource(bool focus) + { + this->focusSelectedSource = focus; + } + + bool DesktopCapturer::IsOccluded(const webrtc::DesktopVector & pos) + { + return capturer->IsOccluded(pos); + } } \ No newline at end of file diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopSource.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopSource.cpp index 4faa6bd6..bac8b6ea 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopSource.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopSource.cpp @@ -26,7 +26,7 @@ namespace jni { JavaLocalRef toJava(JNIEnv * env, const webrtc::DesktopCapturer::Source & source) { - const auto javaClass = JavaClasses::get(env); + const std::shared_ptr javaClass = JavaClasses::get(env); jobject obj = env->NewObject(javaClass->cls, javaClass->ctor, JavaString::toJava(env, source.title).get(), @@ -37,7 +37,7 @@ namespace jni webrtc::DesktopCapturer::Source toNative(JNIEnv * env, const JavaRef & javaType) { - const auto javaClass = JavaClasses::get(env); + const std::shared_ptr javaClass = JavaClasses::get(env); JavaObject obj(env, javaType); diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCaptureCallback.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCaptureCallback.java index 8dca9d3b..4a9defdf 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCaptureCallback.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCaptureCallback.java @@ -18,8 +18,20 @@ import dev.onvoid.webrtc.media.video.VideoFrame; +/** + * Callback interface for desktop capture operations. Implementers receive captured frames from a desktop capture + * source. + * + * @author Alex Andres + */ public interface DesktopCaptureCallback { + /** + * Called when a frame has been captured from the desktop. + * + * @param result The result of the capture operation. + * @param frame The captured video frame data, if successful. + */ void onCaptureResult(DesktopCapturer.Result result, VideoFrame frame); } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCapturer.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCapturer.java index cc144cd6..55b52396 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCapturer.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopCapturer.java @@ -20,8 +20,30 @@ import java.util.List; +/** + * Abstract base class for desktop capture functionality. + *

+ * The DesktopCapturer provides the core functionality for capturing content from desktop sources + * like screens and windows. It leverages native implementation through JNI for efficient capture + * operations. + *

+ * This class handles source selection, configuration of capture parameters like frame rate + * and focus behavior, and the capture process itself. + *

+ * Implementations must provide the concrete native functionality for different platforms. + * + * @see ScreenCapturer + * @see WindowCapturer + * + * @author Alex Andres + */ public abstract class DesktopCapturer extends DisposableNativeObject { + /** + * Represents the result of a desktop capture operation. + * This enum defines possible outcomes when attempting to capture a desktop frame, + * indicating success or different types of failures that may occur during the capture process. + */ public enum Result { /** @@ -50,7 +72,7 @@ public enum Result { /** * The DesktopCapturer doesn't take ownership of the callback. When the - * DesktopCapturer is disposed the callback will be disposed using this + * DesktopCapturer is disposed, the callback will be disposed using this * handle. */ private long callbackHandle; @@ -59,14 +81,45 @@ public enum Result { @Override public native void dispose(); + /** + * Retrieves a list of available desktop sources that can be captured. + * + * @return A list of desktop sources (screens, windows). + */ public native List getDesktopSources(); + /** + * Selects a specific desktop source for capturing. + * + * @param source The desktop source to be captured. + */ public native void selectSource(DesktopSource source); + /** + * Sets whether the selected source should be focused during capture. + * + * @param focus True to focus the selected source, false otherwise. + */ public native void setFocusSelectedSource(boolean focus); + /** + * Sets the maximum frame rate for the desktop capture. + * + * @param maxFrameRate The maximum number of frames to capture per second. + */ + public native void setMaxFrameRate(int maxFrameRate); + + /** + * Starts the desktop capture process with the provided callback. + * + * @param callback The callback that receives capture events and frames. + */ public native void start(DesktopCaptureCallback callback); + /** + * Captures a single frame manually. + * The capture result will be delivered via the callback provided in {@link #start}. + */ public native void captureFrame(); } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopFrame.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopFrame.java index 80c7a47c..727246bd 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopFrame.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopFrame.java @@ -21,34 +21,38 @@ import java.nio.ByteBuffer; import java.util.StringJoiner; +/** + * Represents a desktop frame captured from a screen or window. + * + * @author Alex Andres + */ public class DesktopFrame { - /** - * The rectangle in full desktop coordinates. - */ + /** The rectangle in full desktop coordinates. */ public final Rectangle frameRect; - /** - * The size of the frame in full desktop coordinate space. - */ + /** The size of the frame in full desktop coordinate space. */ public final Dimension frameSize; - /** - * The scale factor from DIPs to physical pixels of the frame. - */ + /** The scale factor from DIPs to physical pixels of the frame. */ public final float scale; - /** - * Distance in the buffer between two neighboring rows in bytes. - */ + /** Distance in the buffer between two neighboring rows in bytes. */ public final int stride; - /** - * The underlying frame buffer. - */ + /** The underlying frame buffer. */ public final ByteBuffer buffer; + /** + * Creates a new desktop frame with the specified properties. + * + * @param frameRect The rectangle in full desktop coordinates. + * @param frameSize The size of the frame in full desktop coordinate space. + * @param scale The scale factor from DIPs to physical pixels of the frame. + * @param stride Distance in the buffer between two neighboring rows in bytes. + * @param buffer The underlying frame buffer. + */ public DesktopFrame(Rectangle frameRect, Dimension frameSize, float scale, int stride, ByteBuffer buffer) { this.frameRect = frameRect; this.frameSize = frameSize; diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSource.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSource.java index c8823f63..f8f1b8fd 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSource.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSource.java @@ -17,15 +17,28 @@ package dev.onvoid.webrtc.media.video.desktop; import java.util.Objects; -import java.util.StringJoiner; +/** + * Represents a desktop source that can be captured, such as a screen or window. + * Desktop sources are uniquely identified by their ID. + * + * @author Alex Andres + */ public class DesktopSource { + /** The title or name of the desktop source. */ public final String title; + /** The unique identifier of the desktop source. */ public final long id; + /** + * Creates a new desktop source with the specified title and ID. + * + * @param title The title or name of the desktop source. + * @param id The unique identifier of the desktop source. + */ public DesktopSource(String title, long id) { this.title = title; this.id = id; diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSourceType.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSourceType.java index c9a01f76..84e2da8f 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSourceType.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/DesktopSourceType.java @@ -16,10 +16,18 @@ package dev.onvoid.webrtc.media.video.desktop; +/** + * Represents the type of desktop source that can be captured for video. + * Used in desktop capture functionality to distinguish between different source types. + * + * @author Alex Andres + */ public enum DesktopSourceType { + /** Represents a screen/monitor desktop source. Used when capturing the entire screen or a specific monitor. */ SCREEN, + /** Represents a window desktop source. Used when capturing a specific application window. */ WINDOW; } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/ScreenCapturer.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/ScreenCapturer.java index 27b43eab..76eb7032 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/ScreenCapturer.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/ScreenCapturer.java @@ -16,12 +16,23 @@ package dev.onvoid.webrtc.media.video.desktop; +/** + * A screen capture implementation of the DesktopCapturer. This class provides functionality to capture screen content. + * + * @author Alex Andres + */ public class ScreenCapturer extends DesktopCapturer { + /** + * Creates a new ScreenCapturer instance and initializes the components required for screen capturing. + */ public ScreenCapturer() { initialize(); } + /** + * Initializes the native components required for screen capturing. + */ private native void initialize(); } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/WindowCapturer.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/WindowCapturer.java index 945f261d..fc61ab06 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/WindowCapturer.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/desktop/WindowCapturer.java @@ -16,12 +16,24 @@ package dev.onvoid.webrtc.media.video.desktop; +/** + * A capturer for individual windows on the desktop. Allows for capturing specific application windows for streaming + * or recording. + * + * @author Alex Andres + */ public class WindowCapturer extends DesktopCapturer { + /** + * Constructs a new WindowCapturer instance and initializes the components required for window capturing. + */ public WindowCapturer() { initialize(); } + /** + * Initializes the native implementation of the window capturer. + */ private native void initialize(); } diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java index 4efb4cfd..3a869ba1 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/audio/VoiceActivityDetectorTest.java @@ -62,7 +62,7 @@ void testProcessAndGetProbability() { @Test void testDispose() { - // First operation should work. + // The First operation should work. detector.process(new byte[320], 160, 16000); // Dispose resources. From 0d44451cfb59265b61f8b50a5a8829c9ca045897 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Mon, 14 Apr 2025 10:49:03 +0200 Subject: [PATCH 26/28] fix: DesktopCapturer SetMaxFrameRate --- webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp b/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp index 4bc3f999..e1df6ed9 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_DesktopCapturer.cpp @@ -91,7 +91,7 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapture jni::DesktopCapturer * capturer = GetHandle(env, caller); CHECK_HANDLE(capturer); - capturer->setMaxFrameRate(maxFrameRate); + capturer->SetMaxFrameRate(maxFrameRate); } JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_desktop_DesktopCapturer_start From 70a7840a12f0878cd6b728b01606bc0f1e64e015 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Wed, 7 May 2025 16:11:45 +0200 Subject: [PATCH 27/28] fix: AudioConverter destination buffer size --- .../dev/onvoid/webrtc/media/audio/AudioConverter.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioConverter.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioConverter.java index f04137fa..95080e6a 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioConverter.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/audio/AudioConverter.java @@ -27,10 +27,13 @@ */ public class AudioConverter extends DisposableNativeObject { + /** The number of samples in a 10 ms frame for the input audio. */ private final int srcSamples; + /** The number of samples in a 10 ms frame for the output audio. */ private final int dstSamples; + /** The number of output samples after conversion in a 10 ms frame. */ private final int dstSamplesOut; @@ -46,7 +49,7 @@ public class AudioConverter extends DisposableNativeObject { public AudioConverter(int srcSampleRate, int srcChannels, int dstSampleRate, int dstChannels) { this.srcSamples = srcSampleRate / 100 * srcChannels; - this.dstSamples = Math.max(srcSampleRate, dstSampleRate) / 100 * dstChannels; + this.dstSamples = dstSampleRate / 100 * dstChannels; this.dstSamplesOut = (dstSampleRate / 100) * dstChannels; initialize(srcSampleRate, srcChannels, dstSampleRate, dstChannels); @@ -96,10 +99,8 @@ public int convert(byte[] src, byte[] dst) { @Override public native void dispose(); - private native void initialize(int srcSampleRate, int srcChannels, - int dstSampleRate, int dstChannels); + private native void initialize(int srcSampleRate, int srcChannels, int dstSampleRate, int dstChannels); - public native void convertInternal(byte[] src, int nSrcSamples, byte[] dst, - int nDstSamples); + public native void convertInternal(byte[] src, int nSrcSamples, byte[] dst, int nDstSamples); } From 8f87fe30d7f95b032e0ceca3e2d7f4ca6fc61143 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Fri, 6 Jun 2025 20:42:14 +0200 Subject: [PATCH 28/28] fix: comment out retain and release calls in buffer conversion --- .../dev/onvoid/webrtc/media/video/NativeI420Buffer.java | 8 ++++---- .../onvoid/webrtc/media/video/VideoBufferConverter.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java index d0e615de..ba8f78e3 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java @@ -94,7 +94,7 @@ public int getHeight() { @Override public I420Buffer toI420() { - retain(); +// retain(); return this; } @@ -159,13 +159,13 @@ private static VideoFrameBuffer cropAndScale(final I420Buffer buffer, int cropX, dataU.position(cropX / 2 + cropY / 2 * buffer.getStrideU()); dataV.position(cropX / 2 + cropY / 2 * buffer.getStrideV()); - buffer.retain(); +// buffer.retain(); return wrap(scaleWidth, scaleHeight, dataY.slice(), buffer.getStrideY(), dataU.slice(), buffer.getStrideU(), dataV.slice(), buffer.getStrideV()); } - buffer.retain(); +// buffer.retain(); I420Buffer newBuffer = allocate(scaleWidth, scaleHeight); @@ -174,7 +174,7 @@ private static VideoFrameBuffer cropAndScale(final I420Buffer buffer, int cropX, newBuffer.getDataY(), newBuffer.getStrideY(), newBuffer.getDataU(), newBuffer.getStrideU(), newBuffer.getDataV(), newBuffer.getStrideV(), scaleWidth, scaleHeight); - buffer.release(); +// buffer.release(); return newBuffer; } diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/VideoBufferConverter.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/VideoBufferConverter.java index dd4df23a..be99329e 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/VideoBufferConverter.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/VideoBufferConverter.java @@ -40,7 +40,7 @@ public static void convertFromI420(VideoFrameBuffer src, byte[] dst, FourCC four i420.getWidth(), i420.getHeight(), fourCC.value()); - i420.release(); +// i420.release(); } public static void convertFromI420(VideoFrameBuffer src, ByteBuffer dst, FourCC fourCC) throws Exception { @@ -82,7 +82,7 @@ public static void convertFromI420(VideoFrameBuffer src, ByteBuffer dst, FourCC fourCC.value()); } - i420.release(); +// i420.release(); } private native static void I420toByteArray(