static int demux_rtp_control(struct demuxer *demuxer, int cmd, void *arg) { Nemesi_DemuxerStreamData * ndsd = demuxer->priv; rtsp_ctrl * ctl = ndsd->rtsp; sdp_attr * r_attr = NULL; sdp_range r = {0, 0}; double time = ndsd->time[NEMESI_SESSION_VIDEO] ? ndsd->time[NEMESI_SESSION_VIDEO] : ndsd->time[NEMESI_SESSION_AUDIO]; if (!ctl->rtsp_queue) return DEMUXER_CTRL_DONTKNOW; r_attr = sdp_get_attr(ctl->rtsp_queue->info->attr_list, "range"); if (r_attr) r = sdp_parse_range(r_attr->value); switch (cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: if (r.end == 0) return DEMUXER_CTRL_DONTKNOW; *((double *)arg) = ((double)r.end) - ((double)r.begin); return DEMUXER_CTRL_OK; case DEMUXER_CTRL_GET_PERCENT_POS: if (r.end == 0) return DEMUXER_CTRL_DONTKNOW; *((int *)arg) = (int)( time * 100 / (r.end - r.begin) ); return DEMUXER_CTRL_OK; default: return DEMUXER_CTRL_DONTKNOW; } }
/* * Configure PnP Information results */ static int config_pnp(prop_dictionary_t dict, sdp_data_t *rec) { sdp_data_t value; uintmax_t v; uint16_t attr; int vendor, product, source; vendor = -1; product = -1; source = -1; while (sdp_get_attr(rec, &attr, &value)) { switch (attr) { case 0x0201: /* Vendor ID */ if (sdp_get_uint(&value, &v) && v <= UINT16_MAX) vendor = (int)v; break; case 0x0202: /* Product ID */ if (sdp_get_uint(&value, &v) && v <= UINT16_MAX) product = (int)v; break; case 0x0205: /* Vendor ID Source */ if (sdp_get_uint(&value, &v) && v <= UINT16_MAX) source = (int)v; break; default: break; } } if (vendor == -1 || product == -1) return ENOATTR; if (source != 0x0002) /* "USB Implementers Forum" */ return ENOATTR; if (!prop_dictionary_set_uint16(dict, BTDEVvendor, (uint16_t)vendor)) return errno; if (!prop_dictionary_set_uint16(dict, BTDEVproduct, (uint16_t)product)) return errno; return 0; }
static void demux_seek_rtp(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) { Nemesi_DemuxerStreamData * ndsd = demuxer->priv; rtsp_ctrl * ctl = ndsd->rtsp; sdp_attr * r_attr = NULL; sdp_range r = {0, 0}; double time = ndsd->time[NEMESI_SESSION_VIDEO] ? ndsd->time[NEMESI_SESSION_VIDEO] : ndsd->time[NEMESI_SESSION_AUDIO]; if (!ctl->rtsp_queue) return; r_attr = sdp_get_attr(ctl->rtsp_queue->info->attr_list, "range"); if (r_attr) r = sdp_parse_range(r_attr->value); //flags & 1 -> absolute seek //flags & 2 -> percent seek if (flags == 0) { time += rel_seek_secs; if (time < r.begin) time = r.begin; else if (time > r.end) time = r.end; ndsd->seek = time; mp_msg(MSGT_DEMUX,MSGL_WARN,"libNemesi SEEK %f on %f - %f)\n", time, r.begin, r.end); if (!rtsp_seek(ctl, time, 0)) { RTSP_Error err = rtsp_wait(ctl); if (err.got_error) { mp_msg(MSGT_DEMUX, MSGL_ERR, "Error Performing Seek: %s\n", err.message.reply_str); demuxer->stream->eof = 1; } else mp_msg(MSGT_DEMUX, MSGL_INFO, "Seek, performed\n"); } else { mp_msg(MSGT_DEMUX, MSGL_ERR, "Unable to pause stream to perform seek\n"); demuxer->stream->eof = 1; } } else mp_msg(MSGT_DEMUX, MSGL_ERR, "Unsupported seek type\n"); }
ATF_TC_BODY(check_sdp_get_attr, tc) { uint8_t data[] = { 0x09, 0x00, 0x00, // uint16 0x0000 0x35, 0x05, // seq8(5) 0x19, 0x00, 0x00, // uuid16 0x0000 0x08, 0x00, // uint8 0x00 0x08, 0x00, // uint8 0x00 0x09, 0x00, 0x01, // uint16 0x0001 0x19, 0x12, 0x34, // uuid16 0x1234 }; sdp_data_t test = { data, data + sizeof(data) }; sdp_data_t value; uint16_t attr; /* * sdp_get_attr expects a UINT16 followed by any data item * and advances test if successful */ ATF_REQUIRE(sdp_get_attr(&test, &attr, &value)); ATF_CHECK_EQ(attr, 0x0000); ATF_CHECK_EQ(sdp_data_type(&value), SDP_DATA_SEQ8); ATF_CHECK_EQ(sdp_data_size(&value), 7); ATF_REQUIRE_EQ(sdp_get_attr(&test, &attr, &value), false); ATF_REQUIRE(sdp_get_data(&test, &value)); ATF_CHECK_EQ(sdp_data_type(&value), SDP_DATA_UINT8); ATF_CHECK_EQ(sdp_data_size(&value), 2); ATF_REQUIRE(sdp_get_attr(&test, &attr, &value)); ATF_CHECK_EQ(attr, 0x0001); ATF_CHECK_EQ(sdp_data_type(&value), SDP_DATA_UUID16); ATF_CHECK_EQ(sdp_data_size(&value), 3); ATF_CHECK_EQ(test.next, test.end); }
/* * Configure HF results */ static int config_hf(prop_dictionary_t dict, sdp_data_t *rec) { prop_object_t obj; sdp_data_t value; int32_t channel; uint16_t attr; channel = -1; while (sdp_get_attr(rec, &attr, &value)) { switch (attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: channel = parse_pdl(&value, SDP_UUID_PROTOCOL_RFCOMM); break; default: break; } } if (channel == -1) return ENOATTR; obj = prop_string_create_cstring_nocopy("btsco"); if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj)) return errno; prop_object_release(obj); obj = prop_bool_create(true); if (obj == NULL || !prop_dictionary_set(dict, BTSCOlisten, obj)) return errno; prop_object_release(obj); obj = prop_number_create_integer(channel); if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj)) return errno; prop_object_release(obj); return 0; }
/* * Configure HID results */ static int config_hid(prop_dictionary_t dict, sdp_data_t *rec) { prop_object_t obj; int32_t control_psm, interrupt_psm, reconnect_initiate, hid_length; uint8_t *hid_descriptor; sdp_data_t value; const char *mode; uint16_t attr; control_psm = -1; interrupt_psm = -1; reconnect_initiate = -1; hid_descriptor = NULL; hid_length = -1; while (sdp_get_attr(rec, &attr, &value)) { switch (attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: control_psm = parse_pdl(&value, SDP_UUID_PROTOCOL_L2CAP); break; case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: interrupt_psm = parse_apdl(&value, SDP_UUID_PROTOCOL_L2CAP); break; case 0x0205: /* HIDReconnectInitiate */ reconnect_initiate = parse_boolean(&value); break; case 0x0206: /* HIDDescriptorList */ if (parse_hid_descriptor(&value)) { hid_descriptor = value.next; hid_length = value.end - value.next; } break; default: break; } } if (control_psm == -1 || interrupt_psm == -1 || reconnect_initiate == -1 || hid_descriptor == NULL || hid_length == -1) return ENOATTR; obj = prop_string_create_cstring_nocopy("bthidev"); if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj)) return errno; prop_object_release(obj); obj = prop_number_create_integer(control_psm); if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVcontrolpsm, obj)) return errno; prop_object_release(obj); obj = prop_number_create_integer(interrupt_psm); if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVinterruptpsm, obj)) return errno; prop_object_release(obj); obj = prop_data_create_data(hid_descriptor, hid_length); if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVdescriptor, obj)) return errno; mode = hid_mode(obj); prop_object_release(obj); obj = prop_string_create_cstring_nocopy(mode); if (obj == NULL || !prop_dictionary_set(dict, BTDEVmode, obj)) return errno; prop_object_release(obj); if (!reconnect_initiate) { obj = prop_bool_create(true); if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVreconnect, obj)) return errno; prop_object_release(obj); } return 0; }