Locked Capability disposal problems

  • Friday, February 16, 2007 1:57 PM
     
     
    Dear Jason,

    I've got kind of a weird bug that we cannot pin down that you might be able to help us with.  For the latest version of I-MINDS, we branched the code into three different versions:  moderator, user, and logger.  The purpose of the logger version is to log all messages sent in the capability to our own database (we use MySQL right now to store metadata and are thinking of modifying Archiver later to support better data tracking).  We were having each moderator and user log their own data, but when we started testing over wireless, we found that the system couldn't handle that many TCP/IP database connections (standard wireless problem where inherent packet loss slowed down the system).  To resolve this issue, we just maintain one database connection to log all messages.

    The problem is this:  when ever the logger leaves the venue, rejoins any venue, and starts the capability back up, weird things happen.  Inside the AddCapability(capability) event handling code, the capability is not null when we save it, but after the first participant is added through the ParticipantAdded event, the capability is suddenly null and we get a null pointer exception whenever we try to access it and remains it null until we close CXP.  Leaving and rejoining the venue again causes the same problem.

    This is a problem no matter how many people are using CXP (even if it is just the logger and no one else) and the first time we load the capability, it works perfectly fine.  It only happens when we leave a venue then come back into any venue and restart the capability.  Also, this is not a problem for our other two versions of I-MINDS (moderator and user) and both of those methods use the same basic structure for the CXP generated events (AddCapability, ParticipantAdded, etc.). 

    Do you have any ideas what might be going on?  I'd be happy to provide any extra information that you need.

    Thanks a lot,
    Adam
    • Moved by Max Wang_Chinasoft Thursday, April 28, 2011 8:06 PM forum consolidation (From:Developer Discussions)
    •  

All Replies

  • Tuesday, February 20, 2007 4:24 PM
     
     

    Hi Adam,

    Sounds like you have a strange one here. 

    What kind of capability does the Logger start?  Wouldn't the logger just be a Receiver only of any capabilities that other's started and not start its own?  Or do you start a capability in order to do the logging and all other capabilities funnel through this one?

    Are we discussing owned capabilities or channel capabilities (from others, for the logger)?

    What do you mean by the "same basic structure"?  Can you diff the various versions to see if anything stands out as being an Oops?

    How long do you stay out of the venue before re-entering?

    JVE

  • Friday, February 23, 2007 3:18 AM
     
     

    Hi Adam

     

    Have you resolved your problem?

     

    I experienced a similar problem but I thought I had induced the problem with all my own hacks (I still think I have).

     

    The problem was evident for me when entering a venue where a presentation capability was already operational and there is more than one other participant in the venue.

     

    If the RTCP packet belonging to the owner of the presentation capability arrived before the other participant’s RTCP packet everything is cool however if the RTCP packet from one of the participants arrived before the owner's RTCP packet a Null reference exception was written to the event log and the capability was not hooked.

     

    I discovered that if the participants RTCP packet arrives first owner of the capability was set to null.

     

    In Conference.cs ->

     

    private static void _RtpStreamAdded(object sender, RtpEvents.RtpStreamEventsArgs ea)

    { …….}

    else

    {

    // Try to convert an existing ICapabilitySender into an ICapabilityViewer if it exists...

    if (capabilitySenders.ContainsKey(capabilityKey))

    {

    iCV = capabilitySenders[capabilityKey] as ICapabilityViewer;

    }

                       

    if (iCV == null) // None found, create a new CapabilityViewer from scratch

    {

    iCV = Conference.CreateCapabilityForRtpStream(ea.RtpStream);

    }

     

    /////Added this line to assign owner to iCV

    iCV.Owner = participants[ea.RtpStream.Properties.CName];

    /////

     

    // Make sure we add the stream first before calling RaiseCapabilityViewerAdded so that ICapability.Owner will be set when CapabilityViewerAdded is handled

    iCV.StreamAdded(ea.RtpStream);

     

    AddCapabilityViewer(iCV);

    }

     

    I added the line:

     

    iCV.Owner = participants[ea.RtpStream.Properties.CName]

     

    to assign the name of the owner to the iCV.  The next line:

     

    iCV.StreamAdded(ea.RtpStream);

     

    was not doing it for me under all circumstances.

     

    As I say it was probably my hacks that caused the problem in the first place but I couldn’t find where.

     

    I would be interested to know if you entered that line does it help your problem?

     

    Michael W

  • Friday, February 23, 2007 1:58 PM
     
     
    Hey guys,

    Thanks a lot for your responses!  We really appreciate it.

    It turns out we tracked down the source of our problems.  Here is the snippet of code:

    public override void AddCapability(ICapability capability)
    {
           base.AddCapability (capability);

           if(mergedCapability == null)
           {
                    mergedCapability = (IMINDSCapability) capability;
               
                    // Hook the ObjectReceived event so we can receive incoming data
                    mergedCapability.ObjectReceived += new CapabilityObjectReceivedEventHandler(objectReceived);

                    // hook the participant added and removed events here
                    HookRtpEvents();
           }

           // using this line instead of the above one causes problems!
           // the events will be hooked too many times!
           //HookRtpEvents();

    }//end AddCapability method

    The HookRtpEvents method just attaches the ParticipantAdded and ParticipantRemoved events to the proper delegates.  Originally, we had it outside of the if(capability null) statement, but it turns out this caused those events to be hooked BOTH times the capability is added (for both the viewer and sender copies).  Moving the method call into the if block solved the problem -- the delegates were only hooked once and we no longer have any null pointer exceptions. 

    The null pointer exception kept happening in a method called by the ParticipantAdded delegate which tried to send data to the new participant, so it makes sense that hooking that event twice would cause a problem -- the first time it was hooked, the capability probably wasn't a sender yet and the event fired before the sender version of AddCapability was called.

    Thanks again,
    Adam
  • Friday, February 23, 2007 5:27 PM
     
     

    Adam,

    Glad to hear you tracked the problem down.  Sounds like your interpretation of the problem and solution are reasonable.

    JVE

  • Friday, February 23, 2007 5:31 PM
     
     

    Michael,

    Is your presentation capability a channel or an owned capability?  If it's a channel, there could be some problems like you suggest, though we never saw any in the event log, even if the Rtcp packets came in 'out of order' (with regards to who started the capability).  As a matter of fact, Patrick and I specifically discussed and tried to handle that scenario for channels.

    In the end, channels are a fine idea, but harder to get correct.  I am pretty sure our presentation capability is now owned.

    JVE