0

I'm trying to create a simple Voip client application using the Linphone NuGet (LinphoneSDK.5.1.73.nupkg).

For that I created a solution with two C# projects (target framework: .net Framework 4.8, ; target platform: x86): one as a wrapper of Linphone (named as My.Voip) and the other for the application itself (named as My.Voip.Client).

In My.Voip, I added the Nuget LinphoneSDK 5.1.73, that I previously downloaded to my computer.

In this project, I created a class with a function that returns the version of Linphone, following the tutorial from Linphone.

using Linphone;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace My.Voip
{
    public class Engine
    {
        public Core StoredCore { get; set; }

        public string Version()
        {

            Factory factory = Factory.Instance;
            string assetsPath = Path.Combine(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "share");
            factory.TopResourcesDir = assetsPath;
            factory.DataResourcesDir = assetsPath;
            factory.SoundResourcesDir = Path.Combine(assetsPath, "sounds", "linphone");
            factory.RingResourcesDir = Path.Combine(factory.SoundResourcesDir, "rings");
            factory.ImageResourcesDir = Path.Combine(assetsPath, "images");
            factory.MspluginsDir = ".";

            Core core = factory.CreateCore("", "", IntPtr.Zero);


            // You should store the Core to keep a reference to it at all times while your app is alive.
            // A good solution for that is to either subclass the Application object or create a Service.
            StoredCore = core;
            return Core.Version;
        }
    }
}

In My.Voip.Client, I added a reference to the My.Voip project.

Now, in My.Voip.Client, I created a winform that, on load shows the version of Linphone.

 private void Form1_Load(object sender, EventArgs e)
        {
            My.Voip.Engine x = new My.Voip.Engine();
            MessageBox.Show(x.Version());
            
        }

The problem that I'm facing is that i get an error when I invoke the Version method:

System.DllNotFoundException: 'Unable to load DLL 'linphone': The specified module could not be found. (Exception from HRESULT: 0x8007007E)'

The error is traced back to the file ~My.Voip\linphonecs\LinphoneWrapper.cs, line 33104:

        static public Linphone.Factory Instance
        {
            get
            {
                IntPtr ptr = linphone_factory_get(); //<-Exception is thrown here
                Linphone.Factory obj = fromNativePtr<Linphone.Factory>(ptr, true);
                return obj;
            }
        }

The Instance is invoked in the class Engine->function Version->Factory factory = Factory.Instance;

I've tried to change the target platform as x64 and AnyCPU, reference the Nuget directly to the winforms application, but I get always the same error. I've, also, tried to use the Nuget directly from the Linphone repository, and the result is the same error, too.

What do I need to do to run this correctly?

RSilva
  • 6,753
  • 11
  • 43
  • 49
  • I think your dll is not loaded in runtime. Can you try Assembly.LoadFrom("your.dll"); to verify it. – Albert Einstein Jul 04 '23 at 14:39
  • The following may be of interest: [LinPhone Wiki](https://wiki.linphone.org/xwiki/wiki/public/view/Lib/Getting%20started/Windows%20UWP/#HFromourPackageRegistry283E3Dv5.2.029) and [nuget](https://www.nuget.org/downloads). – Tu deschizi eu inchid Jul 04 '23 at 14:56
  • @Tudeschizieuinchid I've already followed the LinPhone Wiki instructions and the result is the same – RSilva Jul 04 '23 at 15:15
  • You may consider using a newer version of the package (>= v5.2.0) that uses NuGet package manager. – Tu deschizi eu inchid Jul 04 '23 at 15:42
  • @Tudeschizieuinchid I've already done that. I've tried using the LinphoneSDK.Windows 5.2.78 and the result is the same error, too. – RSilva Jul 04 '23 at 15:44
  • That library has a bunch of unmanaged DLL dependencies, linphone is just one of them. Because they are unmanaged, the build system doesn't know that these dlls have to be copied into the My.Voip.Client project's build directory. You have to help, use xcopy in a post-build event. – Hans Passant Jul 04 '23 at 17:31

1 Answers1

-1

The following describes the necessary steps to use NuGet package LinphoneSDK.Windows (v5.2.77) in a WinForms project.

Since only x86 files exist for WinForms, before adding the NuGet package one needs to switch the build configuration from AnyCPU to x86.

At the end of this post (under Additional Information), you'll find the troubleshooting process I used to make the determination that the project needs to target x86.


Try the following:

Create a new Windows Forms App (.NET Framework) (name: VoipTest; Framework: .NET Framework 4.8)

enter image description here

Use Configuration Manager to change the configuration to x86

  • In VS menu, click Build

  • Select Configuration Manager...

  • Select the drop-down under Active solution platform, select <New...> enter image description here

  • Select the drop-down under Type or select the new platform, select X86

    enter image description here

  • Click OK

    enter image description here

  • Click Close

Add NuGet package source

  • In VS menu, click Tools

  • Select Options...

  • Expand NuGet Package Manager

  • Select General

  • Under Package Management, select PackageReference

  • Select Package Sources

    enter image description here

  • Click enter image description here

  • You'll now see:

    enter image description here

  • For name, enter Linphone (if desired the name can be changed)

  • For Source, enter: https://gitlab.linphone.org/api/v4/projects/411/packages/nuget/index.json

  • Click Update

    enter image description here

  • Click OK

Open Solution Explorer

  • In VS menu, click View
  • Select Solution Explorer

Add NuGet package (name: )

  • In Solution Explorer, right-click <project name> (ex: VoipTest)

  • Select Manage NuGet Packages...

  • Change the Package source to Linphone

    enter image description here

  • Select LinphoneSDK.Windows

    enter image description here

  • Select version 5.2.77

    enter image description here

  • Click Install

  • If a message box appears, click OK

Create a new class (name: Engine**)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
using Linphone;

namespace VoipTest
{
    public class Engine : IDisposable
    {
        private Core _core = null;

        public void Dispose()
        {
            if (_core != null)
            {
                _core.Stop();
            }
        }

        public string Version()
        {
            string configFolder = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "LinPhoneConfig");
            Debug.WriteLine($"configFolder: {configFolder}");

            Factory factory = Factory.Instance;
            _core = factory.CreateCore(configFolder, null, IntPtr.Zero);

            //Linphone.Factory.Instance.CreateCore(configFolder, null, IntPtr.Zero);

            _core.Start();

            Debug.WriteLine($"version: {Core.Version}");

            return Core.Version;
        }
    }
}

Add Button to Form1 (name: btnRun)

Double-click the button to add Click event handler

Form1.cs

private void btnRun_Click(object sender, EventArgs e)
{
    using (Engine engine = new Engine())
    {
        string version = engine.Version();

        Debug.WriteLine($"version: {version}");
    }
}

When you build the solution, you'll notice that the DLLs get copied to the output directory.


Additional Information:

NuGet packages are downloaded to %UserProfile%\.nuget\packages which is where you'll find linphonesdk.windows\5.2.77. When one builds the project, the appropriate .targets file (under linphonesdk.windows\5.2.77\build\<version>) is read. If one opens LinphoneSDK.Windows.targets file using Notepad, one sees the following:

<PropertyGroup>
    <LinphoneSDK-Platform Condition="'$(Platform)' == 'Win32'">x86</LinphoneSDK-Platform>
    <LinphoneSDK-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</LinphoneSDK-Platform>
    <LinphoneSDK-Framework Condition="'$(TargetPlatformIdentifier)' != 'UAP10.0' and '$(TargetPlatformIdentifier)' != 'UAP'">netcore</LinphoneSDK-Framework>
    <LinphoneSDK-Framework Condition="'$(TargetPlatformIdentifier)' == 'UAP10.0' or '$(TargetPlatformIdentifier)' == 'UAP'">uap10.0</LinphoneSDK-Framework>
    <LinphoneSDK-Content Condition="'$(LinphoneSDK-Content)' == ''">share</LinphoneSDK-Content>
    <LinphoneSDK-LibrariesPath>$(MSBuildThisFileDirectory)\..\..\lib\$(LinphoneSDK-Framework)\$(LinphoneSDK-Platform)</LinphoneSDK-LibrariesPath>
</PropertyGroup>

For more information see MSBuild .targets files.

In order to figure out what values are being used, in Visual Studio, one can

Change the verbosity of the build process

  • In VS menu, click Tools
  • Select Options
  • Expand Projects and Solutions
  • Select Build and Run
  • Under MSBuild project build output verbosity, change to Diagnostic
  • Click OK

Then clean and re-build the project.

In order to know the values that are being used, in the Output window, search for Platform. When configuration has been set to x86 one sees Platform = x86.

Next search for TargetPlatformIdentifier. For a WinForms app, one sees TargetPlatformIdentifier = Windows.

Now search for LinphoneSDK-Framework, and LinphoneSDK-LibrariesPath, and LinphoneSDK-Platform. When configuration is set to x86, One sees:

1>LinphoneSDK-Content = share
1>LinphoneSDK-Framework = netcore
1>LinphoneSDK-LibrariesPath = C:\Users\<username>\.nuget\packages\linphonesdk.windows\5.2.77\build\net48\\..\..\lib\netcore\x86
1>LinphoneSDK-Platform = x86

And if the build configuration is set to x64:

1>LinphoneSDK-Content = share
1>LinphoneSDK-Framework = netcore
1>LinphoneSDK-LibrariesPath = C:\Users\<username>\.nuget\packages\linphonesdk.windows\5.2.77\build\net48\\..\..\lib\netcore\x64
1>LinphoneSDK-Platform = x64

The path

C:\Users\<username>\.nuget\packages\linphonesdk.windows\5.2.77\build\net48\\..\..\lib\netcore\x64

is the same as

C:\Users\<username>\.nuget\packages\linphonesdk.windows\5.2.77\lib\netcore\x64

If one opens Windows Explorer and goes to the path, one notices that this path doesn't exist.

Likewise for AnyCPU:

1>LinphoneSDK-Content = share
1>LinphoneSDK-Framework = netcore
1>LinphoneSDK-LibrariesPath = C:\Users\<username>\.nuget\packages\linphonesdk.windows\5.2.77\build\net48\\..\..\lib\netcore\AnyCPU
1>LinphoneSDK-Platform = AnyCPU

Since the package only contains DLL files for x86 for the type of project that we've created, one needs to compile for x86 or no DLLs will be copied to the output folder.

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24