guint8 gst_rdt_packet_data_get_flags (GstRDTPacket * packet) { guint header; gboolean length_included_flag; guint8 *bufdata; g_return_val_if_fail (packet != NULL, 0); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0); bufdata = GST_BUFFER_DATA (packet->buffer); header = packet->offset; length_included_flag = (bufdata[header] & 0x80) == 0x80; /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } /* get flags */ return bufdata[header]; }
guint16 gst_rdt_packet_data_get_stream_id (GstRDTPacket * packet) { guint16 result; guint header; gboolean length_included_flag; guint8 *bufdata; g_return_val_if_fail (packet != NULL, 0); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0); bufdata = GST_BUFFER_DATA (packet->buffer); header = packet->offset; length_included_flag = (bufdata[header] & 0x80) == 0x80; result = (bufdata[header] & 0x3e) >> 1; if (result == 31) { /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } /* skip asm_rule_number and timestamp */ header += 5; /* stream_id_expansion */ result = GST_READ_UINT16_BE (&bufdata[header]); } return result; }
guint32 gst_rdt_packet_data_get_timestamp (GstRDTPacket * packet) { guint header; gboolean length_included_flag; guint8 *bufdata; g_return_val_if_fail (packet != NULL, 0); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0); bufdata = GST_BUFFER_DATA (packet->buffer); header = packet->offset; length_included_flag = (bufdata[header] & 0x80) == 0x80; /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } /* skip asm_rule_number */ header += 1; /* get timestamp */ return GST_READ_UINT32_BE (&bufdata[header]); }
guint8 gst_rdt_packet_data_get_flags (GstRDTPacket * packet) { GstMapInfo map; guint8 result; guint header; gboolean length_included_flag; g_return_val_if_fail (packet != NULL, 0); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0); gst_buffer_map (packet->buffer, &map, GST_MAP_READ); header = packet->offset; length_included_flag = (map.data[header] & 0x80) == 0x80; /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } /* get flags */ result = map.data[header]; gst_buffer_unmap (packet->buffer, &map); return result; }
guint32 gst_rdt_packet_data_get_timestamp (GstRDTPacket * packet) { GstMapInfo map; guint header; gboolean length_included_flag; guint32 result; g_return_val_if_fail (packet != NULL, 0); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0); gst_buffer_map (packet->buffer, &map, GST_MAP_READ); header = packet->offset; length_included_flag = (map.data[header] & 0x80) == 0x80; /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } /* skip asm_rule_number */ header += 1; /* get timestamp */ result = GST_READ_UINT32_BE (&map.data[header]); gst_buffer_unmap (packet->buffer, &map); return result; }
static GstFlowReturn gst_rdt_depay_chain (GstPad * pad, GstBuffer * buf) { GstRDTDepay *rdtdepay; GstFlowReturn ret; GstClockTime timestamp; gboolean more; GstRDTPacket packet; rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad)); if (GST_BUFFER_IS_DISCONT (buf)) { GST_LOG_OBJECT (rdtdepay, "received discont"); rdtdepay->discont = TRUE; } if (rdtdepay->header) { GstBuffer *out; out = rdtdepay->header; rdtdepay->header = NULL; /* push header data first */ ret = gst_rdt_depay_push (rdtdepay, out); } /* save timestamp */ timestamp = GST_BUFFER_TIMESTAMP (buf); ret = GST_FLOW_OK; GST_LOG_OBJECT (rdtdepay, "received buffer timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); /* data is in RDT format. */ more = gst_rdt_buffer_get_first_packet (buf, &packet); while (more) { GstRDTType type; type = gst_rdt_packet_get_type (&packet); GST_DEBUG_OBJECT (rdtdepay, "Have packet of type %04x", type); if (GST_RDT_IS_DATA_TYPE (type)) { GST_DEBUG_OBJECT (rdtdepay, "We have a data packet"); ret = gst_rdt_depay_handle_data (rdtdepay, timestamp, &packet); } else { switch (type) { default: GST_DEBUG_OBJECT (rdtdepay, "Ignoring packet"); break; } } if (ret != GST_FLOW_OK) break; more = gst_rdt_packet_move_to_next (&packet); } return ret; }
gboolean gst_rdt_packet_data_peek_data (GstRDTPacket * packet, guint8 ** data, guint * size) { guint header; guint8 *bufdata; gboolean length_included_flag; gboolean need_reliable_flag; guint8 stream_id; guint8 asm_rule_number; g_return_val_if_fail (packet != NULL, FALSE); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), FALSE); bufdata = GST_BUFFER_DATA (packet->buffer); header = packet->offset; length_included_flag = (bufdata[header] & 0x80) == 0x80; need_reliable_flag = (bufdata[header] & 0x40) == 0x40; stream_id = (bufdata[header] & 0x3e) >> 1; /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } asm_rule_number = (bufdata[header] & 0x3f); /* skip timestamp and asm_rule_number */ header += 5; if (stream_id == 0x1f) { /* skip stream_id_expansion */ header += 2; } if (need_reliable_flag) { /* skip total_reliable */ header += 2; } if (asm_rule_number == 63) { /* skip asm_rule_number_expansion */ header += 2; } if (data) *data = &bufdata[header]; if (size) *size = packet->length - (header - packet->offset); return TRUE; }
guint8 * gst_rdt_packet_data_map (GstRDTPacket * packet, guint * size) { GstMapInfo map; guint header; gboolean length_included_flag; gboolean need_reliable_flag; guint8 stream_id; guint8 asm_rule_number; g_return_val_if_fail (packet != NULL, NULL); g_return_val_if_fail (packet->map.data == NULL, NULL); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), NULL); gst_buffer_map (packet->buffer, &map, GST_MAP_READ); header = packet->offset; length_included_flag = (map.data[header] & 0x80) == 0x80; need_reliable_flag = (map.data[header] & 0x40) == 0x40; stream_id = (map.data[header] & 0x3e) >> 1; /* skip seq_no and header bits */ header += 3; if (length_included_flag) { /* skip length */ header += 2; } asm_rule_number = (map.data[header] & 0x3f); /* skip timestamp and asm_rule_number */ header += 5; if (stream_id == 0x1f) { /* skip stream_id_expansion */ header += 2; } if (need_reliable_flag) { /* skip total_reliable */ header += 2; } if (asm_rule_number == 63) { /* skip asm_rule_number_expansion */ header += 2; } if (size) *size = packet->length - (header - packet->offset); packet->map = map; return &map.data[header]; }
guint16 gst_rdt_packet_data_get_seq (GstRDTPacket * packet) { guint header; guint8 *bufdata; g_return_val_if_fail (packet != NULL, FALSE); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), FALSE); bufdata = GST_BUFFER_DATA (packet->buffer); /* skip header bits */ header = packet->offset + 1; /* read seq_no */ return GST_READ_UINT16_BE (&bufdata[header]); }
guint16 gst_rdt_packet_data_get_seq (GstRDTPacket * packet) { GstMapInfo map; guint header; guint16 result; g_return_val_if_fail (packet != NULL, FALSE); g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), FALSE); gst_buffer_map (packet->buffer, &map, GST_MAP_READ); /* skip header bits */ header = packet->offset + 1; /* read seq_no */ result = GST_READ_UINT16_BE (&map.data[header]); gst_buffer_unmap (packet->buffer, &map); return result; }
static GstFlowReturn gst_rdt_manager_chain_rdt (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstFlowReturn res; GstRDTManager *rdtmanager; GstRDTManagerSession *session; GstClockTime timestamp; GstRDTPacket packet; guint32 ssrc; guint8 pt; gboolean more; rdtmanager = GST_RDT_MANAGER (parent); GST_DEBUG_OBJECT (rdtmanager, "got RDT packet"); ssrc = 0; pt = 0; GST_DEBUG_OBJECT (rdtmanager, "SSRC %08x, PT %d", ssrc, pt); /* find session */ session = gst_pad_get_element_private (pad); /* see if we have the pad */ if (!session->active) { activate_session (rdtmanager, session, ssrc, pt); session->active = TRUE; } if (GST_BUFFER_IS_DISCONT (buffer)) { GST_DEBUG_OBJECT (rdtmanager, "received discont"); session->discont = TRUE; } res = GST_FLOW_OK; /* take the timestamp of the buffer. This is the time when the packet was * received and is used to calculate jitter and clock skew. We will adjust * this timestamp with the smoothed value after processing it in the * jitterbuffer. */ timestamp = GST_BUFFER_TIMESTAMP (buffer); /* bring to running time */ timestamp = gst_segment_to_running_time (&session->segment, GST_FORMAT_TIME, timestamp); more = gst_rdt_buffer_get_first_packet (buffer, &packet); while (more) { GstRDTType type; type = gst_rdt_packet_get_type (&packet); GST_DEBUG_OBJECT (rdtmanager, "Have packet of type %04x", type); if (GST_RDT_IS_DATA_TYPE (type)) { GST_DEBUG_OBJECT (rdtmanager, "We have a data packet"); res = gst_rdt_manager_handle_data_packet (session, timestamp, &packet); } else { switch (type) { default: GST_DEBUG_OBJECT (rdtmanager, "Ignoring packet"); break; } } if (res != GST_FLOW_OK) break; more = gst_rdt_packet_move_to_next (&packet); } gst_buffer_unref (buffer); return res; }
static gboolean read_packet_header (GstRDTPacket * packet) { guint8 *data; guint size; guint offset; guint length; guint length_offset; g_return_val_if_fail (packet != NULL, FALSE); g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); data = GST_BUFFER_DATA (packet->buffer); size = GST_BUFFER_SIZE (packet->buffer); offset = packet->offset; /* check if we are at the end of the buffer, we add 3 because we also want to * ensure we can read the type, which is always at offset 1 and 2 bytes long. */ if (offset + 3 > size) return FALSE; /* read type */ packet->type = GST_READ_UINT16_BE (&data[offset + 1]); length = -1; length_offset = -1; /* figure out the length of the packet, this depends on the type */ if (GST_RDT_IS_DATA_TYPE (packet->type)) { if (data[offset] & 0x80) /* length is present */ length_offset = 3; } else { switch (packet->type) { case GST_RDT_TYPE_ASMACTION: if (data[offset] & 0x80) length_offset = 5; break; case GST_RDT_TYPE_BWREPORT: if (data[offset] & 0x80) length_offset = 3; break; case GST_RDT_TYPE_ACK: if (data[offset] & 0x80) length_offset = 3; break; case GST_RDT_TYPE_RTTREQ: length = 3; break; case GST_RDT_TYPE_RTTRESP: length = 11; break; case GST_RDT_TYPE_CONGESTION: length = 11; break; case GST_RDT_TYPE_STREAMEND: length = 9; /* total_reliable */ if (data[offset] & 0x80) length += 2; /* stream_id_expansion */ if ((data[offset] & 0x7c) == 0x7c) length += 2; /* ext_flag, FIXME, get string length */ if ((data[offset] & 0x1) == 0x1) length += 7; break; case GST_RDT_TYPE_REPORT: if (data[offset] & 0x80) length_offset = 3; break; case GST_RDT_TYPE_LATENCY: if (data[offset] & 0x80) length_offset = 3; break; case GST_RDT_TYPE_INFOREQ: length = 3; /* request_time_ms */ if (data[offset] & 0x2) length += 2; break; case GST_RDT_TYPE_INFORESP: length = 3; /* has_rtt_info */ if (data[offset] & 0x4) { length += 4; /* is_delayed */ if (data[offset] & 0x2) { length += 4; } } if (data[offset] & 0x1) { /* buffer_info_count, FIXME read and skip */ length += 2; } break; case GST_RDT_TYPE_AUTOBW: if (data[offset] & 0x80) length_offset = 3; break; case GST_RDT_TYPE_INVALID: default: goto unknown_packet; } } if (length != -1) { /* we have a fixed length */ packet->length = length; } else if (length_offset != -1) { /* we can read the length from an offset */ packet->length = GST_READ_UINT16_BE (&data[length_offset]); } else { /* length is remainder of packet */ packet->length = size - offset; } /* the length should be smaller than the remaining size */ if (packet->length + offset > size) goto invalid_length; return TRUE; /* ERRORS */ unknown_packet: { packet->type = GST_RDT_TYPE_INVALID; return FALSE; } invalid_length: { packet->type = GST_RDT_TYPE_INVALID; packet->length = 0; return FALSE; } }