static int parse_attribute_ssrc(struct sdp_attribute *output) { PARSE_DECL; struct attribute_ssrc *s; output->attr = ATTR_SSRC; PARSE_INIT; EXTRACT_TOKEN(u.ssrc.id_str); EXTRACT_TOKEN(u.ssrc.attr_str); s = &output->u.ssrc; s->id = strtoul(s->id_str.s, NULL, 10); if (!s->id) return -1; s->attr = s->attr_str; str_chr_str(&s->value, &s->attr, ':'); if (s->value.s) { s->attr.len = s->value.s - s->attr.s; str_shift(&s->value, 1); } return 0; }
char *read_from_stdin(){ char c; char *cc; //char first_str[s_size+1]; char *str; int j; str = malloc((s_size+1)*sizeof(char)); j = 0; while(scanf("%c",&c)){ if((c != '\n')&&(c != ' ')){ if(j == s_size){ *(str+j) = '\0'; break; }else{ *(str+j) = c; j++; } } } printf("%s",str); while(scanf("%c",&c) != EOF){ if((c != '\n')&&(c != ' ')){ cc[0] = c; cc[1] = '\0'; str = str_shift(cc,str,s_size,g_size); } } return(str); }
INLINE void ng_sdes_option(struct sdp_ng_flags *out, bencode_item_t *it, unsigned int strip) { str s; if (!bencode_get_str(it, &s)) return; str_shift(&s, strip); if (!str_cmp(&s, "no") || !str_cmp(&s, "off") || !str_cmp(&s, "disabled") || !str_cmp(&s, "disable")) out->sdes_off = 1; else if (!str_cmp(&s, "unencrypted_srtp") || !str_cmp(&s, "UNENCRYPTED_SRTP")) out->sdes_unencrypted_srtp = 1; else if (!str_cmp(&s, "unencrypted_srtcp") || !str_cmp(&s, "UNENCRYPTED_SRTCP")) out->sdes_unencrypted_srtcp = 1; else if (!str_cmp(&s, "unauthenticated_srtp") || !str_cmp(&s, "UNAUTHENTICATED_SRTP")) out->sdes_unauthenticated_srtp = 1; else if (!str_cmp(&s, "encrypted_srtp") || !str_cmp(&s, "ENCRYPTED_SRTP")) out->sdes_encrypted_srtp = 1; else if (!str_cmp(&s, "encrypted_srtcp") || !str_cmp(&s, "ENCRYPTED_SRTCP")) out->sdes_encrypted_srtcp = 1; else if (!str_cmp(&s, "authenticated_srtp") || !str_cmp(&s, "AUTHENTICATED_SRTP")) out->sdes_authenticated_srtp = 1; else ilog(LOG_WARN, "Unknown 'SDES' flag encountered: '"STR_FORMAT"'", STR_FMT(&s)); }
int rtp_payload(struct rtp_header **out, str *p, const str *s) { struct rtp_header *rtp; struct rtp_extension *ext; const char *err; err = "short packet (header)"; if (s->len < sizeof(*rtp)) goto error; rtp = (void *) s->s; err = "invalid header version"; if ((rtp->v_p_x_cc & 0xc0) != 0x80) /* version 2 */ goto error; if (!p) goto done; *p = *s; /* fixed header */ str_shift(p, sizeof(*rtp)); /* csrc list */ err = "short packet (CSRC list)"; if (str_shift(p, (rtp->v_p_x_cc & 0xf) * 4)) goto error; if ((rtp->v_p_x_cc & 0x10)) { /* extension */ err = "short packet (extension header)"; if (p->len < sizeof(*ext)) goto error; ext = (void *) p->s; err = "short packet (header extensions)"; if (str_shift(p, 4 + ntohs(ext->length) * 4)) goto error; } done: *out = rtp; return 0; error: ilog(LOG_DEBUG | LOG_FLAG_LIMIT, "Error parsing RTP header: %s", err); return -1; }
static int64_t __mp_avio_seek_set(struct media_player *mp, int64_t offset) { ilog(LOG_DEBUG, "__mp_avio_seek_set(%" PRIi64 ")", offset); if (offset < 0) return AVERROR(EINVAL); mp->read_pos = *mp->blob; if (str_shift(&mp->read_pos, offset)) return AVERROR_EOF; return offset; }
static int parse_attribute_rtpmap(struct sdp_attribute *output) { PARSE_DECL; char *ep; struct attribute_rtpmap *a; struct rtp_payload_type *pt; output->attr = ATTR_RTPMAP; PARSE_INIT; EXTRACT_TOKEN(u.rtpmap.payload_type_str); EXTRACT_TOKEN(u.rtpmap.encoding_str); a = &output->u.rtpmap; pt = &a->rtp_pt; pt->payload_type = strtoul(a->payload_type_str.s, &ep, 10); if (ep == a->payload_type_str.s) return -1; str_chr_str(&a->clock_rate_str, &a->encoding_str, '/'); if (!a->clock_rate_str.s) return -1; pt->encoding = a->encoding_str; pt->encoding.len -= a->clock_rate_str.len; str_shift(&a->clock_rate_str, 1); str_chr_str(&pt->encoding_parameters, &a->clock_rate_str, '/'); if (pt->encoding_parameters.s) { a->clock_rate_str.len -= pt->encoding_parameters.len; str_shift(&pt->encoding_parameters, 1); } if (!a->clock_rate_str.len) return -1; pt->clock_rate = strtoul(a->clock_rate_str.s, &ep, 10); if (ep && ep != a->clock_rate_str.s + a->clock_rate_str.len) return -1; return 0; }
INLINE void str_hyphenate(bencode_item_t *it) { str s; if (!bencode_get_str(it, &s)) return; while (s.len) { str_chr_str(&s, &s, ' '); if (!s.s || !s.len) break; *s.s = '-'; str_shift(&s, 1); } }
static int __ensure_codec_handler(struct media_player *mp, AVStream *avs) { if (mp->handler) return 0; // synthesise rtp payload type struct rtp_payload_type src_pt = { .payload_type = -1 }; // src_pt.codec_def = codec_find_by_av(avs->codec->codec_id); `codec` is deprecated src_pt.codec_def = codec_find_by_av(avs->CODECPAR->codec_id); if (!src_pt.codec_def) { ilog(LOG_ERR, "Attempting to play media from an unsupported file format/codec"); return -1; } src_pt.encoding = src_pt.codec_def->rtpname_str; src_pt.channels = avs->CODECPAR->channels; src_pt.clock_rate = avs->CODECPAR->sample_rate; codec_init_payload_type(&src_pt, mp->media); // find suitable output payload type struct rtp_payload_type *dst_pt; for (GList *l = mp->media->codecs_prefs_send.head; l; l = l->next) { dst_pt = l->data; if (dst_pt->codec_def && !dst_pt->codec_def->supplemental) goto found; } dst_pt = NULL; found: if (!dst_pt) { ilog(LOG_ERR, "No supported output codec found in SDP"); return -1; } ilog(LOG_DEBUG, "Output codec for media playback is " STR_FORMAT, STR_FMT(&dst_pt->encoding_with_params)); // if we played anything before, scale our sync TS according to the time // that has passed if (mp->sync_ts_tv.tv_sec) { long long ts_diff_us = timeval_diff(&rtpe_now, &mp->sync_ts_tv); mp->sync_ts += ts_diff_us * dst_pt->clock_rate / 1000000 / dst_pt->codec_def->clockrate_mult; } mp->handler = codec_handler_make_playback(&src_pt, dst_pt, mp->sync_ts); if (!mp->handler) return -1; mp->duration = avs->duration * 1000 * avs->time_base.num / avs->time_base.den; return 0; } // appropriate lock must be held static void media_player_read_packet(struct media_player *mp) { if (!mp->fmtctx) return; int ret = av_read_frame(mp->fmtctx, &mp->pkt); if (ret < 0) { if (ret == AVERROR_EOF) { ilog(LOG_DEBUG, "EOF reading from media stream"); return; } ilog(LOG_ERR, "Error while reading from media stream"); return; } if (!mp->fmtctx->streams) { ilog(LOG_ERR, "No AVStream present in format context"); goto out; } AVStream *avs = mp->fmtctx->streams[0]; if (!avs) { ilog(LOG_ERR, "No AVStream present in format context"); goto out; } if (__ensure_codec_handler(mp, avs)) goto out; // scale pts and duration according to sample rate long long duration_scaled = mp->pkt.duration * avs->CODECPAR->sample_rate * avs->time_base.num / avs->time_base.den; unsigned long long pts_scaled = mp->pkt.pts * avs->CODECPAR->sample_rate * avs->time_base.num / avs->time_base.den; long long us_dur = mp->pkt.duration * 1000000LL * avs->time_base.num / avs->time_base.den; ilog(LOG_DEBUG, "read media packet: pts %llu duration %lli (scaled %llu/%lli, %lli us), " "sample rate %i, time_base %i/%i", (unsigned long long) mp->pkt.pts, (long long) mp->pkt.duration, pts_scaled, duration_scaled, us_dur, avs->CODECPAR->sample_rate, avs->time_base.num, avs->time_base.den); // synthesise fake RTP header and media_packet context struct rtp_header rtp = { .timestamp = pts_scaled, // taken verbatim by handler_func_playback w/o byte swap .seq_num = htons(mp->seq), }; struct media_packet packet = { .tv = rtpe_now, .call = mp->call, .media = mp->media, .rtp = &rtp, .ssrc_out = mp->ssrc_out, }; str_init_len(&packet.raw, (char *) mp->pkt.data, mp->pkt.size); packet.payload = packet.raw; mp->handler->func(mp->handler, &packet); // as this is timing sensitive and we may have spent some time decoding, // update our global "now" timestamp gettimeofday(&rtpe_now, NULL); // keep track of RTP timestamps and real clock. look at the last packet we received // and update our sync TS. if (packet.packets_out.head) { struct codec_packet *p = packet.packets_out.head->data; if (p->rtp) { mp->sync_ts = ntohl(p->rtp->timestamp); mp->sync_ts_tv = p->to_send; } } media_packet_encrypt(mp->crypt_handler->out->rtp_crypt, mp->sink, &packet); mutex_lock(&mp->sink->out_lock); if (media_socket_dequeue(&packet, mp->sink)) ilog(LOG_ERR, "Error sending playback media to RTP sink"); mutex_unlock(&mp->sink->out_lock); timeval_add_usec(&mp->next_run, us_dur); timerthread_obj_schedule_abs(&mp->tt_obj, &mp->next_run); out: av_packet_unref(&mp->pkt); } // call->master_lock held in W static int media_player_play_init(struct media_player *mp) { media_player_shutdown(mp); // find call media suitable for playback struct call_media *media; for (GList *l = mp->ml->medias.head; l; l = l->next) { media = l->data; if (media->type_id != MT_AUDIO) continue; if (!MEDIA_ISSET(media, SEND)) continue; if (media->streams.length == 0) continue; goto found; } media = NULL; found: if (!media) { ilog(LOG_ERR, "No suitable SDP section for media playback"); return -1; } mp->media = media; mp->sink = media->streams.head->data; mp->crypt_handler = determine_handler(&transport_protocols[PROTO_RTP_AVP], media, 1); return 0; } // call->master_lock held in W static void media_player_play_start(struct media_player *mp) { // needed to have usable duration for some formats. ignore errors. avformat_find_stream_info(mp->fmtctx, NULL); mp->next_run = rtpe_now; // give ourselves a bit of a head start with decoding timeval_add_usec(&mp->next_run, -50000); media_player_read_packet(mp); } #endif // call->master_lock held in W int media_player_play_file(struct media_player *mp, const str *file) { #ifdef WITH_TRANSCODING if (media_player_play_init(mp)) return -1; char file_s[PATH_MAX]; snprintf(file_s, sizeof(file_s), STR_FORMAT, STR_FMT(file)); int ret = avformat_open_input(&mp->fmtctx, file_s, NULL, NULL); if (ret < 0) { ilog(LOG_ERR, "Failed to open media file for playback: %s", av_error(ret)); return -1; } media_player_play_start(mp); return 0; #else return -1; #endif } #ifdef WITH_TRANSCODING static int __mp_avio_read_wrap(void *opaque, uint8_t *buf, int buf_size) { struct media_player *mp = opaque; if (buf_size < 0) return AVERROR(EINVAL); if (buf_size == 0) return 0; if (!mp->read_pos.len) return AVERROR_EOF; int len = buf_size; if (len > mp->read_pos.len) len = mp->read_pos.len; memcpy(buf, mp->read_pos.s, len); str_shift(&mp->read_pos, len); return len; } static int __mp_avio_read(void *opaque, uint8_t *buf, int buf_size) { ilog(LOG_DEBUG, "__mp_avio_read(%i)", buf_size); int ret = __mp_avio_read_wrap(opaque, buf, buf_size); ilog(LOG_DEBUG, "__mp_avio_read(%i) = %i", buf_size, ret); return ret; }
static int parse_attribute_crypto(struct sdp_attribute *output) { PARSE_DECL; char *endp; struct attribute_crypto *c; int salt_key_len, enc_salt_key_len; int b64_state = 0; unsigned int b64_save = 0; gsize ret; str s; u_int32_t u32; const char *err; output->attr = ATTR_CRYPTO; PARSE_INIT; EXTRACT_TOKEN(u.crypto.tag_str); EXTRACT_TOKEN(u.crypto.crypto_suite_str); EXTRACT_TOKEN(u.crypto.key_params_str); c = &output->u.crypto; c->tag = strtoul(c->tag_str.s, &endp, 10); err = "invalid 'tag'"; if (endp == c->tag_str.s) goto error; c->crypto_suite = crypto_find_suite(&c->crypto_suite_str); err = "unknown crypto suite"; if (!c->crypto_suite) goto error; salt_key_len = c->crypto_suite->master_key_len + c->crypto_suite->master_salt_len; enc_salt_key_len = ceil((double) salt_key_len * 4.0/3.0); err = "invalid key parameter length"; if (c->key_params_str.len < 7 + enc_salt_key_len) goto error; err = "unknown key method"; if (strncasecmp(c->key_params_str.s, "inline:", 7)) goto error; c->key_base64_str = c->key_params_str; str_shift(&c->key_base64_str, 7); ret = g_base64_decode_step(c->key_base64_str.s, enc_salt_key_len, (guchar *) c->key_salt_buf, &b64_state, &b64_save); err = "invalid base64 encoding"; if (ret != salt_key_len) goto error; c->master_key.s = c->key_salt_buf; c->master_key.len = c->crypto_suite->master_key_len; c->salt.s = c->master_key.s + c->master_key.len; c->salt.len = c->crypto_suite->master_salt_len; c->lifetime_str = c->key_params_str; str_shift(&c->lifetime_str, 7 + enc_salt_key_len); if (c->lifetime_str.len >= 2) { err = "invalid key parameter syntax"; if (c->lifetime_str.s[0] != '|') goto error; str_shift(&c->lifetime_str, 1); str_chr_str(&c->mki_str, &c->lifetime_str, '|'); if (!c->mki_str.s) { if (str_chr(&c->lifetime_str, ':')) { c->mki_str = c->lifetime_str; c->lifetime_str = STR_NULL; } } else { c->lifetime_str.len = c->mki_str.s - c->lifetime_str.s; str_shift(&c->mki_str, 1); } } else c->lifetime_str = STR_NULL; if (c->lifetime_str.s) { if (c->lifetime_str.len >= 3 && !memcmp(c->lifetime_str.s, "2^", 2)) { c->lifetime = strtoull(c->lifetime_str.s + 2, NULL, 10); err = "invalid key lifetime"; if (!c->lifetime || c->lifetime > 64) goto error; c->lifetime = 1ULL << c->lifetime; } else c->lifetime = strtoull(c->lifetime_str.s, NULL, 10); err = "invalid key lifetime"; if (!c->lifetime || c->lifetime > c->crypto_suite->srtp_lifetime #ifdef STRICT_SDES_KEY_LIFETIME || c->lifetime > c->crypto_suite->srtcp_lifetime #endif ) goto error; } if (c->mki_str.s) { str_chr_str(&s, &c->mki_str, ':'); err = "invalid MKI specification"; if (!s.s) goto error; u32 = htonl(strtoul(c->mki_str.s, NULL, 10)); c->mki_len = strtoul(s.s + 1, NULL, 10); err = "MKI too long"; if (c->mki_len > sizeof(c->mki)) goto error; memset(c->mki, 0, c->mki_len); if (sizeof(u32) >= c->mki_len) memcpy(c->mki, ((void *) &u32) + (sizeof(u32) - c->mki_len), c->mki_len); else memcpy(c->mki + (c->mki_len - sizeof(u32)), &u32, sizeof(u32)); } while (extract_token(&start, end, &s) == 0) { if (!str_cmp(&s, "UNENCRYPTED_SRTCP")) c->unencrypted_srtcp = 1; else if (!str_cmp(&s, "UNENCRYPTED_SRTP")) c->unencrypted_srtp = 1; else if (!str_cmp(&s, "UNAUTHENTICATED_SRTP")) c->unauthenticated_srtp = 1; } return 0; error: ilog(LOG_ERROR, "Failed to parse a=crypto attribute: %s", err); return -1; }