Files
ewsdr/DMRBindings.pas
T

169 lines
4.3 KiB
ObjectPascal

unit DMRBindings;
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
interface
uses
Classes, SysUtils, DynLibs;
const
DMR_ABI_VERSION = 1;
DMR_AMBE_BITS = 96;
DMR_PCM_SAMPLES = 160;
type
TDMRMbeResult = packed record
ErrorsC0: LongInt;
ErrorsTotal: LongInt;
end;
PDMRMbeResult = ^TDMRMbeResult;
function DMRLoad: Boolean;
procedure DMRUnload;
function DMRLoaded: Boolean;
function DMRLastError: string;
function DMRMbeCreate(UVQuality: Integer): Pointer;
procedure DMRMbeDestroy(Decoder: Pointer);
procedure DMRMbeReset(Decoder: Pointer);
function DMRMbeDecode(Decoder: Pointer; Bits: PByte; PCM: PSingle;
ResultInfo: PDMRMbeResult): Integer;
implementation
type
TAbiVersion = function: LongWord; cdecl;
TMbeCreate = function(UVQuality: LongInt): Pointer; cdecl;
TMbeDestroy = procedure(Decoder: Pointer); cdecl;
TMbeReset = procedure(Decoder: Pointer); cdecl;
TMbeDecode = function(Decoder: Pointer; Bits: PByte; PCM: PSingle;
ResultInfo: Pointer): LongInt; cdecl;
var
GLib: TLibHandle = dynlibs.NilHandle;
GLastError: string = '';
GAbiVersion: TAbiVersion = nil;
GMbeCreate: TMbeCreate = nil;
GMbeDestroy: TMbeDestroy = nil;
GMbeReset: TMbeReset = nil;
GMbeDecode: TMbeDecode = nil;
function Symbol(const Name: PChar): Pointer;
begin
Result := GetProcedureAddress(GLib, Name);
if Result = nil then
GLastError := 'Missing DMR symbol: ' + string(Name);
end;
function DMRLoad: Boolean;
const
{$IFDEF WINDOWS}
Names: array[0..0] of string = ('ewsdr_dmr.dll');
{$ELSE}
{$IFDEF DARWIN}
Names: array[0..0] of string = ('libewsdr_dmr.dylib');
{$ELSE}
Names: array[0..1] of string = ('libewsdr_dmr.so', 'libewsdr_dmr.so.1');
{$ENDIF}
{$ENDIF}
var
i: Integer;
LocalName, BuildName: string;
begin
if GLib <> dynlibs.NilHandle then Exit(True);
GLastError := '';
for i := Low(Names) to High(Names) do
begin
LocalName := ExtractFilePath(ParamStr(0)) + Names[i];
GLib := LoadLibrary(LocalName);
// Lazarus debug binaries live in bin/<target>/ while the documented
// optional adapter build lives in build/dmr. Make an in-tree build
// immediately usable without a system-wide cmake --install.
if GLib = dynlibs.NilHandle then
begin
BuildName := ExpandFileName(ExtractFilePath(ParamStr(0)) +
'../../build/dmr/' + Names[i]);
GLib := LoadLibrary(BuildName);
end;
if GLib = dynlibs.NilHandle then GLib := LoadLibrary(Names[i]);
if GLib <> dynlibs.NilHandle then Break;
end;
if GLib = dynlibs.NilHandle then
begin
GLastError := 'Optional EWSDR DMR library not found';
Exit(False);
end;
GAbiVersion := TAbiVersion(Symbol('ewsdr_dmr_abi_version'));
GMbeCreate := TMbeCreate(Symbol('ewsdr_dmr_mbe_create'));
GMbeDestroy := TMbeDestroy(Symbol('ewsdr_dmr_mbe_destroy'));
GMbeReset := TMbeReset(Symbol('ewsdr_dmr_mbe_reset'));
GMbeDecode := TMbeDecode(Symbol('ewsdr_dmr_mbe_decode'));
if not Assigned(GAbiVersion) or not Assigned(GMbeCreate) or
not Assigned(GMbeDestroy) or not Assigned(GMbeReset) or
not Assigned(GMbeDecode) then
begin
DMRUnload;
Exit(False);
end;
if GAbiVersion() <> DMR_ABI_VERSION then
begin
GLastError := Format('Unsupported EWSDR DMR ABI: %d', [GAbiVersion()]);
DMRUnload;
Exit(False);
end;
Result := True;
end;
procedure DMRUnload;
begin
GAbiVersion := nil;
GMbeCreate := nil;
GMbeDestroy := nil;
GMbeReset := nil;
GMbeDecode := nil;
if GLib <> dynlibs.NilHandle then
begin
UnloadLibrary(GLib);
GLib := dynlibs.NilHandle;
end;
end;
function DMRLoaded: Boolean;
begin
Result := GLib <> dynlibs.NilHandle;
end;
function DMRLastError: string;
begin
Result := GLastError;
end;
function DMRMbeCreate(UVQuality: Integer): Pointer;
begin
if Assigned(GMbeCreate) then Result := GMbeCreate(UVQuality)
else Result := nil;
end;
procedure DMRMbeDestroy(Decoder: Pointer);
begin
if Assigned(GMbeDestroy) and (Decoder <> nil) then GMbeDestroy(Decoder);
end;
procedure DMRMbeReset(Decoder: Pointer);
begin
if Assigned(GMbeReset) and (Decoder <> nil) then GMbeReset(Decoder);
end;
function DMRMbeDecode(Decoder: Pointer; Bits: PByte; PCM: PSingle;
ResultInfo: PDMRMbeResult): Integer;
begin
if not Assigned(GMbeDecode) then Exit(-1);
Result := GMbeDecode(Decoder, Bits, PCM, ResultInfo);
end;
end.