Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/call.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/call.hpp	(revision 4665)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/call.hpp	(revision 4666)
@@ -1089,4 +1089,13 @@
      */
     bool hasMedia() const;
+    
+    /**
+     * Get media for the specified media index.
+     *
+     * @psaram med_idx      Media index.
+     *
+     * @return              The media or NULL if invalid or inactive.
+     */
+    Media *getMedia(unsigned med_idx) const;
 
     /**
@@ -1420,4 +1429,15 @@
     MediaTransportInfo getMedTransportInfo(unsigned med_idx) const throw(Error);
 
+    /**
+     * Internal function (callled by Endpoint( to process update to call
+     * medias when call media state changes.
+     */
+    void processMediaUpdate(OnCallMediaStateParam &prm);
+
+    /**
+     * Internal function (called by Endpoint) to process call state change.
+     */
+    void processStateChange(OnCallStateParam &prm);
+    
 public:
     /*
@@ -1665,11 +1685,9 @@
     {}
 
-protected:
-    friend class Endpoint;
-    
 private:
     Account             &acc;
     pjsua_call_id 	 id;
     Token                userData;
+    std::vector<Media *> medias;
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/media.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/media.hpp	(revision 4665)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/media.hpp	(revision 4666)
@@ -142,9 +142,22 @@
     virtual ~Media();
 
+    /**
+     * Get type of the media.
+     *
+     * @return          The media type.
+     */
+    pjmedia_type getType() const;
+
 protected:
     /**
      * Constructor.
      */
-    Media();
+    Media(pjmedia_type med_type);
+
+private:
+    /**
+     * Media type.
+     */
+    pjmedia_type        type;
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/call.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/call.cpp	(revision 4665)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/call.cpp	(revision 4666)
@@ -19,4 +19,5 @@
 #include <pjsua2/account.hpp>
 #include <pjsua2/call.hpp>
+#include <pjsua2/endpoint.hpp>
 #include <pj/ctype.h>
 #include "util.hpp"
@@ -139,4 +140,21 @@
 
 //////////////////////////////////////////////////////////////////////////////
+
+/* Call Audio Media. */
+class CallAudioMedia : public AudioMedia
+{
+public:
+    /*
+     * Set the conference port identification associated with the
+     * call audio media.
+     */
+    void setPortId(int id);
+};
+
+
+void CallAudioMedia::setPortId(int id)
+{
+    this->id = id;
+}
 
 CallOpParam::CallOpParam(bool useDefaultCallSetting)
@@ -409,4 +427,17 @@
 }
 
+Media *Call::getMedia(unsigned med_idx) const
+{
+    /* Check if the media index is valid and if the media has a valid port ID */
+    if (med_idx >= medias.size() ||
+        (medias[med_idx] && medias[med_idx]->getType() == PJMEDIA_TYPE_AUDIO &&
+         ((AudioMedia *)medias[med_idx])->getPortId() == PJSUA_INVALID_ID))
+    {
+        return NULL;
+    }
+    
+    return medias[med_idx];
+}
+
 pjsip_dialog_cap_status Call::remoteHasCap(int htype,
                                            const string &hname,
@@ -563,10 +594,18 @@
 int Call::vidGetStreamIdx() const
 {
+#if PJSUA_HAS_VIDEO
     return pjsua_call_get_vid_stream_idx(id);
+#else
+    return PJSUA_INVALID_ID;
+#endif
 }
 
 bool Call::vidStreamIsRunning(int med_idx, pjmedia_dir dir) const
 {
+#if PJSUA_HAS_VIDEO
     return pjsua_call_vid_stream_is_running(id, med_idx, dir);
+#else
+    return false;
+#endif
 }
 
@@ -574,4 +613,5 @@
                         const CallVidSetStreamParam &param) throw(Error)
 {
+#if PJSUA_HAS_VIDEO
     pjsua_call_vid_strm_op_param prm;
     
@@ -580,4 +620,7 @@
     prm.cap_dev = param.capDev;
     PJSUA2_CHECK_EXPR( pjsua_call_set_vid_strm(id, op, &prm) );
+#else
+    PJSUA2_RAISE_ERROR(PJ_EINVOP);
+#endif
 }
 
@@ -613,2 +656,58 @@
     return mti;
 }
+
+void Call::processMediaUpdate(OnCallMediaStateParam &prm)
+{
+    pjsua_call_info pj_ci;
+    unsigned mi;
+    
+    if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS) {
+        for (mi = 0; mi < pj_ci.media_cnt; mi++) {
+            if (mi >= medias.size()) {
+                if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
+                    medias.push_back(new CallAudioMedia);
+                } else {
+                    medias.push_back(NULL);
+                }
+            }
+            
+            if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
+                CallAudioMedia *aud_med = (CallAudioMedia *)medias[mi];
+                
+                aud_med->setPortId(pj_ci.media[mi].stream.aud.conf_slot);
+                /* Add media if the conference slot ID is valid. */
+                if (pj_ci.media[mi].stream.aud.conf_slot != PJSUA_INVALID_ID)
+                {
+                    Endpoint::instance().addMedia((AudioMedia &)*aud_med);
+                } else {
+                    Endpoint::instance().removeMedia((AudioMedia &)*aud_med);
+                }
+            }
+        }
+    }
+    
+    /* Call media state callback. */
+    onCallMediaState(prm);
+}
+
+void Call::processStateChange(OnCallStateParam &prm)
+{
+    pjsua_call_info pj_ci;
+    unsigned mi;
+    
+    if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS &&
+        pj_ci.state == PJSIP_INV_STATE_DISCONNECTED)
+    {
+        /* Clear medias. */
+        for (mi = 0; mi < medias.size(); mi++) {
+            if (medias[mi])
+                delete medias[mi];
+        }
+        medias.clear();
+    }
+    
+    onCallState(prm);
+    /* If the state is DISCONNECTED, this call may have already been deleted
+     * by the application in the callback, so do not access it anymore here.
+     */
+}
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp	(revision 4665)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp	(revision 4666)
@@ -709,5 +709,5 @@
     prm.e.fromPj(*e);
     
-    call->onCallState(prm);
+    call->processStateChange(prm);
     /* If the state is DISCONNECTED, call may have already been deleted
      * by the application in the callback, so do not access it anymore here.
@@ -736,7 +736,7 @@
 	return;
     }
-    
+
     OnCallMediaStateParam prm;
-    call->onCallMediaState(prm);
+    call->processMediaUpdate(prm);
 }
 
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/media.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/media.cpp	(revision 4665)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/media.cpp	(revision 4666)
@@ -56,5 +56,6 @@
 }
 ///////////////////////////////////////////////////////////////////////////////
-Media::Media()
+Media::Media(pjmedia_type med_type)
+: type(med_type)
 {
 
@@ -66,7 +67,12 @@
 }
 
+pjmedia_type Media::getType() const
+{
+    return type;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 AudioMedia::AudioMedia() 
-: id(PJSUA_INVALID_ID), mediaPool(NULL)
+: Media(PJMEDIA_TYPE_AUDIO), id(PJSUA_INVALID_ID), mediaPool(NULL)
 {
 
