Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need a way to load Static library for iOS in Unity via your Nuget based C# DLL #1859

Closed
WaqasGameDev opened this issue Feb 13, 2025 · 7 comments

Comments

@WaqasGameDev
Copy link

Hi, I'm from the unity Ecosystem and I went through very good discussions between you and a unity developer and following those threads, I was able to build and run your solution for Offline TTS in android and it works nicely. But the issue now I'm having is I want to do the same in iOS too but your code in C# DLL (I got it from nuget package of yours) only imports DLL by naming the library which in unity is only valid for dynamic libraries. And for iOS, we need to link static libraries and for that unity required DLL import attribute to be like [DllImport("__internal")] instead of [DllImport("sherpa-onnx-c-api")]

Is there any way we can have 2 versions of that DLL or if the code for the DLL is open source, can I have the source code files so that I can have 2 DLLs one for android shared library and one for ios static.

Thanks.

@csukuangfj
Copy link
Collaborator

if the code for the DLL is open source,

Everything is open-sourced.


can I have the source code files

Yes, the code is at https://github.com/k2-fsa/sherpa-onnx


one for ios static

https://github.com/k2-fsa/sherpa-onnx/blob/master/build-ios.sh
this script can build sherpa-onnx static libs for ios


FYI: We have been using ios shared libs in flutter for iOS. The code for building sherpa-onnx shared libs for ios is at
https://github.com/k2-fsa/sherpa-onnx/blob/master/build-ios-shared.sh

@WaqasGameDev
Copy link
Author

Hi thank you for responding so fast. The issue is not that I'm not able to build libraries. I was able to build. But issue was current C# DLL imports library considering via name istead of __internal keyword as per unity's this documentation. But I'll check into your links and will try to modify the DLL to see if I'm able to fix it. I'll report it back here for future readers comming from Unity community.

Image

@csukuangfj
Copy link
Collaborator

Can you rename the dll to _internal?

@WaqasGameDev WaqasGameDev changed the title Need a way to load Static library for iOS in C# DLL Need a way to load Static library for iOS in Unity via your Nuget based C# DLL Feb 14, 2025
@WaqasGameDev
Copy link
Author

WaqasGameDev commented Feb 14, 2025

I dont think renaming would work. Because what I showed you in the image above (I'm rewriting the same code below) is how Unity want's it to be.

using UnityEngine;
using System.Runtime.InteropServices;

class ExampleScript : MonoBehaviour {
    #if UNITY_IPHONE
    // On iOS plugins are statically linked into
    // the executable, so we have to use __Internal as the
    // library name.
    [DllImport ("__Internal")]
    #else
    // Other platforms load plugins dynamically, so pass the
    // name of the plugin's dynamic library.
    [DllImport ("PluginName")]   
    #endif
    private static extern float ExamplePluginFunction ();

    void Awake () {
        // Calls the ExamplePluginFunction inside the plugin
        // And prints 5 to the console
        print (ExamplePluginFunction ());
       }
    }

But in your current DLL, this is the code

#region Assembly sherpa-onnx, Version=1.10.43.0, Culture=neutral, PublicKeyToken=null
// G:\Unity 2\Hi Mian Games\LLama_Test\Assets\Packages\org.k2fsa.sherpa.onnx.1.10.43\lib\netstandard2.0\sherpa-onnx.dll
// Decompiled with ICSharpCode.Decompiler 8.1.1.7464
#endregion

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace SherpaOnnx;

public class OfflineTts : IDisposable
{
    private HandleRef _handle;

    public int SampleRate => SherpaOnnxOfflineTtsSampleRate(_handle.Handle);

    public int NumSpeakers => SherpaOnnxOfflineTtsNumSpeakers(_handle.Handle);

    public OfflineTts(OfflineTtsConfig config)
    {
        IntPtr handle = SherpaOnnxCreateOfflineTts(ref config);
        _handle = new HandleRef(this, handle);
    }

    public OfflineTtsGeneratedAudio Generate(string text, float speed, int speakerId)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        byte[] array = new byte[bytes.Length + 1];
        Array.Copy(bytes, array, bytes.Length);
        array[bytes.Length] = 0;
        return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerate(_handle.Handle, array, speakerId, speed));
    }

    public OfflineTtsGeneratedAudio GenerateWithCallback(string text, float speed, int speakerId, OfflineTtsCallback callback)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        byte[] array = new byte[bytes.Length + 1];
        Array.Copy(bytes, array, bytes.Length);
        array[bytes.Length] = 0;
        return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerateWithCallback(_handle.Handle, array, speakerId, speed, callback));
    }

    public OfflineTtsGeneratedAudio GenerateWithCallbackProgress(string text, float speed, int speakerId, OfflineTtsCallbackProgress callback)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        byte[] array = new byte[bytes.Length + 1];
        Array.Copy(bytes, array, bytes.Length);
        array[bytes.Length] = 0;
        return new OfflineTtsGeneratedAudio(SherpaOnnxOfflineTtsGenerateWithProgressCallback(_handle.Handle, array, speakerId, speed, callback));
    }

    public void Dispose()
    {
        Cleanup();
        GC.SuppressFinalize(this);
    }

    ~OfflineTts()
    {
        Cleanup();
    }

    private void Cleanup()
    {
        SherpaOnnxDestroyOfflineTts(_handle.Handle);
        _handle = new HandleRef(this, IntPtr.Zero);
    }

    [DllImport("sherpa-onnx-c-api")]
    private static extern IntPtr SherpaOnnxCreateOfflineTts(ref OfflineTtsConfig config);

    [DllImport("sherpa-onnx-c-api")]
    private static extern void SherpaOnnxDestroyOfflineTts(IntPtr handle);

    [DllImport("sherpa-onnx-c-api")]
    private static extern int SherpaOnnxOfflineTtsSampleRate(IntPtr handle);

    [DllImport("sherpa-onnx-c-api")]
    private static extern int SherpaOnnxOfflineTtsNumSpeakers(IntPtr handle);

    [DllImport("sherpa-onnx-c-api")]
    private static extern IntPtr SherpaOnnxOfflineTtsGenerate(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, int sid, float speed);

    [DllImport("sherpa-onnx-c-api", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr SherpaOnnxOfflineTtsGenerateWithCallback(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, int sid, float speed, OfflineTtsCallback callback);

    [DllImport("sherpa-onnx-c-api", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr SherpaOnnxOfflineTtsGenerateWithProgressCallback(IntPtr handle, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] byte[] utf8Text, int sid, float speed, OfflineTtsCallbackProgress callback);
}
#if false // Decompilation log
'226' items in cache
------------------
Resolve: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
Found single assembly: 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
WARN: Version mismatch. Expected: '2.0.0.0', Got: '2.1.0.0'
Load from: 'C:\Program Files\Unity\Editor\2021.3.14f1\Editor\Data\NetStandard\ref\2.1.0\netstandard.dll'
------------------
Resolve: 'System.Runtime.InteropServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'
Found single assembly: 'System.Runtime.InteropServices, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
WARN: Version mismatch. Expected: '2.0.0.0', Got: '4.1.2.0'
Load from: 'C:\Program Files\Unity\Editor\2021.3.14f1\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.dll'
------------------
Resolve: 'System.Runtime.CompilerServices.Unsafe, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'
Could not find by name: 'System.Runtime.CompilerServices.Unsafe, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'
------------------
Resolve: 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
Found single assembly: 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
Load from: 'C:\Program Files\Unity\Editor\2021.3.14f1\Editor\Data\NetStandard\ref\2.1.0\netstandard.dll'
#endif

So notice how your C# DLL currently importing the library via its name which only works for Android platform in unity. To make it work on ios to link static library, I'll have to modify name to the keyword __internal and then it will load ios library too in unity.

@DavidPolastik
Copy link

did you manage it?

@WaqasGameDev
Copy link
Author

WaqasGameDev commented Feb 23, 2025

Hi David, I just could not find time to work on it. But today I'm gonna work on it and will let you know how it went.

@WaqasGameDev
Copy link
Author

Hi @DavidPolastik @csukuangfj so finally it loaded in unity iOS too. All I had to do is decomplie main dll and the replaced
[DllImport("sherpa-onnx-c-api")] with [DllImport("__Internal")] and put ios .h and .a files in Assets/Plugins/iOS and then made a build and it loaded library and I was able to get proper TTS. Here is the modified library to load ios artifacts statically.

sherpa-onnx.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants