Re: A proposal for splitting RTCTrack into RtpSender and RtpReceiver.

It seems really powerful, love it.

2014/1/7 Peter Thatcher <pthatcher@google.com>:
> Some of the discussions in the recent W3C WebRTC WG have centered around the
> idea of having "rtp send doohickeys" and "rtp receive doohickeys", which
> would represent objects that control sending and receiving a single media
> track, respectively.  I think this would be a good direction for the ORTC
> API to take, and I think would improve upon the ORTC API greatly.   You can
> think of this as splitting the "RTCTrack" into two classes: a "sender" class
> and a "receiver" class, refining their methods and attributes.
>
> I propose an API something like the following.  I'm using the names
> "RtpSender" and  "RtpReceiver" which Justin Uberti proposed to the W3C.
>
> // An RTCRtpSender sends one MediaStreamTrack
> // over one RTCConnection.
> // If you want to send a whole MediaStream with multiple tracks,
> // Create multiple RtpSenders.
> [Constructor(MediaStreamTrack track, RTCConnection transport)]
> interface RTCRtpSender {
>   readonly attribute MediaStreamTrack track;
>   readonly attribute RTCConnection transport;
>
>   // The way media is sent is controlled by the given "parameters".
>   // The sender starts sending when send() is called,
>   // And stops sending when stop() is called.
>   // send() may be called more than once to change parameters.
>   // stop() is final, just like MediaStreamTrack.
>   void send(RTCRtpParameters parameters);
> void stop();
>
>   // NOTE: We can't have a readonly attribute because apparently
>   // In WebIDL, "readonly" doesn't make the returned object
>   // readonly, just the reference.
>   RTCRtpParameters parameters();
>
>   // Instead of a top-level getRtcCapabilities and getRtcCodecs(),
>   // We have a static method on the RtpSender and RtpReceiver
>   // (send and receive capabilities might be different).
>  static RTCRtpCapabilities getCapabilities();
>   // While JS can construct and negotiate parameters just based on
>   // the capabilities, doing so is usually a pain, so we provide two
>   // convenience methods to help with the process.  The first
>   // creates parameters based on capabilities and the second filters
>   // already created paremters based on capabilities.  This allows
>   // for a lot of flexibility of which side does the neogitation and
>   // when.(We're not confined to an offer/answer model).
>  static RtpParameters createParameters(
>     MediaStreamTrack track
>     optional RTCRtpCapabilities capabilities);
>  static RTCRtpParameters filterParameters(
>     RTCRtpParameters parameters,
>    optional RTCRtpCapabilities capabilities);
> }
>
> // An RTCRtpReceiver receives one MediaStreamTrack over one
> // RTCConnection.  If you want to receive a whole MediaStream with
> // multiple tracks, create multiple RtpReceivers.
> [Constructor(optional RTCConnection transport)]
> interface RTCRtpReceiver {
>  // The media coming from the transport is available from the
>   // track.  The track is null until receive() is called, and once
>   // it is set to non-null, will not changed.
>   readonly attribute MediaStreamTrack? track;
>   readonly attribute RTCConnection transport;
>
>   // The way media is received is controlled by the given
>   // "parameters".  The receiver starts receiving when receive() is
>   // called, and stops sending when stop() is called.
>   // receive() may be called more than once to change parameters.
>   // stop() is final, and the receive can never receive again.
>   void receive(RTCRtpParameters parameters);
> void stop();
>
>   // NOTE: We can't have a readonly attribute because apparently
>   // In WebIDL, "readonly" doesn't make the returned object
>   RTCRtpParameters parameters();
>
>   // Instead of a top-level getRtcCapabilities and getRtcCodecs(),
>   // We have a static method on the RtpSender and RtpReceiver
>   // (send and receive capabilities might be different).
>  static RTCRtpCapabilities getCapabilities();
>   // While JS can construct and negotiate parameters just based on
>   // the capabilities, doing so is usually a pain, so we provide two
>   // convenience methods to help with the process.  The first
>   // creates parameters based on capabilities and the second filters
>   // already created paremters based on capabilities.  This allows
>   // for a lot of flexibility of which side does the neogitation and
>   // when. (We're not confined to an offer/answer model).
>  static RtpParameters createParameters(
>     DOMString kind,  // "audio" or "video"
>     optional RTCRtpCapabilities capabilities);
>  static RTCRtpParameters filterParameters(
>     RTCRtpParameters parameters,
>    optional RTCRtpCapabilities capabilities);
> }
>
> // The RTCRtpParameters contains much of what currently exists as /
> // attributes of RTCTrack, but as a dictionary, it's much easier to
> // serialize/deserialize for signalling, and pass into and out from
> // convenience methods for neogitation.  Finally, it allows changing
> // of parameters in an atomic way.
> dictionary RTCRtpParameters {
>   sequence<RTCRtpCodec> codecs;
>
>   // Can specify multiple multiple layers or "encodings",
>   // such as for simulcast, RTX, FEC, etc in the future.
>   sequence<RTCRtpEncodingParameters> encodings;
>
>   // TODO: RTP header extensions, "appID", ...
> }
>
> dictionary RTCRtpEncodingParameters {
>   unsigned int ssrc;
>
>   // TODO: Things to control various layers, simulcast, rtx, etc.
>   // For now, let's just recognize that we need more than one
>   // and we need more than the SSRC.  So let's make a dictionary,
>   // and figure out the details later.
> }
>
>
> Finally, here's an example of how it could be used:
>
> // Assume we already have a way to signal, a transport
> // (RTCConnection), and audio and video tracks. This is an example
> // of  how to offer them  and get back an answer with audio and
> // video tracks, and begin sending and receiving them.
> function initiate(signaller, transport, audioTrack, videoTrack) {
>   var audioSender = new RTCRtpSender(audioTrack, transport);
>   var videoSender = new RTCRtpSender(videoTrack, transport);
>   var audioReceiver = new RTCRtpReceiver(transport);
>   var videoReceiver = new RTCRtpReceiver(transport);
>
>   var sendAudioParams = RTCRtpSender.createParameters(audioTrack);
>   var sendVideoParams = RTCRtpSender.createParameters(videoTrack);
>   signaller.offerTracks({
>     // The initiator offers parameters it wants to send with,
>     // and the capabilities it has for receiving.
>     "rtpCaps": RTCRtpReceiver.getCapabilities(),
>     "audio": sendAudioParams,
>     "video": sendVideoParams
>   }, function(answer) {
>     // The responder answers with parameters it wants to send with
>     // and the capabilities it has for receiving.
>     audioSendParams = RTCRtpSender.filterParameters(
>        sendAudioParams, answer.rtpCaps);
>     videoSendParams = RTCRtpSender.filterParameters(
>        sendVideoParams, answer.rtpCaps
>     var audioRecvParams = RTCRtpSender.filterParameters(
>        answer.audio);
>     var videoRecvParams = RTCRtpSender.filterParameters(
>        answer.video);
>
>     audioSender.send(audioSendParams);
>     videoSender.send(videoSendParams)
>     audioReceiver.receive(audioRecvParams);
>     videoReceiver.receive(videoRecvParams);
>
>     // Now we can render/play
>     // audioReceiver.track and videoReceiver.track.
>   });
> }
>
> // Assume we already have a way to signal, a transport
> // (RTCConnection), and audio and video tracks. This is an example
> // of how to answer an offer with audio and video tracks, and begin
> // sending and receiving them.
> function accept(
>   signaller, remote, transport, audioTrack, videoTrack) {
>   var audioSender = new RTCRtpSender(audioTrack, transport);
>   var videoSender = new RTCRtpSender(videoTrack, transport);
>   var audioReceiver = new RTCRtpReceiver(transport);
>   var videoReceiver = new RTCRtpReceiver(transport);
>
>   var audioSendParams = RTCRtpSender.createParameters(
>     audioTrack, remote.rtpCaps);
>   var videoSendParams = RTCRtpSender.createParameters(
>     videoTrack, remote.rtpCaps);
>   var audioRecvParams = RTCRtpSender.filterParameters(
>      remote.audio);
>   var videoRecvParams = RTCRtpSender.filterParameters(
>      remote.video);
>
>   audioSender.send(audioSendParams);
>   videoSender.send(videoSendParams)
>   audioReceiver.receive(audioRecvParams);
>   videoReceiver.receive(videoRecvParams);
>
>   signaller.answerTracks({
>     "rtpCaps": RTCRtpReceiver.getCapabilities(),
>     "audio": audioSender.parameters(),
>     "video": videoSender.parameters()
>   });
>
>   // Now we can render/play
>   // audioReceiver.track and videoReceiver.track.
> }
>



-- 
Iñaki Baz Castillo
<ibc@aliax.net>

Received on Tuesday, 7 January 2014 10:31:19 UTC