summaryrefslogtreecommitdiffstats
path: root/media/cast/sender/frame_sender.h
blob: 8128c99c4939bdebb0ae322ba3c64c752697a726 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This is the base class for an object that send frames to a receiver.
// TODO(hclam): Refactor such that there is no separate AudioSender vs.
// VideoSender, and the functionality of both is rolled into this class.

#ifndef MEDIA_CAST_SENDER_FRAME_SENDER_H_
#define MEDIA_CAST_SENDER_FRAME_SENDER_H_

#include <stdint.h>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_sender.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
#include "media/cast/sender/congestion_control.h"

namespace media {
namespace cast {

struct SenderEncodedFrame;

class FrameSender {
 public:
  FrameSender(scoped_refptr<CastEnvironment> cast_environment,
              bool is_audio,
              CastTransportSender* const transport_sender,
              int rtp_timebase,
              uint32_t ssrc,
              double max_frame_rate,
              base::TimeDelta min_playout_delay,
              base::TimeDelta max_playout_delay,
              base::TimeDelta animated_playout_delay,
              CongestionControl* congestion_control);
  virtual ~FrameSender();

  int rtp_timebase() const { return rtp_timebase_; }

  // Calling this function is only valid if the receiver supports the
  // "extra_playout_delay", rtp extension.
  void SetTargetPlayoutDelay(base::TimeDelta new_target_playout_delay);

  base::TimeDelta GetTargetPlayoutDelay() const {
    return target_playout_delay_;
  }

  // Called by the encoder with the next EncodeFrame to send.
  void SendEncodedFrame(int requested_bitrate_before_encode,
                        scoped_ptr<SenderEncodedFrame> encoded_frame);

 protected:
  // Returns the number of frames in the encoder's backlog.
  virtual int GetNumberOfFramesInEncoder() const = 0;

  // Returns the duration of the data in the encoder's backlog plus the duration
  // of sent, unacknowledged frames.
  virtual base::TimeDelta GetInFlightMediaDuration() const = 0;

 protected:
  // Schedule and execute periodic sending of RTCP report.
  void ScheduleNextRtcpReport();
  void SendRtcpReport(bool schedule_future_reports);

  void OnMeasuredRoundTripTime(base::TimeDelta rtt);

  const scoped_refptr<CastEnvironment> cast_environment_;

  // Sends encoded frames over the configured transport (e.g., UDP).  In
  // Chromium, this could be a proxy that first sends the frames from a renderer
  // process to the browser process over IPC, with the browser process being
  // responsible for "packetizing" the frames and pushing packets into the
  // network layer.
  CastTransportSender* const transport_sender_;

  const uint32_t ssrc_;

 protected:
  // Schedule and execute periodic checks for re-sending packets.  If no
  // acknowledgements have been received for "too long," AudioSender will
  // speculatively re-send certain packets of an unacked frame to kick-start
  // re-transmission.  This is a last resort tactic to prevent the session from
  // getting stuck after a long outage.
  void ScheduleNextResendCheck();
  void ResendCheck();
  void ResendForKickstart();

  // Protected for testability.
  void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback);

  // Returns true if too many frames would be in-flight by encoding and sending
  // the next frame having the given |frame_duration|.
  bool ShouldDropNextFrame(base::TimeDelta frame_duration) const;

  // Record or retrieve a recent history of each frame's timestamps.
  // Warning: If a frame ID too far in the past is requested, the getters will
  // silently succeed but return incorrect values.  Be sure to respect
  // media::cast::kMaxUnackedFrames.
  void RecordLatestFrameTimestamps(uint32_t frame_id,
                                   base::TimeTicks reference_time,
                                   RtpTimeTicks rtp_timestamp);
  base::TimeTicks GetRecordedReferenceTime(uint32_t frame_id) const;
  RtpTimeTicks GetRecordedRtpTimestamp(uint32_t frame_id) const;

  // Returns the number of frames that were sent but not yet acknowledged.
  int GetUnacknowledgedFrameCount() const;

  // Playout delay represents total amount of time between a frame's
  // capture/recording on the sender and its playback on the receiver
  // (i.e., shown to a user).  This should be a value large enough to
  // give the system sufficient time to encode, transmit/retransmit,
  // receive, decode, and render; given its run-time environment
  // (sender/receiver hardware performance, network conditions,etc.).

  // The |target_playout delay_| is the current delay that is adaptively
  // adjusted based on feedback from video capture engine and the congestion
  // control. In case of interactive content, the target is adjusted to start
  // at |min_playout_delay_| and in case of animated content, it starts out at
  // |animated_playout_delay_| and then adaptively adjust based on feedback
  // from congestion control.
  base::TimeDelta target_playout_delay_;
  const base::TimeDelta min_playout_delay_;
  const base::TimeDelta max_playout_delay_;
  // Starting playout delay for animated content.
  const base::TimeDelta animated_playout_delay_;

  // If true, we transmit the target playout delay to the receiver.
  bool send_target_playout_delay_;

  // Max encoded frames generated per second.
  double max_frame_rate_;

  // Counts how many RTCP reports are being "aggressively" sent (i.e., one per
  // frame) at the start of the session.  Once a threshold is reached, RTCP
  // reports are instead sent at the configured interval + random drift.
  int num_aggressive_rtcp_reports_sent_;

  // This is "null" until the first frame is sent.  Thereafter, this tracks the
  // last time any frame was sent or re-sent.
  base::TimeTicks last_send_time_;

  // The ID of the last frame sent.  Logic throughout FrameSender assumes this
  // can safely wrap-around.  This member is invalid until
  // |!last_send_time_.is_null()|.
  uint32_t last_sent_frame_id_;

  // The ID of the latest (not necessarily the last) frame that has been
  // acknowledged.  Logic throughout AudioSender assumes this can safely
  // wrap-around.  This member is invalid until |!last_send_time_.is_null()|.
  uint32_t latest_acked_frame_id_;

  // Counts the number of duplicate ACK that are being received.  When this
  // number reaches a threshold, the sender will take this as a sign that the
  // receiver hasn't yet received the first packet of the next frame.  In this
  // case, VideoSender will trigger a re-send of the next frame.
  int duplicate_ack_counter_;

  // This object controls how we change the bitrate to make sure the
  // buffer doesn't overflow.
  scoped_ptr<CongestionControl> congestion_control_;

  // The most recently measured round trip time.
  base::TimeDelta current_round_trip_time_;

 private:
  // Returns the maximum media duration currently allowed in-flight.  This
  // fluctuates in response to the currently-measured network latency.
  base::TimeDelta GetAllowedInFlightMediaDuration() const;

  // RTP timestamp increment representing one second.
  const int rtp_timebase_;

  const bool is_audio_;

  // Ring buffers to keep track of recent frame timestamps (both in terms of
  // local reference time and RTP media time).  These should only be accessed
  // through the Record/GetXXX() methods.
  base::TimeTicks frame_reference_times_[256];
  RtpTimeTicks frame_rtp_timestamps_[256];

  // NOTE: Weak pointers must be invalidated before all other member variables.
  base::WeakPtrFactory<FrameSender> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(FrameSender);
};

}  // namespace cast
}  // namespace media

#endif  // MEDIA_CAST_SENDER_FRAME_SENDER_H_