- JS 側のインタフェース設計をどうするか?
- iOS/Android の DataChannel のインタフェースを調査する
- そもそも libwebrtc の機能的に iOS/Android の間で差異があるか?
https://developer.mozilla.org/ja/docs/Web/API/RTCDataChannel
- createDataChannel()
- https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDataChannel
- ピアに新たに datachannel を作成する
- ondatachannel
- https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ondatachannel
- リモートのピアに datachannel が追加されたときに発火する
- label
- ordered
- protocol
- id
- readyState
- bufferedAmount
- binaryType
- maxPacketLifeType
- maxRetransmits
- negotiated
- reliable (dublicated)
- stream (duplicated)
https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannelEvent
- onopen
- onmessage
- onclose
- onerror
- close()
- send()
- DOMString (だいたい String), Blob, ArrayBuffer, ArrayBufferView を送信することができる
public DataChannel createDataChannel(String label, DataChannel.Init init) {
return nativeCreateDataChannel(label, init);
}
createDataChannel 相当のメソッドが実装されている
public class DataChannel {
/** Java wrapper for WebIDL RTCDataChannel. */
public static class Init {
public boolean ordered = true;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int maxRetransmitTimeMs = -1;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int maxRetransmits = -1;
public String protocol = "";
public boolean negotiated;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int id = -1;
@CalledByNative("Init")
boolean getOrdered() {
return ordered;
}
@CalledByNative("Init")
int getMaxRetransmitTimeMs() {
return maxRetransmitTimeMs;
}
@CalledByNative("Init")
int getMaxRetransmits() {
return maxRetransmits;
}
@CalledByNative("Init")
String getProtocol() {
return protocol;
}
@CalledByNative("Init")
boolean getNegotiated() {
return negotiated;
}
@CalledByNative("Init")
int getId() {
return id;
}
}
DataChannel.Init クラス。こちらを configuration 的にcreateDataChannel に渡して datachannel を作成できる。
/** Java version of C++ DataChannelObserver. */
public interface Observer {
/** The data channel's bufferedAmount has changed. */
@CalledByNative("Observer") public void onBufferedAmountChange(long previousAmount);
/** The data channel state has changed. */
@CalledByNative("Observer") public void onStateChange();
/**
* A data buffer was successfully received. NOTE: |buffer.data| will be
* freed once this function returns so callers who want to use the data
* asynchronously must make sure to copy it first.
*/
@CalledByNative("Observer") public void onMessage(Buffer buffer);
}
....
/** Send |data| to the remote peer; return success. */
public boolean send(Buffer buffer) {
checkDataChannelExists();
// TODO(fischman): this could be cleverer about avoiding copies if the
// ByteBuffer is direct and/or is backed by an array.
byte[] data = new byte[buffer.data.remaining()];
buffer.data.get(data);
return nativeSend(data, buffer.binary);
}
こちらの send 関数の Buffer に boolean binary プロパティが付与されていて、こちらで
binaryType については binary
パラメータによって UTF-8 or binary data
が選択できる模様。
@implementation RTCPeerConnection (DataChannel)
- (nullable RTCDataChannel *)dataChannelForLabel:(NSString *)label
configuration:(RTCDataChannelConfiguration *)configuration {
std::string labelString = [NSString stdStringForString:label];
const webrtc::DataChannelInit nativeInit =
configuration.nativeDataChannelInit;
rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
self.nativePeerConnection->CreateDataChannel(labelString,
&nativeInit);
if (!dataChannel) {
return nil;
}
return [[RTCDataChannel alloc] initWithFactory:self.factory nativeDataChannel:dataChannel];
}
@end
dataChannelForLabel
が pc.createDataChannel()
相当のメソッドとなる。
class DataChannelDelegateAdapter : public DataChannelObserver {
public:
DataChannelDelegateAdapter(RTCDataChannel *channel) { channel_ = channel; }
void OnStateChange() override {
[channel_.delegate dataChannelDidChangeState:channel_];
}
void OnMessage(const DataBuffer& buffer) override {
RTCDataBuffer *data_buffer =
[[RTCDataBuffer alloc] initWithNativeBuffer:buffer];
[channel_.delegate dataChannel:channel_
didReceiveMessageWithBuffer:data_buffer];
}
void OnBufferedAmountChange(uint64_t previousAmount) override {
id<RTCDataChannelDelegate> delegate = channel_.delegate;
SEL sel = @selector(dataChannel:didChangeBufferedAmount:);
if ([delegate respondsToSelector:sel]) {
[delegate dataChannel:channel_ didChangeBufferedAmount:previousAmount];
}
}
onmessage, onstatechange(close やら open やら error の状態変更), onbufferedamountchange などのイベントを受け取れそう
各種 configration(isOrdered) などは↑の RTCDataChannelConfiguration クラスで定義してある。
こちらも binaryType については isBinary
パラメータによって UTF-8 or binary data
が選択できる模様
react-native-webrtc-kit の WebRTCPeerConnectionObserver.java
に以下のようなコードがある。
@Override
public void onDataChannel(DataChannel dataChannel) {
// DataChannel は現在対応しない
}
ここで peer.ondatachannel
相当のイベントを受け取ることができる。
RTCPeerConnection.m に以下のようなコードがある
- (void)peerConnection:(RTCPeerConnection*)peerConnection didOpenDataChannel:(RTCDataChannel*)dataChannel {
// DataChannel は現在対応しない
}
ここで peer.ondatachannel
相当のイベントを受け取ることができる。
以上を踏まえて、JS / Native 側に必要な実装事項をまとめると
-
RTCDataChannel
クラスを追加する -
datachannel.onstatechange, datachannel.onmessage datachannel.onbufferedamountchange
コールバックを実装する- datachannel のイベントハンドラを実装する
-
peerConnection.createDataChannel()
メソッドを追加する- 新たに datachannel を作成する関数
- 引数は label, options にすると仮定すると
- options で isBinary, isOrderd, MaxPacketLifeTime, MaxRetransmits などを設定できるようにする必要がある
- 引数は label, options にすると仮定すると
- 新たに datachannel を作成する関数
-
peerConnection.ondatachannel()
イベントハンドラを追加する- リモートに datachannel が新規に作成されたときのコールバック
ネイティブ から ondatachannel を JS に受け渡す例として
- (void)peerConnection:(RTCPeerConnection*)peerConnection didOpenDataChannel:(RTCDataChannel*)dataChannel {
// DataChannel は現在対応しない
}
に
- (void)peerConnection:(RTCPeerConnection*)peerConnection didOpenDataChannel:(RTCDataChannel*)dataChannel {
[self.bridge.eventDispatcher sendDeviceEventWithName:@"peerConnectionGotDataChannel"
body:@{@"valueTag": peerConnection.valueTag,
@"datachannel": @{
@"label": ... // 色々情報を付与する
}
}
}
のような実装が考えられる。
@kgrvaidya Please give me more information about your app. e.g.