trying to assign callback variable with SDL for audio - c++

When I try to assign the callback variable in the AudioSpec structure, the compiler doesn't like it when I'm trying to assign a type "void function" to a type SDL_AudioCallback.
void mainEngineCW4::myAudioCallback(void* userdata, Uint8* stream, int Glen) {
AudioData* audio = (AudioData*)userdata;
if (audio->length == 0)
return;
Uint32 length = (Uint32)len;
length = (length > audio->length ? audio->length : length); // if length is more than the audio length, then set length to be the audio.length, if not, set it to be the length passed to the function
SDL_memcpy(stream, audio->position, length);
audio->position += length;
audio->length -= length; }
void mainEngineCW4::playAudio() // this function is for loading an audio device, and playing the audio through that device {
AudioData audio;
audio.position = wavStart;
audio.length = wavLength;
wavSpec.callback = mainEngineCW4::myAudioCallback;
wavSpec.userdata = &audio;
audioDevice = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (audioDevice == 0)
{
std::cerr << SDL_GetError() << std::endl;
return;
}
SDL_PauseAudioDevice(audioDevice, 0); // mildly confused by why they decided to call the function for starting to play audio for "PauseAudioDevice" but yeah. this plays audio. }
I've split the responsibilities of the controlling audio into three functions, loadAudio, startAudio and endAudio. I've assigned the variables needed for the audio in the .h file, so it is accessible for all the functions in the class.

The SDL callback signature is a stand-alone function of type void (*)(void* userdata, Uint8* stream, int len).
Your callback signature is close but not quite a match: void (mainEngineCW4::*)(void* userdata, Uint8* stream, int len).
The main difference is that it is a member function, which is part of its type. In short, that type -- member function -- implies that you must call it with an instance of a class, which becomes the this pointer, e.g., myEngine->myAudioCallback( ... ). Stand-alone functions do not have a this pointer and so would be called like standAloneAudioCallback( ... ).
One way to resolve this is to make myAudioCallback a static member function. Another way is to make is a non-member (aka, stand-alone) function.
In either case, if you need to access (non-static) member data for the mainEngineCW4 class that it is currently a part of, you will need to get access to it, usually by a static or global variable or by using the userdata param to store the class instance. I'd need to see a little more of your program to demonstrate it precisely.
Update responding to your comments:
There are a couple ways you could do this. Probably what you want is to set the userdata in your audio spec to your instance of the engine class and pass in a static (or standalone) callback that uses that pointer to call the member function:
class mainEngineCW4
{
struct AudioData { /* ... */ };
// Private static member function, but could be a stand-alone function
static void myStaticAudioCallback( void* const userData, Uint8* const stream, const int len )
{
const auto myEngine = reinterpret_cast<mainEngineCW4*>( userData );
myEngine->myAudioCallback( stream, len );
}
void myAudioCallback( const Uint8* const stream, const int len )
{
// ... Process stream using AudioData struct or whatever
}
public:
void playAudio()
{
auto audioSpec = SDL_AudioSpec{};
// ... set the freq and format and what not in the audio spec
audioSpec.callback = &myStaticAudioCallback;
audioSpec.userdata = this;
const auto audioDevice = SDL_OpenAudioDevice( NULL, 0, &audioSpec, NULL, SDL_AUDIO_ALLOW_ANY_CHANGE);
// ...
}
};
I've written it here all in the class definition for concision, but you can split it out to the .h/.cpp if you want. I've also added some const's, which are good practice, and I followed "Almost Always Auto" style.

as metal replied earlier, the mistake is that i tried to define myAudioCallback in my mainEngineCW4 class.
class mainEngineCW4
{
public:
void myAudioCallback();
}
instead, declare it outside the class.
the error i ran into at first while doing this, was not being able to access the struct AudioData, but that was also defined in the class. simply define both outside of the class.
class mainEngineCW4
{}
struct AudioData {
Uint8* position;
Uint32 length;};
void myAudioCallback(void* userdata, Uint8* stream, int len);

Related

Scope and Usage of Nested Classes

I'm writing some code that interfaces with a GPS receiver and I'm trying to understand if the way I'm attempting to implement it is possible and if so how to do it.
The GPS communicates with an Arduino via I2C and I want to have a single object that handles all of the GPS interface commands. The basic structure is as follows:
Header File (Simplified)
//UBLOX.h
class UBLOX_INTERFACE
{
private:
const uint8_t i2cAddress;
public:
UBLOX_INTERFACE(uint8_t address);
class NMEA
{
private:
void intakeNMEA(); //This function needs access to UBLOX_INTERFACE::i2cAddress
//Other local variables and functions
};
class UBX_COMMS
{
private:
uint8_t prepAndSendPacket(uint8_t packet[], const uint16_t packetLength);
public:
UBX_COMMS(uint8_t ubxclass, uint8_t id, uint8_t length0, uint8_t length1);
};
class UBX_CFG_RATE : public UBX_COMMS
{
using UBX_COMMS::UBX_COMMS;
private:
public:
bool set(const uint16_t GNSSmeasureRate); // Sets GNSS measurement rate
void poll();
};
class UBX_CFG_RST : public UBX_COMMS
{
using UBX_COMMS::UBX_COMMS;
private:
public:
bool gnssReset(const uint8_t navBbrMask);
bool hardwareReset(const uint8_t resetMode);
};
}
CPP File (Simplified)
//UBLOX.cpp
#include "UBLOX.h"
//UBLOX_INTERFACE Class Functions
UBLOX_INTERFACE::UBLOX_INTERFACE(uint8_t address): i2cAddress(address)
{
NMEA nmea;
UBX_CFG_RATE ubxCFG_RATE(0x06, 0x08, 0, 6); //These values are permanently defined constants for each command type
UBX_CFG_RST ubxCFG_RST(0x06, 0x04, 0, 4);
}
//NMEA Class Functions
void UBLOX_INTERFACE::NMEA::intakeNMEA()
{
Wire.beginTransmission(i2cAddress); //This line has a compile error: invalid use of non-static data member 'UBLOX_INTERFACE::i2cAddress'
//There's a whole bunch more after this but not relevant to this question
}
//UBX_COMMS Class Functions
UBLOX_INTERFACE::UBX_COMMS::UBX_COMMS(uint8_t ubxclass, uint8_t id, uint8_t length0, uint8_t length1) : classByte(ubxclass), idByte(id), payloadLength{length0, length1}, stdPacketLength(packetLengthCalc(length0, length1)){};
uint8_t UBLOX_INTERFACE::UBX_COMMS::prepAndSendPacket(uint8_t packet[], const uint16_t packetLength)
{
calcAndInsertUBXChecksum(packet, packetLength);
Wire.beginTransmission(i2cAddress); //error: invalid use of non-static data member 'UBLOX_INTERFACE::i2cAddress'
Wire.write(packet, packetLength);
uint8_t errorCode = Wire.endTransmission();
return errorCode;
}
// UBX_CFG_RATE Class Functions
//definition of UBLOX_INTERFACE::UBX_CFG_PRT::setPort() and UBLOX_INTERFACE::UBX_CFG_PRT::poll()
// UBX_CFG_RST Class Functions
//definition of UBLOX_INTERFACE::UBX_CFG_RST::gnssReset() and UBLOX_INTERFACE::UBX_CFG_PRT::hardwareReset()
Example of how I want to use this
void main()
{
UBLOX_INTERFACE u;
u.ubxCFG_RST.hardwareReset();
u.ubxCFG_RATE.set(SOME SETTINGS HERE);
while(true)
{
u.nmea.intakeNMEA();
}
}
The real code I'm working with does not compile. Currently I'm getting errors in all of the subclasses where I attempt to use the UBLOX_INTERFACE::i2cAddress function: error: invalid use of non-static data member 'UBLOX_INTERFACE::i2cAddress' If I change the i2cAddress to be static, then I get a different error saying I have to use a non-static variable in the class construction. And on top of that, I'm unsure if my method of initializing the subclasses within the parent class constructor is even valid. Can anyone explain if this method is valid or what I should be doing instead?
You are trying to access i2cAddress from the class NMEA but you have defined the variable in the class UBLOX_INTERFACE.
The classes might be defined inside each other, but the instances of the classes does not have access to eachothers variable.
Alternatives would be to either make i2cAddress static, or global or to send a pointer or copy of i2cAddress or to UBLOX_INTERFACE to the class NMEA at some point.
Or depending on your code (i do understand it fully), you might want to put i2cAddress as a member variable of NMEA, that would also solve the problem.
Edit:
If you want to initialize a static member variable in the constructor, it is not possible to do it in the initializer list
//UBLOX_INTERFACE Class Functions
UBLOX_INTERFACE::UBLOX_INTERFACE(uint8_t address) // not here :
{
i2cAddress = address; // This should work
// The following variables does only exist in this function,
// I think that you might want to move these to the function body
// instead
NMEA nmea;
UBX_CFG_RATE ubxCFG_RATE(0x06, 0x08, 0, 6); //These values are permanently defined constants for each command type
UBX_CFG_RST ubxCFG_RST(0x06, 0x04, 0, 4);
}
And about if it would be possible to initialize like classes like you do: No I dont think it works like it does now. You need to add the classes as class members, and then initialize them in the initialize list like you previously did with i2cAddress.

Reference to non-static member function must be called when processing callbacks inside a class

I have the following API code provided by PiGPIO library. Basically it allows you to set a callback function when the state of a pin was changed.
Normally the API looks like this:
typedef void (*gpio_callback_t)(int, int, uint32_t);
int gpioSetAlertFunc(int, gpio_callback_t)
And it can be called like this:
void callback_func(int pin, int NewLevel, uint32_t CurrentTicks)
{
// Callback process
}
int main()
{
// Setting up callback function
gpioSetAlertFunc(10, callback_func)
// Do stuff while callback will be called independently
}
Now the code above works perfectly!
The big problem comes when I try to wrap this code in a C++ class.
The class shall look like the following:
class Pin
{
public:
Pin()
{
gpioSetAlertFunc(10, this->internal_gpio_callback) );
}
void internal_callback_func(int pin, int level, uint32_t tick)
{
cout << "New level: " << pin << " " << level;
}
}
The problem is that the reference to that function is not allowed as it is not a static function. For things to be more complicated, I can't just make the callback function static. That callback function will interact a lot with the rest of the class methods and it's internal variables.
Do you know a workaround for this? Or maybe a dirty hack using pointers or something?
An unbroken C-style callback will accept a void* argument to pass arbitrary user-defined data. Since this one doesn't, its a bug in the library design. Raise an issue with the library authors.
To work around this issue you need to create a closure as a C-compatible function. There's no way to do that is standard C or C++. There are libraries (non-standard-conforming and not portable by necessity) that solve this problem though. One such library is GNU libffcall, another one is libffi. Both allow you to create closures that behave like normal C functions.
The gpio library code has no concept of your Pin classes, but you cannot call your member callback function without knowing which Pin object to call it on. Thus, you need some (non-member) function that finds the Pin object to use in the function call.
It appears that this information comes in the form of the int pin parameter. Thus, you need a (free) function that knows about all your Pin objects and which pin number they have, finds the correct one and calls its callback function:
class Pin
{
public:
explicit Pin(int pin);
void internal_callback_func(int level, uint32_t tick);
private:
int _pin;
};
// Alternatively a std::array, a std::map or similar.
std::vector<Pin> allPins;
void pinCallback(int pin, int level, uint32_t tick)
{
Pin& pinObject = allPins[pin];
pinObject.internal_callback_func(level, tick);
// The Pin object presumably knows its own number.
}
Pin::Pin(int pin) : _pin(pin)
{
gpioSetAlertFunc(_pin, pinCallback);
}
void Pin::internal_callback_func(int level, uint32_t tick)
{
cout << "New level: " << _pin << " " << level;
}
void mainOrSo()
{
// Create some pins and store them in the vector. Each one registers the callback on construction.
for (int i = 0; i < 16; ++i)
allPins.emplace_back(i);
}

C delegate to C++

I have a small problem using a library that gets images from a CMOS camera.
The library permits to use a stream functionality and I have three access point to set (three delegates) for when I get an image, when an image is dropped and when there is an error.
typedef void(* StreamCallbackPtr)( IMAGE *image );
typedef void(* StreamErrorCallbackPtr)();
typedef void(* StreamFrameDroppedCallbackPtr)();
int Stream_Start( DEVICE device, IMAGEFORMAT format, StreamCallbackPtr stream_callback, StreamFrameDroppedCallbackPtr f_dropped_callback, StreamErrorCallbackPtr error_callback );
I enter a StreamCallbackPtr as soon as an image is ready on the camera, but keep in mind that I do not have any ways of changing the library code.
And here is the question: How do I plug my own delegate in C++ ?
Lets say I use this stream functionality inside a class, I know that I have at least two options; the wrapper, and global variables. The first one seems compromised since I cannot pass anything else than an IMAGE, and I want to avoid using global variables (it would be static members in this case).
Any ideas ?
You could use a static member function as the StreamCallbackPtr which then can access a private static reference or list of references to the C++ delegates which wish to receive the message.
That way you have hidden most of the details as private to the class.
The code below is pseudo-C++ (I haven't checked it properly) but it should give you the idea of what I am suggesting.
class Delegate
{
protected:
void Callback( IMAGE *image ) = 0;
void Error() = 0;
void FrameDropped() = 0;
public:
static void SetDelegate(Delegate* d) { delegateInstance = d; }
static void StaticCallback( IMAGE *image)
{
// Invoke the delegate instance
if (delegateInstance != nullptr) delegateInstance->Callback();
}
// Same for the others...
private:
static Delegate* delegateInstance = nullptr;
};
class MyClass : public Delegate
{
protected:
void Callback( IMAGE *image )
{
// Now the callback is in a delegate instance
}
};
int main(void)
{
MyClass mc;
Delegate::SetDelegate(&mc);
StreamCallbackPtr scp = &Delegate::StaticCallback;
// Register the other static callbacks...
return 0;
}

Avoiding a static member function in c++ when using a callback interface from C

I would like to access the data within this member function that is static. Right now the member function is static so that I can use it with a third party API written in C that has typdef function pointer for callback purposes. Based on the info below, what is the best way to get around the need to create a static function in order to use the data from the following function member within other member functions of my class that are non-static. Maybe there is a way to still use this static function but still overcome the inability to mix static with non-static variables. My code does works as is but with no ability to access the data in the following callback function.
void TextDetect::vtrCB(vtrTextTrack *track, void *calldata) /*acts as a callback*/
{
/*specifically would like to take data from "track" to a deep copy so that I don't loose scope over the data withing that struct */
}
In an associated API written in C, there are the following two lines of code that I am forced to use:
typedef void (*vtrCallback)(vtrTextTrack *track, void *calldata);
int vtrInitialize(const char *inifile, vtrCallback cb, void *calldata);
Here is the header of my class:
#include <vtrapi.h>
#include <opencv.hpp>
class TextDetect {
const char * inifile;
vtrImage *vtrimage;
int framecount;
public:
TextDetect();
~TextDetect();
static void vtrCB(vtrTextTrack *track, void *calldata);
int vtrTest(cv::Mat);
bool DrawBox(cv::Mat&);
};
TextDetect::TextDetect() : inifile("vtr.ini")
{
if (vtrInitialize(inifile, vtrCB /*run into problems here*/, NULL) == -1)
std::cout << "Error: Failure to initialize" << std::endl;
vtrimage = new vtrImage;
framecount = 0;
}
void TextDetect::vtrCB(vtrTextTrack *track, void *calldata) /*acts as a callback*/
{
/*specifically would like to take data from "track" to a deep copy so that I don't loose scope over the data withing that struct */
}
I am not sure I understand your precise situation, but here is the standard idiom for wrapping a C++ method into a C callback API:
/*regular method*/
void TextDetect::vtrCB(vtrTextTrack *track)
{
// do all the real work here
}
/*static method*/
void TextDetect::vtrCB_thunk(vtrTextTrack *track, void *data)
{
static_cast<TextDetect *>(data)->vtrCB(track);
}
and then, assuming the function that should call vtrInitialize is also a TextDetect method, you write the call like this:
vtrInitialize(inifile, TextDetect::vtrCB_thunk, static_cast<void *>(this));

Add friend class after declaration

I am trying to write a named pipe server in C++. I have a class called client_pool which contains a container of the pipe's instances, and a single public member function write, which asynchronously sends data to all connected clients.
Problem is, clients have the tendency to disconnect unexpectedly. When this happens, the call to WriteFileEx fails with ERROR_NO_DATA. When that happens, i want to go to the client_pool class and tell it to close the client handle and remove it from the container. However, since WriteFileEx is so fricking hard to use, I created a helper class called write_context in an anonymous namespace.
So the end result is, that I want to call a private method in client_pool, which is declared in clients.h, from the class write_context, which is declared in clients.cpp. Something like that (details/error handling omitted):
clients.h
class client_pool {
struct implementation;
std::unique_ptr<implementation> pimpl;
public:
void write(uint8_t *data, size_t size);
};
clients.cpp
struct client_pool::implementation {
set<HANDLE> connected;
// ...
void disconnect(HANDLE victim)
{
CloseHandle(victim);
connected.erase(victim);
}
};
namespace { struct write_context {
OVERLAPPED overlapped;
client_pool *owner;
HANDLE target;
const uint8_t *buffer;
size_t total_size;
size_t written;
// ...
void next_chunk()
{
if(!WriteFileEx(/* ... */, write_context::completion_routine)) {
if(GetLastError() == ERROR_NO_DATA) {
// I want to do something like
owner->pimpl->disconnect(target);
}
}
}
static void CALLBACK completion_routine(DWORD errcode, DWORD transferred, LPOVERLAPPED overlapped)
{
auto self = reinterpret_cast<write_context*>(overlapped);
self->written += transferred;
if(errcode == ERROR_MORE_DATA) {
self->next_chunk();
} else {
delete self;
}
}
}; }
void client_pool::write(uint8_t *data, size_t size)
{
for each handle in pimpl->connected {
auto context = new write_context(this, handle, data, size);
context->next_chunk();
}
}
Obviously, the line owner->pimpl->disconnect(target); doesn't compile because pimpl is private. What can I do / what are my alternatvies?
Directly accessing pimpl->connected and write_context directly in your client_pool::write method is kinda contrary to the point of the pimpl idiom. You could probably make a case otherwise, until you run into a problem just like this.
I would just create an implementation::write method for which you can pass through the arguments and a pointer to client_pool.
I think if you use a named namespace instead of a anonymous namespace you could place this line inside the class definition:
friend void namespace_name::next_chunk()
Or there's placing all that extra stuff in the anonymous namespace as static functions inside the class. Because static methods and structs don't change the ABI, you can hide it from all other instances via a preprocessor trick.
Or there's the brutal and horrifying:
#define class struct
#define private public
#define protected public
Make write_context a friend of implementation. Pass pimpl as the owner of write_context.
Sorry, but this is not the best way to use PIMPL idiom.
PIMPL hides implementation details of it's owner and should be accessed only through its owners interface. So, if you want to call "client_pool::implementation" method than it should be moved to "client_pool" interface and its implementation should delegate work to "client_pool::implementation" class. In other case this looks like design bug.