[rtmpdump] [PATCH] AMF Object Callback

Chris Larsen clarsen at euphoriaaudio.com
Sat Jul 30 02:33:41 CEST 2011

> So I guess this list has become the C Programming workshop.

Hey, I'm here to learn and to try and help the community. I do work mostly
in C++ so I'm not a brilliant C coder.

> Except for very trivial cases, I don't see that the current approach is of
much use. If you wanted to write a callback that intercepts a particular
type of message 
> and computes a reply to send back, the callback function at least needs to
also get the RTMP * pointer as an argument. If you want to write a callback
> accesses some other variables in the program, you at least need to give it
a context pointer that can be set to point to a structure containing
whatever other 
> data it needs.

I've been using this callback in a very trivial fashion to grab and format
status codes and parse the strings for authentication information, something
that is unique to various CDNs. So I apologize for not thinking about more
advanced uses. The only other ways to get such information out of libRTMP is
to use the logging callback or parse stderr. However I was using static
global variables which, as you pointed out, is a bad idea so certainly
passing a context pointer of some kind makes much more sense.

> Also, if you want to intercept a particular message and then act on it,
you probably need to be able to return a result code. I would say
>	#define AMF_CB_CONTINUE	0xffff	/* continue with normal processing
>	#define AMF_CB_SUCCESS	0	/* callback did everything, stop
processing */
>	/* any other value: error code, stop processing */

> So your prototype should look like:
>	typedef int (AMF_ObjectCallback)(RTMP *, AMFObject *, void *);
> With
>	void RTMP_SetAMFCallback(RTMP *r, AMFObject *obj, void *ctx)

Regarding the return code, since the onus is on the client to take any
actions it needs depending on the object, does libRTMP really care whether
the client found what it needed to? The client should just return when it's
done with the object and libRTMP will continue on it's way. A return code
could be used for logging so I could add that if you want me to. I'll add
the RTMP and context pointers though.

> The other problem with all of this is that it requires the callback to
duplicate a lot of librtmp's parsing before it can discover if it actually
needs to do anything.

All of the parsing has been completed before the callback is executed. The
client just has to include amf.h and it can do whatever is necessary. I
didn't touch the AMF_Dump calls but I could wrap them in an else statement
so that if the client has set a callback, the dumps are not performed. Let
me know if I should do that.

> So again, the question is - what good is this? How do you actually expect
to be able to use this feature? Give an actual example, one that would
actually work, 
> given what you've proposed.

The example I have implemented, as has been talked about on the list before,
is that of authenticating to an ingest FMS server where the CDN has written
a custom module to authorize publishing.  It's pretty much the same as the
AMF_Dump function. Some of the CDNs use a multiple connect approach where
they send an error message with a token and then you have to reconnect using
that token. When the initial connect fails, my client checks to see if a
token was received and if so, attempts to reconnect.

void MyClass::AMFCallback(RTMP *r, AMFObject *obj, void *ctx){
  for (int n = 0; n < obj->o_num; n++){
    if (obj->o_props[n].p_type == AMF_STRING &&
obj->o_props[n].p_name.av_len > 0 
      && strncmp(obj->o_props[n].p_name.av_val, "description", 11) == 0 
      &&  obj->o_props[n].p_vu.p_aval.av_val != NULL){
      std::string temp = obj->o_props[n].p_vu.p_aval.av_val;
      if (temp.find("authentication required notice") != temp.npos){
          MyClass *client = (MyClass *)ctx;
          client->auth_value = temp; // parsed of course to get the actual

Thank you for your feedback.

More information about the rtmpdump mailing list