Search code examples
pythonc++boost-python

boost::python how to use function member as python callback


I want to use this python module: https://python-omxplayer-wrapper.readthedocs.io/en/latest/ on my c++ app.

It is a omxplayer python wrapper and has some callback events that I want to link to my c++ class function member.

I did it with success using a static function like this:

void foo(py::object player) { 
    std::cout << "pause event callback" << std::endl; 
}

py::object mod = py::import("omxplayer.player");

OMXPlayer::pyOMXPlayer = mod.attr("OMXPlayer")(_file, args, NULL, NULL, _dbus_name, _pause);

OMXPlayer::pyOMXPlayer.attr("pauseEvent") = py::make_function( &foo );

Where OMXPlayer is my c++ class.

I tried to use boost::bind and boost::function without success.

How can use OMXPlayer::onPause() function instead of static foo function?

Edit with example:

OMXPlayer.cpp

    #include "OMXPlayer.h"
    OMXPlayer::OMXPlayer(std::string _file, 
        std::vector<std::string> _args, 
        bool _pause, 
        std::string _dbus_name){
    
    
    try{
        Py_Initialize();
        py::object mod = py::import("omxplayer.player");
        
        
        py::list args;
        for(auto const& value: _args) {
            args.append(value);
        }
        
        

        OMXPlayer::pyOMXPlayer = mod.attr("OMXPlayer")(_file, args, NULL, NULL, _dbus_name, _pause);
        
        pyOMXPlayer.attr("pauseEvent"   ) = py::make_function(&OMXPlayer::onPause);
        
        OMXPlayer::active = false;

    }
    catch(py::error_already_set){
        PyErr_Print();
    }

}


void OMXPlayer::onPause(){
    std::cout << "onPause" << std::endl;
}

void OMXPlayer::pause(){
    try{
        OMXPlayer::pyOMXPlayer.attr("pause")();
    }
    catch(py::error_already_set){
        PyErr_Print();
    }
}

OMXPlayer.h

#include <boost/python.hpp>
#include <boost/function.hpp>

#include <vector>
#include <iostream>
#include <atomic>

namespace py = boost::python;

class OMXPlayer{
    public:
        OMXPlayer(std::string _file, 
            std::vector<std::string> _args, 
            bool _pause = false, 
            std::string _dbus_name = "");
        
        void pause();
        void onPause();
};

main.cpp function:

#include "OMXPlayer.h"

int main(){
    
    OMXPlayer player1("/root/Setteventi.mp4", std::vector<std::string> {"--loop"}, false, "org.mpris.MediaPlayer2.omxplayer1");

    player1.pause();


}

You can see the python Class from here: https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/

When eventPause on python side is called it throw this:

Traceback (most recent call last):
  File "<decorator-gen-56>", line 2, in pause
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 48, in wrapped
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 550, in pause
    self.pauseEvent(self)
Boost.Python.ArgumentError: Python argument types in
    None.None(OMXPlayer)
did not match C++ signature:
    None(OMXPlayer {lvalue})
Traceback (most recent call last):
  File "<decorator-gen-56>", line 2, in pause
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 48, in wrapped
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 550, in pause
    self.pauseEvent(self)
Boost.Python.ArgumentError: Python argument types in
    None.None(OMXPlayer)
did not match C++ signature:
    None(OMXPlayer {lvalue})

Solution

  • Ok, with @pptaszni help I found how to do it.

    The problem was that boost could not detarmine the function signature because boost::bind return a function object.

    To avoid this problem, I have to specify the signature when call make_function.

    Example:

    pyOMXPlayer.attr("pauseEvent") = py::make_function( boost::bind(&OMXPlayer::onPause, this, _1), py::default_call_policies(), boost::mpl::vector<void, py::object>() );
    

    The tricky part is the last argument of py::make_function

    Thanks @pptaszni