Plugin implementation in Corona Native

I’ve worked through the excellent iOS Corona Native tutorial that Scott posted and got a test plugin working for simple cases - ie I can register a function, call it from my Lua code and have it generate an event which get’s picked up by the listener function registered when I call the plugin .init function.

However when I want to take it to the next level I’m hitting an issue.  I’m developing a plugin with a simple interface.

plugin.init( listener ) -- initialise the plugin and register the event listener plugin.start() -- start a monitoring process that continually sends events back to the listener plugin.stop() -- stop the monitoring process

To implement the monitoring / recording process in my Objective C code in the start function I use an NSTimer scheduledTimerWithTimeInterval : block to basically create a closure and this appears to work fine - the block repeats fine and will happily NSLog() until I call the stop() function which calls the invalidate method on the above NSTimer instance.

However when I attempt to create a new event from within the block the code stops at the following line 

Self \*library = (Self \*)CoronaLuaToUserdata( L, lua\_upvalueindex( 1 ) );

With an EXC_BAD_ACCESS (code=1, address=0x0b) error - as far as I can tell it’s getting a null reference from somewhere but I can’t work out why.

Here’s the code from my plugin

class PluginLibrary { protected: PluginLibrary(); static int Finalizer( lua\_State \*L ); public: typedef PluginLibrary Self; &nbsp;&nbsp;&nbsp;static const char kName[]; &nbsp;&nbsp;&nbsp;static const char kEvent[]; &nbsp;&nbsp;&nbsp;bool Initialize( CoronaLuaRef listener ); &nbsp;&nbsp;&nbsp;CoronaLuaRef GetListener() const { return fListener; } static int Open( lua\_State \*L ); static Self \*ToLibrary( lua\_State \*L ); static int init( lua\_State \*L ); static int start( lua\_State \*L ); static int stop( lua\_State \*L ); static int trigger( lua\_State \*L ); private: static void sendMessage( lua\_State \*L, NSString \*message ); static void sendFrequency( lua\_State \*L, double frequency ); static int updateCounter(); &nbsp;&nbsp;&nbsp;CoronaLuaRef fListener; }; // ---------------------------------------------------------------------------- int fakeFreqValue; bool recording; NSTimer \*heartbeat; // ---------------------------------------------------------------------------- const char PluginLibrary::kName[] = "plugin.tuner"; // This corresponds to the name of the library, e.g. [Lua] require "plugin.library" const char PluginLibrary::kEvent[] = "Tuner"; // This corresponds to the event name, e.g. [Lua] event.name PluginLibrary::PluginLibrary() : fListener( NULL ) { fakeFreqValue = 0; recording = NO; heartbeat = nil; } bool PluginLibrary::Initialize( CoronaLuaRef listener ) { &nbsp;&nbsp;&nbsp;&nbsp;// Can only initialize listener once &nbsp;&nbsp;&nbsp;&nbsp;bool result = ( NULL == fListener ); &nbsp;&nbsp;&nbsp;&nbsp;if ( result ) { fListener = listener; } &nbsp;&nbsp;&nbsp;&nbsp;return result; } int PluginLibrary::Open( lua\_State \*L ) { &nbsp;&nbsp;&nbsp;&nbsp;// Register \_\_gc callback &nbsp;&nbsp;&nbsp;&nbsp;const char kMetatableName[] = \_\_FILE\_\_; // Globally unique string to prevent collision &nbsp;&nbsp;&nbsp;&nbsp;CoronaLuaInitializeGCMetatable( L, kMetatableName, Finalizer ); &nbsp;&nbsp;&nbsp;&nbsp;// Functions in library &nbsp;&nbsp;&nbsp;&nbsp;const luaL\_Reg kVTable[] = &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; { "init", init }, &nbsp;&nbsp;&nbsp;&nbsp;{ "start", start }, { "stop", stop }, { "trigger", trigger }, &nbsp;&nbsp;&nbsp;&nbsp;{ NULL, NULL } &nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;// Set library as upvalue for each library function &nbsp;&nbsp;&nbsp;&nbsp;Self \*library = new Self; &nbsp;&nbsp;&nbsp;&nbsp;CoronaLuaPushUserdata( L, library, kMetatableName ); &nbsp;&nbsp;&nbsp;&nbsp;luaL\_openlib( L, kName, kVTable, 1 ); // leave "library" on top of stack &nbsp;&nbsp;&nbsp;&nbsp;return 1; } int PluginLibrary::Finalizer( lua\_State \*L ) { &nbsp;&nbsp;&nbsp;&nbsp;Self \*library = (Self \*)CoronaLuaToUserdata( L, 1 ); &nbsp;&nbsp;&nbsp;&nbsp;CoronaLuaDeleteRef( L, library-\>GetListener() ); &nbsp;&nbsp;&nbsp;&nbsp;delete library; &nbsp;&nbsp;&nbsp;&nbsp;return 0; } PluginLibrary \*PluginLibrary::ToLibrary( lua\_State \*L ) { &nbsp;&nbsp;&nbsp;&nbsp;// library is pushed as part of the closure &nbsp;&nbsp;&nbsp;&nbsp;Self \*library = (Self \*)CoronaLuaToUserdata( L, lua\_upvalueindex( 1 ) ); &nbsp;&nbsp;&nbsp;&nbsp;return library; } // [Lua] library.init( listener ) int PluginLibrary::init( lua\_State \*L ) { &nbsp;&nbsp;&nbsp;&nbsp;int listenerIndex = 1; // TODO - Request permission to use the microphone... &nbsp;&nbsp;&nbsp;&nbsp;if ( CoronaLuaIsListener( L, listenerIndex, kEvent ) ) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Self \*library = ToLibrary( L ); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CoronaLuaRef listener = CoronaLuaNewRef( L, listenerIndex ); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;library-\>Initialize( listener ); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;return 0; } int PluginLibrary::updateCounter() { fakeFreqValue += 1; return fakeFreqValue; } // [Lua] library.start( word ) - start sampling int PluginLibrary::start( lua\_State \*L ) { if (!recording) { // Start sampling the mic and set up a regular heartbeat to send the calculated frequency value via the registered listener... NSString \*message = @"Recording..."; // Fake with a simple counter for now... heartbeat = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer \* \_Nonnull timer) { // NSLog(@"Bing %i",updateCounter()); sendFrequency(L, updateCounter()); }]; recording = YES; sendMessage(L, message); } return 0; } // [Lua] library.off( word ) - stop sampling int PluginLibrary::stop( lua\_State \*L ) { if (recording) { // Stop sampling the mic and stop the heartbeat function... NSString \*message = @"Stopped"; [heartbeat invalidate]; heartbeat = nil; recording = NO; fakeFreqValue = 0; sendMessage(L, message); } return 0; } // [Lua] library.trigger( word ) - force a read and transmit via a despatched event... int PluginLibrary::trigger( lua\_State \*L ) { fakeFreqValue += 1; sendFrequency(L, (double)fakeFreqValue); return 0; } // ---------------------------------------------------------------------------- void PluginLibrary::sendMessage( lua\_State \*L, NSString \*message ) { // Create event and add the data to it Self \*library = ToLibrary(L); CoronaLuaNewEvent(L, kEvent); lua\_pushstring(L, [message UTF8String]); lua\_setfield(L,-2,"message"); CoronaLuaDispatchEvent(L, library-\>GetListener(), 0); } void PluginLibrary::sendFrequency( lua\_State \*L, double value ) { NSLog(@"sendFrequency %f",value); lua\_Number frequency = value; // Create event and add the data to it Self \*library = ToLibrary(L); // \<\<-- This is where it blows up when called from within a block CoronaLuaNewEvent(L, kEvent); lua\_pushnumber(L, frequency); lua\_setfield(L,-2,"frequency"); CoronaLuaDispatchEvent(L, library-\>GetListener(), 0); }

Any help or pointers in the right direction would be gratefully appreciated.

Update - This question was originally posted on a different thread and has since had some more information and a partial solution which others might find useful.  The other thread can be found here https://forums.coronalabs.com/topic/70041-request-for-coding-native-plugins-guide/

Thanks to @vlads for his help

Update - This question was originally posted on a different thread and has since had some more information and a partial solution which others might find useful.  The other thread can be found here https://forums.coronalabs.com/topic/70041-request-for-coding-native-plugins-guide/

Thanks to @vlads for his help