3

I'm using the WebRTC library which has a very specific API. The peerConnection.setRemoteDescription method's 2nd argument is supposed to be a callback for when it finishes setting the remote description:

This is one of my wrapper functions for my WebRTC class:

export function setRemoteSdp(peerConnection, sdp, callback) {
  if (!sdp) return;
  return peerConnection.setRemoteDescription(
    new RTCSessionDescription(sdp),
    callback, // <-------------
  );
}

And this is a sketch of what I want to do:

function receivedSdp(action$, store) {
  return action$.ofType(VideoStream.RECEIVED_SDP)
    .mergeMap(action => {
      const {peerConnection} = store.getState().videoStreams;
      const {sdp} = action.payload;

      return WebRTC.setRemoteSdp(peerConnection, sdp, () => {
        return myReducer.myAction(); // <------ return action as the callback
      })
    })
};

This doesn't work since I'm not returning an Observable. Is there a way to do this?

P.S. this is the WebRTC API: https://github.com/oney/react-native-webrtc/blob/master/RTCPeerConnection.js#L176

bigpotato
  • 26,262
  • 56
  • 178
  • 334

2 Answers2

4

martin's answer is correct about using Observable.create or new Observable--same thing (except it's not clear to me why you need the mergeAll() since the mergeMap will flatten?)

As a bonus, you could also use Observable.bindCallback for this.

// bindCallback is a factory factory, it creates a function that
// when called with any arguments will return an Observable that
// wraps setRemoteSdp, handling the callback portion for you.
// I'm using setRemoteSdp.bind(WebRTC) because I don't know
// if setRemoteSdp requires its calling context to be WebRTC
// so it's "just in case". It might not be needed.
const setRemoteSdpObservable = Observable.bindCallback(WebRTC.setRemoteSdp.bind(WebRTC));

setRemoteSdpObservable(peerConnection, sdp)
  .subscribe(d => console.log(d));

Usage inside your epic would be something like this

// observables are lazy, so defining this outside of our epic
// is totally cool--it only sets up the factory
const setRemoteSdpObservable = Observable.bindCallback(WebRTC.setRemoteSdp.bind(WebRTC));

function receivedSdp(action$, store) {
  return action$.ofType(VideoStream.RECEIVED_SDP)
    .mergeMap(action => {
      const {peerConnection} = store.getState().videoStreams;
      const {sdp} = action.payload;

      return setRemoteSdpObservable(peerConnection)
        .map(result => myReducer.myAction());
    })
};

You could use this to create Observable wrappers for all the WebRTC apis.

jayphelps
  • 15,276
  • 3
  • 41
  • 54
3

So the problem is that setRemoteSdp doesn't return an Observable while myReducer.myAction() does and that's the Observable you want to merge?

You can use Observable.create and wrap the WebRTC.setRemoteSdp call:

.mergeMap(action => {
  return Observable.create(observer => {
    WebRTC.setRemoteSdp(peerConnection, sdp, () => {
      observer.next(myReducer.myAction());
      observer.complete();
    })
  });
}
.mergeAll()

The Observable.create returns an Observable that emits another Observable from myReducer.myAction(). Now I have in fact so-called higher-order that I want to flatten using mergeAll() (concatAll would work as well).

martin
  • 93,354
  • 25
  • 191
  • 226