void CrowdDetectorFilterImpl::busMessage (GstMessage *message)
{
  const GstStructure *st;
  gchar *roiID;
  const gchar *type;
  std::string roiIDStr, typeStr;

  if (GST_MESSAGE_SRC (message) != GST_OBJECT (crowdDetector) ||
      GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) {
    return;
  }

  st = gst_message_get_structure (message);
  type = gst_structure_get_name (st);

  if (!gst_structure_get (st, "roi", G_TYPE_STRING , &roiID, NULL) ) {
    GST_WARNING ("The message does not contain the roi ID");
    return;
  }

  roiIDStr = roiID;
  typeStr = type;

  g_free (roiID);

  if (typeStr == "fluidity-event") {

    double fluidity_percentage;
    int fluidity_level;

    if (! (gst_structure_get (st, "fluidity_percentage", G_TYPE_DOUBLE,
                              &fluidity_percentage, NULL) ) ) {
      GST_WARNING ("The message does not contain the fluidity percentage");
      return;
    }

    if (! (gst_structure_get (st, "fluidity_level", G_TYPE_INT,
                              &fluidity_level, NULL) ) ) {
      GST_WARNING ("The message does not contain the fluidity level");
      return;
    }

    try {
      CrowdDetectorFluidity event (shared_from_this(),
                                   CrowdDetectorFluidity::getName(),
                                   fluidity_percentage, fluidity_level,
                                   roiIDStr);
      signalCrowdDetectorFluidity (event);
    } catch (std::bad_weak_ptr &e) {
    }
  } else if (typeStr == "occupancy-event") {

    double occupancy_percentage;
    int occupancy_level;

    if (! (gst_structure_get (st, "occupancy_percentage", G_TYPE_DOUBLE,
                              &occupancy_percentage, NULL) ) ) {
      GST_WARNING ("The message does not contain the occupancy percentage");
      return;
    }

    if (! (gst_structure_get (st, "occupancy_level", G_TYPE_INT,
                              &occupancy_level, NULL) ) ) {
      GST_WARNING ("The message does not contain the occupancy level");
      return;
    }

    try {
      CrowdDetectorOccupancy event (shared_from_this(),
                                    CrowdDetectorOccupancy::getName(),
                                    occupancy_percentage, occupancy_level,
                                    roiIDStr);
      signalCrowdDetectorOccupancy (event);
    } catch (std::bad_weak_ptr &e) {
    }
  } else if (typeStr == "direction-event") {

    double direction_angle;

    if (! (gst_structure_get (st, "direction_angle", G_TYPE_DOUBLE,
                              &direction_angle, NULL) ) ) {
      GST_WARNING ("The message does not contain the direction angle");
      return;
    }

    try {
      CrowdDetectorDirection event ( shared_from_this(),
                                     CrowdDetectorDirection::getName(),
                                     direction_angle, roiIDStr);
      signalCrowdDetectorDirection (event);
    } catch (std::bad_weak_ptr &e) {
    }
  } else {
    GST_WARNING ("The message does not have the correct name");
  }
}
CrowdDetectorFilterImpl::CrowdDetectorFilterImpl (
  const std::vector<std::shared_ptr<RegionOfInterest>> &rois,
  std::shared_ptr< MediaObjectImpl > parent) :
  FilterImpl (parent)
{
  GstBus *bus;
  std::shared_ptr<MediaPipelineImpl> pipe;
  GstStructure *roisStructure;

  pipe = std::dynamic_pointer_cast<MediaPipelineImpl> (getMediaPipeline() );

  g_object_set (element, "filter-factory", "crowddetector", NULL);

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipe->getPipeline() ) );

  g_object_get (G_OBJECT (element), "filter", &crowdDetector, NULL);

  if (crowdDetector == NULL) {
    g_object_unref (bus);
    throw KurentoException (MEDIA_OBJECT_NOT_AVAILABLE,
                            "Media Object not available");
  }

  roisStructure = gst_structure_new_empty  ("Rois");

  for (auto roi : rois) {
    GstStructure *roiStructureAux = get_structure_from_roi (roi);

    gst_structure_set (roisStructure,
                       roi->getId().c_str(), GST_TYPE_STRUCTURE,
                       roiStructureAux,
                       NULL);

    gst_structure_free (roiStructureAux);
  }

  g_object_set (G_OBJECT (crowdDetector), ROIS_PARAM, roisStructure, NULL);
  gst_structure_free (roisStructure);

  busMessageLambda = [&] (GstMessage * message) {
    const GstStructure *st;
    gchar *roiID;
    const gchar *type;
    std::string roiIDStr, typeStr;

    if (GST_MESSAGE_SRC (message) != GST_OBJECT (crowdDetector) ||
        GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) {
      return;
    }

    st = gst_message_get_structure (message);
    type = gst_structure_get_name (st);

    if (!gst_structure_get (st, "roi", G_TYPE_STRING , &roiID, NULL) ) {
      GST_WARNING ("The message does not contain the roi ID");
      return;
    }

    roiIDStr = roiID;
    typeStr = type;

    g_free (roiID);

    if (typeStr == "fluidity-event") {

      double fluidity_percentage;
      int fluidity_level;

      if (! (gst_structure_get (st, "fluidity_percentage", G_TYPE_DOUBLE,
                                &fluidity_percentage, NULL) ) ) {
        GST_WARNING ("The message does not contain the fluidity percentage");
        return;
      }

      if (! (gst_structure_get (st, "fluidity_level", G_TYPE_INT,
                                &fluidity_level, NULL) ) ) {
        GST_WARNING ("The message does not contain the fluidity level");
        return;
      }

      try {
        CrowdDetectorFluidity event (fluidity_percentage, fluidity_level, roiIDStr,
                                     shared_from_this(),
                                     CrowdDetectorFluidity::getName() );
        signalCrowdDetectorFluidity (event);
      } catch (std::bad_weak_ptr &e) {
      }
    } else if (typeStr == "occupancy-event") {

      double occupancy_percentage;
      int occupancy_level;

      if (! (gst_structure_get (st, "occupancy_percentage", G_TYPE_DOUBLE,
                                &occupancy_percentage, NULL) ) ) {
        GST_WARNING ("The message does not contain the occupancy percentage");
        return;
      }

      if (! (gst_structure_get (st, "occupancy_level", G_TYPE_INT,
                                &occupancy_level, NULL) ) ) {
        GST_WARNING ("The message does not contain the occupancy level");
        return;
      }

      try {
        CrowdDetectorOccupancy event (occupancy_level, occupancy_percentage,
                                      roiIDStr, shared_from_this(),
                                      CrowdDetectorOccupancy::getName() );
        signalCrowdDetectorOccupancy (event);
      } catch (std::bad_weak_ptr &e) {
      }
    } else if (typeStr == "direction-event") {

      double direction_angle;

      if (! (gst_structure_get (st, "direction_angle", G_TYPE_DOUBLE,
                                &direction_angle, NULL) ) ) {
        GST_WARNING ("The message does not contain the direction angle");
        return;
      }

      try {
        CrowdDetectorDirection event (direction_angle, roiIDStr, shared_from_this(),
                                      CrowdDetectorDirection::getName() );
        signalCrowdDetectorDirection (event);
      } catch (std::bad_weak_ptr &e) {
      }
    } else {
      GST_WARNING ("The message does not have the correct name");
    }
  };

  bus_handler_id = g_signal_connect (bus, "message",
                                     G_CALLBACK (bus_message_adaptor),
                                     &busMessageLambda);
  g_object_unref (bus);

  // There is no need to reference crowddetector because its life cycle is the same as the filter life cycle
  g_object_unref (crowdDetector);
}