Re: [Bug 18485] Change DTMF API to be on PeerConnection

On 2012-08-09 01:40, Martin Thomson wrote:
> On 8 August 2012 14:26, Justin Uberti <juberti@google.com> wrote:
>> Option D seems like a good way to get what we need without spending too much
>> effort on this legacy use case.
>
> The problem with all of these - D included - is that DTMF is not
> prearranged at the point that the track is added to the
> PeerConnection, so either all streams have DTMF negotiated or none do.
>   The former ensures that some negotiations will fail (or remove DTMF),
> but will ensure that the DTMF is available everywhere it can be.  The
> latter forces applications to add DTMF themselves, probably by SDP
> bashing.
>
> Given how much we care for this legacy use case - and I care even less
> than most - I would suggest the API that minimizes impact on existing
> APIs.  Randell's basic suggestion is good, the choice of
> implementation point is not:
>
>> Personally, I'd have SendDTMF() operate on a MediaStreamTrack, and be an
>> event.  This would mean that if you have a MediaStreamTrack connected to two
>> PeerConnections (quite possible), the event would be cloned and bubble up to
>> both PeerConnections, which would then send DTMF (if possible).  I'd have
>> PlayDTMF() operate on a track in remote or localstream via PeerConnection,
>> and it would insert tones.
>
> As I described separately, I'm not convinced that adding more stuff to
> PeerConnection is the right answer, and I'm interested in learning why
> this choice is considered superior to the current proposal, or
> something even more explicit as I outlined.
>
> That is, send:
>
> var track = new DtmfAudioStreamTrack(stream.audioTracks[0]);
> stream = new MediaStream(track);
> track.sendTones('12');
>
> Receive:
>
> var track = pc.remoteStreams[0].audioTracks[0];
> if (track instanceof DtmfAudioStreamTrack) {
>      track.addEventListener('tone', function(dtmfEvent) {
>          if (dtmfEvent.state === 'start') {
>              dtmfTones[dtmfEvent.tone].enable();
>              keyLog += dtmfEvent.tone;
>          } else if (dtmfEvent.state === 'end') {
>              dtmfTones[dtmfEvent.tone].disable();
>          }
>      });
> }
>

Included the idl from Martins mail in another thread.

[Constructor(MediaStreamTrack audioTrack)]
interface DtmfAudioStreamTrack : MediaStreamTrack, EventTarget {
     void playTones (DOMString tones,
             optional unsigned long duration = 100);
     void startTone (DOMString tone);
     void endTone ();

     attribute DtmfCallback? ontone;
};

----

I like this approach since it doesn't pollute the general part of the 
MediaStream API with DTMF functionality at same time as it doesn't add 
more functions to the PeerConnection API.

Since we need methods like startTone() and endTone() to emulate a dial 
pad as well as the convenience method to simply send a few tones for a 
duration of time, we need more than one or two functions. I think it's 
nicer to have these in a separate interface compared to adding them 
directly to PeerConnection. Also, if we decide to support incoming DTMF 
tones, it's more straight forward to have an object to register event 
listeners on compared to the approach with "static-like" functions on 
PeerConnection (e.g. pc.incomingDTMF(track, function (dtmf) {...});).

One thing that might be confusing for developers is how the original 
MediaStreamTrack and the new DtmfAudioStreamTrack relate to each other 
since they are both MediaStreamTrack objects. Do I need to add the 
DtmfAudioStreamTrack to the same stream that provided the 
MediaStreamTrack (passed to the constructor) and send that stream with 
PeerConnection. Should it go into a MediaStream on it's own? If the 
tracks are in the same stream and transmitted with PeerConnection, what 
happens if I remove the MediaStreamTrack that was used to create the 
DtmfAudioStreamTrack? The DtmfAudioStreamTrack could also be added to 
another stream that is sent somewhere else than the MediaStreamTrack 
used to create the DtmfAudioStreamTrack. Should the DtmfAudioStreamTrack 
be in the MediaStream.audioTracks list? It doesn't really behave as a 
normal MediaStreamTrack.

I don't see any reason why the DtmfAudioStreamTrack needs to be a 
MediaStreamTrack. We could simply have an object that's used as a remote 
to insert and receive DTMF on associated MediaStreamTrack objects.

[Constructor(MediaStreamTrack outgoingAudioTrack,
     optional MediaStreamTrack incomingAudioTrack)]
interface DtmfTransceiver : EventTarget {
     void playTones (DOMString tones,
             optional unsigned long duration = 100);
     void startTone (DOMString tone);
     void endTone ();

     attribute Function? ontone;
};

--- Example ---
// we have a connected PeerConnection, pc
var outgoingAudioTrack = pc.localStreams[0].audioTracks[0];
var incomingAudioTrack = pc.remoteStreams[0].audioTracks[0];

var dtmf = new DtmfTransceiver(outgoingAudioTrack, incomingAudioTrack);

dtmf.playTones("1 2 3"); // could be played back in "incomingAudioTrack"

dtmf.ontone = function (evt) { ... };
------

We could initially skip the ontone stuff and add it back if we decide 
that we need to be able to receive DTMF as well.

/Adam

Received on Friday, 10 August 2012 12:49:48 UTC