i have a problem with preloading a library.
But first I'll explain what I intend to do. I've developed a Blazor web application using the Un4Seen Bass Audio libraries. The application is hosted on the Kestrel Web Server and I wanted to deploy the application as a service (systemd).
The application works flawlessly and is designed to run on both Ubuntu and Windows systems. As I said, it works the way I want it to. Just not as a service.
As already mentioned, the Un4Seen audio libraries are required for execution, which are stored in the project structure as follows.
[AppRoot]
¦
+---....
¦
+---Bass.Net.dll
¦
+---....
¦
+---libs
+---unix
¦ +---x64
¦ ¦ libbass.so
¦ ¦ libbassalac.so
¦ ¦ libbassenc.so
¦ ¦ libbassenc_flac.so
¦ ¦ libbassenc_mp3.so
¦ ¦ libbassenc_opus.so
¦ ¦ libbassflac.so
¦ ¦ libbassmix.so
¦ ¦ libbassopus.so
¦ ¦ libbasswebm.so
¦ ¦ libbass_aac.so
¦ ¦ libbass_ac3.so
¦ ¦
¦ +---x86
¦ libbass.so
¦ libbassalac.so
¦ libbassenc.so
¦ libbassenc_flac.so
¦ libbassenc_mp3.so
¦ libbassenc_opus.so
¦ libbassflac.so
¦ libbassmix.so
¦ libbassopus.so
¦ libbasswebm.so
¦ libbass_aac.so
¦ libbass_ac3.so
¦
+---Win32NT
+---x64
¦ bass.dll
¦ bassalac.dll
¦ bassenc.dll
¦ bassenc_flac.dll
¦ bassenc_mp3.dll
¦ bassenc_opus.dll
¦ bassflac.dll
¦ bassmix.dll
¦ bassopus.dll
¦ basswebm.dll
¦ bass_aac.dll
¦ bass_ac3.dll
¦
+---x86
bass.dll
bassalac.dll
bassenc.dll
bassenc_flac.dll
bassenc_mp3.dll
bassenc_opus.dll
bassflac.dll
bassmix.dll
bassopus.dll
basswebm.dll
bass_aac.dll
bass_ac3.dll
With the following method i initialize the Bass Libraries:
private bool InitializeBassLibrary()
{
var appPath = new Uri(Assembly.GetEntryAssembly()?.GetName().CodeBase ?? throw new NullReferenceException())
.LocalPath;
appPath = Path.GetDirectoryName(appPath);
if (string.IsNullOrEmpty(appPath))
{
return false;
}
var librariesPath = appPath;
var osPlatform = Environment.OSVersion.Platform;
switch (osPlatform)
{
case PlatformID.Win32NT:
{
librariesPath += Environment.Is64BitProcess ? "\\libs\\win32nt\\x64\\" : "\\libs\\win32nt\\x86\\";
break;
}
case PlatformID.Unix:
{
// Add following paths to search path for libs of your linux distribution.
// e.g. for Ubuntu
// ldconfig /full/path/to/libs/unix/x64
// ldconfig /full/path/to/libs/unix/x86
break;
}
}
BassNet.Registration("mail@domain.dom", "X123456789012345");
if (osPlatform == PlatformID.Win32NT)
{
var libLoadIsOk = Bass.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassAac.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassAc3.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassAlac.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassFlac.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassOpus.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassEnc.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassEnc_Flac.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassEnc_Mp3.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassEnc_Opus.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
libLoadIsOk = BassMix.LoadMe(librariesPath);
if (!libLoadIsOk)
{
return false;
}
}
if (osPlatform == PlatformID.Unix)
{
// For preloading BASS libs execute creation of fake streams or execute GetVersion() Methods if exists.
Bass.BASS_GetVersion(4);
_ = BassAc3.BASS_AC3_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
_ = BassAlac.BASS_ALAC_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
_ = BassFlac.BASS_FLAC_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
_ = BassOpus.BASS_OPUS_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT);
BassEnc.BASS_Encode_GetVersion();
BassEnc_Flac.BASS_Encode_FLAC_GetVersion();
BassEnc_Mp3.BASS_Encode_MP3_GetVersion();
BassEnc_Opus.BASS_Encode_OPUS_GetVersion();
BassMix.BASS_Mixer_GetVersion();
}
Bass.BASS_Init(AudioDevice, AudioDeviceSamplingRate, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
if (Bass.BASS_ErrorGetCode() != BASSError.BASS_OK)
{
return false;
}
return true;
}
The Ubuntu version of the application is released for linux-x64 and is then copied to an Ubuntu machine.
So that the library assignment works correctly under Ubuntu, I created the file /etc/ld.so.conf.d/app_name.conf
.
/etc/ld.so.conf.d/app_name.conf
/usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/x64
/usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/x86
This LD configuration file was then successfully applied with sudo ldconfig -v
.
Whatever the reason, to get it working I had to preload the libbass.so
library with LD_PRELOAD
although it already has it in /etc/ld.so.conf.d/app_name.conf
should be discoverable. I entered the LD_PRELOAD
variable system-wide via /etc/environment
and the value /usr/share/nginx/html/app_name/libs/unix/x64/libbass.so
set.
For those who don't know the bass audio libraries: libbass.so is the main library. The other files are plugins.
If I don't set the LD_PRELOAD
variable the application won't start and gives the error: symbol lookup error: /usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/ x64/libbass_ac3.so: undefined symbol: BASS_GetVersion
. This is completely misleading because the method is not called at all. At least not on libbass_ac3.so. Took a bit to figure out it's from libbass.so.
If I then start the application with: sudo [app_file_name] --environment [custom_environment]
the app works as expected.
Now finally comes the problem
I configured this Kestrel hosted application as a service in systemd. The following service file was created for this purpose.
/etc/systemd/system/app_name.service
[Unit]
Description=DDS-Audio-Transcoder for transcoding audio files to different audio formats
[Service]
WorkingDirectory=/usr/share/nginx/html/app-name
ExecStart=/usr/share/nginx/html/app-name/app-name-start-binary --environment TestInstance3Unix
Restart=always
RestartSec=150
KillSignal=SIGINT
SyslogIdentifier=bit-dds-transcoder
User=www-data
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
Environment="LD_PRELOAD=libbass.so"
Environment="LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/share/nginx/html/dds-transcoder-service/libs/unix/x64:/usr/share/nginx/html/dds-transcoder-service/libs/unix/x86"
[Install]
WantedBy=multi-user.target
The service was enabled with: sudo systemctl enable app_name.service
Then I tried with: sudo systemctl start app_name.service
to start the service and nothing happens.
The syslog says the following:
Jul 4 23:04:49 l01-v-s-0081 systemd[1]: app_name.service: Scheduled restart job, restart counter is at 21.
Jul 4 23:04:49 l01-v-s-0081 systemd[1]: Stopped app_name.
Jul 4 23:04:49 l01-v-s-0081 systemd[1]: Started app_name.
Jul 4 23:04:50 l01-v-s-0081 app_name[2241]: /usr/share/nginx/html/app_name/app-name-start-binary: symbol lookup error: /usr/share/nginx/html/dds-audio-transcoder-service/libs/unix/x64/libbass_ac3.so: undefined symbol: BASS_GetVersion
Jul 4 23:04:50 l01-v-s-0081 systemd[1]: dds-audio-transcoder.service: Main process exited, code=exited, status=127/n/a
Jul 4 23:04:50 l01-v-s-0081 systemd[1]: dds-audio-transcoder.service: Failed with result 'exit-code'.
System Informations
esx Virtual Mashine with Ubuntu 20.04 .Net 5.0
What i'm missing or what i have done wrong?
Remember! Without systemd it works fine.
I'm really grateful for every tip.
Many greetings
Marcus