diff --git a/Cargo.lock b/Cargo.lock index 2b7aa825..08b08f23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -414,12 +414,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "1.0.4" @@ -1804,27 +1798,32 @@ dependencies = [ [[package]] name = "jni" -version = "0.21.1" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" dependencies = [ - "cesu8", "cfg-if", "combine", - "jni-sys 0.3.1", + "jni-macros", + "jni-sys", "log", - "thiserror 1.0.69", + "simd_cesu8", + "thiserror 2.0.18", "walkdir", - "windows-sys 0.45.0", + "windows-link 0.2.1", ] [[package]] -name = "jni-sys" -version = "0.3.1" +name = "jni-macros" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ - "jni-sys 0.4.1", + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", ] [[package]] @@ -3350,6 +3349,22 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "sketches-ddsketch" version = "0.3.1" @@ -4408,22 +4423,13 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -4432,7 +4438,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -4444,35 +4450,20 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -4493,36 +4484,18 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -4535,48 +4508,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/acknowledgments/acknowledgments.html b/acknowledgments/acknowledgments.html index a42511a0..a9de6398 100644 --- a/acknowledgments/acknowledgments.html +++ b/acknowledgments/acknowledgments.html @@ -45,7 +45,7 @@
MIT License
@@ -2359,7 +2355,6 @@ DEALINGS IN THE SOFTWARE.
MIT License
Used by:
Copyright (c) 2015 The rust-jni-sys Developers
@@ -3875,8 +3870,9 @@ SOFTWARE.
MIT License (synthesized)
Used by:
MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.
The MIT License (MIT)
-
-Copyright (c) 2016 Prevoty, Inc. and jni-rs contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
diff --git a/acknowledgments/acknowledgments.md b/acknowledgments/acknowledgments.md
index 0602c863..88bb9edd 100644
--- a/acknowledgments/acknowledgments.md
+++ b/acknowledgments/acknowledgments.md
@@ -1783,7 +1783,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
```
-## windows-sys 0.45.0, windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.42.2, windows-targets 0.52.6, windows_aarch64_msvc 0.42.2, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.42.2, windows_x86_64_msvc 0.52.6
+## windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.52.6, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.52.6
```
MIT License
@@ -2201,7 +2201,7 @@ DEALINGS IN THE SOFTWARE.
```
-## jni-sys 0.3.1, jni-sys 0.4.1
+## jni-sys 0.4.1
```
Copyright (c) 2015 The rust-jni-sys Developers
@@ -3605,7 +3605,7 @@ SOFTWARE.
```
-## cesu8 1.1.0, jni-sys-macros 0.4.1, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2
+## jni-macros 0.22.4, jni-sys-macros 0.4.1, jni 0.22.4, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2
```
MIT License
@@ -3629,6 +3629,30 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
```
+## simdutf8 0.1.5
+
+```
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+```
+
## ident_case 1.0.1
```
@@ -3654,7 +3678,7 @@ SOFTWARE.
```
-## curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21
+## curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, simd_cesu8 1.1.1, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21
```
Permission is hereby granted, free of charge, to any
@@ -3977,33 +4001,6 @@ SOFTWARE.
```
-## jni 0.21.1
-
-```
-The MIT License (MIT)
-
-Copyright (c) 2016 Prevoty, Inc. and jni-rs contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-```
-
## same-file 1.0.6, winapi-util 0.1.11
```
diff --git a/acknowledgments/acknowledgments.plist b/acknowledgments/acknowledgments.plist
index 4a6b042c..37984381 100644
--- a/acknowledgments/acknowledgments.plist
+++ b/acknowledgments/acknowledgments.plist
@@ -1868,7 +1868,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
License
MIT License
Title
- windows-sys 0.45.0, windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.42.2, windows-targets 0.52.6, windows_aarch64_msvc 0.42.2, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.42.2, windows_x86_64_msvc 0.52.6
+ windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.52.6, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.52.6
Type
PSGroupSpecifier
@@ -2340,7 +2340,7 @@ SOFTWARE.
License
MIT License
Title
- jni-sys 0.3.1, jni-sys 0.4.1
+ jni-sys 0.4.1
Type
PSGroupSpecifier
@@ -3931,7 +3931,35 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
License
MIT License
Title
- cesu8 1.1.0, jni-sys-macros 0.4.1, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2
+ jni-macros 0.22.4, jni-sys-macros 0.4.1, jni 0.22.4, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2
+ Type
+ PSGroupSpecifier
+
+
+ FooterText
+ MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ License
+ MIT License
+ Title
+ simdutf8 0.1.5
Type
PSGroupSpecifier
@@ -3993,7 +4021,7 @@ DEALINGS IN THE SOFTWARE.
License
MIT License
Title
- curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21
+ curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, simd_cesu8 1.1.1, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21
Type
PSGroupSpecifier
@@ -4339,37 +4367,6 @@ SOFTWARE.
FooterText
The MIT License (MIT)
-Copyright (c) 2016 Prevoty, Inc. and jni-rs contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
- License
- MIT License
- Title
- jni 0.21.1
- Type
- PSGroupSpecifier
-
-
- FooterText
- The MIT License (MIT)
-
Copyright (c) 2017 Andrew Gallant
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d64cd491..61285a65 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4baf5a11..5f38436f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 1aa94a42..adff685a 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 7101f8e4..e509b2dd 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/src/android/build.gradle b/src/android/build.gradle
index 2dc450c9..7f7f8502 100644
--- a/src/android/build.gradle
+++ b/src/android/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id 'com.android.library' version '8.4.0'
+ id 'com.android.library' version '9.1.1'
id 'maven-publish'
id 'signing'
}
@@ -15,66 +15,73 @@ ext.release_jni_lib_dirs = project.hasProperty("releaseRingrtcLibDir") ? [releas
ext.webrtc_jar = project.hasProperty("webrtcJar") ? webrtcJar : "libs/libwebrtc.jar"
ext.asset_dir = project.hasProperty("assetDir") ? assetDir : "assets"
-android {
- namespace 'org.signal.ringrtc'
+base {
+ archivesName = "ringrtc-android"
+}
- compileSdk 34
+android {
+ namespace = 'org.signal.ringrtc'
+
+ compileSdk = 34
defaultConfig {
- minSdk 21
- targetSdk 33
- versionName ringrtcVersion
- archivesBaseName = "ringrtc-android"
+ minSdk = 21
+ targetSdk = 33
+ versionName = ringrtcVersion
consumerProguardFiles "proguard-rules.pro"
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
sourceSets {
release {
jniLibs.srcDirs = release_jni_lib_dirs
java.srcDirs = ['api/']
- assets.srcDir asset_dir
+ assets.srcDirs = [asset_dir]
}
debug {
jniLibs.srcDirs = debug_jni_lib_dirs
java.srcDirs = ['api/']
- assets.srcDir asset_dir
+ assets.srcDirs = [asset_dir]
}
}
compileOptions {
- coreLibraryDesugaringEnabled true
+ coreLibraryDesugaringEnabled = true
}
- packagingOptions {
+ packaging {
// Libraries are already stripped if necessary when linked.
- doNotStrip "**/*.so"
+ jniLibs.keepDebugSymbols.add('**/*.so')
}
publishing {
- singleVariant("release")
+ singleVariant("release")
}
}
dependencies {
api files(webrtc_jar)
- api 'androidx.annotation:annotation:1.4.0'
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
- androidTestImplementation "androidx.test:runner:1.4.0"
- androidTestImplementation "androidx.test:core:1.4.0"
- androidTestImplementation "org.mockito:mockito-android:5.1.1"
+ api 'androidx.annotation:annotation:1.10.0'
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
+ androidTestImplementation "androidx.test:runner:1.5.0"
+ androidTestImplementation "androidx.test:core:1.5.0"
+ androidTestImplementation "org.mockito:mockito-android:5.12.0"
}
-task javadoc(type: Javadoc) {
- source = android.sourceSets.release.java.sourceFiles
- classpath += files(android.bootClasspath)
- // There doesn't seem to be a convenient way to do this with just one variant.
- android.libraryVariants.all { v ->
- classpath += v.getCompileClasspath(null)
+tasks.register('javadoc', Javadoc) {
+ source = fileTree(dir: 'api', include: '**/*.java')
+ failOnError = false
+ if (project.hasProperty('docsDir')) {
+ destinationDir = new File(docsDir, 'javadoc')
}
- // Normally this is set by the 'java' plugin, but that's not compatible with 'android-library'
- if (project.hasProperty("docsDir")) {
- destinationDir = new File(docsDir, "javadoc")
+}
+
+androidComponents {
+ onVariants(selector().withBuildType('release')) { variant ->
+ tasks.named('javadoc').configure { task ->
+ task.classpath = files(androidComponents.sdkComponents.bootClasspath) +
+ project.configurations.named("${variant.name}CompileClasspath").get()
+ }
}
}
@@ -85,7 +92,7 @@ afterEvaluate {
from components.release
group = 'org.signal'
- artifactId = archivesBaseName
+ artifactId = base.archivesName.get()
version = ringrtcVersion
pom {
@@ -137,7 +144,7 @@ afterEvaluate {
}
signing {
- required { isReleaseVersion && gradle.taskGraph.hasTask(getPath() + ":publish") }
+ required = { isReleaseVersion && gradle.taskGraph.hasTask(getPath() + ":publish") }
def signingKeyId = findProperty("signingKeyId")
def signingKey = findProperty("signingKey")
@@ -150,8 +157,8 @@ afterEvaluate {
}
}
-task version {
- group 'Info'
+tasks.register('version') {
+ group = 'Info'
description = 'Prints the versions as read from the version config file.'
doLast {
println "RingRTC version: " + ringrtcVersion
diff --git a/src/android/src/androidTest/java/CallManagerTest.java b/src/android/src/androidTest/java/CallManagerTest.java
index 47c39c19..f7e9c5c8 100644
--- a/src/android/src/androidTest/java/CallManagerTest.java
+++ b/src/android/src/androidTest/java/CallManagerTest.java
@@ -3,6 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import org.signal.ringrtc.CallException;
+import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager;
import org.signal.ringrtc.GroupCall;
@@ -18,8 +20,10 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
import static org.mockito.Mockito.*;
public class CallManagerTest extends CallTestBase {
@@ -147,4 +151,78 @@ public class CallManagerTest extends CallTestBase {
callManager.receivedHttpResponse(requestId.getValue(), 404, new byte[] {});
latch.await();
}
+
+ @Test
+ public void testFromEraIdRoundTrip() {
+ CallId a1 = CallId.fromEra("mesozoic");
+ CallId a2 = CallId.fromEra("mesozoic");
+ CallId b = CallId.fromEra("cenozoic");
+ errors.checkThat(a1, is(a2));
+ errors.checkThat(a1, is(not(b)));
+ errors.checkThat(a1.longValue(), is(not(0L)));
+ }
+
+ @Test
+ public void testAddAssetWithNoSourceThrows() throws Exception {
+ CallManager callManager = CallManager.createCallManager(mock());
+ try {
+ callManager.addAsset("group", (byte[]) null);
+ errors.addError(new AssertionError("expected CallException"));
+ } catch (CallException ex) {
+ errors.checkThat(ex.getMessage(),
+ is("addAsset requires either a filePath or content"));
+ }
+ }
+
+ @Test
+ public void testSetAudioEnableNoActiveCallThrows() throws Exception {
+ CallManager callManager = CallManager.createCallManager(mock());
+ try {
+ callManager.setAudioEnable(true);
+ errors.addError(new AssertionError("expected CallException"));
+ } catch (CallException ex) {
+ }
+ }
+
+ @Test
+ public void testPeekWithManyMembers() throws Exception {
+ final int GROUP_SIZE = 256;
+ final int PARTICIPANTS = 100;
+ CallManager.Observer observer = mock();
+ CallManager callManager = CallManager.createCallManager(observer);
+
+ GroupCall.GroupMemberInfo[] memberInfos = new GroupCall.GroupMemberInfo[GROUP_SIZE];
+ StringBuilder participants = new StringBuilder("[");
+ for (int i = 0; i < GROUP_SIZE; i++) {
+ byte[] opaque = fakeOpaqueUserId(i);
+ memberInfos[i] = new GroupCall.GroupMemberInfo(UUID.nameUUIDFromBytes(opaque), opaque);
+ if (i < PARTICIPANTS) {
+ if (i > 0) participants.append(',');
+ participants.append("{\"opaqueUserId\":\"")
+ .append(sha256Hex(opaque))
+ .append("\",\"demuxId\":")
+ .append(32 * (i + 1))
+ .append('}');
+ }
+ }
+ participants.append(']');
+
+ String body = "{\"conferenceId\":\"jurassic\",\"maxDevices\":" + (PARTICIPANTS + 1)
+ + ",\"participants\":" + participants + ",\"pendingClients\":[]}";
+
+ CountDownLatch latch = new CountDownLatch(1);
+ callManager.peekGroupCall("sfu.example", new byte[] { 1, 2, 3 }, Arrays.asList(memberInfos), result -> {
+ errors.checkThat(result.getEraId(), is("jurassic"));
+ errors.checkThat(result.getDeviceCountIncludingPendingDevices(), is((long) PARTICIPANTS));
+ errors.checkThat(result.getJoinedMembers().size(), is(PARTICIPANTS));
+ latch.countDown();
+ });
+
+ ArgumentCaptor requestId = ArgumentCaptor.forClass(Long.class);
+ verify(observer).onSendHttpRequest(requestId.capture(), startsWith("sfu.example"), eq(CallManager.HttpMethod.GET), any(), any());
+
+ callManager.receivedHttpResponse(requestId.getValue(), 200, body.getBytes("UTF-8"));
+ errors.checkThat("peek result lambda fired",
+ latch.await(30, TimeUnit.SECONDS), is(true));
+ }
}
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index 2906c505..9f7bf10f 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -74,7 +74,7 @@ zkgroup = { git = "https://github.com/signalapp/libsignal", tag = "v0.89.2" }
neon = { version = "1.1.1", optional = true, default-features = false, features = ["napi-6"] }
# Optional, needed to check Android-specific code when not targeting Android
-jni = { version = "0.21.1", optional = true, default-features = false }
+jni = { version = "0.22.4", optional = true, default-features = false }
# Optional, needed by the "http" feature
ureq = { version = "3.1.4", optional = true }
@@ -138,7 +138,7 @@ path = "tests/outgoing.rs"
required-features = ["sim"]
[target.'cfg(target_os="android")'.dependencies]
-jni = { version = "0.21.1", default-features = false }
+jni = { version = "0.22.4", default-features = false }
[dev-dependencies]
uuid = { version = "1.19.0" }
diff --git a/src/rust/src/android/android_platform.rs b/src/rust/src/android/android_platform.rs
index 0d527478..eb080b22 100644
--- a/src/rust/src/android/android_platform.rs
+++ b/src/rust/src/android/android_platform.rs
@@ -13,13 +13,26 @@ use std::{
};
use jni::{
- JNIEnv, JavaVM,
- objects::{AutoLocal, GlobalRef, JObject, JValue},
+ Env, JavaVM, jni_str,
+ objects::{Global, JObject},
+ refs::{IntoAuto, LoaderContext, Reference as _},
sys::{jint, jlong, jshort},
};
use crate::{
- android::{error::AndroidError, jni_util::*, webrtc_java_media_stream::JavaMediaStream},
+ android::{
+ error::AndroidError,
+ types::{
+ self, CallEndReason as JCallEndReason, CallEvent, CallLinkRootKey as JCallLinkRootKey,
+ CallLinkState as JCallLinkState, CallMediaType as JCallMediaType,
+ CallSummary as JCallSummary, ConnectionState, HangupType, HttpHeader, HttpMethod,
+ HttpResult, JArrayList, JBoolean, JFloat, JHashMap, JLong, JoinState,
+ MediaQualityStats as JMediaQualityStats, PeekInfo as JPeekInfo,
+ QualityStats as JQualityStats, Reaction, ReceivedAudioLevel as JReceivedAudioLevel,
+ RemoteDeviceState, SpeechEvent,
+ },
+ webrtc_java_media_stream::JavaMediaStream,
+ },
common::{
ApplicationEvent, CallConfig, CallDirection, CallEndReason, CallId, CallMediaType,
DeviceId, Result,
@@ -31,6 +44,7 @@ use crate::{
group_call,
platform::{Platform, PlatformItem},
signaling,
+ util::try_scoped,
},
lite::{
call_links::{CallLinkRestrictions, CallLinkRootKey, CallLinkState, Empty},
@@ -44,31 +58,12 @@ use crate::{
},
};
-const RINGRTC_PACKAGE: &str = jni_class_name!(org.signal.ringrtc);
-const CALL_SUMMARY_CLASS: &str = jni_class_name!(org.signal.ringrtc.CallSummary);
-const CALL_SUMMARY_QUALITY_STATS_CLASS: &str =
- jni_class_name!(org.signal.ringrtc.CallSummary::QualityStats);
-const CALL_SUMMARY_MEDIA_QUALITY_STATS_CLASS: &str =
- jni_class_name!(org.signal.ringrtc.CallSummary::MediaQualityStats);
-const CALL_LINK_STATE_CLASS: &str = jni_class_name!(org.signal.ringrtc.CallLinkState);
-const CALL_LINK_ROOT_KEY_CLASS: &str = jni_class_name!(org.signal.ringrtc.CallLinkRootKey);
-const CALL_MANAGER_CLASS: &str = "CallManager";
-const GROUP_CALL_CLASS: &str = "GroupCall";
-const HTTP_HEADER_CLASS: &str = jni_class_name!(org.signal.ringrtc.HttpHeader);
-const HTTP_RESULT_CLASS: &str = jni_class_name!(org.signal.ringrtc.CallManager::HttpResult);
-const PEEK_INFO_CLASS: &str = jni_class_name!(org.signal.ringrtc.PeekInfo);
-const REACTION_CLASS: &str = jni_class_name!(org.signal.ringrtc.GroupCall::Reaction);
-const REMOTE_DEVICE_STATE_CLASS: &str =
- jni_class_name!(org.signal.ringrtc.GroupCall::RemoteDeviceState);
-const RECEIVED_AUDIO_LEVEL_CLASS: &str =
- jni_class_name!(org.signal.ringrtc.GroupCall::ReceivedAudioLevel);
-
/// Android implementation for platform::Platform::AppIncomingMedia
pub type AndroidMediaStream = JavaMediaStream;
impl PlatformItem for AndroidMediaStream {}
-/// Android implementation for platform::Platform::AppRemotePeer
-pub type AndroidGlobalRef = GlobalRef;
+/// Android implementation for platform::Platform::AppRemotePeer.
+pub type AndroidGlobalRef = Arc>>;
impl PlatformItem for AndroidGlobalRef {}
/// Android implementation for platform::Platform::AppCallContext
@@ -76,7 +71,7 @@ struct JavaCallContext {
/// Java JVM object.
platform: AndroidPlatform,
/// Java CallContext object.
- jni_call_context: GlobalRef,
+ jni_call_context: Global>,
}
impl Drop for JavaCallContext {
@@ -84,19 +79,20 @@ impl Drop for JavaCallContext {
info!("JavaCallContext::drop()");
// call into CMI to close CallContext object
- if let Ok(env) = &mut self.platform.java_env() {
+ let _ = self.platform.with_java_env(|env| -> Result<()> {
let jni_call_manager = self.platform.jni_call_manager.as_obj();
let jni_call_context = self.jni_call_context.as_obj();
- let _ = jni_call_method(
+ jni_call_method!(
env,
jni_call_manager,
- "closeCall",
- jni_args!((
+ jni_str!("closeCall"),
+ (
jni_call_context => org.signal.ringrtc.CallManager::CallContext,
- ) -> void),
- );
- }
+ ) -> void
+ )?;
+ Ok(())
+ });
}
}
@@ -110,7 +106,7 @@ unsafe impl Send for AndroidCallContext {}
impl PlatformItem for AndroidCallContext {}
impl AndroidCallContext {
- pub fn new(platform: AndroidPlatform, jni_call_context: GlobalRef) -> Self {
+ pub fn new(platform: AndroidPlatform, jni_call_context: Global>) -> Self {
Self {
inner: Arc::new(JavaCallContext {
platform,
@@ -119,8 +115,8 @@ impl AndroidCallContext {
}
}
- pub fn to_jni(&self) -> GlobalRef {
- self.inner.jni_call_context.clone()
+ pub fn to_jni(&self) -> &Global> {
+ &self.inner.jni_call_context
}
}
@@ -129,7 +125,7 @@ struct JavaConnection {
/// Java JVM object.
platform: AndroidPlatform,
/// Java Connection object.
- jni_connection: GlobalRef,
+ jni_connection: Global>,
}
impl Drop for JavaConnection {
@@ -137,19 +133,19 @@ impl Drop for JavaConnection {
info!("JavaConnection::drop()");
// call into CMI to close Connection object
- if let Ok(env) = &mut self.platform.java_env() {
- let jni_call_manager = self.platform.jni_call_manager.as_obj();
- let jni_connection = self.jni_connection.as_obj();
-
- let _ = jni_call_method(
+ let jni_call_manager = self.platform.jni_call_manager.as_obj();
+ let jni_connection = self.jni_connection.as_obj();
+ let _ = self.platform.with_java_env(|env| -> Result<()> {
+ jni_call_method!(
env,
jni_call_manager,
- "closeConnection",
- jni_args!((
+ jni_str!("closeConnection"),
+ (
jni_connection => org.signal.ringrtc.Connection,
- ) -> void),
- );
- }
+ ) -> void
+ )?;
+ Ok(())
+ });
}
}
@@ -163,7 +159,7 @@ unsafe impl Send for AndroidConnection {}
impl PlatformItem for AndroidConnection {}
impl AndroidConnection {
- fn new(platform: AndroidPlatform, jni_connection: GlobalRef) -> Self {
+ fn new(platform: AndroidPlatform, jni_connection: Global>) -> Self {
Self {
inner: Arc::new(JavaConnection {
platform,
@@ -172,8 +168,8 @@ impl AndroidConnection {
}
}
- pub fn to_jni(&self) -> GlobalRef {
- self.inner.jni_connection.clone()
+ pub fn to_jni(&self) -> &Global> {
+ &self.inner.jni_connection
}
}
@@ -182,14 +178,9 @@ pub struct AndroidPlatform {
/// Java JVM object.
jvm: JavaVM,
/// Java org.signal.ringrtc.CallManager object.
- jni_call_manager: GlobalRef,
- /// Cache of Java classes needed at runtime
- class_cache: ClassCache,
+ jni_call_manager: Global>,
}
-unsafe impl Sync for AndroidPlatform {}
-unsafe impl Send for AndroidPlatform {}
-
impl fmt::Display for AndroidPlatform {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AndroidPlatform")
@@ -205,9 +196,6 @@ impl fmt::Debug for AndroidPlatform {
impl Drop for AndroidPlatform {
fn drop(&mut self) {
info!("Dropping AndroidPlatform");
- // ensure this thread is attached to the JVM as our GlobalRefs
- // go out of scope
- let _ = self.java_env();
}
}
@@ -217,25 +205,22 @@ macro_rules! request_update_via_jni {
$f:literal,
$i:ident
) => {{
- let mut env = match $s.java_env() {
- Ok(v) => v,
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
let jni_call_manager = $s.jni_call_manager.as_obj();
let jni_client_id = $i as jlong;
- const METHOD: &str = $f;
- let result = jni_call_method(
- &mut env,
- jni_call_manager,
- METHOD,
- jni_args!((jni_client_id => long) -> void)
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
+ const METHOD: &jni::strings::JNIStr = jni_str!($f);
+ if let Err(error) = $s.with_java_env(|env| -> Result<()> {
+ jni_call_method!(
+ env,
+ jni_call_manager,
+ METHOD,
+ (
+ jni_client_id => long,
+ ) -> void
+ )?;
+ Ok(())
+ }) {
+ error!("jni_call_method: {:?}", error);
}
}};
}
@@ -264,9 +249,6 @@ impl Platform for AndroidPlatform {
audio_levels_interval,
);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
-
let audio_jitter_buffer_max_packets = call_config.audio_jitter_buffer_config.max_packets;
let audio_jitter_buffer_max_target_delay_ms =
call_config.audio_jitter_buffer_config.max_target_delay_ms;
@@ -288,29 +270,32 @@ impl Platform for AndroidPlatform {
let android_call_context = call.call_context()?;
let jni_call_context = android_call_context.to_jni();
- let jni_connection = jni_call_method(
- env,
- jni_call_manager,
- "createConnection",
- jni_args!((
- (connection_ptr.as_ptr() as jlong) => long,
- call_id_jlong => long,
- jni_remote_device_id => int,
- jni_call_context.as_obj() => org.signal.ringrtc.CallManager::CallContext,
- audio_jitter_buffer_max_packets => int,
- audio_jitter_buffer_max_target_delay_ms => int,
- ) -> org.signal.ringrtc.Connection),
- )?;
+ self.with_java_env(|env| {
+ let jni_connection = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("createConnection"),
+ (
+ connection_ptr.as_ptr() as jlong => long,
+ call_id_jlong => long,
+ jni_remote_device_id => int,
+ jni_call_context.as_obj() => org.signal.ringrtc.CallManager::CallContext,
+ audio_jitter_buffer_max_packets => int,
+ audio_jitter_buffer_max_target_delay_ms => int,
+ ) -> org.signal.ringrtc.Connection
+ )?
+ .into_object()?;
- if jni_connection.is_null() {
- return Err(AndroidError::CreateJniConnection.into());
- }
- let jni_connection = env.new_global_ref(jni_connection)?;
- let platform = self.try_clone()?;
- let android_connection = AndroidConnection::new(platform, jni_connection);
- connection.set_app_connection(android_connection)?;
+ if jni_connection.is_null() {
+ return Err(AndroidError::CreateJniConnection.into());
+ }
+ let jni_connection = env.new_global_ref(jni_connection)?;
+ let platform = self.try_clone()?;
+ let android_connection = AndroidConnection::new(platform, jni_connection);
+ connection.set_app_connection(android_connection)?;
- Ok(connection)
+ Ok(connection)
+ })
}
fn on_start_call(
@@ -325,40 +310,30 @@ impl Platform for AndroidPlatform {
call_id, direction
);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ let jni_remote = remote_peer.as_obj();
+ let call_id_jlong = u64::from(call_id) as jlong;
+ let is_outgoing = match direction {
+ CallDirection::Outgoing => true,
+ CallDirection::Incoming => false,
+ };
+ let jni_call_media_type =
+ JCallMediaType::from_native_index(env, call_media_type as i32)?.auto();
- let jni_remote = remote_peer.as_obj();
- let call_id_jlong = u64::from(call_id) as jlong;
- let is_outgoing = match direction {
- CallDirection::Outgoing => true,
- CallDirection::Incoming => false,
- };
- let jni_call_media_type = match self.java_enum(
- env,
- CALL_MANAGER_CLASS,
- "CallMediaType",
- call_media_type as i32,
- ) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- return Err(error);
- }
- };
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onStartCall"),
+ (
+ jni_remote => org.signal.ringrtc.Remote,
+ call_id_jlong => long,
+ is_outgoing => boolean,
+ jni_call_media_type => org.signal.ringrtc.CallManager::CallMediaType,
+ ) -> void
+ )?;
- jni_call_method(
- env,
- jni_call_manager,
- "onStartCall",
- jni_args!((
- jni_remote => org.signal.ringrtc.Remote,
- call_id_jlong => long,
- is_outgoing => boolean,
- jni_call_media_type => org.signal.ringrtc.CallManager::CallMediaType,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
fn on_call_ended(
@@ -370,27 +345,24 @@ impl Platform for AndroidPlatform {
) -> Result<()> {
info!("on_call_ended(): {}", reason);
- let env = &mut self.java_env()?;
+ self.with_java_env(|env| {
+ let jni_remote = remote_peer.as_obj();
+ let jni_summary = self.make_call_summary_object(env, &summary)?;
+ let jni_reason = JCallEndReason::from_native_index(env, reason as i32)?.auto();
- let jni_remote = remote_peer.as_obj();
- let jni_summary = self.make_call_summary_object(env, &summary)?;
- let jni_reason = AutoLocal::new(
- self.java_enum(env, CALL_MANAGER_CLASS, "CallEndReason", reason as i32)?,
- env,
- );
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onCallEnded"),
+ (
+ jni_remote => org.signal.ringrtc.Remote,
+ jni_reason => org.signal.ringrtc.CallManager::CallEndReason,
+ jni_summary => org.signal.ringrtc.CallSummary,
+ ) -> void
+ )?;
- jni_call_method(
- env,
- self.jni_call_manager.as_obj(),
- "onCallEnded",
- jni_args!((
- jni_remote => org.signal.ringrtc.Remote,
- jni_reason => org.signal.ringrtc.CallManager::CallEndReason,
- jni_summary => org.signal.ringrtc.CallSummary,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
fn on_event(
@@ -401,27 +373,22 @@ impl Platform for AndroidPlatform {
) -> Result<()> {
info!("on_event(): {}", event);
- let env = &mut self.java_env()?;
+ self.with_java_env(|env| {
+ let jni_remote = remote_peer.as_obj();
+ let jni_event = CallEvent::from_native_index(env, event as i32)?.auto();
- let jni_remote = remote_peer.as_obj();
- let jni_event = match self.java_enum(env, CALL_MANAGER_CLASS, "CallEvent", event as i32) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- return Err(error);
- }
- };
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onEvent"),
+ (
+ jni_remote => org.signal.ringrtc.Remote,
+ jni_event => org.signal.ringrtc.CallManager::CallEvent,
+ ) -> void
+ )?;
- jni_call_method(
- env,
- self.jni_call_manager.as_obj(),
- "onEvent",
- jni_args!((
- jni_remote => org.signal.ringrtc.Remote,
- jni_event => org.signal.ringrtc.CallManager::CallEvent,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
// Network route changes for 1:1 calls
@@ -435,18 +402,18 @@ impl Platform for AndroidPlatform {
network_route
);
- let env = &mut self.java_env()?;
-
- jni_call_method(
- env,
- self.jni_call_manager.as_obj(),
- "onNetworkRouteChanged",
- jni_args!((
- remote_peer.as_obj() => org.signal.ringrtc.Remote,
- network_route.local_adapter_type as i32 => int,
- ) -> void),
- )?;
- Ok(())
+ self.with_java_env(|env| {
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onNetworkRouteChanged"),
+ (
+ remote_peer.as_obj() => org.signal.ringrtc.Remote,
+ network_route.local_adapter_type as i32 => int,
+ ) -> void
+ )?;
+ Ok(())
+ })
}
fn on_audio_levels(
@@ -460,19 +427,19 @@ impl Platform for AndroidPlatform {
captured_level, received_level
);
- let env = &mut self.java_env()?;
-
- jni_call_method(
- env,
- self.jni_call_manager.as_obj(),
- "onAudioLevels",
- jni_args!((
- remote_peer.as_obj() => org.signal.ringrtc.Remote,
- captured_level as i32 => int,
- received_level as i32 => int,
- ) -> void),
- )?;
- Ok(())
+ self.with_java_env(|env| {
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onAudioLevels"),
+ (
+ remote_peer.as_obj() => org.signal.ringrtc.Remote,
+ captured_level as i32 => int,
+ received_level as i32 => int,
+ ) -> void
+ )?;
+ Ok(())
+ })
}
fn on_low_bandwidth_for_video(
@@ -482,18 +449,18 @@ impl Platform for AndroidPlatform {
) -> Result<()> {
info!("on_low_bandwidth_for_video(): recovered: {}", recovered);
- let env = &mut self.java_env()?;
-
- jni_call_method(
- env,
- self.jni_call_manager.as_obj(),
- "onLowBandwidthForVideo",
- jni_args!((
+ self.with_java_env(|env| {
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onLowBandwidthForVideo"),
+ (
remote_peer.as_obj() => org.signal.ringrtc.Remote,
recovered => boolean,
- ) -> void),
- )?;
- Ok(())
+ ) -> void
+ )?;
+ Ok(())
+ })
}
fn on_send_offer(
@@ -508,50 +475,43 @@ impl Platform for AndroidPlatform {
info!("on_send_offer(): call_id: {}", call_id);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (3).
+ let capacity = 8;
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let jni_remote = remote_peer.as_obj();
+ let call_id_jlong = u64::from(call_id) as jlong;
+ let receiver_device_id = receiver_device_id as jint;
+ let jni_opaque = JObject::from(env.byte_array_from_slice(&offer.opaque)?);
+ let jni_call_media_type =
+ match JCallMediaType::from_native_index(env, offer.call_media_type as i32) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("jni_call_media_type: {:?}", error);
+ return Ok(());
+ }
+ };
- // Set a frame capacity of min (5) + objects (3).
- let capacity = 8;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let jni_remote = remote_peer.as_obj();
- let call_id_jlong = u64::from(call_id) as jlong;
- let receiver_device_id = receiver_device_id as jint;
- let jni_opaque = JObject::from(env.byte_array_from_slice(&offer.opaque)?);
- let jni_call_media_type = match self.java_enum(
- env,
- CALL_MANAGER_CLASS,
- "CallMediaType",
- offer.call_media_type as i32,
- ) {
- Ok(v) => v,
- Err(error) => {
- error!("jni_call_media_type: {:?}", error);
- return Ok(());
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onSendOffer"),
+ (
+ call_id_jlong => long,
+ jni_remote => org.signal.ringrtc.Remote,
+ receiver_device_id => int,
+ broadcast => boolean,
+ jni_opaque => [byte],
+ jni_call_media_type => org.signal.ringrtc.CallManager::CallMediaType,
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
}
- };
- let result = jni_call_method(
- env,
- jni_call_manager,
- "onSendOffer",
- jni_args!((
- call_id_jlong => long,
- jni_remote => org.signal.ringrtc.Remote,
- receiver_device_id => int,
- broadcast => boolean,
- jni_opaque => [byte],
- jni_call_media_type => org.signal.ringrtc.CallManager::CallMediaType,
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
-
- Ok(())
- })?;
-
- Ok(())
+ Ok(())
+ })
+ })
}
fn on_send_answer(
@@ -569,37 +529,34 @@ impl Platform for AndroidPlatform {
call_id, receiver_device_id
);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (2).
+ let capacity = 7;
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let jni_remote = remote_peer.as_obj();
+ let call_id_jlong = u64::from(call_id) as jlong;
+ let receiver_device_id = receiver_device_id as jint;
+ let jni_opaque = JObject::from(env.byte_array_from_slice(&send.answer.opaque)?);
- // Set a frame capacity of min (5) + objects (2).
- let capacity = 7;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let jni_remote = remote_peer.as_obj();
- let call_id_jlong = u64::from(call_id) as jlong;
- let receiver_device_id = receiver_device_id as jint;
- let jni_opaque = JObject::from(env.byte_array_from_slice(&send.answer.opaque)?);
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onSendAnswer"),
+ (
+ call_id_jlong => long,
+ jni_remote => org.signal.ringrtc.Remote,
+ receiver_device_id => int,
+ broadcast => boolean,
+ jni_opaque => [byte],
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
+ }
- let result = jni_call_method(
- env,
- jni_call_manager,
- "onSendAnswer",
- jni_args!((
- call_id_jlong => long,
- jni_remote => org.signal.ringrtc.Remote,
- receiver_device_id => int,
- broadcast => boolean,
- jni_opaque => [byte],
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
-
- Ok(())
- })?;
-
- Ok(())
+ Ok(())
+ })
+ })
}
fn on_send_ice(
@@ -619,54 +576,51 @@ impl Platform for AndroidPlatform {
call_id, receiver_device_id, broadcast
);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (3) + elements (N * 3 object per element).
+ let capacity = 8 + send.ice.candidates.len() * 3;
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let jni_remote = remote_peer.as_obj();
+ let call_id_jlong = u64::from(call_id) as jlong;
+ let receiver_device_id = receiver_device_id as jint;
- // Set a frame capacity of min (5) + objects (3) + elements (N * 3 object per element).
- let capacity = (8 + send.ice.candidates.len() * 3) as i32;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let jni_remote = remote_peer.as_obj();
- let call_id_jlong = u64::from(call_id) as jlong;
- let receiver_device_id = receiver_device_id as jint;
+ let list = JArrayList::with_capacity(env, send.ice.candidates.len() as jint)?;
+ let ice_candidate_list = match jni::objects::JList::cast_local(env, list) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("ice_candidate_list: {:?}", error);
+ return Ok(());
+ }
+ };
- let list = jni_new_arraylist(env, send.ice.candidates.len())?;
- let ice_candidate_list = match env.get_list(&list) {
- Ok(v) => v,
- Err(error) => {
- error!("ice_candidate_list: {:?}", error);
- return Ok(());
+ for candidate in send.ice.candidates {
+ let jni_opaque = JObject::from(env.byte_array_from_slice(&candidate.opaque)?);
+ let result = ice_candidate_list.add(env, &jni_opaque);
+ if result.is_err() {
+ error!("ice_candidate_list.add: {:?}", result.err());
+ continue;
+ }
}
- };
- for candidate in send.ice.candidates {
- let jni_opaque = JObject::from(env.byte_array_from_slice(&candidate.opaque)?);
- let result = ice_candidate_list.add(env, &jni_opaque);
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onSendIceCandidates"),
+ (
+ call_id_jlong => long,
+ jni_remote => org.signal.ringrtc.Remote,
+ receiver_device_id => int,
+ broadcast => boolean,
+ ice_candidate_list => java.util.List,
+ ) -> void
+ );
if result.is_err() {
- error!("ice_candidate_list.add: {:?}", result.err());
- continue;
+ error!("jni_call_method: {:?}", result.err());
}
- }
- let result = jni_call_method(
- env,
- jni_call_manager,
- "onSendIceCandidates",
- jni_args!((
- call_id_jlong => long,
- jni_remote => org.signal.ringrtc.Remote,
- receiver_device_id => int,
- broadcast => boolean,
- ice_candidate_list => java.util.List,
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
-
- Ok(())
- })?;
-
- Ok(())
+ Ok(())
+ })
+ })
}
fn on_send_hangup(
@@ -681,40 +635,33 @@ impl Platform for AndroidPlatform {
info!("on_send_hangup(): call_id: {}", call_id);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ let jni_remote = remote_peer.as_obj();
+ let call_id_jlong = u64::from(call_id) as jlong;
+ let receiver_device_id = receiver_device_id as jint;
- let jni_remote = remote_peer.as_obj();
- let call_id_jlong = u64::from(call_id) as jlong;
- let receiver_device_id = receiver_device_id as jint;
+ let (hangup_type, hangup_device_id) = send.hangup.to_type_and_device_id();
+ // We set the device_id to 0 in case it is not defined. It will
+ // only be used for hangup types other than Normal.
+ let hangup_device_id = hangup_device_id.unwrap_or(0) as jint;
+ let jni_hangup_type = HangupType::from_native_index(env, hangup_type as i32)?.auto();
- let (hangup_type, hangup_device_id) = send.hangup.to_type_and_device_id();
- // We set the device_id to 0 in case it is not defined. It will
- // only be used for hangup types other than Normal.
- let hangup_device_id = hangup_device_id.unwrap_or(0) as jint;
- let jni_hangup_type =
- match self.java_enum(env, CALL_MANAGER_CLASS, "HangupType", hangup_type as i32) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- return Err(error);
- }
- };
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onSendHangup"),
+ (
+ call_id_jlong => long,
+ jni_remote => org.signal.ringrtc.Remote,
+ receiver_device_id => int,
+ broadcast => boolean,
+ jni_hangup_type => org.signal.ringrtc.CallManager::HangupType,
+ hangup_device_id => int,
+ ) -> void
+ )?;
- jni_call_method(
- env,
- jni_call_manager,
- "onSendHangup",
- jni_args!((
- call_id_jlong => long,
- jni_remote => org.signal.ringrtc.Remote,
- receiver_device_id => int,
- broadcast => boolean,
- jni_hangup_type => org.signal.ringrtc.CallManager::HangupType,
- hangup_device_id => int,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
fn on_send_busy(&self, remote_peer: &Self::AppRemotePeer, call_id: CallId) -> Result<()> {
@@ -724,26 +671,25 @@ impl Platform for AndroidPlatform {
info!("on_send_busy(): call_id: {}", call_id);
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ let jni_remote = remote_peer.as_obj();
+ let call_id_jlong = u64::from(call_id) as jlong;
+ let receiver_device_id = receiver_device_id as jint;
- let jni_remote = remote_peer.as_obj();
- let call_id_jlong = u64::from(call_id) as jlong;
- let receiver_device_id = receiver_device_id as jint;
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onSendBusy"),
+ (
+ call_id_jlong => long,
+ jni_remote => org.signal.ringrtc.Remote,
+ receiver_device_id => int,
+ broadcast => boolean,
+ ) -> void
+ )?;
- jni_call_method(
- env,
- jni_call_manager,
- "onSendBusy",
- jni_args!((
- call_id_jlong => long,
- jni_remote => org.signal.ringrtc.Remote,
- receiver_device_id => int,
- broadcast => boolean,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
fn send_call_message(
@@ -752,33 +698,30 @@ impl Platform for AndroidPlatform {
message: Vec,
urgency: group_call::SignalingMessageUrgency,
) -> Result<()> {
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (2).
+ let capacity = 7;
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let jni_recipient_uuid = JObject::from(env.byte_array_from_slice(&recipient_uuid)?);
+ let jni_message = JObject::from(env.byte_array_from_slice(&message)?);
- // Set a frame capacity of min (5) + objects (2).
- let capacity = 7;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let jni_recipient_uuid = JObject::from(env.byte_array_from_slice(&recipient_uuid)?);
- let jni_message = JObject::from(env.byte_array_from_slice(&message)?);
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("sendCallMessage"),
+ (
+ jni_recipient_uuid => [byte],
+ jni_message => [byte],
+ urgency as i32 => int,
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
+ }
- let result = jni_call_method(
- env,
- jni_call_manager,
- "sendCallMessage",
- jni_args!((
- jni_recipient_uuid => [byte],
- jni_message => [byte],
- urgency as i32 => int,
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
-
- Ok(())
- })?;
-
- Ok(())
+ Ok(())
+ })
+ })
}
fn send_call_message_to_group(
@@ -788,53 +731,50 @@ impl Platform for AndroidPlatform {
urgency: group_call::SignalingMessageUrgency,
recipients_override: HashSet,
) -> Result<()> {
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (3) + elements (N * 1 object per element).
+ let capacity = 8 + recipients_override.len();
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let jni_group_id = JObject::from(env.byte_array_from_slice(&group_id)?);
- // Set a frame capacity of min (5) + objects (3) + elements (N * 1 object per element).
- let capacity = (8 + recipients_override.len()) as i32;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let jni_group_id = JObject::from(env.byte_array_from_slice(&group_id)?);
+ let list = JArrayList::with_capacity(env, recipients_override.len() as jint)?;
+ let recipients_override_list = jni::objects::JList::cast_local(env, list)?;
+ for recipient in recipients_override {
+ let jni_opaque_user_id = match env.byte_array_from_slice(&recipient) {
+ Ok(v) => JObject::from(v),
+ Err(error) => {
+ error!("{:?}", error);
+ continue;
+ }
+ };
- let list = jni_new_arraylist(env, recipients_override.len())?;
- let recipients_override_list = env.get_list(&list)?;
- for recipient in recipients_override {
- let jni_opaque_user_id = match env.byte_array_from_slice(&recipient) {
- Ok(v) => JObject::from(v),
- Err(error) => {
- error!("{:?}", error);
+ let result = recipients_override_list.add(env, &jni_opaque_user_id);
+ if result.is_err() {
+ error!("{:?}", result.err());
continue;
}
- };
-
- let result = recipients_override_list.add(env, &jni_opaque_user_id);
- if result.is_err() {
- error!("{:?}", result.err());
- continue;
}
- }
- let jni_message = JObject::from(env.byte_array_from_slice(&message)?);
+ let jni_message = JObject::from(env.byte_array_from_slice(&message)?);
- let result = jni_call_method(
- env,
- jni_call_manager,
- "sendCallMessageToGroup",
- jni_args!((
- jni_group_id => [byte],
- jni_message => [byte],
- urgency as i32 => int,
- recipients_override_list => java.util.List,
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("sendCallMessageToGroup"),
+ (
+ jni_group_id => [byte],
+ jni_message => [byte],
+ urgency as i32 => int,
+ recipients_override_list => java.util.List,
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
+ }
- Ok(())
- })?;
-
- Ok(())
+ Ok(())
+ })
+ })
}
fn send_call_message_to_adhoc_group(
@@ -844,59 +784,56 @@ impl Platform for AndroidPlatform {
expiration: u64,
recipients_to_endorsements: HashMap>,
) -> Result<()> {
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (3) + key-values (2 objects per pair).
+ let capacity = 8 + 2 * recipients_to_endorsements.len();
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let map = JHashMap::with_capacity(env, recipients_to_endorsements.len() as jint)?;
+ let jni_recipients_map = jni::objects::JMap::cast_local(env, map)?;
+ for (recipient, endorsement) in recipients_to_endorsements {
+ let jni_opaque_user_id = match env.byte_array_from_slice(&recipient) {
+ Ok(v) => JObject::from(v),
+ Err(error) => {
+ error!("{:?}", error);
+ continue;
+ }
+ };
+ let jni_endorsement = match env.byte_array_from_slice(&endorsement) {
+ Ok(v) => JObject::from(v),
+ Err(error) => {
+ error!("{:?}", error);
+ continue;
+ }
+ };
- // Set a frame capacity of min (5) + objects (3) + key-values (2 objects per pair).
- let capacity = (8 + (2 * recipients_to_endorsements.len())) as i32;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let map = jni_new_hashmap(env, recipients_to_endorsements.len())?;
- let jni_recipients_map = env.get_map(&map)?;
- for (recipient, endorsement) in recipients_to_endorsements {
- let jni_opaque_user_id = match env.byte_array_from_slice(&recipient) {
- Ok(v) => JObject::from(v),
- Err(error) => {
- error!("{:?}", error);
+ let result = jni_recipients_map.put(env, &jni_opaque_user_id, &jni_endorsement);
+ if result.is_err() {
+ error!("{:?}", result.err());
continue;
}
- };
- let jni_endorsement = match env.byte_array_from_slice(&endorsement) {
- Ok(v) => JObject::from(v),
- Err(error) => {
- error!("{:?}", error);
- continue;
- }
- };
-
- let result = jni_recipients_map.put(env, &jni_opaque_user_id, &jni_endorsement);
- if result.is_err() {
- error!("{:?}", result.err());
- continue;
}
- }
- let jni_message = JObject::from(env.byte_array_from_slice(&message)?);
- let jni_expiration = expiration as jlong;
+ let jni_message = JObject::from(env.byte_array_from_slice(&message)?);
+ let jni_expiration = expiration as jlong;
- let result = jni_call_method(
- env,
- jni_call_manager,
- "sendCallMessageToAdhocGroup",
- jni_args!((
- jni_message => [byte],
- urgency as i32 => int,
- jni_expiration => long,
- jni_recipients_map => java.util.Map,
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("sendCallMessageToAdhocGroup"),
+ (
+ jni_message => [byte],
+ urgency as i32 => int,
+ jni_expiration => long,
+ jni_recipients_map => java.util.Map,
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
+ }
- Ok(())
- })?;
-
- Ok(())
+ Ok(())
+ })
+ })
}
fn create_incoming_media(
@@ -915,43 +852,40 @@ impl Platform for AndroidPlatform {
) -> Result<()> {
info!("connect_incoming_media():");
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
-
let jni_call_context = app_call_context.to_jni();
- let jni_media_stream = incoming_media.global_ref(env)?;
+ self.with_java_env(|env| {
+ let jni_media_stream = incoming_media.global_ref(env)?;
- jni_call_method(
- env,
- jni_call_manager,
- "onConnectMedia",
- jni_args!((
- jni_call_context.as_obj() => org.signal.ringrtc.CallManager::CallContext,
- jni_media_stream.as_obj() => org.webrtc.MediaStream,
- ) -> void),
- )?;
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onConnectMedia"),
+ (
+ jni_call_context.as_obj() => org.signal.ringrtc.CallManager::CallContext,
+ jni_media_stream.as_obj() => org.webrtc.MediaStream,
+ ) -> void
+ )?;
- Ok(())
+ Ok(())
+ })
}
fn disconnect_incoming_media(&self, app_call_context: &Self::AppCallContext) -> Result<()> {
info!("disconnect_incoming_media():");
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
-
let jni_call_context = app_call_context.to_jni();
+ self.with_java_env(|env| {
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onCloseMedia"),
+ (
+ jni_call_context.as_obj() => org.signal.ringrtc.CallManager::CallContext,
+ ) -> void
+ )?;
- jni_call_method(
- env,
- jni_call_manager,
- "onCloseMedia",
- jni_args!((
- jni_call_context.as_obj() => org.signal.ringrtc.CallManager::CallContext,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
fn compare_remotes(
@@ -961,23 +895,23 @@ impl Platform for AndroidPlatform {
) -> Result {
info!("remotes_equal():");
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ let jni_remote1 = remote_peer1.as_obj();
+ let jni_remote2 = remote_peer2.as_obj();
- let jni_remote1 = remote_peer1.as_obj();
- let jni_remote2 = remote_peer2.as_obj();
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("compareRemotes"),
+ (
+ jni_remote1 => org.signal.ringrtc.Remote,
+ jni_remote2 => org.signal.ringrtc.Remote,
+ ) -> boolean
+ )?
+ .into_bool()?;
- let result = jni_call_method(
- env,
- jni_call_manager,
- "compareRemotes",
- jni_args!((
- jni_remote1 => org.signal.ringrtc.Remote,
- jni_remote2 => org.signal.ringrtc.Remote,
- ) -> boolean),
- )?;
-
- Ok(result != 0)
+ Ok(result)
+ })
}
fn on_offer_expired(
@@ -993,21 +927,18 @@ impl Platform for AndroidPlatform {
fn on_call_concluded(&self, remote_peer: &Self::AppRemotePeer, _call_id: CallId) -> Result<()> {
info!("on_call_concluded():");
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
+ self.with_java_env(|env| {
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("onCallConcluded"),
+ (
+ remote_peer.as_obj() => org.signal.ringrtc.Remote,
+ ) -> void
+ )?;
- let jni_remote_peer = remote_peer.as_obj();
-
- jni_call_method(
- env,
- jni_call_manager,
- "onCallConcluded",
- jni_args!((
- jni_remote_peer => org.signal.ringrtc.Remote,
- ) -> void),
- )?;
-
- Ok(())
+ Ok(())
+ })
}
// Group Calls
@@ -1021,39 +952,28 @@ impl Platform for AndroidPlatform {
) {
info!("group_call_ring_update():");
- if let Ok(env) = &mut self.java_env() {
- let group_id = match env.byte_array_from_slice(&group_id) {
- Ok(slice) => JObject::from(slice),
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
+ let _ = self.with_java_env(|env| {
+ let group_id = JObject::from(env.byte_array_from_slice(&group_id)?);
let ring_id = jlong::from(ring_id);
- let sender = match env.byte_array_from_slice(&sender) {
- Ok(slice) => JObject::from(slice),
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
+ let sender = JObject::from(env.byte_array_from_slice(&sender)?);
let update = update as jint;
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "groupCallRingUpdate",
- jni_args!((
+ jni_str!("groupCallRingUpdate"),
+ (
group_id => [byte],
ring_id => long,
sender => [byte],
update => int,
- ) -> void),
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
fn request_membership_proof(&self, client_id: group_call::ClientId) {
@@ -1073,34 +993,25 @@ impl Platform for AndroidPlatform {
) {
info!("handle_connection_state_changed():");
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
let jni_client_id = client_id as jlong;
- let jni_connection_state = match self.java_enum(
- env,
- GROUP_CALL_CLASS,
- "ConnectionState",
- connection_state.ordinal(),
- ) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
+ let jni_connection_state =
+ ConnectionState::from_native_index(env, connection_state.ordinal())?.auto();
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleConnectionStateChanged",
- jni_args!((
+ jni_str!("handleConnectionStateChanged"),
+ (
jni_client_id => long,
- jni_connection_state => org.signal.ringrtc.GroupCall::ConnectionState
- ) -> void),
+ jni_connection_state => org.signal.ringrtc.GroupCall::ConnectionState,
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
fn handle_network_route_changed(
@@ -1113,17 +1024,18 @@ impl Platform for AndroidPlatform {
client_id, network_route
);
- if let Ok(env) = &mut self.java_env() {
- let _ = jni_call_method(
+ let _ = self.with_java_env(|env| {
+ jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleNetworkRouteChanged",
- jni_args!((
+ jni_str!("handleNetworkRouteChanged"),
+ (
client_id as jlong => long,
network_route.local_adapter_type as i32 => int,
- ) -> void),
- );
- }
+ ) -> void
+ )?;
+ Ok(())
+ });
}
fn handle_speaking_notification(
@@ -1136,26 +1048,20 @@ impl Platform for AndroidPlatform {
client_id, event
);
- if let Ok(env) = &mut self.java_env() {
- let jni_speech_event =
- match self.java_enum(env, GROUP_CALL_CLASS, "SpeechEvent", event.ordinal()) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
+ let _ = self.with_java_env(|env| {
+ let jni_speech_event = SpeechEvent::from_native_index(env, event.ordinal())?.auto();
- let _ = jni_call_method(
+ jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleSpeakingNotification",
- jni_args!((
+ jni_str!("handleSpeakingNotification"),
+ (
client_id as jlong => long,
- jni_speech_event => org.signal.ringrtc.GroupCall::SpeechEvent
- ) -> void),
- );
- }
+ jni_speech_event => org.signal.ringrtc.GroupCall::SpeechEvent,
+ ) -> void
+ )?;
+ Ok(())
+ });
}
fn handle_audio_levels(
@@ -1169,31 +1075,28 @@ impl Platform for AndroidPlatform {
client_id, captured_level, received_levels,
);
- if let Ok(mut env) = self.java_env() {
+ let _ = self.with_java_env(|env| {
// Set a frame capacity of min (5) + objects (2) + elements (N * 2 per level).
- let capacity = (5 + 2 + received_levels.len() * 2) as i32;
+ let capacity = 5 + 2 + received_levels.len() * 2;
if let Err(e) = env.with_local_frame(capacity, |env| -> Result<()> {
// create Java List
let received_level_class =
- self.class_cache.get_class(RECEIVED_AUDIO_LEVEL_CLASS)?;
+ JReceivedAudioLevel::lookup_class(env, &LoaderContext::default())?;
- let list = jni_new_arraylist(env, received_levels.len())?;
- let received_levels_list = env.get_list(&list)?;
+ let list = JArrayList::with_capacity(env, received_levels.len() as jint)?;
+ let received_levels_list = jni::objects::JList::cast_local(env, list)?;
for received in received_levels {
- let args = jni_args!((
+ let received_level_obj = match jni_new_object!(env, &*received_level_class, (
received.demux_id as jlong => long,
received.level as jint => int,
- ) -> void);
-
- let received_level_obj =
- match env.new_object(received_level_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("jni_received_level: {:?}", error);
- continue;
- }
- };
+ )) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("jni_received_level: {:?}", error);
+ continue;
+ }
+ };
let result = received_levels_list.add(env, &received_level_obj);
if result.is_err() {
@@ -1202,22 +1105,23 @@ impl Platform for AndroidPlatform {
}
}
- let _ = jni_call_method(
+ let _ = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleAudioLevels",
- jni_args!((
+ jni_str!("handleAudioLevels"),
+ (
client_id as jlong => long,
captured_level as jint => int,
received_levels_list => java.util.List,
- ) -> void),
+ ) -> void
);
Ok(())
}) {
error!("handle_audio_levels: {:?}", e);
}
- }
+ Ok(())
+ });
}
fn handle_low_bandwidth_for_video(&self, client_id: group_call::ClientId, recovered: bool) {
@@ -1226,23 +1130,23 @@ impl Platform for AndroidPlatform {
client_id, recovered
);
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
// Set a frame capacity of min (5).
let capacity = 5;
- let _ = env.with_local_frame(capacity, |env| -> Result<()> {
- let _ = jni_call_method(
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let _ = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleLowBandwidthForVideo",
- jni_args!((
+ jni_str!("handleLowBandwidthForVideo"),
+ (
client_id as jlong => long,
recovered => boolean,
- ) -> void),
+ ) -> void
);
Ok(())
- });
- }
+ })
+ });
}
fn handle_reactions(
@@ -1255,24 +1159,22 @@ impl Platform for AndroidPlatform {
client_id, reactions,
);
- if let Ok(mut env) = self.java_env() {
+ let _ = self.with_java_env(|env| {
// Set a frame capacity of min (5) + objects (1) + elements (N * 2 per reaction).
- let capacity = (5 + 1 + reactions.len() * 2) as i32;
+ let capacity = 5 + 1 + reactions.len() * 2;
if let Err(e) = env.with_local_frame(capacity, |env| -> Result<()> {
// create Java List
- let reaction_class = self.class_cache.get_class(REACTION_CLASS)?;
+ let reaction_class = Reaction::lookup_class(env, &LoaderContext::default())?;
- let list = jni_new_arraylist(env, reactions.len())?;
- let reactions_list = env.get_list(&list)?;
+ let list = JArrayList::with_capacity(env, reactions.len() as jint)?;
+ let reactions_list = jni::objects::JList::cast_local(env, list)?;
for reaction in reactions {
let jni_value = JObject::from(env.new_string(reaction.value)?);
- let args = jni_args!((
+ let reaction_obj = match jni_new_object!(env, &*reaction_class, (
reaction.demux_id as jlong => long,
jni_value => java.lang.String,
- ) -> void);
-
- let reaction_obj = match env.new_object(reaction_class, args.sig, &args.args) {
+ )) {
Ok(v) => v,
Err(error) => {
error!("jni_reaction: {:?}", error);
@@ -1287,21 +1189,22 @@ impl Platform for AndroidPlatform {
}
}
- let _ = jni_call_method(
+ let _ = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleReactions",
- jni_args!((
+ jni_str!("handleReactions"),
+ (
client_id as jlong => long,
reactions_list => java.util.List,
- ) -> void),
+ ) -> void
);
Ok(())
}) {
error!("handle_reactions: {:?}", e);
}
- }
+ Ok(())
+ });
}
fn handle_raised_hands(&self, client_id: group_call::ClientId, raised_hands: Vec) {
@@ -1310,24 +1213,16 @@ impl Platform for AndroidPlatform {
client_id, raised_hands,
);
- if let Ok(mut env) = self.java_env() {
+ let _ = self.with_java_env(|env| {
// Set a frame capacity of min (5) + objects (1) + N elements.
- let capacity = (5 + 1 + raised_hands.len()) as i32;
+ let capacity = 5 + 1 + raised_hands.len();
if let Err(e) = env.with_local_frame(capacity, |env| -> Result<()> {
// create Java List
- let long_class = self
- .class_cache
- .get_class(jni_class_name!(java.lang.Long))?;
-
- let list = jni_new_arraylist(env, raised_hands.len())?;
- let raised_hands_list = env.get_list(&list)?;
+ let list = JArrayList::with_capacity(env, raised_hands.len() as jint)?;
+ let raised_hands_list = jni::objects::JList::cast_local(env, list)?;
for raised_hand in raised_hands {
- let args = jni_args!((
- raised_hand as jlong => long,
- ) -> void);
-
- let raised_hand_obj = match env.new_object(long_class, args.sig, &args.args) {
+ let raised_hand_obj = match JLong::new(env, raised_hand as jlong) {
Ok(v) => v,
Err(error) => {
error!("jni_raised_hands: {:?}", error);
@@ -1342,21 +1237,22 @@ impl Platform for AndroidPlatform {
}
}
- let _ = jni_call_method(
+ let _ = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleRaisedHands",
- jni_args!((
+ jni_str!("handleRaisedHands"),
+ (
client_id as jlong => long,
raised_hands_list => java.util.List,
- ) -> void),
+ ) -> void
);
Ok(())
}) {
error!("handle_raised_hands: {:?}", e);
}
- }
+ Ok(())
+ });
}
fn handle_join_state_changed(
@@ -1366,44 +1262,32 @@ impl Platform for AndroidPlatform {
) {
info!("handle_join_state_changed():");
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
let jni_client_id = client_id as jlong;
- let jni_join_state =
- match self.java_enum(env, GROUP_CALL_CLASS, "JoinState", join_state.ordinal()) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
+ let jni_join_state = JoinState::from_native_index(env, join_state.ordinal())?.auto();
let jni_demux_id = match join_state {
group_call::JoinState::Pending(demux_id)
| group_call::JoinState::Joined(demux_id) => {
- match self.get_optional_u32_long_object(env, Some(demux_id)) {
- Ok(v) => v,
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- }
+ self.get_optional_u32_long_object(env, Some(demux_id))?
}
_ => JObject::null(),
};
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleJoinStateChanged",
- jni_args!((
+ jni_str!("handleJoinStateChanged"),
+ (
jni_client_id => long,
jni_join_state => org.signal.ringrtc.GroupCall::JoinState,
- jni_demux_id => java.lang.Long
- ) -> void),
+ jni_demux_id => java.lang.Long,
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
fn handle_remote_devices_changed(
@@ -1414,18 +1298,18 @@ impl Platform for AndroidPlatform {
) {
info!("handle_remote_devices_changed():");
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
// Set a frame capacity of min (5) + objects (2) + elements (N * 2 object per element).
- let capacity = (7 + remote_device_states.len() * 2) as i32;
+ let capacity = 7 + remote_device_states.len() * 2;
if let Err(e) = env.with_local_frame(capacity, |env| -> Result<()> {
let jni_client_id = client_id as jlong;
// create Java List
let remote_device_state_class =
- self.class_cache.get_class(REMOTE_DEVICE_STATE_CLASS)?;
+ RemoteDeviceState::lookup_class(env, &LoaderContext::default())?;
- let list = jni_new_arraylist(env, remote_device_states.len())?;
- let remote_device_state_list = env.get_list(&list)?;
+ let list = JArrayList::with_capacity(env, remote_device_states.len() as jint)?;
+ let remote_device_state_list = jni::objects::JList::cast_local(env, list)?;
for remote_device_state in remote_device_states {
let jni_demux_id = remote_device_state.demux_id as jlong;
@@ -1490,28 +1374,29 @@ impl Platform for AndroidPlatform {
}
};
- let args = jni_args!((
- jni_demux_id => long,
- jni_user_id_byte_array => [byte],
- remote_device_state.media_keys_received => boolean,
- jni_audio_muted => java.lang.Boolean,
- jni_video_muted => java.lang.Boolean,
- jni_presenting => java.lang.Boolean,
- jni_sharing_screen => java.lang.Boolean,
- jni_added_time => long,
- jni_speaker_time => long,
- jni_forwarding_video => java.lang.Boolean,
- remote_device_state.is_higher_resolution_pending => boolean,
- ) -> void);
-
- let remote_device_state_obj =
- match env.new_object(remote_device_state_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("remote_device_state_obj: {:?}", error);
- continue;
- }
- };
+ let remote_device_state_obj = match jni_new_object!(
+ env,
+ &*remote_device_state_class,
+ (
+ jni_demux_id => long,
+ jni_user_id_byte_array => [byte],
+ remote_device_state.media_keys_received => boolean,
+ jni_audio_muted => java.lang.Boolean,
+ jni_video_muted => java.lang.Boolean,
+ jni_presenting => java.lang.Boolean,
+ jni_sharing_screen => java.lang.Boolean,
+ jni_added_time => long,
+ jni_speaker_time => long,
+ jni_forwarding_video => java.lang.Boolean,
+ remote_device_state.is_higher_resolution_pending => boolean,
+ )
+ ) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("remote_device_state_obj: {:?}", error);
+ continue;
+ }
+ };
let result = remote_device_state_list.add(env, &remote_device_state_obj);
if result.is_err() {
@@ -1520,14 +1405,14 @@ impl Platform for AndroidPlatform {
}
}
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleRemoteDevicesChanged",
- jni_args!((
+ jni_str!("handleRemoteDevicesChanged"),
+ (
jni_client_id => long,
remote_device_state_list => java.util.List,
- ) -> void),
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
@@ -1537,7 +1422,8 @@ impl Platform for AndroidPlatform {
}) {
error!("handle_remote_devices_changed {:?}", e);
}
- }
+ Ok(())
+ });
}
fn handle_incoming_video_track(
@@ -1548,26 +1434,27 @@ impl Platform for AndroidPlatform {
) {
info!("handle_incoming_video_track():");
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
let jni_client_id = client_id as jlong;
let jni_remote_demux_id = remote_demux_id as jlong;
let jni_native_video_track_owned_rc =
incoming_video_track.rffi().clone().into_owned().as_ptr() as jlong;
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleIncomingVideoTrack",
- jni_args!((
+ jni_str!("handleIncomingVideoTrack"),
+ (
jni_client_id => long,
jni_remote_demux_id => long,
- jni_native_video_track_owned_rc => long
- ) -> void),
+ jni_native_video_track_owned_rc => long,
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
fn handle_peek_changed(
@@ -1578,10 +1465,10 @@ impl Platform for AndroidPlatform {
) {
info!("handle_peek_changed():");
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
// Set a frame capacity of min (5) + objects (5) + elements (N * 1 object per element).
- let capacity = (10 + joined_members.len()) as i32;
- let _ = env.with_local_frame(capacity, |env| -> Result<()> {
+ let capacity = 10 + joined_members.len();
+ env.with_local_frame(capacity, |env| -> Result<()> {
let jni_client_id = client_id as jlong;
let jni_peek_info =
@@ -1593,22 +1480,22 @@ impl Platform for AndroidPlatform {
}
};
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handlePeekChanged",
- jni_args!((
+ jni_str!("handlePeekChanged"),
+ (
jni_client_id => long,
jni_peek_info => org.signal.ringrtc.PeekInfo,
- ) -> void),
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
Ok(())
- });
- }
+ })
+ });
}
fn handle_ended(
@@ -1619,39 +1506,26 @@ impl Platform for AndroidPlatform {
) {
info!("handle_ended():");
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
let jni_client_id = client_id as jlong;
- let jni_reason =
- match self.java_enum(env, CALL_MANAGER_CLASS, "CallEndReason", reason as i32) {
- Ok(v) => AutoLocal::new(v, env),
- Err(error) => {
- error!("call_end_reason: {:?}", error);
- return;
- }
- };
+ let jni_reason = JCallEndReason::from_native_index(env, reason as i32)?.auto();
+ let jni_summary = self.make_call_summary_object(env, &summary)?;
- let jni_summary = match self.make_call_summary_object(env, &summary) {
- Ok(v) => v,
- Err(e) => {
- error!("make_call_summary_object: {:?}", e);
- return;
- }
- };
-
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleEnded",
- jni_args!((
+ jni_str!("handleEnded"),
+ (
jni_client_id => long,
jni_reason => org.signal.ringrtc.CallManager::CallEndReason,
jni_summary => org.signal.ringrtc.CallSummary,
- ) -> void),
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
fn handle_remote_mute_request(&self, client_id: group_call::ClientId, mute_source: DemuxId) {
@@ -1660,23 +1534,24 @@ impl Platform for AndroidPlatform {
client_id, mute_source,
);
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
let jni_client_id = client_id as jlong;
let jni_mute_source = mute_source as jlong;
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleRemoteMuteRequest",
- jni_args!((
+ jni_str!("handleRemoteMuteRequest"),
+ (
jni_client_id => long,
jni_mute_source => long,
- ) -> void),
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
fn handle_observed_remote_mute(
@@ -1690,204 +1565,124 @@ impl Platform for AndroidPlatform {
client_id, mute_source, mute_target
);
- if let Ok(env) = &mut self.java_env() {
+ let _ = self.with_java_env(|env| {
let jni_client_id = client_id as jlong;
let jni_mute_source = mute_source as jlong;
let jni_mute_target = mute_target as jlong;
- let result = jni_call_method(
+ let result = jni_call_method!(
env,
self.jni_call_manager.as_obj(),
- "handleObservedRemoteMute",
- jni_args!((
+ jni_str!("handleObservedRemoteMute"),
+ (
jni_client_id => long,
jni_mute_source => long,
jni_mute_target => long,
- ) -> void),
+ ) -> void
);
if result.is_err() {
error!("jni_call_method: {:?}", result.err());
}
- }
+ Ok(())
+ });
}
}
impl AndroidPlatform {
/// Create a new AndroidPlatform object.
- pub fn new(env: &mut JNIEnv, jni_call_manager: GlobalRef) -> Result {
- let mut class_cache = ClassCache::new();
- for class in &[
- jni_class_name!(org.signal.ringrtc.CallManager::CallEvent),
- jni_class_name!(org.signal.ringrtc.CallManager::CallMediaType),
- jni_class_name!(org.signal.ringrtc.CallManager::HangupType),
- jni_class_name!(org.signal.ringrtc.CallManager::HttpMethod),
- jni_class_name!(org.signal.ringrtc.CallManager::CallEndReason),
- jni_class_name!(org.signal.ringrtc.GroupCall::ConnectionState),
- jni_class_name!(org.signal.ringrtc.GroupCall::JoinState),
- jni_class_name!(org.signal.ringrtc.GroupCall::SpeechEvent),
- CALL_LINK_STATE_CLASS,
- CALL_LINK_ROOT_KEY_CLASS,
- HTTP_HEADER_CLASS,
- HTTP_RESULT_CLASS,
- PEEK_INFO_CLASS,
- REACTION_CLASS,
- REMOTE_DEVICE_STATE_CLASS,
- RECEIVED_AUDIO_LEVEL_CLASS,
- CALL_SUMMARY_CLASS,
- CALL_SUMMARY_QUALITY_STATS_CLASS,
- CALL_SUMMARY_MEDIA_QUALITY_STATS_CLASS,
- jni_class_name!(java.lang.Boolean),
- jni_class_name!(java.lang.Float),
- jni_class_name!(java.lang.Integer),
- jni_class_name!(java.lang.Long),
- ] {
- class_cache.add_class(env, class)?;
- }
+ pub fn new(env: &mut Env, jni_call_manager: Global>) -> Result {
+ types::init_class_cache(env)?;
Ok(Self {
jvm: env.get_java_vm()?,
jni_call_manager,
- class_cache,
})
}
- /// Return the Java JNIEnv.
- fn java_env(&self) -> Result> {
- Ok(self.jvm.attach_current_thread_as_daemon()?.into())
+ /// Run a closure with a JNI Env attached to the current thread.
+ ///
+ /// If the function `f` leaves a Java exception pending, for example, if
+ /// the Java callback threw. Reports uncaught exceptions on destruction.
+ fn with_java_env(&self, f: F) -> Result
+ where
+ F: FnOnce(&mut jni::Env) -> Result,
+ {
+ self.jvm.attach_current_thread(|env| {
+ let result = f(env);
+ if let Some(exception) = env.exception_occurred() {
+ env.exception_clear();
+ let _ = try_scoped(|| -> Result<()> {
+ let thread = jni_call_static_method!(
+ env,
+ jni_str!("java/lang/Thread"),
+ jni_str!("currentThread"),
+ () -> java.lang.Thread
+ )?
+ .into_object()?;
+ let handler = jni_call_method!(
+ env,
+ &thread,
+ jni_str!("getUncaughtExceptionHandler"),
+ () -> java.lang.Thread::UncaughtExceptionHandler
+ )?
+ .into_object()?;
+ jni_call_method!(
+ env,
+ &handler,
+ jni_str!("uncaughtException"),
+ (
+ thread => java.lang.Thread,
+ exception => java.lang.Throwable,
+ ) -> void
+ )?;
+ Ok(())
+ });
+ }
+ result
+ })
}
pub fn try_clone(&self) -> Result {
- let env = self.java_env()?;
- Ok(Self {
- jvm: env.get_java_vm()?,
- jni_call_manager: self.jni_call_manager.clone(),
- class_cache: self.class_cache.clone(),
+ self.with_java_env(|env| {
+ Ok(Self {
+ jvm: env.get_java_vm()?,
+ jni_call_manager: env.new_global_ref(self.jni_call_manager.as_obj())?,
+ })
})
}
- fn java_enum<'a>(
- &self,
- env: &mut JNIEnv<'a>,
- parent: &str,
- class: &str,
- value: i32,
- ) -> Result> {
- let class_path = format!("{}/{}${}", RINGRTC_PACKAGE, parent, class);
- let class_object = self.class_cache.get_class(&class_path)?;
- const ENUM_FROM_NATIVE_INDEX_METHOD: &str = "fromNativeIndex";
- let method_signature = format!("(I)L{};", class_path);
- let args = [JValue::from(value)];
- match env.call_static_method(
- class_object,
- ENUM_FROM_NATIVE_INDEX_METHOD,
- &method_signature,
- &args,
- ) {
- Ok(v) => Ok(v.l()?),
- Err(_) => Err(AndroidError::JniCallStaticMethod(
- class_path,
- ENUM_FROM_NATIVE_INDEX_METHOD.to_string(),
- method_signature.to_string(),
- )
- .into()),
- }
- }
-
fn get_optional_boolean_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
value: Option,
) -> Result> {
match value {
None => Ok(JObject::null()),
- Some(value) => {
- let class_name = jni_class_name!(java.lang.Boolean);
- let class = match self.class_cache.get_class(class_name) {
- Ok(v) => v,
- Err(_) => {
- return Err(
- AndroidError::JniGetLangClassNotFound(class_name.to_string()).into(),
- );
- }
- };
-
- let args = jni_args!((value => boolean) -> void);
- let jni_object = match env.new_object(class, args.sig, &args.args) {
- Ok(v) => v,
- Err(_) => {
- return Err(
- AndroidError::JniNewLangObjectFailed(class_name.to_string()).into()
- );
- }
- };
-
- Ok(jni_object)
- }
+ Some(value) => Ok(JBoolean::new(env, value)?.into()),
}
}
// Converts Option to a Java Long.
fn get_optional_u32_long_object<'local>(
&self,
- env: &mut JNIEnv<'local>,
+ env: &mut Env<'local>,
value: Option,
) -> Result> {
match value {
None => Ok(JObject::null()),
- Some(value) => {
- let class_name = jni_class_name!(java.lang.Long);
- let class = match self.class_cache.get_class(class_name) {
- Ok(v) => v,
- Err(_) => {
- return Err(
- AndroidError::JniGetLangClassNotFound(class_name.to_string()).into(),
- );
- }
- };
- let args = jni_args!((value as jni::sys::jlong => long) -> void);
- let jni_object = match env.new_object(class, args.sig, &args.args) {
- Ok(v) => v,
- Err(_) => {
- return Err(
- AndroidError::JniNewLangObjectFailed(class_name.to_string()).into()
- );
- }
- };
-
- Ok(jni_object)
- }
+ Some(value) => Ok(JLong::new(env, value as jlong)?.into()),
}
}
// Converts Option to Java Float.
fn get_optional_f32_float_object<'local>(
&self,
- env: &mut JNIEnv<'local>,
+ env: &mut Env<'local>,
value: Option,
) -> Result> {
match value {
None => Ok(JObject::null()),
- Some(value) => {
- let class_name = jni_class_name!(java.lang.Float);
- let class = match self.class_cache.get_class(class_name) {
- Ok(v) => v,
- Err(_) => {
- return Err(
- AndroidError::JniGetLangClassNotFound(class_name.to_string()).into(),
- );
- }
- };
- let args = jni_args!((value as jni::sys::jfloat => float) -> void);
- let jni_object = match env.new_object(class, args.sig, &args.args) {
- Ok(v) => v,
- Err(_) => {
- return Err(
- AndroidError::JniNewLangObjectFailed(class_name.to_string()).into()
- );
- }
- };
- Ok(jni_object)
- }
+ Some(value) => Ok(JFloat::new(env, value)?.into()),
}
}
@@ -1901,16 +1696,13 @@ impl AndroidPlatform {
body,
} = request;
- let env = &mut self.java_env()?;
- let jni_call_manager = self.jni_call_manager.as_obj();
-
- // Set a frame capacity of min (5) + objects (4) + elements (N * 3 objects per element).
- let capacity = (9 + headers.len() * 3) as i32;
- env.with_local_frame(capacity, |env| -> Result<()> {
- let jni_request_id = request_id as jlong;
- let jni_url = JObject::from(env.new_string(url)?);
- let jni_method =
- match self.java_enum(env, CALL_MANAGER_CLASS, "HttpMethod", method as i32) {
+ self.with_java_env(|env| {
+ // Set a frame capacity of min (5) + objects (4) + elements (N * 3 objects per element).
+ let capacity = 9 + headers.len() * 3;
+ env.with_local_frame(capacity, |env| -> Result<()> {
+ let jni_request_id = request_id as jlong;
+ let jni_url = JObject::from(env.new_string(url)?);
+ let jni_method = match HttpMethod::from_native_index(env, method as i32) {
Ok(v) => v,
Err(error) => {
error!("jni_method: {:?}", error);
@@ -1918,55 +1710,56 @@ impl AndroidPlatform {
}
};
- // create Java List
- let http_header_class = match self.class_cache.get_class(HTTP_HEADER_CLASS) {
- Ok(v) => v,
- Err(error) => {
- error!("http_header_class: {:?}", error);
- return Ok(());
+ // create Java List
+ let http_header_class =
+ match HttpHeader::lookup_class(env, &LoaderContext::default()) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("http_header_class: {:?}", error);
+ return Ok(());
+ }
+ };
+ let list = JArrayList::with_capacity(env, headers.len() as jint)?;
+ let jni_headers = match jni::objects::JList::cast_local(env, list) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("jni_headers: {:?}", error);
+ return Ok(());
+ }
+ };
+ for (name, value) in headers.iter() {
+ let jni_name = JObject::from(env.new_string(name)?);
+ let jni_value = JObject::from(env.new_string(value)?);
+ let http_header_obj = jni_new_object!(env, &*http_header_class, (
+ jni_name => java.lang.String,
+ jni_value => java.lang.String,
+ ))?;
+ jni_headers.add(env, &http_header_obj)?;
}
- };
- let list = jni_new_arraylist(env, headers.len())?;
- let jni_headers = match env.get_list(&list) {
- Ok(v) => v,
- Err(error) => {
- error!("jni_headers: {:?}", error);
- return Ok(());
+
+ let jni_body = match body {
+ None => JObject::null(),
+ Some(body) => JObject::from(env.byte_array_from_slice(&body)?),
+ };
+
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("sendHttpRequest"),
+ (
+ jni_request_id => long,
+ jni_url => java.lang.String,
+ jni_method => org.signal.ringrtc.CallManager::HttpMethod,
+ jni_headers => java.util.List,
+ jni_body => [byte],
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
}
- };
- for (name, value) in headers.iter() {
- let jni_name = JObject::from(env.new_string(name)?);
- let jni_value = JObject::from(env.new_string(value)?);
- let args = jni_args!((
- jni_name => java.lang.String,
- jni_value => java.lang.String,
- ) -> void);
- let http_header_obj = env.new_object(http_header_class, args.sig, &args.args)?;
- jni_headers.add(env, &http_header_obj)?;
- }
- let jni_body = match body {
- None => JObject::null(),
- Some(body) => JObject::from(env.byte_array_from_slice(&body)?),
- };
-
- let result = jni_call_method(
- env,
- jni_call_manager,
- "sendHttpRequest",
- jni_args!((
- jni_request_id => long,
- jni_url => java.lang.String,
- jni_method => org.signal.ringrtc.CallManager::HttpMethod,
- jni_headers => java.util.List,
- jni_body => [byte],
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
-
- Ok(())
+ Ok(())
+ })
})
}
@@ -1975,74 +1768,34 @@ impl AndroidPlatform {
request_id: u32,
response: std::result::Result,
) {
- let mut env = match self.java_env() {
- Ok(v) => v,
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
- let jni_call_manager = self.jni_call_manager.as_obj();
+ let _ = self.with_java_env(|env| {
+ let http_result_class = HttpResult::lookup_class(env, &LoaderContext::default())?;
- let http_result_class = match self.class_cache.get_class(HTTP_RESULT_CLASS) {
- Ok(v) => v,
- Err(error) => {
- error!("http_result_class: {:?}", error);
- return;
- }
- };
-
- let result_object = match response {
- Ok(result) => {
- let call_link_state = Some(result);
- match self.make_call_link_state_object(&mut env, &call_link_state) {
- Ok(state) => {
- // Unconstrained generics get erased to java.lang.Object.
- let args = jni_args!((
- state => java.lang.Object,
- ) -> void);
- match env.new_object(http_result_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("new HttpResult(CallLinkState): {:?}", error);
- return;
- }
- }
- }
- Err(error) => {
- error!("new CallLinkState: {:?}", error);
- return;
- }
+ let result_object = match response {
+ Ok(result) => {
+ let call_link_state = Some(result);
+ let state = self.make_call_link_state_object(env, &call_link_state)?;
+ // Unconstrained generics get erased to java.lang.Object.
+ jni_new_object!(env, &*http_result_class, (
+ state => java.lang.Object,
+ ))?
}
- }
- Err(status) => {
- let args = jni_args!((
+ Err(status) => jni_new_object!(env, &*http_result_class, (
status.code as jshort => short,
- ) -> void);
- match env.new_object(http_result_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("new HttpResult(short): {:?}", error);
- return;
- }
- }
- }
- };
+ ))?,
+ };
- match jni_call_method(
- &mut env,
- jni_call_manager,
- "handleCallLinkResponse",
- jni_args!((
- request_id as jlong => long,
- result_object => org.signal.ringrtc.CallManager::HttpResult,
- ) -> void),
- ) {
- Ok(()) => {}
- Err(error) => {
- error!("handleCallLinkResponse: {:?}", error);
- }
- }
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("handleCallLinkResponse"),
+ (
+ request_id as jlong => long,
+ result_object => org.signal.ringrtc.CallManager::HttpResult,
+ ) -> void
+ )?;
+ Ok(())
+ });
}
pub fn handle_empty_result(
@@ -2050,91 +1803,50 @@ impl AndroidPlatform {
request_id: u32,
response: std::result::Result,
) {
- let mut env = match self.java_env() {
- Ok(v) => v,
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
- let jni_call_manager = self.jni_call_manager.as_obj();
+ let _ = self.with_java_env(|env| {
+ let http_result_class = HttpResult::lookup_class(env, &LoaderContext::default())?;
- let http_result_class = match self.class_cache.get_class(HTTP_RESULT_CLASS) {
- Ok(v) => v,
- Err(error) => {
- error!("http_result_class: {:?}", error);
- return;
- }
- };
+ let result_object = match response {
+ Ok(_) => {
+ // need to provide a non-null Object, so we use java.lang.Boolean
+ let success_filler = self.get_optional_boolean_object(env, Some(true))?;
- let result_object = match response {
- Ok(_) => {
- // need to provide a non-null Object, so we use java.lang.Boolean
- let success_filler = match self.get_optional_boolean_object(&mut env, Some(true)) {
- Ok(v) => v,
- Err(error) => {
- error!("empty result success filler java.lang.Boolean: {:?}", error);
- return;
- }
- };
-
- // Unconstrained generics get erased to java.lang.Object.
- let args = jni_args!((
- success_filler => java.lang.Object,
- ) -> void);
- match env.new_object(http_result_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("new HttpResult(Boolean): {:?}", error);
- return;
- }
+ // Unconstrained generics get erased to java.lang.Object.
+ jni_new_object!(env, &*http_result_class, (
+ success_filler => java.lang.Object,
+ ))?
}
- }
- Err(status) => {
- let args = jni_args!((
+ Err(status) => jni_new_object!(env, &*http_result_class, (
status.code as jshort => short,
- ) -> void);
- match env.new_object(http_result_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("new HttpResult(short): {:?}", error);
- return;
- }
- }
- }
- };
+ ))?,
+ };
- match jni_call_method(
- &mut env,
- jni_call_manager,
- "handleEmptyResponse",
- jni_args!((
- request_id as jlong => long,
- result_object => org.signal.ringrtc.CallManager::HttpResult,
- ) -> void),
- ) {
- Ok(()) => {}
- Err(error) => {
- error!("handleEmptyResponse: {:?}", error);
- }
- }
+ jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("handleEmptyResponse"),
+ (
+ request_id as jlong => long,
+ result_object => org.signal.ringrtc.CallManager::HttpResult,
+ ) -> void
+ )?;
+ Ok(())
+ });
}
fn make_media_quality_stats_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
media_quality_stats: &MediaQualityStats,
) -> jni::errors::Result> {
- let media_quality_stats_class = match self
- .class_cache
- .get_class(CALL_SUMMARY_MEDIA_QUALITY_STATS_CLASS)
- {
- Ok(v) => v,
- Err(error) => {
- error!("media_quality_stats_class: {:?}", error);
- return Ok(JObject::null());
- }
- };
+ let media_quality_stats_class =
+ match JMediaQualityStats::lookup_class(env, &LoaderContext::default()) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("media_quality_stats_class: {:?}", error);
+ return Ok(JObject::null());
+ }
+ };
let rtt_median =
match self.get_optional_f32_float_object(env, media_quality_stats.rtt_median) {
Ok(v) => v,
@@ -2178,23 +1890,21 @@ impl AndroidPlatform {
}
};
- let args = jni_args!((
+ jni_new_object!(env, &*media_quality_stats_class, (
rtt_median => java.lang.Float,
jitter_median_send => java.lang.Float,
jitter_median_recv => java.lang.Float,
packet_loss_fraction_send => java.lang.Float,
packet_loss_fraction_recv => java.lang.Float,
- ) -> void);
-
- env.new_object(media_quality_stats_class, args.sig, &args.args)
+ ))
}
fn make_quality_stats_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
quality_stats: &QualityStats,
) -> jni::errors::Result> {
- let quality_stats_class = match self.class_cache.get_class(CALL_SUMMARY_QUALITY_STATS_CLASS)
+ let quality_stats_class = match JQualityStats::lookup_class(env, &LoaderContext::default())
{
Ok(v) => v,
Err(error) => {
@@ -2214,21 +1924,19 @@ impl AndroidPlatform {
let audio_stats = self.make_media_quality_stats_object(env, &quality_stats.audio_stats)?;
let video_stats = self.make_media_quality_stats_object(env, &quality_stats.video_stats)?;
- let args = jni_args!((
+ jni_new_object!(env, &*quality_stats_class, (
rtt_median_connection => java.lang.Float,
audio_stats => org.signal.ringrtc.CallSummary::MediaQualityStats,
- video_stats => org.signal.ringrtc.CallSummary::MediaQualityStats
- ) -> void);
-
- env.new_object(quality_stats_class, args.sig, &args.args)
+ video_stats => org.signal.ringrtc.CallSummary::MediaQualityStats,
+ ))
}
fn make_call_summary_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
call_summary: &CallSummary,
) -> jni::errors::Result> {
- let call_summary_class = match self.class_cache.get_class(CALL_SUMMARY_CLASS) {
+ let call_summary_class = match JCallSummary::lookup_class(env, &LoaderContext::default()) {
Ok(v) => v,
Err(error) => {
error!("call_summary_class: {:?}", error);
@@ -2236,10 +1944,11 @@ impl AndroidPlatform {
}
};
- let call_id_hash = if let Some(id) = call_summary.call_id_hash.as_ref() {
- env.byte_array_from_slice(id)?.into()
- } else {
- JObject::null()
+ let call_id_hash = {
+ match call_summary.call_id_hash.as_ref() {
+ Some(id) => env.byte_array_from_slice(id)?.into(),
+ None => JObject::null(),
+ }
};
let quality_stats_object =
self.make_quality_stats_object(env, &call_summary.quality_stats)?;
@@ -2260,58 +1969,55 @@ impl AndroidPlatform {
let raw_call_end_reason_text = env.new_string(call_summary.call_end_reason_text.clone())?;
let is_survey_candidate = call_summary.is_survey_candidate;
- let args = jni_args!((
- call_id_hash => [byte],
- start_time => long,
- end_time => long,
- quality_stats_object => org.signal.ringrtc.CallSummary::QualityStats,
- raw_stats_object => [byte],
- raw_stats_text => java.lang.String,
- raw_call_end_reason_text => java.lang.String,
- is_survey_candidate => boolean,
- ) -> void);
-
- env.new_object(call_summary_class, args.sig, &args.args)
+ jni_new_object!(env, &*call_summary_class, (
+ call_id_hash => [byte],
+ start_time => long,
+ end_time => long,
+ quality_stats_object => org.signal.ringrtc.CallSummary::QualityStats,
+ raw_stats_object => [byte],
+ raw_stats_text => java.lang.String,
+ raw_call_end_reason_text => java.lang.String,
+ is_survey_candidate => boolean,
+ ))
}
fn make_call_link_root_key_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
root_key: &CallLinkRootKey,
) -> jni::errors::Result> {
- let call_link_root_key_class = match self.class_cache.get_class(CALL_LINK_ROOT_KEY_CLASS) {
- Ok(v) => v,
- Err(error) => {
- error!("call_link_root_key_class: {:?}", error);
- return Ok(JObject::null());
- }
- };
+ let call_link_root_key_class =
+ match JCallLinkRootKey::lookup_class(env, &LoaderContext::default()) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("call_link_root_key_class: {:?}", error);
+ return Ok(JObject::null());
+ }
+ };
let key_bytes = JObject::from(env.byte_array_from_slice(root_key.as_slice())?);
- let args = jni_args!((
+ jni_new_object!(env, &*call_link_root_key_class, (
key_bytes => [byte],
false => boolean,
- ) -> void);
-
- env.new_object(call_link_root_key_class, args.sig, &args.args)
+ ))
}
fn make_call_link_state_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
call_link_state: &Option,
) -> jni::errors::Result> {
match call_link_state {
None => Ok(JObject::null()),
Some(state) => {
- let call_link_state_class = match self.class_cache.get_class(CALL_LINK_STATE_CLASS)
- {
- Ok(v) => v,
- Err(error) => {
- error!("call_link_state_class: {:?}", error);
- return Ok(JObject::null());
- }
- };
+ let call_link_state_class =
+ match JCallLinkState::lookup_class(env, &LoaderContext::default()) {
+ Ok(v) => v,
+ Err(error) => {
+ error!("call_link_state_class: {:?}", error);
+ return Ok(JObject::null());
+ }
+ };
let name_object = JObject::from(env.new_string(state.name.clone())?);
@@ -2329,27 +2035,25 @@ impl AndroidPlatform {
let root_key = self.make_call_link_root_key_object(env, &state.root_key)?;
- let args = jni_args!((
+ jni_new_object!(env, &*call_link_state_class, (
name_object => java.lang.String,
raw_restrictions => int,
state.revoked => boolean,
expiration_in_epoch_seconds as jlong => long,
root_key => org.signal.ringrtc.CallLinkRootKey,
- ) -> void);
-
- env.new_object(call_link_state_class, args.sig, &args.args)
+ ))
}
}
}
fn make_peek_info_object<'a>(
&self,
- env: &mut JNIEnv<'a>,
+ env: &mut Env<'a>,
peek_info: &PeekInfo,
joined_members: &mut dyn ExactSizeIterator- ,
) -> Result
> {
- let list = jni_new_arraylist(env, joined_members.len())?;
- let joined_member_list = env.get_list(&list)?;
+ let list = JArrayList::with_capacity(env, joined_members.len() as jint)?;
+ let joined_member_list = jni::objects::JList::cast_local(env, list)?;
for joined_member in joined_members {
let jni_opaque_user_id = match env.byte_array_from_slice(joined_member) {
Ok(v) => JObject::from(v),
@@ -2385,8 +2089,8 @@ impl AndroidPlatform {
let jni_device_count_excluding_pending = peek_info.devices.len() as jlong;
let pending_users = peek_info.unique_pending_users();
- let pending_user_list = jni_new_arraylist(env, pending_users.len())?;
- let pending_user_list = env.get_list(&pending_user_list)?;
+ let pending_user_list = JArrayList::with_capacity(env, pending_users.len() as jint)?;
+ let pending_user_list = jni::objects::JList::cast_local(env, pending_user_list)?;
for pending_user in pending_users {
let jni_opaque_user_id = match env.byte_array_from_slice(pending_user) {
Ok(v) => JObject::from(v),
@@ -2412,23 +2116,23 @@ impl AndroidPlatform {
}
};
- let args = jni_args!((
- joined_member_list => java.util.List,
- jni_creator => [byte],
- jni_era_id => java.lang.String,
- jni_max_devices => java.lang.Long,
- jni_device_count_including_pending => long,
- jni_device_count_excluding_pending => long,
- pending_user_list => java.util.List,
- jni_call_link_state => org.signal.ringrtc.CallLinkState,
- ) -> org.signal.ringrtc.PeekInfo);
- let result = env.call_static_method(
- self.class_cache.get_class(PEEK_INFO_CLASS)?,
- "fromNative",
- args.sig,
- &args.args,
+ let peek_info_class = JPeekInfo::lookup_class(env, &LoaderContext::default())?;
+ let result = jni_call_static_method!(
+ env,
+ &*peek_info_class,
+ jni_str!("fromNative"),
+ (
+ joined_member_list => java.util.List,
+ jni_creator => [byte],
+ jni_era_id => java.lang.String,
+ jni_max_devices => java.lang.Long,
+ jni_device_count_including_pending => long,
+ jni_device_count_excluding_pending => long,
+ pending_user_list => java.util.List,
+ jni_call_link_state => org.signal.ringrtc.CallLinkState,
+ ) -> org.signal.ringrtc.PeekInfo
)?;
- Ok(result.l()?)
+ Ok(result.into_object()?)
}
}
@@ -2444,84 +2148,67 @@ impl sfu::Delegate for AndroidPlatform {
fn handle_peek_result(&self, request_id: u32, peek_result: PeekResult) {
info!("handle_peek_response():");
- let mut env = match self.java_env() {
- Ok(v) => v,
- Err(error) => {
- error!("{:?}", error);
- return;
- }
- };
- let jni_call_manager = self.jni_call_manager.as_obj();
+ let _ = self.with_java_env(|env| {
+ let result_object = match peek_result {
+ Ok(peek_info) => {
+ let joined_members = peek_info.unique_users();
- let http_result_class = match self.class_cache.get_class(HTTP_RESULT_CLASS) {
- Ok(v) => v,
- Err(error) => {
- error!("http_result_class: {:?}", error);
- return;
- }
- };
+ // Set a frame capacity of min (5) + objects (5) + elements (N * 1 object per element).
+ let capacity = 10 + joined_members.len();
+ let result = env
+ .with_local_frame_returning_local::<_, JObject<'static>, anyhow::Error>(
+ capacity,
+ |env| {
+ let jni_peek_info = match self.make_peek_info_object(
+ env,
+ &peek_info,
+ &mut joined_members.into_iter(),
+ ) {
+ Ok(value) => value,
+ Err(e) => {
+ error!("make_peek_info_object: {:?}", e);
+ return Ok(JObject::null());
+ }
+ };
- let result_object = match peek_result {
- Ok(peek_info) => {
- let joined_members = peek_info.unique_users();
-
- // Set a frame capacity of min (5) + objects (5) + elements (N * 1 object per element).
- let capacity = (10 + joined_members.len()) as i32;
- let result = env.with_local_frame_returning_local(capacity, |env| -> Result<_> {
- let jni_peek_info = match self.make_peek_info_object(
- env,
- &peek_info,
- &mut joined_members.into_iter(),
- ) {
- Ok(value) => value,
- Err(e) => {
- error!("make_peek_info_object: {:?}", e);
- return Ok(JObject::null());
+ let http_result_class =
+ HttpResult::lookup_class(env, &LoaderContext::default())?;
+ Ok(jni_new_object!(env, &*http_result_class, (
+ jni_peek_info => java.lang.Object,
+ ))?)
+ },
+ );
+ match result {
+ Ok(v) if !v.is_null() => v,
+ Ok(_) => return Ok(()),
+ Err(error) => {
+ error!("new HttpResult(PeekInfo): {:?}", error);
+ return Ok(());
}
- };
-
- let args = jni_args!((
- jni_peek_info => java.lang.Object,
- ) -> void);
- Ok(env.new_object(http_result_class, args.sig, &args.args)?)
- });
- match result {
- Ok(v) if !v.is_null() => v,
- Ok(_) => {
- // Already logged, so just bail out early.
- return;
- }
- Err(error) => {
- error!("new HttpResult(PeekInfo): {:?}", error);
- return;
}
}
- }
- Err(status) => {
- let args = jni_args!((
- status.code as jshort => short,
- ) -> void);
- match env.new_object(http_result_class, args.sig, &args.args) {
- Ok(v) => v,
- Err(error) => {
- error!("new HttpResult(short): {:?}", error);
- return;
- }
+ Err(status) => {
+ let http_result_class =
+ HttpResult::lookup_class(env, &LoaderContext::default())?;
+ jni_new_object!(env, &*http_result_class, (
+ status.code as jshort => short,
+ ))?
}
- }
- };
+ };
- let result = jni_call_method(
- &mut env,
- jni_call_manager,
- "handlePeekResponse",
- jni_args!((
- request_id as jlong => long,
- result_object => org.signal.ringrtc.CallManager::HttpResult,
- ) -> void),
- );
- if result.is_err() {
- error!("jni_call_method: {:?}", result.err());
- }
+ let result = jni_call_method!(
+ env,
+ self.jni_call_manager.as_obj(),
+ jni_str!("handlePeekResponse"),
+ (
+ request_id as jlong => long,
+ result_object => org.signal.ringrtc.CallManager::HttpResult,
+ ) -> void
+ );
+ if result.is_err() {
+ error!("jni_call_method: {:?}", result.err());
+ }
+ Ok(())
+ });
}
}
diff --git a/src/rust/src/android/api/call_link_root_key.rs b/src/rust/src/android/api/call_link_root_key.rs
index 49550e12..8c75201d 100644
--- a/src/rust/src/android/api/call_link_root_key.rs
+++ b/src/rust/src/android/api/call_link_root_key.rs
@@ -3,122 +3,106 @@
// SPDX-License-Identifier: AGPL-3.0-only
//
-use std::borrow::Cow;
-
+use anyhow::Result;
use jni::{
- JNIEnv,
+ EnvUnowned, jni_str,
objects::{JByteArray, JClass, JObject, JString},
};
-use crate::{
- android::{error, jni_util::*},
- core::util::try_scoped,
- lite::call_links::CallLinkRootKey,
-};
+use crate::{android::error::ThrowCallException, lite::call_links::CallLinkRootKey};
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeParseKeyString<'local>(
- mut env: JNIEnv<'local>,
+ mut unowned_env: EnvUnowned<'local>,
_class: JClass,
string: JString,
) -> JByteArray<'local> {
- try_scoped(|| {
- let string = env.get_string(&string)?;
- let key = CallLinkRootKey::try_from(Cow::from(&string).as_ref())?;
- Ok(env.byte_array_from_slice(key.as_slice())?)
- })
- .unwrap_or_else(|e| {
- error::throw_error(&mut env, e);
- JByteArray::default()
- })
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ let string = string.try_to_string(env)?;
+ let key = CallLinkRootKey::try_from(string.as_str())?;
+ Ok(env.byte_array_from_slice(key.as_slice())?)
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeValidateKeyBytes(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_class: JClass,
bytes: JByteArray,
) {
- try_scoped(|| {
- let bytes = env.convert_byte_array(bytes)?;
- let _ = CallLinkRootKey::try_from(bytes.as_slice())?;
- Ok(())
- })
- .unwrap_or_else(|e| error::throw_error(&mut env, e))
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ let bytes = env.convert_byte_array(bytes)?;
+ let _ = CallLinkRootKey::try_from(bytes.as_slice())?;
+ Ok(())
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_generate<'local>(
- mut env: JNIEnv<'local>,
+ mut unowned_env: EnvUnowned<'local>,
_class: JClass,
) -> JObject<'local> {
- try_scoped(|| {
- let key = CallLinkRootKey::generate(rand::rngs::OsRng);
- let bytes = env.byte_array_from_slice(key.as_slice())?;
- let object = jni_new_object(
- &mut env,
- jni_class_name!(org.signal.ringrtc.CallLinkRootKey),
- jni_args!((bytes => [byte]) -> void),
- )?;
- Ok(object)
- })
- .unwrap_or_else(|e| {
- error::throw_error(&mut env, e);
- JObject::default()
- })
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ let key = CallLinkRootKey::generate(rand::rngs::OsRng);
+ let bytes = env.byte_array_from_slice(key.as_slice())?;
+ let object = jni_new_object!(env, jni_str!("org/signal/ringrtc/CallLinkRootKey"), (
+ bytes => [byte],
+ ))?;
+ Ok(object)
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_generateAdminPasskey<'local>(
- mut env: JNIEnv<'local>,
+ mut unowned_env: EnvUnowned<'local>,
_class: JClass,
) -> JByteArray<'local> {
- try_scoped(|| {
- let passkey = CallLinkRootKey::generate_admin_passkey(rand::rngs::OsRng);
- Ok(env.byte_array_from_slice(&passkey)?)
- })
- .unwrap_or_else(|e| {
- error::throw_error(&mut env, e);
- JByteArray::default()
- })
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ let passkey = CallLinkRootKey::generate_admin_passkey(rand::rngs::OsRng);
+ Ok(env.byte_array_from_slice(&passkey)?)
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeDeriveRoomId<'local>(
- mut env: JNIEnv<'local>,
+ mut unowned_env: EnvUnowned<'local>,
_class: JClass,
key_bytes: JByteArray,
) -> JByteArray<'local> {
- try_scoped(|| {
- let key_bytes = env.convert_byte_array(key_bytes)?;
- let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
- Ok(env.byte_array_from_slice(&key.derive_room_id())?)
- })
- .unwrap_or_else(|e| {
- error::throw_error(&mut env, e);
- JByteArray::default()
- })
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ let key_bytes = env.convert_byte_array(key_bytes)?;
+ let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
+ Ok(env.byte_array_from_slice(&key.derive_room_id())?)
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeToFormattedString<'local>(
- mut env: JNIEnv<'local>,
+ mut unowned_env: EnvUnowned<'local>,
_class: JClass,
key_bytes: JByteArray,
) -> JString<'local> {
- try_scoped(|| {
- let key_bytes = env.convert_byte_array(key_bytes)?;
- let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
- Ok(env.new_string(key.to_formatted_string())?)
- })
- .unwrap_or_else(|e| {
- error::throw_error(&mut env, e);
- JString::default()
- })
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ let key_bytes = env.convert_byte_array(key_bytes)?;
+ let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
+ Ok(env.new_string(key.to_formatted_string())?)
+ })
+ .resolve::()
}
diff --git a/src/rust/src/android/api/jni_call_manager.rs b/src/rust/src/android/api/jni_call_manager.rs
index 23d00fa7..9176858e 100644
--- a/src/rust/src/android/api/jni_call_manager.rs
+++ b/src/rust/src/android/api/jni_call_manager.rs
@@ -8,161 +8,149 @@
//! Native JNI interfaces, called by
//! org.signal.ringrtc.CallManager objects.
-use std::{borrow::Cow, time::Duration};
+use std::time::Duration;
+use anyhow::Result;
use jni::{
- JNIEnv,
+ EnvUnowned,
objects::{JByteArray, JClass, JObject, JString},
- strings::JavaStr,
sys::{jboolean, jbyte, jint, jlong, jobject},
};
use crate::{
android::{
- android_platform::AndroidPlatform, call_manager, call_manager::AndroidCallManager, error,
+ android_platform::AndroidPlatform, call_manager, call_manager::AndroidCallManager,
+ error::ThrowCallException,
},
common::{CallConfig, CallMediaType, DataMode, DeviceId},
- core::{connection::Connection, group_call, signaling, util::try_scoped},
+ core::{connection::Connection, group_call, signaling},
webrtc,
};
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcGetBuildInfo<'local>(
- mut env: JNIEnv<'local>,
+ mut unowned_env: EnvUnowned<'local>,
_class: JClass,
) -> JObject<'local> {
- match call_manager::get_build_info(&mut env) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- JObject::default()
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<_> { call_manager::get_build_info(env) })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcInitialize(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_class: JClass,
) {
- if let Err(e) = call_manager::initialize(&mut env) {
- error::throw_error(&mut env, e);
- }
+ unowned_env
+ .with_env(|env| -> Result<()> { call_manager::initialize(env) })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcCreateCallManager(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_class: JClass,
jni_call_manager: JObject,
) -> jlong {
- match call_manager::create_call_manager(&mut env, jni_call_manager) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- 0
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<_> { call_manager::create_call_manager(env, jni_call_manager) })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcCreatePeerConnection(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
peer_connection_factory: jlong,
native_connection_borrowed: jlong,
jni_rtc_config: JObject,
jni_media_constraints: JObject,
) -> jlong {
- match call_manager::create_peer_connection(
- &mut env,
- peer_connection_factory,
- webrtc::ptr::Borrowed::from_ptr(
- native_connection_borrowed as *mut Connection,
- ),
- jni_rtc_config,
- jni_media_constraints,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- 0
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ call_manager::create_peer_connection(
+ env,
+ peer_connection_factory,
+ webrtc::ptr::Borrowed::from_ptr(
+ native_connection_borrowed as *mut Connection,
+ ),
+ jni_rtc_config,
+ jni_media_constraints,
+ )
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcSetSelfUuid(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
uuid: JByteArray,
) {
- match call_manager::set_self_uuid(&env, call_manager as *mut AndroidCallManager, uuid) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::set_self_uuid(env, call_manager as *mut AndroidCallManager, uuid)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcAddAsset(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
asset_group: JString,
file_path: JString,
content: JByteArray,
) {
- match call_manager::add_asset(
- &mut env,
- call_manager as *mut AndroidCallManager,
- asset_group,
- file_path,
- content,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::add_asset(
+ env,
+ call_manager as *mut AndroidCallManager,
+ asset_group,
+ file_path,
+ content,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcCall(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
jni_remote: JObject,
call_media_type: jint,
local_device: jint,
) {
- match call_manager::call(
- &env,
- call_manager as *mut AndroidCallManager,
- jni_remote,
- CallMediaType::from_i32(call_media_type),
- local_device as DeviceId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::call(
+ env,
+ call_manager as *mut AndroidCallManager,
+ jni_remote,
+ CallMediaType::from_i32(call_media_type),
+ local_device as DeviceId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcProceed(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
@@ -178,99 +166,94 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcProceed(
Some(Duration::from_millis(audio_levels_interval_millis as u64))
};
- match call_manager::proceed(
- &env,
- call_manager as *mut AndroidCallManager,
- call_id,
- jni_call_context,
- CallConfig::default()
- .with_data_mode(DataMode::from_i32(data_mode))
- .with_dred_duration(dred_duration as u8)
- .with_enable_vp9(enable_vp9 != 0),
- audio_levels_interval,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::proceed(
+ env,
+ call_manager as *mut AndroidCallManager,
+ call_id,
+ jni_call_context,
+ CallConfig::default()
+ .with_data_mode(DataMode::from_i32(data_mode))
+ .with_dred_duration(dred_duration as u8)
+ .with_enable_vp9(enable_vp9),
+ audio_levels_interval,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcMessageSent(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
) {
- match call_manager::message_sent(call_manager as *mut AndroidCallManager, call_id) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::message_sent(call_manager as *mut AndroidCallManager, call_id)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcMessageSendFailure(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
) {
- match call_manager::message_send_failure(call_manager as *mut AndroidCallManager, call_id) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::message_send_failure(call_manager as *mut AndroidCallManager, call_id)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcHangup(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
) {
- match call_manager::hangup(call_manager as *mut AndroidCallManager) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::hangup(call_manager as *mut AndroidCallManager)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcCancelGroupRing(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
group_id: JByteArray,
ring_id: jlong,
reason: jint,
) {
- match call_manager::cancel_group_ring(
- &env,
- call_manager as *mut AndroidCallManager,
- group_id,
- ring_id,
- reason,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::cancel_group_ring(
+ env,
+ call_manager as *mut AndroidCallManager,
+ group_id,
+ ring_id,
+ reason,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedAnswer(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
@@ -280,27 +263,26 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedAnsw
sender_identity_key: JByteArray,
receiver_identity_key: JByteArray,
) {
- match call_manager::received_answer(
- &env,
- call_manager as *mut AndroidCallManager,
- call_id,
- jni_remote,
- remote_device as DeviceId,
- opaque,
- sender_identity_key,
- receiver_identity_key,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_answer(
+ env,
+ call_manager as *mut AndroidCallManager,
+ call_id,
+ jni_remote,
+ remote_device as DeviceId,
+ opaque,
+ sender_identity_key,
+ receiver_identity_key,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedOffer(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
@@ -313,30 +295,29 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedOffe
sender_identity_key: JByteArray,
receiver_identity_key: JByteArray,
) {
- match call_manager::received_offer(
- &env,
- call_manager as *mut AndroidCallManager,
- call_id,
- jni_remote,
- remote_device as DeviceId,
- opaque,
- message_age_sec as u64,
- CallMediaType::from_i32(call_media_type),
- local_device as DeviceId,
- sender_identity_key,
- receiver_identity_key,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_offer(
+ env,
+ call_manager as *mut AndroidCallManager,
+ call_id,
+ jni_remote,
+ remote_device as DeviceId,
+ opaque,
+ message_age_sec as u64,
+ CallMediaType::from_i32(call_media_type),
+ local_device as DeviceId,
+ sender_identity_key,
+ receiver_identity_key,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedIceCandidates(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
@@ -344,25 +325,24 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedIceC
remote_device: jint,
jni_ice_candidates: JObject,
) {
- match call_manager::received_ice(
- &mut env,
- call_manager as *mut AndroidCallManager,
- call_id,
- jni_remote,
- remote_device as DeviceId,
- jni_ice_candidates,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_ice(
+ env,
+ call_manager as *mut AndroidCallManager,
+ call_id,
+ jni_remote,
+ remote_device as DeviceId,
+ jni_ice_candidates,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedHangup(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
@@ -371,50 +351,49 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedHang
hangup_type: jint,
device_id: jint,
) {
- match call_manager::received_hangup(
- &env,
- call_manager as *mut AndroidCallManager,
- call_id,
- jni_remote,
- remote_device as DeviceId,
- signaling::HangupType::from_i32(hangup_type).unwrap_or(signaling::HangupType::Normal),
- device_id as DeviceId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_hangup(
+ env,
+ call_manager as *mut AndroidCallManager,
+ call_id,
+ jni_remote,
+ remote_device as DeviceId,
+ signaling::HangupType::from_i32(hangup_type)
+ .unwrap_or(signaling::HangupType::Normal),
+ device_id as DeviceId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedBusy(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
jni_remote: JObject,
remote_device: jint,
) {
- match call_manager::received_busy(
- &env,
- call_manager as *mut AndroidCallManager,
- call_id,
- jni_remote,
- remote_device as DeviceId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_busy(
+ env,
+ call_manager as *mut AndroidCallManager,
+ call_id,
+ jni_remote,
+ remote_device as DeviceId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedCallMessage(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
sender_uuid: JByteArray,
@@ -423,228 +402,209 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedCall
message: JByteArray,
message_age_sec: jlong,
) {
- match call_manager::received_call_message(
- &env,
- call_manager as *mut AndroidCallManager,
- sender_uuid,
- sender_device_id as DeviceId,
- local_device_id as DeviceId,
- message,
- message_age_sec as u64,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_call_message(
+ env,
+ call_manager as *mut AndroidCallManager,
+ sender_uuid,
+ sender_device_id as DeviceId,
+ local_device_id as DeviceId,
+ message,
+ message_age_sec as u64,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReceivedHttpResponse(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
request_id: jlong,
status_code: jint,
body: JByteArray,
) {
- match call_manager::received_http_response(
- &env,
- call_manager as *mut AndroidCallManager,
- request_id,
- status_code,
- body,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::received_http_response(
+ env,
+ call_manager as *mut AndroidCallManager,
+ request_id,
+ status_code,
+ body,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcHttpRequestFailed(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
request_id: jlong,
) {
- match call_manager::http_request_failed(call_manager as *mut AndroidCallManager, request_id) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::http_request_failed(call_manager as *mut AndroidCallManager, request_id)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcAcceptCall(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
) {
- match call_manager::accept_call(call_manager as *mut AndroidCallManager, call_id) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::accept_call(call_manager as *mut AndroidCallManager, call_id)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcGetActiveConnection(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
) -> jobject {
- // Return a jobject instead of a JObject because the Connection is a GlobalRef, which can't be
- // safely converted to a JObject (it's meant to be used as a &JObject).
- match call_manager::get_active_connection(call_manager as *mut AndroidCallManager) {
- Ok(v) => v.as_raw(),
- Err(e) => {
- error::throw_error(&mut env, e);
- std::ptr::null_mut() as jobject
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<_> {
+ call_manager::get_active_connection(call_manager as *mut AndroidCallManager)
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcGetActiveCallContext(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
) -> jobject {
- // Return a jobject instead of a JObject because the CallContext is a GlobalRef, which can't be
- // safely converted to a JObject (it's meant to be used as a &JObject).
- match call_manager::get_active_call_context(call_manager as *mut AndroidCallManager) {
- Ok(v) => v.as_raw(),
- Err(e) => {
- error::throw_error(&mut env, e);
- std::ptr::null_mut() as jobject
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<_> {
+ call_manager::get_active_call_context(call_manager as *mut AndroidCallManager)
+ })
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcSetAudioEnable(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
enable: jboolean,
) {
- match call_manager::set_audio_enable(call_manager as *mut AndroidCallManager, enable != 0) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_audio_enable(call_manager as *mut AndroidCallManager, enable)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcSetVideoEnable(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
enable: jboolean,
) {
- match call_manager::set_video_enable(call_manager as *mut AndroidCallManager, enable != 0) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_video_enable(call_manager as *mut AndroidCallManager, enable)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcSetOutgoingVideoIsScreenShare(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
is_screenshare: jboolean,
) {
- match call_manager::set_outgoing_video_is_screenshare(
- call_manager as *mut AndroidCallManager,
- is_screenshare != 0,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_outgoing_video_is_screenshare(
+ call_manager as *mut AndroidCallManager,
+ is_screenshare,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcUpdateDataMode(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
data_mode: jint,
) {
- match call_manager::update_data_mode(
- call_manager as *mut AndroidCallManager,
- DataMode::from_i32(data_mode),
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::update_data_mode(
+ call_manager as *mut AndroidCallManager,
+ DataMode::from_i32(data_mode),
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcDrop(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
call_id: jlong,
) {
- match call_manager::drop_call(call_manager as *mut AndroidCallManager, call_id) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::drop_call(call_manager as *mut AndroidCallManager, call_id)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReset(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
) {
- match call_manager::reset(call_manager as *mut AndroidCallManager) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::reset(call_manager as *mut AndroidCallManager)
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcClose(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
) {
- match call_manager::close(call_manager as *mut AndroidCallManager) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::close(call_manager as *mut AndroidCallManager)
+ })
+ .resolve::();
}
// Call Links
@@ -652,7 +612,7 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcClose(
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReadCallLink(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
sfu_url: JString,
@@ -660,25 +620,24 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcReadCallLink
root_key: JByteArray,
request_id: jlong,
) {
- match call_manager::read_call_link(
- &mut env,
- call_manager as *mut AndroidCallManager,
- sfu_url,
- auth_credential_presentation,
- root_key,
- request_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::read_call_link(
+ env,
+ call_manager as *mut AndroidCallManager,
+ sfu_url,
+ auth_credential_presentation,
+ root_key,
+ request_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcCreateCallLink(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
sfu_url: JString,
@@ -689,28 +648,27 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcCreateCallLi
restrictions: jint,
request_id: jlong,
) {
- match call_manager::create_call_link(
- &mut env,
- call_manager as *mut AndroidCallManager,
- sfu_url,
- create_credential_presentation,
- root_key,
- admin_passkey,
- call_link_public_params,
- restrictions,
- request_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::create_call_link(
+ env,
+ call_manager as *mut AndroidCallManager,
+ sfu_url,
+ create_credential_presentation,
+ root_key,
+ admin_passkey,
+ call_link_public_params,
+ restrictions,
+ request_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcUpdateCallLink(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
sfu_url: JString,
@@ -722,29 +680,28 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcUpdateCallLi
new_revoked: jint,
request_id: jlong,
) {
- match call_manager::update_call_link(
- &mut env,
- call_manager as *mut AndroidCallManager,
- sfu_url,
- auth_credential_presentation,
- root_key,
- admin_passkey,
- new_name,
- new_restrictions,
- new_revoked,
- request_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::update_call_link(
+ env,
+ call_manager as *mut AndroidCallManager,
+ sfu_url,
+ auth_credential_presentation,
+ root_key,
+ admin_passkey,
+ new_name,
+ new_restrictions,
+ new_revoked,
+ request_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcDeleteCallLink(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
sfu_url: JString,
@@ -753,20 +710,19 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcDeleteCallLi
admin_passkey: JByteArray,
request_id: jlong,
) {
- match call_manager::delete_call_link(
- &mut env,
- call_manager as *mut AndroidCallManager,
- sfu_url,
- auth_credential_presentation,
- root_key,
- admin_passkey,
- request_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::delete_call_link(
+ env,
+ call_manager as *mut AndroidCallManager,
+ sfu_url,
+ auth_credential_presentation,
+ root_key,
+ admin_passkey,
+ request_id,
+ )
+ })
+ .resolve::();
}
// Group Calls
@@ -774,7 +730,7 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcDeleteCallLi
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcPeekGroupCall(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
request_id: jlong,
@@ -782,25 +738,24 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcPeekGroupCal
membership_proof: JByteArray,
jni_serialized_group_members: JByteArray,
) {
- match call_manager::peek_group_call(
- &mut env,
- call_manager as *mut AndroidCallManager,
- request_id,
- sfu_url,
- membership_proof,
- jni_serialized_group_members,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::peek_group_call(
+ env,
+ call_manager as *mut AndroidCallManager,
+ request_id,
+ sfu_url,
+ membership_proof,
+ jni_serialized_group_members,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcPeekCallLinkCall(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
request_id: jlong,
@@ -808,25 +763,24 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_CallManager_ringrtcPeekCallLink
auth_credential_presentation: JByteArray,
root_key: JByteArray,
) {
- match call_manager::peek_call_link_call(
- &mut env,
- call_manager as *mut AndroidCallManager,
- request_id,
- sfu_url,
- auth_credential_presentation,
- root_key,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::peek_call_link_call(
+ env,
+ call_manager as *mut AndroidCallManager,
+ request_id,
+ sfu_url,
+ auth_credential_presentation,
+ root_key,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcCreateGroupCallClient(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_cls: JClass,
call_manager: jlong,
group_id: JByteArray,
@@ -838,30 +792,30 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcCreateGroupCal
native_audio_track_borrowed_rc: jlong,
native_video_track_borrowed_rc: jlong,
) -> jlong {
- match call_manager::create_group_call_client(
- &mut env,
- call_manager as *mut AndroidCallManager,
- group_id,
- sfu_url,
- hkdf_extra_info,
- audio_levels_interval_millis,
- dred_duration,
- native_peer_connection_factory_borrowed_rc,
- native_audio_track_borrowed_rc,
- native_video_track_borrowed_rc,
- ) {
- Ok(v) => v as i64,
- Err(e) => {
- error::throw_error(&mut env, e);
- group_call::INVALID_CLIENT_ID as i64
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ Ok(call_manager::create_group_call_client(
+ env,
+ call_manager as *mut AndroidCallManager,
+ group_id,
+ sfu_url,
+ hkdf_extra_info,
+ audio_levels_interval_millis,
+ dred_duration,
+ native_peer_connection_factory_borrowed_rc,
+ native_audio_track_borrowed_rc,
+ native_video_track_borrowed_rc,
+ )? as i64)
+ })
+ // Note: The ErrorPolicy returns T::default() which for i64 is 0. This implicitly
+ // matches group_call::INVALID_CLIENT_ID.
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcCreateCallLinkCallClient(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_cls: JClass,
call_manager: jlong,
sfu_url: JString,
@@ -876,524 +830,497 @@ pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcCreateCallLink
native_audio_track_borrowed_rc: jlong,
native_video_track_borrowed_rc: jlong,
) -> jlong {
- match call_manager::create_call_link_call_client(
- &mut env,
- call_manager as *mut AndroidCallManager,
- sfu_url,
- endorsement_public_key,
- auth_presentation,
- call_link_bytes,
- admin_passkey,
- hkdf_extra_info,
- audio_levels_interval_millis,
- dred_duration,
- native_peer_connection_factory_borrowed_rc,
- native_audio_track_borrowed_rc,
- native_video_track_borrowed_rc,
- ) {
- Ok(v) => v as i64,
- Err(e) => {
- error::throw_error(&mut env, e);
- group_call::INVALID_CLIENT_ID as i64
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ Ok(call_manager::create_call_link_call_client(
+ env,
+ call_manager as *mut AndroidCallManager,
+ sfu_url,
+ endorsement_public_key,
+ auth_presentation,
+ call_link_bytes,
+ admin_passkey,
+ hkdf_extra_info,
+ audio_levels_interval_millis,
+ dred_duration,
+ native_peer_connection_factory_borrowed_rc,
+ native_audio_track_borrowed_rc,
+ native_video_track_borrowed_rc,
+ )? as i64)
+ })
+ // Note: The ErrorPolicy returns T::default() which for i64 is 0. This implicitly
+ // matches group_call::INVALID_CLIENT_ID.
+ .resolve::()
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcDeleteGroupCallClient(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
) {
- match call_manager::delete_group_call_client(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::delete_group_call_client(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcConnect(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
) {
- match call_manager::connect(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::connect(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcJoin(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
) {
- match call_manager::join(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::join(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcLeave(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
) {
- match call_manager::leave(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::leave(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcDisconnect(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
) {
- match call_manager::disconnect(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::disconnect(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetOutgoingAudioMuted(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
muted: bool,
) {
- match call_manager::set_outgoing_audio_muted(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- muted,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_outgoing_audio_muted(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ muted,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetOutgoingAudioMutedRemotely(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
source_demux_id: jlong,
) {
- match call_manager::set_outgoing_audio_muted_remotely(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- source_demux_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_outgoing_audio_muted_remotely(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ source_demux_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSendRemoteMuteRequest(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
target_demux_id: jlong,
) {
- match call_manager::send_remote_mute_request(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- target_demux_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::send_remote_mute_request(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ target_demux_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetOutgoingVideoMuted(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
muted: bool,
) {
- match call_manager::set_outgoing_video_muted(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- muted,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_outgoing_video_muted(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ muted,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetPresenting(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
presenting: jboolean,
) {
- match call_manager::set_presenting(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- presenting != 0,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_presenting(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ presenting,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetOutgoingVideoIsScreenShare(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
is_screenshare: jboolean,
) {
- match call_manager::set_outgoing_group_call_video_is_screenshare(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- is_screenshare != 0,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_outgoing_group_call_video_is_screenshare(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ is_screenshare,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcRing(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
recipient: JByteArray,
) {
- match call_manager::group_ring(
- &env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- recipient,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::group_ring(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ recipient,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcResendMediaKeys(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
) {
- match call_manager::resend_media_keys(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::resend_media_keys(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetDataMode(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
data_mode: jint,
) {
- match call_manager::set_data_mode(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- DataMode::from_i32(data_mode),
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::set_data_mode(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ DataMode::from_i32(data_mode),
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcRequestVideo(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
jni_rendered_resolutions: JObject,
active_speaker_height: jint,
) {
- match call_manager::request_video(
- &mut env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- jni_rendered_resolutions,
- active_speaker_height,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::request_video(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ jni_rendered_resolutions,
+ active_speaker_height,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcApproveUser(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
other_user_id: JByteArray,
) {
- match call_manager::approve_user(
- &env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- other_user_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::approve_user(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ other_user_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcDenyUser(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
other_user_id: JByteArray,
) {
- match call_manager::deny_user(
- &env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- other_user_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::deny_user(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ other_user_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcRemoveClient(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
other_client_demux_id: jlong,
) {
- match call_manager::remove_client(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- other_client_demux_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::remove_client(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ other_client_demux_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcBlockClient(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
other_client_demux_id: jlong,
) {
- match call_manager::block_client(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- other_client_demux_id,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::block_client(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ other_client_demux_id,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetGroupMembers(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
jni_serialized_group_members: JByteArray,
) {
- match call_manager::set_group_members(
- &env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- jni_serialized_group_members,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::set_group_members(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ jni_serialized_group_members,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcSetMembershipProof(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
proof: JByteArray,
) {
- match call_manager::set_membership_proof(
- &env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- proof,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::set_membership_proof(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ proof,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcReact(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
value: JString,
) {
- match call_manager::react(
- &mut env,
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- value,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|env| -> Result<()> {
+ call_manager::react(
+ env,
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ value,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_GroupCall_ringrtcRaiseHand(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_object: JObject,
call_manager: jlong,
client_id: jlong,
raise: bool,
) {
- match call_manager::raise_hand(
- call_manager as *mut AndroidCallManager,
- client_id as group_call::ClientId,
- raise,
- ) {
- Ok(v) => v,
- Err(e) => {
- error::throw_error(&mut env, e);
- }
- }
+ unowned_env
+ .with_env(|_env| -> Result<()> {
+ call_manager::raise_hand(
+ call_manager as *mut AndroidCallManager,
+ client_id as group_call::ClientId,
+ raise,
+ )
+ })
+ .resolve::();
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallId_ringrtcFromEraId(
- mut env: JNIEnv,
+ mut unowned_env: EnvUnowned,
_class: JClass,
era: JString,
) -> jlong {
- try_scoped(|| {
- // Avoid copying if we don't need to.
- let era_cesu8: JavaStr = env.get_string(&era)?;
- let era_utf8: Cow = Cow::from(&era_cesu8);
- Ok(group_call::RingId::from_era_id(&era_utf8).into())
- })
- .unwrap_or_else(|e| {
- error::throw_error(&mut env, e);
- 0
- })
+ unowned_env
+ .with_env(|env| -> Result<_> {
+ let era_string = era.try_to_string(env)?;
+ Ok(group_call::RingId::from_era_id(&era_string).into())
+ })
+ .resolve::()
}
diff --git a/src/rust/src/android/call_manager.rs b/src/rust/src/android/call_manager.rs
index b659bada..2e25704c 100644
--- a/src/rust/src/android/call_manager.rs
+++ b/src/rust/src/android/call_manager.rs
@@ -8,9 +8,10 @@
use std::{borrow::Cow, convert::TryFrom, panic, sync::Arc, time::Duration};
use jni::{
- JNIEnv,
- objects::{GlobalRef, JByteArray, JClass, JObject, JString},
- sys::{jbyte, jint, jlong},
+ Env, jni_sig, jni_str,
+ objects::{JByteArray, JClass, JObject, JString},
+ signature::FieldSignature,
+ sys::{jbyte, jint, jlong, jobject},
};
use log::Level;
@@ -18,7 +19,6 @@ use crate::{
android::{
android_platform::{AndroidCallContext, AndroidPlatform},
error::AndroidError,
- jni_util::*,
logging::init_logging,
webrtc_peer_connection_factory::*,
},
@@ -50,25 +50,23 @@ use crate::{
pub type AndroidCallManager = CallManager;
/// CMI request for build time information
-pub fn get_build_info<'a>(env: &mut JNIEnv<'a>) -> Result> {
+pub fn get_build_info<'a>(env: &mut Env<'a>) -> Result> {
#[cfg(all(debug_assertions, not(test)))]
let debug = true;
#[cfg(any(not(debug_assertions), test))]
let debug = false;
- let result = jni_new_object(
+ Ok(jni_new_object!(
env,
- jni_class_name!(org.signal.ringrtc.BuildInfo),
- jni_args!((debug => boolean) -> void),
- )?;
-
- Ok(result)
+ jni_str!("org/signal/ringrtc/BuildInfo"),
+ (debug => boolean)
+ )?)
}
/// Library initialization routine.
///
/// Sets up the logging infrastructure.
-pub fn initialize(env: &mut JNIEnv) -> Result<()> {
+pub fn initialize(env: &mut Env) -> Result<()> {
init_logging(env, Level::Debug)?;
// Set a custom panic handler that uses the logger instead of
@@ -81,7 +79,7 @@ pub fn initialize(env: &mut JNIEnv) -> Result<()> {
}
/// Creates a new AndroidCallManager object.
-pub fn create_call_manager(env: &mut JNIEnv, jni_call_manager: JObject) -> Result {
+pub fn create_call_manager(env: &mut Env, jni_call_manager: JObject) -> Result {
let platform = AndroidPlatform::new(env, env.new_global_ref(jni_call_manager)?)?;
let http_client = http::DelegatingClient::new(platform.try_clone()?);
@@ -94,7 +92,7 @@ pub fn create_call_manager(env: &mut JNIEnv, jni_call_manager: JObject) -> Resul
/// Create a org.webrtc.PeerConnection object
pub fn create_peer_connection(
- env: &mut JNIEnv,
+ env: &mut Env,
peer_connection_factory: jlong,
mut native_connection: webrtc::ptr::Borrowed>,
jni_rtc_config: JObject,
@@ -121,8 +119,8 @@ pub fn create_peer_connection(
// construct JNI OwnedPeerConnection object
let jni_owned_pc = unsafe {
Java_org_webrtc_PeerConnectionFactory_nativeCreatePeerConnection(
- env.unsafe_clone(),
- JClass::from(JObject::null()),
+ jni::EnvUnowned::from_raw(env.get_raw()),
+ JClass::default(),
peer_connection_factory,
jni_rtc_config,
jni_media_constraints,
@@ -161,7 +159,7 @@ pub fn create_peer_connection(
/// Application notification updating the current user's UUID
pub fn set_self_uuid(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
uuid: JByteArray,
) -> Result<()> {
@@ -171,7 +169,7 @@ pub fn set_self_uuid(
/// Adds an asset to the asset manager.
pub fn add_asset(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
asset_group: JString,
file_path: JString,
@@ -179,12 +177,12 @@ pub fn add_asset(
) -> Result<()> {
use crate::core::assets::AssetHandle;
- let asset_group: String = env.get_string(&asset_group)?.into();
+ let asset_group: String = asset_group.try_to_string(env)?;
let handle = if !content.is_null() {
AssetHandle::Content(env.convert_byte_array(content)?)
} else if !file_path.is_null() {
- let path: String = env.get_string(&file_path)?.into();
+ let path: String = file_path.try_to_string(env)?;
AssetHandle::FilePath(path)
} else {
return Err(anyhow::anyhow!(
@@ -198,20 +196,20 @@ pub fn add_asset(
/// Application notification to start a new call
pub fn call(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
jni_remote: JObject,
call_media_type: CallMediaType,
local_device_id: DeviceId,
) -> Result<()> {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
- let app_remote_peer = env.new_global_ref(jni_remote)?;
+ let app_remote_peer = Arc::new(env.new_global_ref(jni_remote)?);
call_manager.call(app_remote_peer, call_media_type, local_device_id)
}
/// Application notification to proceed with a new call
pub fn proceed(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
call_id: jlong,
jni_call_context: JObject,
@@ -254,7 +252,7 @@ pub fn hangup(call_manager: *mut AndroidCallManager) -> Result<()> {
/// Application notification cancelling a group call ring
pub fn cancel_group_ring(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
group_id: JByteArray,
ring_id: jlong,
@@ -277,7 +275,7 @@ pub fn cancel_group_ring(
/// Application notification of received answer message
#[allow(clippy::too_many_arguments)]
pub fn received_answer(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
call_id: jlong,
remote_peer: JObject,
@@ -288,7 +286,7 @@ pub fn received_answer(
) -> Result<()> {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let call_id = CallId::from(call_id);
- let remote_peer = env.new_global_ref(remote_peer)?;
+ let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
let opaque = if opaque.is_null() {
return Err(RingRtcError::OptionValueNotSet(
@@ -317,7 +315,7 @@ pub fn received_answer(
/// Application notification of received offer message
#[allow(clippy::too_many_arguments)]
pub fn received_offer(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
call_id: jlong,
remote_peer: JObject,
@@ -331,7 +329,7 @@ pub fn received_offer(
) -> Result<()> {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let call_id = CallId::from(call_id);
- let remote_peer = env.new_global_ref(remote_peer)?;
+ let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
let opaque = if opaque.is_null() {
return Err(RingRtcError::OptionValueNotSet(
@@ -361,7 +359,7 @@ pub fn received_offer(
/// Application notification to add ICE candidates to a Connection
pub fn received_ice(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
call_id: jlong,
remote_peer: JObject,
@@ -370,14 +368,15 @@ pub fn received_ice(
) -> Result<()> {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let call_id = CallId::from(call_id);
- let remote_peer = env.new_global_ref(remote_peer)?;
+ let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
// Convert Java list of byte[] into Rust Vector of IceCandidate
- let jni_ice_candidates = env.get_list(&candidates)?;
+ let jni_ice_candidates = jni::objects::JList::cast_local(env, candidates)?;
let mut ice_candidates = Vec::new();
- let mut iterator = jni_ice_candidates.iter(env)?;
+ let iterator = jni_ice_candidates.iter(env)?;
while let Some(jni_ice_candidate) = iterator.next(env)? {
- let jni_ice_candidate: JByteArray<'_> = jni_ice_candidate.into();
+ // SAFETY: Java side must provide a `List`, so each element is `byte[]`.
+ let jni_ice_candidate = unsafe { JByteArray::from_raw(env, jni_ice_candidate.as_raw()) };
let opaque = env.convert_byte_array(jni_ice_candidate)?;
ice_candidates.push(signaling::IceCandidate::new(opaque));
}
@@ -396,7 +395,7 @@ pub fn received_ice(
/// Application notification of received Hangup message
pub fn received_hangup(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
call_id: jlong,
remote_peer: JObject,
@@ -406,7 +405,7 @@ pub fn received_hangup(
) -> Result<()> {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let call_id = CallId::from(call_id);
- let remote_peer = env.new_global_ref(remote_peer)?;
+ let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
call_manager.received_hangup(
remote_peer,
@@ -420,7 +419,7 @@ pub fn received_hangup(
/// Application notification of received Busy message
pub fn received_busy(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
call_id: jlong,
remote_peer: JObject,
@@ -428,7 +427,7 @@ pub fn received_busy(
) -> Result<()> {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let call_id = CallId::from(call_id);
- let remote_peer = env.new_global_ref(remote_peer)?;
+ let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
call_manager.received_busy(
remote_peer,
@@ -439,7 +438,7 @@ pub fn received_busy(
/// Application notification of received call message.
pub fn received_call_message(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
sender_uuid: JByteArray,
sender_device_id: DeviceId,
@@ -474,7 +473,7 @@ pub fn received_call_message(
/// Application notification of received HTTP response.
pub fn received_http_response(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
request_id: jlong,
status_code: jint,
@@ -512,22 +511,22 @@ pub fn accept_call(call_manager: *mut AndroidCallManager, call_id: jlong) -> Res
call_manager.accept_call(call_id)
}
-/// CMI request for the active Connection object
-pub fn get_active_connection(call_manager: *mut AndroidCallManager) -> Result {
+/// CMI request to get the active Connection object (a raw jobject pointing to the Global ref)
+pub fn get_active_connection(call_manager: *mut AndroidCallManager) -> Result {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let connection = call_manager.active_connection()?;
let android_connection = connection.app_connection()?;
- Ok(android_connection.to_jni())
+ Ok(android_connection.to_jni().as_raw())
}
-/// CMI request for the active CallContext object
-pub fn get_active_call_context(call_manager: *mut AndroidCallManager) -> Result {
+/// CMI request to get the active CallContext object (a raw jobject pointing to the Global ref)
+pub fn get_active_call_context(call_manager: *mut AndroidCallManager) -> Result {
let call_manager = unsafe { ptr_as_mut(call_manager)? };
let call = call_manager.active_call()?;
let android_call_context = call.call_context()?;
- Ok(android_call_context.to_jni())
+ Ok(android_call_context.to_jni().as_raw())
}
/// CMI request to set the audio status
@@ -605,14 +604,14 @@ pub fn close(call_manager: *mut AndroidCallManager) -> Result<()> {
// Call Links
pub fn read_call_link(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
sfu_url: JString,
auth_credential_presentation: JByteArray,
root_key: JByteArray,
request_id: jlong,
) -> Result<()> {
- let sfu_url = env.get_string(&sfu_url)?;
+ let sfu_url = sfu_url.try_to_string(env)?;
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
let root_key =
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
@@ -634,7 +633,7 @@ pub fn read_call_link(
#[allow(clippy::too_many_arguments)]
pub fn create_call_link(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
sfu_url: JString,
create_credential_presentation: JByteArray,
@@ -644,7 +643,7 @@ pub fn create_call_link(
restrictions: jint,
request_id: jlong,
) -> Result<()> {
- let sfu_url = env.get_string(&sfu_url)?;
+ let sfu_url = sfu_url.try_to_string(env)?;
let create_credential_presentation = env.convert_byte_array(create_credential_presentation)?;
let root_key =
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
@@ -672,7 +671,7 @@ pub fn create_call_link(
#[allow(clippy::too_many_arguments)]
pub fn update_call_link(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
sfu_url: JString,
auth_credential_presentation: JByteArray,
@@ -683,7 +682,7 @@ pub fn update_call_link(
new_revoked: jint,
request_id: jlong,
) -> Result<()> {
- let sfu_url = env.get_string(&sfu_url)?;
+ let sfu_url = sfu_url.try_to_string(env)?;
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
let root_key =
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
@@ -691,10 +690,10 @@ pub fn update_call_link(
let new_name = if new_name.is_null() {
None
} else {
- Some(env.get_string(&new_name)?)
+ Some(new_name.try_to_string(env)?)
};
let encrypted_name = new_name.map(|name| {
- let name = Cow::from(&name);
+ let name: &str = &name;
if name.is_empty() {
vec![]
} else {
@@ -731,7 +730,7 @@ pub fn update_call_link(
#[allow(clippy::too_many_arguments)]
pub fn delete_call_link(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
sfu_url: JString,
auth_credential_presentation: JByteArray,
@@ -739,7 +738,7 @@ pub fn delete_call_link(
admin_passkey: JByteArray,
request_id: jlong,
) -> Result<()> {
- let sfu_url = env.get_string(&sfu_url)?;
+ let sfu_url = sfu_url.try_to_string(env)?;
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
let root_key =
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
@@ -789,7 +788,7 @@ fn deserialize_to_group_member_info(
}
pub fn peek_group_call(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
request_id: jlong,
sfu_url: JString,
@@ -798,7 +797,7 @@ pub fn peek_group_call(
) -> Result<()> {
let request_id = request_id as u32;
- let sfu_url = env.get_string(&sfu_url)?.into();
+ let sfu_url = sfu_url.try_to_string(env)?;
let membership_proof = env.convert_byte_array(membership_proof)?;
@@ -811,7 +810,7 @@ pub fn peek_group_call(
}
pub fn peek_call_link_call(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
request_id: jlong,
sfu_url: JString,
@@ -820,7 +819,7 @@ pub fn peek_call_link_call(
) -> Result<()> {
let request_id = request_id as u32;
- let sfu_url = env.get_string(&sfu_url)?;
+ let sfu_url = sfu_url.try_to_string(env)?;
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
let root_key =
@@ -844,7 +843,7 @@ pub fn peek_call_link_call(
#[allow(clippy::too_many_arguments)]
pub fn create_group_call_client(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
group_id: JByteArray,
sfu_url: JString,
@@ -856,7 +855,7 @@ pub fn create_group_call_client(
native_video_track_borrowed_rc: jlong,
) -> Result {
let group_id = env.convert_byte_array(group_id)?;
- let sfu_url = env.get_string(&sfu_url)?.into();
+ let sfu_url = sfu_url.try_to_string(env)?;
let hkdf_extra_info = env.convert_byte_array(hkdf_extra_info)?;
let peer_connection_factory = unsafe {
@@ -909,7 +908,7 @@ pub fn create_group_call_client(
#[allow(clippy::too_many_arguments)]
pub fn create_call_link_call_client(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
sfu_url: JString,
endorsement_public_key: JByteArray,
@@ -923,7 +922,7 @@ pub fn create_call_link_call_client(
native_audio_track_borrowed_rc: jlong,
native_video_track_borrowed_rc: jlong,
) -> Result {
- let sfu_url = env.get_string(&sfu_url)?.into();
+ let sfu_url = sfu_url.try_to_string(env)?;
let endorsement_public_key = env.convert_byte_array(endorsement_public_key)?;
let auth_presentation = env.convert_byte_array(auth_presentation)?;
let root_key =
@@ -1086,7 +1085,7 @@ pub fn set_outgoing_group_call_video_is_screenshare(
}
pub fn group_ring(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
recipient: JByteArray,
@@ -1122,51 +1121,53 @@ pub fn set_data_mode(
}
pub fn request_video(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
jni_rendered_resolutions: JObject,
active_speaker_height: jint,
) -> Result<()> {
// Convert Java list of VideoRequest into Rust Vec.
- let jni_rendered_resolution_list = env.get_list(&jni_rendered_resolutions)?;
+ let jni_rendered_resolution_list =
+ jni::objects::JList::cast_local(env, jni_rendered_resolutions)?;
let mut rendered_resolutions: Vec = Vec::new();
- let mut iterator = jni_rendered_resolution_list.iter(env)?;
+ let iterator = jni_rendered_resolution_list.iter(env)?;
while let Some(jni_rendered_resolution) = iterator.next(env)? {
- const LONG_TYPE: &str = jni_signature!(long);
- const INT_TYPE: &str = jni_signature!(int);
- const NULLABLE_INT_TYPE: &str = jni_signature!(java.lang.Integer);
+ const LONG_TYPE: FieldSignature<'static> = jni_sig!(long);
+ const INT_TYPE: FieldSignature<'static> = jni_sig!(int);
+ const NULLABLE_INT_TYPE: FieldSignature<'static> = jni_sig!(java.lang.Integer);
- const DEMUX_ID_FIELD: &str = "demuxId";
- let demux_id =
- jni_get_field(env, &jni_rendered_resolution, DEMUX_ID_FIELD, LONG_TYPE)?.j()?;
+ let demux_id = env
+ .get_field(&jni_rendered_resolution, jni_str!("demuxId"), &LONG_TYPE)?
+ .into_long()?;
let demux_id = demux_id as u32;
- const WIDTH_FIELD: &str = "width";
- let width = jni_get_field(env, &jni_rendered_resolution, WIDTH_FIELD, INT_TYPE)?.i()?;
+ let width = env
+ .get_field(&jni_rendered_resolution, jni_str!("width"), &INT_TYPE)?
+ .into_int()?;
let width = width as u16;
- const HEIGHT_FIELD: &str = "height";
- let height = jni_get_field(env, &jni_rendered_resolution, HEIGHT_FIELD, INT_TYPE)?.i()?;
+ let height = env
+ .get_field(&jni_rendered_resolution, jni_str!("height"), &INT_TYPE)?
+ .into_int()?;
let height = height as u16;
- const FRAMERATE_FIELD: &str = "framerate";
- let framerate = jni_get_field(
- env,
- &jni_rendered_resolution,
- FRAMERATE_FIELD,
- NULLABLE_INT_TYPE,
- )?
- .l()?;
+ let framerate = env
+ .get_field(
+ &jni_rendered_resolution,
+ jni_str!("framerate"),
+ &NULLABLE_INT_TYPE,
+ )?
+ .into_object()?;
let framerate = if framerate.is_null() {
None
} else {
// We have java.lang.Integer, so we need to invoke the function to get the actual
// int value that is attached to it.
- match env.call_method(framerate, "intValue", jni_signature!(() -> int), &[]) {
+ match env.call_method(framerate, jni_str!("intValue"), jni_sig!(() -> int), &[]) {
Ok(jvalue) => {
- match jvalue.i() {
+ match jvalue.into_int() {
Ok(int) => Some(int.to_owned() as u16),
Err(_) => {
// The framerate can be ignored.
@@ -1201,7 +1202,7 @@ pub fn request_video(
}
pub fn approve_user(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
other_user_id: JByteArray,
@@ -1213,7 +1214,7 @@ pub fn approve_user(
}
pub fn deny_user(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
other_user_id: JByteArray,
@@ -1245,7 +1246,7 @@ pub fn block_client(
}
pub fn set_group_members(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
jni_serialized_group_members: JByteArray,
@@ -1258,7 +1259,7 @@ pub fn set_group_members(
}
pub fn set_membership_proof(
- env: &JNIEnv,
+ env: &Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
proof: JByteArray,
@@ -1270,12 +1271,12 @@ pub fn set_membership_proof(
}
pub fn react(
- env: &mut JNIEnv,
+ env: &mut Env,
call_manager: *mut AndroidCallManager,
client_id: group_call::ClientId,
value: JString,
) -> Result<()> {
- let value = env.get_string(&value)?.into();
+ let value: String = value.try_to_string(env)?;
let call_manager = unsafe { ptr_as_mut(call_manager)? };
call_manager.react(client_id, value);
Ok(())
diff --git a/src/rust/src/android/error.rs b/src/rust/src/android/error.rs
index 92b4ad52..9179f81f 100644
--- a/src/rust/src/android/error.rs
+++ b/src/rust/src/android/error.rs
@@ -5,40 +5,76 @@
//! Android Error Codes and Utilities.
-use anyhow::Error;
-use jni::{JNIEnv, errors, objects::JThrowable};
+use std::panic::{AssertUnwindSafe, catch_unwind};
+
+use jni::{
+ Env,
+ errors::ErrorPolicy,
+ jni_str,
+ objects::JThrowable,
+ strings::{JNIStr, JNIString},
+};
use thiserror::Error;
-use crate::{android::jni_util::*, core::util::try_scoped};
+use crate::core::util::try_scoped;
-const CALL_EXCEPTION_CLASS: &str = jni_class_name!(org.signal.ringrtc.CallException);
+const CALL_EXCEPTION_CLASS: &JNIStr = jni_str!("org/signal/ringrtc/CallException");
-/// Convert a `Error` into a Java `org.signal.ringrtc.CallException`
-/// and throw it.
-///
-/// This is used to communicate synchronous errors to the client
-/// application.
-pub fn throw_error(env: &mut JNIEnv, error: Error) {
- if let Ok(exception) = env.exception_occurred() {
- if env.exception_clear().is_ok() {
+/// `ErrorPolicy` that converts Rust errors and panics into a Java
+/// `org.signal.ringrtc.CallException` and throws it to the client.
+#[derive(Debug, Default)]
+pub struct ThrowCallException;
+
+impl ErrorPolicy for ThrowCallException {
+ type Captures<'unowned_env_local: 'native_method, 'native_method> = ();
+
+ fn on_error<'unowned_env_local: 'native_method, 'native_method>(
+ env: &mut Env<'unowned_env_local>,
+ _cap: &mut Self::Captures<'unowned_env_local, 'native_method>,
+ err: anyhow::Error,
+ ) -> jni::errors::Result {
+ // If the closure returned an error while a Java exception was already
+ // pending, preserve that exception as the cause.
+ if let Some(exception) = env.exception_occurred() {
+ env.exception_clear();
let _ = try_scoped(|| {
- let message = env.new_string(error.to_string())?;
- let call_exception: JThrowable = jni_new_object(
- env,
- CALL_EXCEPTION_CLASS,
- jni_args!((
- message => java.lang.String,
- exception => java.lang.Throwable,
- ) -> void),
- )?
- .into();
- Ok(env.throw(call_exception)?)
+ let message = env.new_string(err.to_string())?;
+ let call_exception = jni_new_object!(env, CALL_EXCEPTION_CLASS, (
+ message => java.lang.String,
+ exception => java.lang.Throwable,
+ ))?;
+ // SAFETY: We just constructed CallException, which extends Throwable.
+ let throwable = unsafe { JThrowable::from_raw(env, call_exception.as_raw()) };
+ Ok(env.throw(throwable)?)
});
} else {
- // Don't try to throw our own exception on top of another exception.
+ let jni_msg = JNIString::from(format!("{}", err));
+ let _ = env.throw_new(CALL_EXCEPTION_CLASS, &jni_msg);
}
- } else {
- let _ = env.throw_new(CALL_EXCEPTION_CLASS, format!("{}", error));
+ Ok(T::default())
+ }
+
+ fn on_panic<'unowned_env_local: 'native_method, 'native_method>(
+ env: &mut Env<'unowned_env_local>,
+ _cap: &mut Self::Captures<'unowned_env_local, 'native_method>,
+ payload: Box,
+ ) -> jni::errors::Result {
+ let panic_string = match payload.downcast::<&'static str>() {
+ Ok(s) => (*s).to_string(),
+ Err(payload) => match payload.downcast::() {
+ Ok(s) => *s,
+ Err(payload) => {
+ if let Err(drop_panic) = catch_unwind(AssertUnwindSafe(|| drop(payload))) {
+ log::error!("Panic while dropping panic payload: {:?}", drop_panic);
+ std::mem::forget(drop_panic);
+ }
+ "".to_string()
+ }
+ },
+ };
+ let jni_msg = JNIString::from(format!("Rust panic: {panic_string}"));
+ let _ = env.throw_new(CALL_EXCEPTION_CLASS, &jni_msg);
+ Ok(T::default())
}
}
@@ -48,29 +84,9 @@ pub enum AndroidError {
// Android JNI error codes
#[error("JNI: static method lookup failed. Class: {0}, Method: {1}, Sig: {2}")]
JniStaticMethodLookup(String, String, String),
- #[error("JNI: calling method failed. Method: {0}, Sig: {1}, Error: {2}")]
- JniCallMethod(String, String, errors::Error),
- #[error("JNI: calling static method failed. Class: {0}, Method: {1}, Sig: {2}")]
- JniCallStaticMethod(String, String, String),
- #[error("JNI: calling constructor failed. Constructor: {0}, Sig: {1}")]
- JniCallConstructor(String, String),
- #[error("JNI: getting field failed. Field: {0}, Type: {1}")]
- JniGetField(String, String),
- #[error("JNI: class not found. Type: {0} Add to the cache?")]
- JniGetLangClassNotFound(String),
- #[error("JNI: new object failed. Type: {0}")]
- JniNewLangObjectFailed(String),
#[error("JNI: invalid serialized buffer.")]
JniInvalidSerializedBuffer,
- // Android Class Cache error codes
- #[error("ClassCache: Class is already in cache: {0}")]
- ClassCacheDuplicate(String),
- #[error("ClassCache: class not found in jvm: {0}")]
- ClassCacheNotFound(String),
- #[error("ClassCache: class not found in cache: {0}")]
- ClassCacheLookup(String),
-
// Android Misc error codes
#[error("Creating JNI PeerConnection failed")]
CreateJniPeerConnection,
diff --git a/src/rust/src/android/jni_util.rs b/src/rust/src/android/jni_util.rs
index 0409b267..bede33ba 100644
--- a/src/rust/src/android/jni_util.rs
+++ b/src/rust/src/android/jni_util.rs
@@ -1,31 +1,11 @@
//
-// Copyright 2019-2021 Signal Messenger, LLC
+// Copyright 2019-2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
-//! Utility helpers for JNI access
-
-use std::{
- collections::HashMap,
- convert::{TryFrom, TryInto},
- marker::PhantomData,
-};
-
-use jni::{
- JNIEnv,
- objects::{GlobalRef, JClass, JObject, JValue, JValueOwned},
-};
-
-use crate::{android::error::AndroidError, common::Result, core::util::try_scoped};
-pub use crate::{jni_class_name, jni_signature};
-
macro_rules! jni_arg {
( $arg:expr => boolean ) => {
- >::from($arg)
- };
- // jni_signature will reject this, but having it do something reasonable avoids multiple errors.
- ( $arg:expr => bool ) => {
- >::from($arg)
+ jni::objects::JValue::Bool($arg)
};
( $arg:expr => byte ) => {
jni::objects::JValue::Byte($arg)
@@ -54,306 +34,58 @@ macro_rules! jni_arg {
};
}
-macro_rules! jni_return_type {
- // Unfortunately there's not a conversion directly from JValue to bool, only jboolean.
- (boolean) => {
- jni::sys::jboolean
- };
- // jni_signature will reject this, but having it do something reasonable avoids multiple errors.
- (bool) => {
- jni::sys::jboolean
- };
- (byte) => {
- jni::sys::jbyte
- };
- (char) => {
- jni::sys::jchar
- };
- (short) => {
- jni::sys::jshort
- };
- (int) => {
- jni::sys::jint
- };
- (long) => {
- jni::sys::jlong
- };
- (float) => {
- jni::sys::jfloat
- };
- (double) => {
- jni::sys::jdouble
- };
- (void) => {
- ()
- };
- // Assume anything else is an object. This includes arrays and classes.
- ($($_:tt)+) => {
- jni::objects::JObject
- };
-}
-
-/// Represents a return type, used by [`JniArgs`].
-///
-/// This is an implementation detail of [`jni_args`] and [`JniArgs`]. Using a function type makes
-/// `JniArgs` covariant, which allows the compiler to be less strict about the lifetime marker.
-pub type PhantomReturnType = PhantomData R>;
-
-/// A JNI argument list, type-checked with its signature.
-#[derive(Debug, Clone, Copy)]
-pub struct JniArgs<'local, 'obj_ref, R, const LEN: usize> {
- pub sig: &'static str,
- pub args: [JValue<'local, 'obj_ref>; LEN],
- pub _return: PhantomReturnType,
-}
-
-/// Produces a JniArgs struct from the given arguments and return type.
-///
-/// # Example
-///
-/// ```
-/// let args = jni_args!((name => java.lang.String, 0x3FFF => short) -> void);
-/// assert_eq!(args.sig, "(Ljava/lang/String;S)V");
-/// assert_eq!(args.args.len(), 2);
-/// ```
+/// Builds a `(MethodSignature, [JValue; N])` tuple from a Java-style arg list.
macro_rules! jni_args {
(
(
$( $arg:expr => $arg_base:tt $(. $arg_rest:ident)* $(:: $arg_nested:ident)* ),* $(,)?
) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
) => {
- JniArgs {
- sig: jni_signature!(
+ (
+ jni::jni_sig!(
(
$( $arg_base $(. $arg_rest)* $(:: $arg_nested)* ),*
) -> $ret_base $(. $ret_rest)* $(:: $ret_nested)*
),
- args: [$(jni_arg!($arg => $arg_base)),*],
- _return: PhantomReturnType:: {},
- }
+ [$(jni_arg!($arg => $arg_base)),*],
+ )
}
}
-/// Wrapper around JNIEnv::call_method() with logging.
-pub fn jni_call_method<
- 'input,
- 'output,
- O: AsRef>,
- R: TryFrom, Error = jni::errors::Error>,
- const LEN: usize,
->(
- env: &mut JNIEnv<'output>,
- object: O,
- name: &'static str,
- args: JniArgs,
-) -> Result {
- env.call_method(object, name, args.sig, &args.args)
- .and_then(|v| v.try_into())
- .map_err(|e| AndroidError::JniCallMethod(name.to_string(), args.sig.to_string(), e).into())
-}
-
-/// Wrapper around JNIEnv::call_static_method() with logging.
-#[allow(dead_code)]
-pub fn jni_call_static_method<
- 'output,
- R: TryFrom, Error = jni::errors::Error>,
- const LEN: usize,
->(
- env: &mut JNIEnv<'output>,
- class: &'static str,
- name: &'static str,
- args: JniArgs,
-) -> Result {
- env.call_static_method(class, name, args.sig, &args.args)
- .and_then(|v| v.try_into())
- .map_err(|e| AndroidError::JniCallMethod(name.to_string(), args.sig.to_string(), e).into())
-}
-
-/// Wrapper around JNIEnv::new_object() with logging.
-pub fn jni_new_object<'output, const LEN: usize>(
- env: &mut JNIEnv<'output>,
- class: &'static str,
- args: JniArgs<(), LEN>,
-) -> Result> {
- match env.new_object(class, args.sig, &args.args) {
- Ok(v) => Ok(v),
- Err(_) => {
- Err(AndroidError::JniCallConstructor(class.to_string(), args.sig.to_string()).into())
- }
- }
-}
-
-/// Wrapper around JNIEnv::get_field() with logging.
-pub fn jni_get_field<'input, 'output, O: AsRef>>(
- env: &mut JNIEnv<'output>,
- object: O,
- name: &'static str,
- ty: &'static str,
-) -> Result> {
- env.get_field(object, name, ty)
- .map_err(|_| AndroidError::JniGetField(name.to_string(), ty.to_string()).into())
-}
-
-/// Creates a new java.util.ArrayList object
-pub fn jni_new_arraylist<'output>(
- env: &mut JNIEnv<'output>,
- initial_capacity: usize,
-) -> Result> {
- jni_new_object(
- env,
- jni_class_name!(java.util.ArrayList),
- jni_args!((initial_capacity.try_into().expect("too big for Java") => int) -> void),
- )
-}
-
-/// Creates a new java.util.HashMap object
-pub fn jni_new_hashmap<'output>(
- env: &mut JNIEnv<'output>,
- initial_capacity: usize,
-) -> Result> {
- jni_new_object(
- env,
- jni_class_name!(java.util.HashMap),
- jni_args!((initial_capacity.try_into().expect("too big for Java") => int) -> void),
- )
-}
-
-/// Prints local and global references to the log.
-#[allow(dead_code)]
-pub fn dump_references(env: &mut JNIEnv) {
- let _ = env.with_local_frame(5, |env| -> Result<()> {
- info!("Dumping references ->");
- let _ = env.call_static_method(
- jni_class_name!(dalvik.system.VMDebug),
- "dumpReferenceTables",
- jni_signature!(() -> void),
- &[],
+/// Calls `Env::call_method` with the given args. Returns `Result`.
+///
+/// Use trailing `.into_` to unwrap a typed return.
+macro_rules! jni_call_method {
+ (
+ $env:expr, $obj:expr, $name:expr,
+ ( $($arg_list:tt)* ) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
+ ) => {{
+ let (sig, args) = jni_args!(
+ ( $($arg_list)* ) -> $ret_base $(. $ret_rest)* $(:: $ret_nested)*
);
- info!("<- Done with references");
-
- Ok(())
- });
+ $env.call_method($obj, $name, &sig, &args)
+ }};
}
-/// A cache of Java class objects
+/// Calls `Env::call_static_method` with the given args. Returns `Result`.
+macro_rules! jni_call_static_method {
+ (
+ $env:expr, $class:expr, $name:expr,
+ ( $($arg_list:tt)* ) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
+ ) => {{
+ let (sig, args) = jni_args!(
+ ( $($arg_list)* ) -> $ret_base $(. $ret_rest)* $(:: $ret_nested)*
+ );
+ $env.call_static_method($class, $name, &sig, &args)
+ }};
+}
+
+/// Calls `Env::new_object` with the given args. Returns `Result`.
///
-/// JNI cannot lookup classes by name from threads other than the main
-/// thread. See this FAQ for background:
-/// https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class
-///
-/// The solution here is to look up the class objects at init time on
-/// the main thread and cache a global reference to the object for
-/// later use.
-#[derive(Clone)]
-pub struct ClassCache {
- /// HashMap mapping the class name (String) to Java object
- map: HashMap,
-}
-
-impl ClassCache {
- /// Returns an empty cache
- pub fn new() -> Self {
- Self {
- map: HashMap::new(),
- }
- }
-
- /// Look up the class specified by `class_name` and store a global
- /// reference to the class object result in the cache.
- ///
- /// * Adding the same class twice is treated as an error.
- /// * If the class lookup fails, return an error.
- pub fn add_class(&mut self, env: &mut JNIEnv, class_name: &str) -> Result<()> {
- if self.map.contains_key(class_name) {
- return Err(AndroidError::ClassCacheDuplicate(class_name.to_string()).into());
- }
-
- let class_object = match env.find_class(class_name) {
- Ok(v) => v,
- Err(_) => return Err(AndroidError::ClassCacheNotFound(class_name.to_string()).into()),
- };
-
- let class_ref = env.new_global_ref(JObject::from(class_object))?;
- self.map.insert(String::from(class_name), class_ref);
- Ok(())
- }
-
- /// Retrieve the class object specified by `class_name` and return it.
- ///
- /// * If the class is not in the cache, return an error.
- pub fn get_class(&self, class_name: &str) -> Result<&JClass<'_>> {
- if let Some(class_ref) = self.map.get(class_name) {
- let object = class_ref.as_obj();
- Ok(<&JClass>::from(object))
- } else {
- Err(AndroidError::ClassCacheLookup(class_name.to_string()).into())
- }
- }
-}
-
-/// A wrapper around [`JNIEnv`] that reports uncaught exceptions on destruction.
-///
-/// Normally JNI handles uncaught exceptions when a native thread is "detached" from the JVM, but
-/// RingRTC treats all its callback threads as "daemon" threads that are only detached when the
-/// native thread exits. This regains that functionality.
-///
-/// Because `ExceptionCheckingJNIEnv` implements `Deref`, it should be a drop-in replacement for
-/// most uses of JNIEnv as a value. References to JNIEnv should continue as references.
-pub struct ExceptionCheckingJNIEnv<'a>(JNIEnv<'a>);
-
-impl Drop for ExceptionCheckingJNIEnv<'_> {
- fn drop(&mut self) {
- let result = try_scoped(|| {
- let exception = self.exception_occurred()?;
- if exception.is_null() {
- return Ok(());
- }
- self.exception_clear()?;
- let thread = jni_call_static_method(
- self,
- jni_class_name!(java.lang.Thread),
- "currentThread",
- jni_args!(() -> java.lang.Thread),
- )?;
- let handler = jni_call_method(
- self,
- &thread,
- "getUncaughtExceptionHandler",
- jni_args!(() -> java.lang.Thread::UncaughtExceptionHandler),
- )?;
- jni_call_method(
- self,
- handler,
- "uncaughtException",
- jni_args!((thread => java.lang.Thread, exception => java.lang.Throwable) -> void),
- )?;
- Ok(())
- });
- match result {
- Ok(()) => {}
- Err(e) => {
- error!("unable to rethrow exception: {e}");
- }
- }
- }
-}
-
-impl<'a> From> for ExceptionCheckingJNIEnv<'a> {
- fn from(env: JNIEnv<'a>) -> Self {
- Self(env)
- }
-}
-
-impl<'a> std::ops::Deref for ExceptionCheckingJNIEnv<'a> {
- type Target = JNIEnv<'a>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl std::ops::DerefMut for ExceptionCheckingJNIEnv<'_> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
+/// The constructor's JNI return type is always `void`; this macro embeds that.
+macro_rules! jni_new_object {
+ ( $env:expr, $class:expr, ( $($arg_list:tt)* ) $(,)? ) => {{
+ let (sig, args) = jni_args!(( $($arg_list)* ) -> void);
+ $env.new_object($class, &sig, &args)
+ }};
}
diff --git a/src/rust/src/android/logging.rs b/src/rust/src/android/logging.rs
index ee67eceb..dbed5759 100644
--- a/src/rust/src/android/logging.rs
+++ b/src/rust/src/android/logging.rs
@@ -6,39 +6,27 @@
//! Setup Android logging object
use jni::{
- JNIEnv, JavaVM,
- objects::{GlobalRef, JObject},
+ Env, JavaVM, jni_sig, jni_str,
+ objects::{Global, JObject},
+ signature::MethodSignature,
+ strings::JNIStr,
};
use log::{Level, Log, Metadata, Record};
-use crate::{
- android::{error::AndroidError, jni_util::*},
- common::Result,
-};
+use crate::{android::error::AndroidError, common::Result};
/// Log object for interfacing with existing Android logger.
struct AndroidLogger {
level: Level,
jvm: JavaVM,
- logger_class: GlobalRef,
+ logger_class: Global>,
}
// Method name and signature required of Java logger class
// void log(int level, String message)
-const LOGGER_CLASS: &str = jni_class_name!(org.signal.ringrtc.Log);
-const LOGGER_METHOD: &str = "log";
-const LOGGER_SIG: &str = jni_signature!((int, java.lang.String) -> void);
-
-impl AndroidLogger {
- // This is specifically *not* using ExceptionCheckingJNIEnv:
- // - We may be logging in the middle of some other operation, which might be able to handle
- // uncaught exceptions.
- // - ExceptionCheckingJNIEnv itself can log in failure cases, and we don't want an infinite
- // loop.
- fn get_java_env(&self) -> Result> {
- Ok(self.jvm.attach_current_thread_as_daemon()?)
- }
-}
+const LOGGER_CLASS: &JNIStr = jni_str!("org/signal/ringrtc/Log");
+const LOGGER_METHOD: &JNIStr = jni_str!("log");
+const LOGGER_SIG: MethodSignature<'static, 'static> = jni_sig!((int, java.lang.String) -> void);
impl Log for AndroidLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
@@ -54,25 +42,6 @@ impl Log for AndroidLogger {
return;
}
- // Use the `JavaVM` interface to attach a `JNIEnv` to the current thread.
- let mut env = match self.get_java_env() {
- Ok(v) => v,
- Err(_) => return,
- };
-
- // Attempt to clear any exception before we log anything.
- // We'll rethrow it after logging.
- let exception = env
- .exception_occurred()
- .unwrap_or_else(|_| JObject::null().into());
- if !exception.is_null() {
- let exception_cleared = env.exception_clear();
- if exception_cleared.is_err() {
- // If we can't clear the exception, skip the log.
- return;
- }
- }
-
let get_file_name = || -> Option<&str> {
let file = record.file()?;
file.split(std::path::MAIN_SEPARATOR_STR).last()
@@ -89,43 +58,61 @@ impl Log for AndroidLogger {
let level = record.level() as i32;
- let _ = env.with_local_frame(5, |env| -> Result<()> {
- let msg = match env.new_string(message) {
- Ok(v) => JObject::from(v),
- Err(_) => return Ok(()),
- };
+ let _ = self.jvm.attach_current_thread(|env| -> Result<()> {
+ // Attempt to clear any exception before we log anything.
+ // We'll rethrow it after logging.
+ let exception = env.exception_occurred();
+ let had_exception = exception.is_some();
+ if had_exception {
+ env.exception_clear();
+ }
- let values = [level.into(), (&msg).into()];
+ let _ = env.with_local_frame(5, |env| -> Result<()> {
+ let msg = match env.new_string(&message) {
+ Ok(v) => JObject::from(v),
+ Err(_) => return Ok(()),
+ };
+
+ let values = [level.into(), (&msg).into()];
+
+ // Ignore the result here, can't do anything about it anyway.
+ let _ = env.call_static_method(
+ &self.logger_class,
+ LOGGER_METHOD,
+ &LOGGER_SIG,
+ &values,
+ );
+ Ok(())
+ });
+
+ // If we put an exception "on hold" earlier, try to throw it again now.
+ if let Some(exception) = exception
+ && had_exception
+ {
+ // But check that there hasn't been *another* exception thrown.
+ if env.exception_occurred().is_none() {
+ let _ = env.throw(exception);
+ }
+ }
- // Ignore the result here, can't do anything about it anyway.
- let _ =
- env.call_static_method(&self.logger_class, LOGGER_METHOD, LOGGER_SIG, &values);
Ok(())
});
-
- // If we put an exception "on hold" earlier, try to throw it again now.
- if !exception.is_null() {
- // But check that there hasn't been *another* exception thrown.
- if let Ok(false) = env.exception_check() {
- let _ = env.throw(exception);
- }
- }
}
}
fn flush(&self) {}
}
-pub fn init_logging(env: &mut JNIEnv, level: Level) -> Result<()> {
+pub fn init_logging(env: &mut Env, level: Level) -> Result<()> {
// Check if the Logger class contains a good logger method and signature
if env
- .get_static_method_id(LOGGER_CLASS, LOGGER_METHOD, LOGGER_SIG)
+ .get_static_method_id(LOGGER_CLASS, LOGGER_METHOD, &LOGGER_SIG)
.is_err()
{
return Err(AndroidError::JniStaticMethodLookup(
- String::from(LOGGER_CLASS),
- String::from(LOGGER_METHOD),
- String::from(LOGGER_SIG),
+ LOGGER_CLASS.to_string(),
+ LOGGER_METHOD.to_string(),
+ LOGGER_SIG.sig().to_string(),
)
.into());
}
@@ -134,11 +121,11 @@ pub fn init_logging(env: &mut JNIEnv, level: Level) -> Result<()> {
// main thread, so stash a global ref to the class now, while
// we're on the main thread.
let logger_class = env.find_class(LOGGER_CLASS)?;
- let logger_class = env.new_global_ref(JObject::from(logger_class))?;
+ let logger_class = env.new_global_ref(logger_class)?;
- // `JNIEnv` cannot be sent across thread boundaries. To be able to use JNI
+ // `Env` cannot be sent across thread boundaries. To be able to use JNI
// functions in other threads, we must first obtain the `JavaVM` interface
- // which, unlike `JNIEnv` is `Send`.
+ // which, unlike `Env` is `Send`.
let jvm = env.get_java_vm()?;
let logger = AndroidLogger {
level,
diff --git a/src/rust/src/android/types.rs b/src/rust/src/android/types.rs
new file mode 100644
index 00000000..b0a1423d
--- /dev/null
+++ b/src/rust/src/android/types.rs
@@ -0,0 +1,114 @@
+//
+// Copyright 2026 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+//
+
+use jni::{
+ Env, bind_java_type,
+ refs::{LoaderContext, Reference as _},
+};
+
+// RingRTC App Classes
+bind_java_type! { pub CallSummary => org.signal.ringrtc.CallSummary }
+bind_java_type! { pub QualityStats => org.signal.ringrtc.CallSummary::QualityStats }
+bind_java_type! { pub MediaQualityStats => org.signal.ringrtc.CallSummary::MediaQualityStats }
+bind_java_type! { pub CallLinkState => org.signal.ringrtc.CallLinkState }
+bind_java_type! { pub CallLinkRootKey => org.signal.ringrtc.CallLinkRootKey }
+bind_java_type! { pub HttpHeader => org.signal.ringrtc.HttpHeader }
+bind_java_type! { pub HttpResult => org.signal.ringrtc.CallManager::HttpResult }
+bind_java_type! { pub PeekInfo => org.signal.ringrtc.PeekInfo }
+bind_java_type! { pub Reaction => org.signal.ringrtc.GroupCall::Reaction }
+bind_java_type! { pub RemoteDeviceState => org.signal.ringrtc.GroupCall::RemoteDeviceState }
+bind_java_type! { pub ReceivedAudioLevel => org.signal.ringrtc.GroupCall::ReceivedAudioLevel }
+
+// RingRTC Enum Classes
+bind_java_type! {
+ pub CallEvent => org.signal.ringrtc.CallManager::CallEvent,
+ methods { static fn from_native_index(value: jint) -> CallEvent }
+}
+bind_java_type! {
+ pub CallMediaType => org.signal.ringrtc.CallManager::CallMediaType,
+ methods { static fn from_native_index(value: jint) -> CallMediaType }
+}
+bind_java_type! {
+ pub HangupType => org.signal.ringrtc.CallManager::HangupType,
+ methods { static fn from_native_index(value: jint) -> HangupType }
+}
+bind_java_type! {
+ pub HttpMethod => org.signal.ringrtc.CallManager::HttpMethod,
+ methods { static fn from_native_index(value: jint) -> HttpMethod }
+}
+bind_java_type! {
+ pub CallEndReason => org.signal.ringrtc.CallManager::CallEndReason,
+ methods { static fn from_native_index(value: jint) -> CallEndReason }
+}
+bind_java_type! {
+ pub ConnectionState => org.signal.ringrtc.GroupCall::ConnectionState,
+ methods { static fn from_native_index(value: jint) -> ConnectionState }
+}
+bind_java_type! {
+ pub JoinState => org.signal.ringrtc.GroupCall::JoinState,
+ methods { static fn from_native_index(value: jint) -> JoinState }
+}
+bind_java_type! {
+ pub SpeechEvent => org.signal.ringrtc.GroupCall::SpeechEvent,
+ methods { static fn from_native_index(value: jint) -> SpeechEvent }
+}
+
+// JDK Primitives
+bind_java_type! {
+ pub JBoolean => java.lang.Boolean,
+ constructors { fn new(value: jboolean) }
+}
+bind_java_type! {
+ pub JFloat => java.lang.Float,
+ constructors { fn new(value: jfloat) }
+}
+bind_java_type! {
+ pub JInteger => java.lang.Integer,
+ constructors { fn new(value: jint) }
+}
+bind_java_type! {
+ pub JLong => java.lang.Long,
+ constructors { fn new(value: jlong) }
+}
+
+// JDK Collections
+bind_java_type! {
+ pub JArrayList => java.util.ArrayList,
+ constructors { fn with_capacity(initial_capacity: jint) }
+}
+bind_java_type! {
+ pub JHashMap => java.util.HashMap,
+ constructors { fn with_capacity(initial_capacity: jint) }
+}
+
+pub fn init_class_cache(env: &mut Env) -> jni::errors::Result<()> {
+ let ctx = LoaderContext::default();
+ CallSummary::lookup_class(env, &ctx)?;
+ QualityStats::lookup_class(env, &ctx)?;
+ MediaQualityStats::lookup_class(env, &ctx)?;
+ CallLinkState::lookup_class(env, &ctx)?;
+ CallLinkRootKey::lookup_class(env, &ctx)?;
+ HttpHeader::lookup_class(env, &ctx)?;
+ HttpResult::lookup_class(env, &ctx)?;
+ PeekInfo::lookup_class(env, &ctx)?;
+ Reaction::lookup_class(env, &ctx)?;
+ RemoteDeviceState::lookup_class(env, &ctx)?;
+ ReceivedAudioLevel::lookup_class(env, &ctx)?;
+ CallEvent::lookup_class(env, &ctx)?;
+ CallMediaType::lookup_class(env, &ctx)?;
+ HangupType::lookup_class(env, &ctx)?;
+ HttpMethod::lookup_class(env, &ctx)?;
+ CallEndReason::lookup_class(env, &ctx)?;
+ ConnectionState::lookup_class(env, &ctx)?;
+ JoinState::lookup_class(env, &ctx)?;
+ SpeechEvent::lookup_class(env, &ctx)?;
+ JBoolean::lookup_class(env, &ctx)?;
+ JFloat::lookup_class(env, &ctx)?;
+ JInteger::lookup_class(env, &ctx)?;
+ JLong::lookup_class(env, &ctx)?;
+ JArrayList::lookup_class(env, &ctx)?;
+ JHashMap::lookup_class(env, &ctx)?;
+ Ok(())
+}
diff --git a/src/rust/src/android/webrtc_java_media_stream.rs b/src/rust/src/android/webrtc_java_media_stream.rs
index b0887b71..abcf044b 100644
--- a/src/rust/src/android/webrtc_java_media_stream.rs
+++ b/src/rust/src/android/webrtc_java_media_stream.rs
@@ -6,8 +6,8 @@
//! webrtc::jni::JavaMediaStream Interface.
use jni::{
- JNIEnv,
- objects::{GlobalRef, JObject},
+ Env,
+ objects::{Global, JObject},
sys::jobject,
};
@@ -51,11 +51,11 @@ impl JavaMediaStream {
Ok(Self { rffi })
}
- /// Return a JNI GlobalRef to the JavaMediaStream object
- pub fn global_ref(&self, env: &JNIEnv) -> Result {
+ /// Return a JNI Global to the JavaMediaStream object
+ pub fn global_ref(&self, env: &Env) -> Result>> {
unsafe {
let object = Rust_getJavaMediaStreamObject(self.rffi.borrow());
- Ok(env.new_global_ref(JObject::from_raw(object))?)
+ Ok(env.new_global_ref(JObject::from_raw(env, object))?)
}
}
}
diff --git a/src/rust/src/android/webrtc_peer_connection_factory.rs b/src/rust/src/android/webrtc_peer_connection_factory.rs
index ae93d7cb..2fb3df0a 100644
--- a/src/rust/src/android/webrtc_peer_connection_factory.rs
+++ b/src/rust/src/android/webrtc_peer_connection_factory.rs
@@ -6,7 +6,7 @@
//! Re-exports WebRTC JNI interfaces
use jni::{
- JNIEnv,
+ EnvUnowned,
objects::{JClass, JObject},
sys::jlong,
};
@@ -17,7 +17,7 @@ unsafe extern "C" {
/// Export the nativeCreatePeerConnection() call from the
/// org.webrtc.PeerConnectionFactory class.
pub fn Java_org_webrtc_PeerConnectionFactory_nativeCreatePeerConnection(
- env: JNIEnv,
+ unowned_env: EnvUnowned,
class: JClass,
factory: jlong,
rtcConfig: JObject,
diff --git a/src/rust/src/common/jni_signature.rs b/src/rust/src/common/jni_signature.rs
deleted file mode 100644
index 8421029f..00000000
--- a/src/rust/src/common/jni_signature.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-// Copyright 2021 Signal Messenger, LLC
-// SPDX-License-Identifier: AGPL-3.0-only
-//
-
-//! Macros to generate JNI signature strings.
-//!
-//! Located outside of the `android` module so that the tests get run.
-
-#![allow(unused_macros)]
-
-/// Takes a Java-esque class name of the form `org.signal.Outer::Inner` and turns it into a
-/// JNI-style name `org/signal/Outer$Inner`.
-#[macro_export]
-macro_rules! jni_class_name {
- ( $arg_base:tt $(. $arg_rest:ident)+ $(:: $arg_nested:ident)* ) => {
- concat!(
- stringify!($arg_base),
- $("/", stringify!($arg_rest),)+
- $("$", stringify!($arg_nested),)*
- )
- }
-}
-
-#[test]
-fn test_jni_class_name() {
- assert_eq!(jni_class_name!(foo.bar), "foo/bar");
- assert_eq!(jni_class_name!(foo.bar.baz), "foo/bar/baz");
- assert_eq!(jni_class_name!(foo.bar.baz::garply), "foo/bar/baz$garply");
- assert_eq!(
- jni_class_name!(foo.bar.baz::garply::qux),
- "foo/bar/baz$garply$qux"
- );
-}
-
-/// Converts a function or type signature to a JNI signature string.
-///
-/// This macro uses Rust function syntax `(Foo, Bar) -> Baz`, and uses Rust syntax for Java arrays
-/// `[Foo]`, but otherwise uses Java names for types: `boolean`, `byte`, `void`. Like
-/// [`jni_class_name`], inner classes are indicated with `::` rather than `.`.
-#[macro_export]
-macro_rules! jni_signature {
- ( boolean ) => ("Z");
- ( bool ) => (compile_error!("use Java type 'boolean'"));
- ( byte ) => ("B");
- ( char ) => ("C");
- ( short ) => ("S");
- ( int ) => ("I");
- ( long ) => ("J");
- ( float ) => ("F");
- ( double ) => ("D");
- ( void ) => ("V");
-
- // Escape hatch: provide a literal string.
- ( $x:literal ) => ($x);
-
- // Arrays
- ( [$($contents:tt)+] ) => {
- concat!("[", jni_signature!($($contents)+))
- };
-
- // Classes
- ( $arg_base:tt $(. $arg_rest:ident)+ $(:: $arg_nested:ident)* ) => {
- concat!(
- "L",
- jni_class_name!($arg_base $(. $arg_rest)+ $(:: $arg_nested)*),
- ";"
- )
- };
-
- // Functions
- (
- (
- $( $arg_base:tt $(. $arg_rest:ident)* $(:: $arg_nested:ident)* ),* $(,)?
- ) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
- ) => {
- concat!(
- "(",
- $( jni_signature!($arg_base $(. $arg_rest)* $(:: $arg_nested)*), )*
- ")",
- jni_signature!($ret_base $(. $ret_rest)* $(:: $ret_nested)*)
- )
- };
-}
-
-#[test]
-fn test_jni_signature() {
- // Literals
- assert_eq!(jni_signature!("Lfoo/bar;"), "Lfoo/bar;");
-
- // Classes
- assert_eq!(jni_signature!(foo.bar), "Lfoo/bar;");
- assert_eq!(jni_signature!(foo.bar.baz), "Lfoo/bar/baz;");
- assert_eq!(jni_signature!(foo.bar.baz::garply), "Lfoo/bar/baz$garply;");
- assert_eq!(
- jni_signature!(foo.bar.baz::garply::qux),
- "Lfoo/bar/baz$garply$qux;"
- );
-
- // Arrays
- assert_eq!(jni_signature!([byte]), "[B");
- assert_eq!(jni_signature!([[byte]]), "[[B");
- assert_eq!(jni_signature!([foo.bar]), "[Lfoo/bar;");
- assert_eq!(
- jni_signature!([foo.bar.baz::garply::qux]),
- "[Lfoo/bar/baz$garply$qux;"
- );
-
- // Functions
- assert_eq!(jni_signature!(() -> void), "()V");
- assert_eq!(jni_signature!((byte, int) -> float), "(BI)F");
- assert_eq!(
- jni_signature!(([byte], foo.bar, foo.bar.baz::garply::qux) -> [byte]),
- "([BLfoo/bar;Lfoo/bar/baz$garply$qux;)[B"
- );
- assert_eq!(jni_signature!(() -> foo.bar), "()Lfoo/bar;");
- assert_eq!(
- jni_signature!(() -> foo.bar.baz::garply::qux),
- "()Lfoo/bar/baz$garply$qux;"
- );
-}
diff --git a/src/rust/src/common/mod.rs b/src/rust/src/common/mod.rs
index d4460bab..2e06bd4f 100644
--- a/src/rust/src/common/mod.rs
+++ b/src/rust/src/common/mod.rs
@@ -6,7 +6,6 @@
//! Common types used throughout the library.
pub mod actor;
-pub mod jni_signature;
pub mod slice;
pub mod time;
pub mod units;
diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs
index 1bf24cff..ed7cc245 100644
--- a/src/rust/src/lib.rs
+++ b/src/rust/src/lib.rs
@@ -70,6 +70,7 @@ mod android {
mod call_manager;
mod error;
mod logging;
+ mod types;
mod webrtc_java_media_stream;
mod webrtc_peer_connection_factory;
}