DBUS, Komplexe Datenstrukturen verarbeiten

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

DBUS, Komplexe Datenstrukturen verarbeiten

Beitrag von pluto »

Hallo
Mein Ziel ist es mit Hilfe von DBUS den Aktuellen gespielten Titel von Amarok zu Erfahren sowie bei jeder Änderung Informiert zu werden. Dazu hat Amarok ein DBUS-Signal: TrackChange. Empfangen klappt auch schon ganz gut. Bei Änderungen greift die IF Abfrage bereits. Das Problem dabei ist nur: Wie komme ich an den Inhalt ran? Durch verschiedene Tests bin ich der Auffassung: Das ich ein "DBUS_TYPE_STRUCT" verarbeiten muss aber wie?
Trotz intensiver suche im Internet, konnte ich diese Frage nicht klären. Einfache Daten Typen kann ich schon Verarbeiten. Z.B. habe ich ein Beispiel für Pidgin gefunden, darauf basiert auch dieser Code hier.

Die Entscheidene Stelle um die es mir geht ist: dbus_message_get_args(msg, @err, DBUS_TYPE_STRUCT, [@sp]);
Nur wie komme ich jetzt wieder an den Inhalt ran? Im Prinzip müsste ich "nur" args verarbeiten. Aber ich weiß einfach nicht wie das gehen soll.
Kennt sich wer von euch mit DBUS unter Lazarus aus?

so sieht im Moment mein Test Code aus:
(Ist ein Test Code, daher etwas unaufgeräumt)

Code: Alles auswählen

procedure TListeningThread.Execute;
var
  List:array of Integer;
  sender, body: Pchar;
  s:cfloat;
  b:byte;
  g:PDBusMessageIter;
  s1:String;
  sp:Pointer;
begin
  { Initializes the errors }
  dbus_error_init(@err);
 
  { Connection }
  conn := dbus_bus_get(DBUS_BUS_SESSION, @err);
  try
 
    if dbus_error_is_set(@err) <> 0 then
    begin
      AddLog('Connection Error: ' + err.message);
      dbus_error_free(@err);
    end;
 
    if conn = nil then Exit;
 
    { Request the name of the bus }
    ret := dbus_bus_request_name(conn, 'org.mpris', DBUS_NAME_FLAG_REPLACE_EXISTING, @err);
    if dbus_error_is_set(@err) <> 0 then begin
      AddLog('Name Error: ' + err.message);
      dbus_error_free(@err);
    end;
//    if ret <> DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER then Exit;
    dbus_bus_add_match(conn, 'type=signal, interface=org.freedesktop.MediaPlayer', @err);
    dbus_connection_flush(conn);
    if dbus_error_is_set(@err) <> 0 then
    begin
      AddLog('Match Error: ' + err.message);
      dbus_error_free(@err);
      Exit
    end;
    writeln('Schleife Startet !!!');
    s1:='TestTest';
    sp:=@s1[1];
    while not Terminated do begin
      dbus_connection_read_write(conn, 0);
      msg := dbus_connection_pop_message(conn);
      if msg=nil then begin
        sleep(300);
        Continue;
      end;
 
      if (dbus_message_is_signal(msg, 'org.freedesktop.MediaPlayer', 'TrackChange')=1) then
      begin
        // read the parameters
        if (dbus_message_iter_init(msg, @args)=0) then
          AddLog('Message has no arguments!')
        else begin
          body:='                         ';
          dbus_message_get_args(msg, @err, DBUS_TYPE_STRUCT, [@sp]);
 
//          writeln(body);
//          writelN(dbus_message_type_to_string(msg));
 
//          id:=dbus_message_iter_get_arg_type(@args);
  //        writeln(id);
//          AddLog(Format('Status in Amarok: %s', [body]));
        end
      end;
      dbus_message_unref(msg);
 
      // free the message
    end;
  finally
    dbus_connection_close(conn);
  end;
end; // TListeningThread.Execute
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: DBUS, Komplexe Datenstrukturen verarbeiten

Beitrag von pluto »

Habe eine Lösung danke eins C Beispiels gefunden. Aber hin und wieder verabschiedet sich das Programm.
Ich nehme an, meine Längen Stimmen nicht.

Code: Alles auswählen

procedure TListeningThread.get_MessageIter(aArgs: PDBusMessageIter);
var
  typ,typ2:cint;
  subiter,subiter2:PDBusMessageIter;
  ValueInt32,len:Integer;
  ValueInt64:Int64;
  Str:Pchar;
begin
  subiter:=nil;
  writeln('get_MessageIter:',random(100));
  writeln('=====================================');
  repeat
    try
      typ:=dbus_message_iter_get_arg_type(aArgs);
      writeln('Typ:',Typ,' Char:', Chr(Typ));
      writeln('-----------------------------------');
 
      case typ of
        DBUS_TYPE_INT32: begin
          writeln('DBUS_TYPE_INT32');
          dbus_message_iter_get_basic (aArgs, @ValueInt32);
          writeln('ValueInt32:',ValueInt32);
        end;
 
        DBUS_TYPE_INT64: begin
          writeln('DBUS_TYPE_INT64');
          dbus_message_iter_get_basic (aArgs, @ValueInt64);
          writeln('ValueInt64:',ValueInt64);
        end; // DBUS_TYPE_INT64
 
        DBUS_TYPE_STRING: begin // 115(s)
          writeln('DBUS_TYPE_STRING');
          dbus_message_iter_get_basic (aArgs, @str);
          writeln('STR:',str);
        end; // DBUS_TYPE_STRING
 
        DBUS_TYPE_VARIANT: begin // 118(r)
          writeln('DBUS_TYPE_VARIANT');
        //  len:=dbus_message_iter_get_array_len(aArgs);
        //  writeln('Len:',len);
          Getmem(subiter,SizeOf(DBusMessageIter));
          dbus_message_iter_recurse (aArgs, subiter);
          get_MessageIter(subiter);
          Freemem(subiter);
        end; // DBUS_TYPE_VARIANT
 
        DBUS_TYPE_STRUCT: begin // 114(r)
          writeln('DBUS_TYPE_STRUCT');
          Getmem(subiter,SizeOf(DBusMessageIter));
          dbus_message_iter_recurse (aArgs, subiter);
          get_MessageIter(subiter);
          dbus_message_iter_next (subiter);
          get_MessageIter (subiter);
          Freemem(subiter);
        end; // DBUS_TYPE_STRUCT
 
        DBUS_TYPE_ARRAY: begin // 97(a)
          writeln('DBUS_TYPE_ARRAY');
          Getmem(subiter,SizeOf(DBusMessageIter));
          dbus_message_iter_recurse (aArgs, subiter);
          repeat
            get_MessageIter(subiter);
            dbus_message_iter_next (subiter);
          until dbus_message_iter_get_arg_type(subiter) = DBUS_TYPE_INVALID;
          Freemem(subiter);
        end; // DBUS_TYPE_ARRAY
 
        DBUS_TYPE_DICT_ENTRY: begin // 101(e)
          writeln('DBUS_TYPE_DICT_ENTRY');
          //len:=dbus_message_iter_get_array_len(aArgs);
          //writeln('Len:',len);
          Getmem(subiter,SizeOf(DBusMessageIter));
          dbus_message_iter_recurse (aArgs, subiter);
          get_MessageIter(subiter);
          dbus_message_iter_next (subiter);
          get_MessageIter (subiter);
          Freemem(subiter);
        end; // DBUS_TYPE_DICT_ENTRY
      end;
    finally
    end;
  until dbus_message_iter_next(aArgs) = 0;
  writeln('[Ende]');
end; // TListeningThread.get_MessageIter
Das scheint zu Funktionieren. Wenn ich jetzt in Amarok den Track wechsel, bekomme ich das mit und kann die gesendeten Daten verarbeiten. Mir ist aber unklar, warum ich bei DBUS_TYPE_DICT_ENTR und DBUS_TYPE_VARIANT mein Vorgehen ändern muss, damit es geht.

Vielleicht hilft das ja jemanden weiter. Ihr müsst nur den ersten Code anpassen:
Da wo "dbus_message_get_args(msg, @err, DBUS_TYPE_STRUCT, [@sp]);" steht muss "get_MessageIter(@args);" hin. schon sollte es klappen(oder auch nicht, das ist Zufall, aber in der Regel scheint zu zu gehen).

Edit01: Code geändert, auf ein Tipp aus dem delphigl Channel.
MFG
Michael Springwald

Antworten