void player_put_packet(seq_t seqno, uint8_t *data, int len) { abuf_t *abuf = 0; int16_t buf_fill; pthread_mutex_lock(&ab_mutex); if (!ab_synced) { debug(1, "syncing to first seqno %04X\n", seqno); ab_write = seqno-1; ab_read = seqno; ab_synced = 1; } if (seq_diff(ab_write, seqno) == 1) { // expected packet abuf = audio_buffer + BUFIDX(seqno); ab_write = seqno; } else if (seq_order(ab_write, seqno)) { // newer than expected // Be careful with new packets that are in advance // Those more than a buffer size in advance will cause an Overrun // When buffering the valid threshold should be the buffer fill target itself which should re-sync if (ab_buffering && (seq_diff(ab_read, seqno) > config.buffer_start_fill)) { warn("out of range re-sync %04X (%04X:%04X)", seqno, ab_read, ab_write); ab_resync(); ab_synced = 1; ab_read = seqno; ab_write = seqno; abuf = audio_buffer + BUFIDX(seqno); } else { debug(1, "advance packet %04X (%04X:%04X)\n", seqno, ab_read, ab_write); rtp_request_resend(ab_write+1, seqno-1); abuf = audio_buffer + BUFIDX(seqno); ab_write = seqno; } } else if (seq_order(ab_read, seqno)) { // late but not yet played abuf = audio_buffer + BUFIDX(seqno); if (abuf->ready) { // discard this frame if frame previously received abuf =0; debug(1, "duplicate packet %04X (%04X:%04X)\n", seqno, ab_read, ab_write); } } else { // too late. debug(1, "late packet %04X (%04X:%04X)\n", seqno, ab_read, ab_write); } buf_fill = seq_diff(ab_read, ab_write); pthread_mutex_unlock(&ab_mutex); if (abuf) { alac_decode(abuf->data, data, len); abuf->ready = 1; } pthread_mutex_lock(&ab_mutex); if (ab_buffering && buf_fill >= config.buffer_start_fill) { debug(1, "buffering over. starting play (%04X:%04X)\n", ab_read, ab_write); ab_buffering = 0; } pthread_mutex_unlock(&ab_mutex); }
// get the next frame, when available. return 0 if underrun/stream reset. static short *buffer_get_frame(void) { int16_t buf_fill; seq_t read, next; abuf_t *abuf = 0; int i; if (ab_buffering) return 0; pthread_mutex_lock(&ab_mutex); buf_fill = seq_diff(ab_read, ab_write); if (buf_fill < 1 || !ab_synced) { if (buf_fill < 1) warn("underrun %i (%04X:%04X)", buf_fill, ab_read, ab_write); ab_resync(); pthread_mutex_unlock(&ab_mutex); return 0; } if (buf_fill >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance warn("overrun %i (%04X:%04X)", buf_fill, ab_read, ab_write); read = ab_read; ab_read = ab_write - config.buffer_start_fill; ab_reset((ab_write + 1 - BUFFER_FRAMES), ab_read); // reset any ready frames in those we've skipped (avoiding wrap around) } read = ab_read; ab_read++; buf_fill = seq_diff(ab_read, ab_write); bf_est_update(buf_fill); // check if t+16, t+32, t+64, t+128, ... resend focus boundary // packets have arrived... last-chance resend if (!ab_buffering) { for (i = 16; i <= resend_focus(config.buffer_start_fill); i = (i * 2)) { next = ab_read + i; abuf = audio_buffer + BUFIDX(next); if ((!abuf->ready) && (next < ab_write)){ rtp_request_resend(next, next); debug(1, "last chance resend T+%i, %04X (%04X:%04X)\n", i, next, ab_read, ab_write); } } } abuf_t *curframe = audio_buffer + BUFIDX(read); if (!curframe->ready) { debug(1, "missing frame %04X\n", read); memset(curframe->data, 0, FRAME_BYTES(frame_size)); } curframe->ready = 0; pthread_mutex_unlock(&ab_mutex); return curframe->data; }
// get the next frame, when available. return 0 if underrun/stream reset. static short *buffer_get_frame(void) { int16_t buf_fill; seq_t read, next; abuf_t *abuf = 0; int i; if (ab_buffering) return 0; pthread_mutex_lock(&ab_mutex); buf_fill = seq_diff(ab_read, ab_write); if (buf_fill < 1 || !ab_synced) { if (buf_fill < 1) warn("underrun."); ab_buffering = 1; pthread_mutex_unlock(&ab_mutex); return 0; } if (buf_fill >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance warn("overrun."); ab_read = ab_write - config.buffer_start_fill; } read = ab_read; ab_read++; buf_fill = seq_diff(ab_read, ab_write); bf_est_update(buf_fill); // check if t+16, t+32, t+64, t+128, ... (buffer_start_fill / 2) // packets have arrived... last-chance resend if (!ab_buffering) { for (i = 16; i < (config.buffer_start_fill / 2); i = (i * 2)) { next = ab_read + i; abuf = audio_buffer + BUFIDX(next); if (!abuf->ready) { rtp_request_resend(next, next); } } } abuf_t *curframe = audio_buffer + BUFIDX(read); if (!curframe->ready) { debug(1, "missing frame %04X.", read); memset(curframe->data, 0, FRAME_BYTES(frame_size)); } curframe->ready = 0; pthread_mutex_unlock(&ab_mutex); return curframe->data; }
// reset the audio frames in the range to NOT ready static void ab_reset(seq_t from, seq_t to) { abuf_t *abuf = 0; while (seq_diff(from, to)) { abuf = audio_buffer + BUFIDX(from); abuf->ready = 0; from++; } }
void player_put_packet(seq_t seqno, uint8_t *data, int len) { abuf_t *abuf = 0; int16_t buf_fill; pthread_mutex_lock(&ab_mutex); if (!ab_synced) { debug(2, "syncing to first seqno %04X\n", seqno); ab_write = seqno-1; ab_read = seqno; ab_synced = 1; } if (seq_diff(ab_write, seqno) == 1) { // expected packet abuf = audio_buffer + BUFIDX(seqno); ab_write = seqno; } else if (seq_order(ab_write, seqno)) { // newer than expected rtp_request_resend(ab_write+1, seqno-1); abuf = audio_buffer + BUFIDX(seqno); ab_write = seqno; } else if (seq_order(ab_read, seqno)) { // late but not yet played abuf = audio_buffer + BUFIDX(seqno); } else { // too late. debug(1, "late packet %04X (%04X:%04X)", seqno, ab_read, ab_write); } buf_fill = seq_diff(ab_read, ab_write); pthread_mutex_unlock(&ab_mutex); if (abuf) { alac_decode(abuf->data, data, len); abuf->ready = 1; } pthread_mutex_lock(&ab_mutex); if (ab_buffering && buf_fill >= config.buffer_start_fill) { debug(1, "buffering over. starting play\n"); ab_buffering = 0; bf_est_reset(buf_fill); } pthread_mutex_unlock(&ab_mutex); }
void rtp_request_resend(seq_t first, seq_t last) { if (!running) die("rtp_request_resend called without active stream!"); debug(1, "requesting resend on %d packets (%04X:%04X)\n", seq_diff(first,last) + 1, first, last); char req[8]; // *not* a standard RTCP NACK req[0] = 0x80; req[1] = 0x55|0x80; // Apple 'resend' *(unsigned short *)(req+2) = htons(1); // our seqnum *(unsigned short *)(req+4) = htons(first); // missed seqnum *(unsigned short *)(req+6) = htons(last-first+1); // count sendto(sock, req, sizeof(req), 0, (struct sockaddr*)&rtp_client, sizeof(rtp_client)); }
void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len) { pthread_mutex_lock(&ab_mutex); packet_count++; time_of_last_audio_packet = get_absolute_time_in_fp(); if (connection_state_to_output) { // if we are supposed to be processing these packets if ((flush_rtp_timestamp != 0) && ((timestamp == flush_rtp_timestamp) || seq32_order(timestamp, flush_rtp_timestamp))) { debug(2, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to " "timestamp: %u.", seqno, timestamp, flush_rtp_timestamp); } else { if ((flush_rtp_timestamp != 0x0) && (!seq32_order(timestamp, flush_rtp_timestamp))) // if we have gone past the flush boundary time flush_rtp_timestamp = 0x0; abuf_t *abuf = 0; if (!ab_synced) { debug(2, "syncing to seqno %u.", seqno); ab_write = seqno; ab_read = seqno; ab_synced = 1; } if (ab_write == seqno) { // expected packet abuf = audio_buffer + BUFIDX(seqno); ab_write = SUCCESSOR(seqno); } else if (seq_order(ab_write, seqno)) { // newer than expected // if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8) // debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno: // %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno); int32_t gap = seq_diff(ab_write, PREDECESSOR(seqno)) + 1; if (gap <= 0) debug(1, "Unexpected gap size: %d.", gap); int i; for (i = 0; i < gap; i++) { abuf = audio_buffer + BUFIDX(seq_sum(ab_write, i)); abuf->ready = 0; // to be sure, to be sure abuf->timestamp = 0; abuf->sequence_number = 0; } // debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write); abuf = audio_buffer + BUFIDX(seqno); rtp_request_resend(ab_write, gap); resend_requests++; ab_write = SUCCESSOR(seqno); } else if (seq_order(ab_read, seqno)) { // late but not yet played late_packets++; abuf = audio_buffer + BUFIDX(seqno); } else { // too late. too_late_packets++; /* if (!late_packet_message_sent) { debug(1, "too-late packet received: %u; ab_read: %u; ab_write: %u.", seqno, ab_read, ab_write); late_packet_message_sent=1; } */ } // pthread_mutex_unlock(&ab_mutex); if (abuf) { alac_decode(abuf->data, data, len); abuf->ready = 1; abuf->timestamp = timestamp; abuf->sequence_number = seqno; } // pthread_mutex_lock(&ab_mutex); } int rc = pthread_cond_signal(&flowcontrol); if (rc) debug(1, "Error signalling flowcontrol."); } pthread_mutex_unlock(&ab_mutex); }
int srtp_decrypt(struct srtp *srtp, struct mbuf *mb) { struct srtp_stream *strm; struct rtp_header hdr; struct comp *comp; uint64_t ix; size_t start; int diff; int err; if (!srtp || !mb) return EINVAL; comp = &srtp->rtp; start = mb->pos; err = rtp_hdr_decode(&hdr, mb); if (err) return err; err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq); if (err) return err; diff = seq_diff(strm->s_l, hdr.seq); if (diff > 32768) return ETIMEDOUT; /* Roll-Over Counter (ROC) */ if (diff <= -32768) { strm->roc++; strm->s_l = 0; } ix = srtp_get_index(strm->roc, strm->s_l, hdr.seq); if (comp->hmac) { uint8_t tag_calc[SHA_DIGEST_LENGTH]; uint8_t tag_pkt[SHA_DIGEST_LENGTH]; size_t pld_start, tag_start; if (mbuf_get_left(mb) < comp->tag_len) return EBADMSG; pld_start = mb->pos; tag_start = mb->end - comp->tag_len; mb->pos = tag_start; err = mbuf_read_mem(mb, tag_pkt, comp->tag_len); if (err) return err; mb->pos = mb->end = tag_start; err = mbuf_write_u32(mb, htonl(strm->roc)); if (err) return err; mb->pos = start; err = hmac_digest(comp->hmac, tag_calc, sizeof(tag_calc), mbuf_buf(mb), mbuf_get_left(mb)); if (err) return err; mb->pos = pld_start; mb->end = tag_start; if (0 != memcmp(tag_calc, tag_pkt, comp->tag_len)) return EAUTH; /* * 3.3.2. Replay Protection * * Secure replay protection is only possible when * integrity protection is present. */ if (!srtp_replay_check(&strm->replay_rtp, ix)) return EALREADY; } if (comp->aes) { union vect128 iv; uint8_t *p = mbuf_buf(mb); srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix); aes_set_iv(comp->aes, iv.u8); err = aes_decr(comp->aes, p, p, mbuf_get_left(mb)); if (err) return err; } if (hdr.seq > strm->s_l) strm->s_l = hdr.seq; mb->pos = start; return 0; }
int srtp_encrypt(struct srtp *srtp, struct mbuf *mb) { struct srtp_stream *strm; struct rtp_header hdr; struct comp *comp; size_t start; uint64_t ix; int err; if (!srtp || !mb) return EINVAL; comp = &srtp->rtp; start = mb->pos; err = rtp_hdr_decode(&hdr, mb); if (err) return err; err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq); if (err) return err; /* Roll-Over Counter (ROC) */ if (seq_diff(strm->s_l, hdr.seq) <= -32768) { strm->roc++; strm->s_l = 0; } ix = 65536ULL * strm->roc + hdr.seq; if (comp->aes) { union vect128 iv; uint8_t *p = mbuf_buf(mb); srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix); aes_set_iv(comp->aes, iv.u8); err = aes_encr(comp->aes, p, p, mbuf_get_left(mb)); if (err) return err; } if (comp->hmac) { const size_t tag_start = mb->end; uint8_t tag[SHA_DIGEST_LENGTH]; mb->pos = tag_start; err = mbuf_write_u32(mb, htonl(strm->roc)); if (err) return err; mb->pos = start; err = hmac_digest(comp->hmac, tag, sizeof(tag), mbuf_buf(mb), mbuf_get_left(mb)); if (err) return err; mb->pos = mb->end = tag_start; err = mbuf_write_mem(mb, tag, comp->tag_len); if (err) return err; } if (hdr.seq > strm->s_l) strm->s_l = hdr.seq; mb->pos = start; return 0; }
int h265_decode(struct viddec_state *vds, struct vidframe *frame, bool marker, uint16_t seq, struct mbuf *mb) { static const uint8_t nal_seq[3] = {0, 0, 1}; int err, ret, got_picture, i; struct h265_nal hdr; AVPacket avpkt; enum vidfmt fmt; if (!vds || !frame || !mb) return EINVAL; err = h265_nal_decode(&hdr, mbuf_buf(mb)); if (err) return err; mbuf_advance(mb, H265_HDR_SIZE); #if 1 debug("h265: decode: %s type=%2d %s\n", h265_is_keyframe(hdr.nal_unit_type) ? "<KEY>" : " ", hdr.nal_unit_type, h265_nalunit_name(hdr.nal_unit_type)); #endif if (vds->frag && hdr.nal_unit_type != H265_NAL_FU) { debug("h265: lost fragments; discarding previous NAL\n"); fragment_rewind(vds); vds->frag = false; } /* handle NAL types */ if (0 <= hdr.nal_unit_type && hdr.nal_unit_type <= 40) { mb->pos -= H265_HDR_SIZE; err = mbuf_write_mem(vds->mb, nal_seq, 3); err |= mbuf_write_mem(vds->mb, mbuf_buf(mb),mbuf_get_left(mb)); if (err) goto out; } else if (H265_NAL_FU == hdr.nal_unit_type) { struct fu fu; err = fu_decode(&fu, mb); if (err) return err; if (fu.s) { if (vds->frag) { debug("h265: lost fragments; ignoring NAL\n"); fragment_rewind(vds); } vds->frag_start = vds->mb->pos; vds->frag = true; hdr.nal_unit_type = fu.type; err = mbuf_write_mem(vds->mb, nal_seq, 3); err = h265_nal_encode_mbuf(vds->mb, &hdr); if (err) goto out; } else { if (!vds->frag) { debug("h265: ignoring fragment\n"); return 0; } if (seq_diff(vds->frag_seq, seq) != 1) { debug("h265: lost fragments detected\n"); fragment_rewind(vds); vds->frag = false; return 0; } } err = mbuf_write_mem(vds->mb, mbuf_buf(mb), mbuf_get_left(mb)); if (err) goto out; if (fu.e) vds->frag = false; vds->frag_seq = seq; } else { warning("h265: unknown NAL type %u\n", hdr.nal_unit_type); return ENOSYS; } if (!marker) { if (vds->mb->end > DECODE_MAXSZ) { warning("h265: decode buffer size exceeded\n"); err = ENOMEM; goto out; } return 0; } if (vds->frag) { err = EPROTO; goto out; } av_init_packet(&avpkt); avpkt.data = vds->mb->buf; avpkt.size = (int)vds->mb->end; ret = avcodec_decode_video2(vds->ctx, vds->pict, &got_picture, &avpkt); if (ret < 0) { debug("h265: decode error\n"); err = EPROTO; goto out; } if (!got_picture) { /* debug("h265: no picture\n"); */ goto out; } switch (vds->pict->format) { case PIX_FMT_YUV420P: fmt = VID_FMT_YUV420P; break; #if 0 case PIX_FMT_YUV444P: fmt = VID_FMT_YUV444; break; #endif default: warning("h265: decode: bad pixel format (%i) (%s)\n", vds->pict->format, av_get_pix_fmt_name(vds->pict->format)); goto out; } for (i=0; i<4; i++) { frame->data[i] = vds->pict->data[i]; frame->linesize[i] = vds->pict->linesize[i]; } frame->size.w = vds->ctx->width; frame->size.h = vds->ctx->height; frame->fmt = fmt; out: mbuf_rewind(vds->mb); vds->frag = false; return err; }