Hi <@UJRUJP0F9>, I want C++ code invoke a callback...
# multiplatform
p
Hi @Artyom Degtyarev [JB], I want C++ code invoke a callback that is implemented in Kotlin, and that callback need to return a string, is that possible? Currently I declare the callback in C header like this:
Copy code
typedef const char* (*PCClientOnPreferCodecs)(void*, const char*, const char*);
And my Kotlin code implementing it is:
Copy code
private fun PCClientCallbackOnPreferCodecs(opaque: COpaquePointer?, peerUidPtr: CPointer<ByteVar>?, sdpPtr: CPointer<ByteVar>?): CPointer<ByteVar>? {
  initRuntimeIfNeeded()
  if (opaque == null) {
    return null
  }
  memScoped {
    return opaque.asStableRef<PeerConnectionClientCallback>().get().onPreferCodecs(peerUid, sdp).cstr.ptr
  }
}
I pass it into C++ with
staticCFunction(::PCClientCallbackOnPreferCodecs)
, and pass
opaque
with
StableRef.create(callback).asCPointer()
. It could be compiled and linked, but at runtime the string I get at C++ is scrambled code.
a
Ugh, maybe the problem here is that you use
memScoped
block here. Pointers allocated like that become invalid as soon as you get out of the block.
p
Thanks for your quick reply! But if I don't use
memScoped
, how could I convert
String
to
CPointer<ByteVar>
?
a
There is an example using nativeHeap in the documentation (https://github.com/JetBrains/kotlin-native/blob/master/INTEROP.md#working-with-the-strings). I am thinking on how it should be done most correctly, but it should be enough to proof the idea.
p
I tried this, the code looks like:
Copy code
private fun PCClientCallbackOnPreferCodecs(opaque: COpaquePointer?, peerUidPtr: CPointer<ByteVar>?, sdpPtr: CPointer<ByteVar>?): CPointer<ByteVar>? {
  initRuntimeIfNeeded()
  if (opaque == null) {
    return null
  }
  return opaque.asStableRef<PeerConnectionClientCallback>().get().onPreferCodecs(peerUid, sdp).cstr.getPointer(nativeHeap)
}
But it couldn't compile, it fails with
Type mismatch: inferred type is nativeHeap but AutofreeScope was expected
.
m
Strings in Kotlin are in UTF-16, so if passed directly to C++ it become char16_t[]
p
@msink I don't think so, my other code, e.g. kotlin call C++ and pass kotlin String into C++, works fine with
const char*
.
m
Then it is converted on the fly utf8<->utf16, allocating temporary arrays in nativeHeap, as said above.
p
Okay... then how could I achieve my goal? Could you please help me?
m
.cstr.getPointer(nativeHeap)
is broken, I use
.cstr.place(nativeHeap.allocArray(buflen))
instead. But you have to somehow calculate or guess
buflen
here. And somewhere later call
nativeHeap.free(it)
, or else you will have memory leak.
p
thanks man! I'll try that. is it mandatory to free it in kotlin? can I free it in C++?
m
Not sure, likely it's different heap, so should be called from Kotlin. But nothing prevents you from wrapping it to Kotlin function callable from C.
p
Oh yes, that's a great idea!