非公開となったWWDC17のCore Bluetoothセッションの内容まとめ - L2CAP編
はじめに
WWDC17のセッション動画は以下で閲覧可能:
・・・のように一見見えますが、実は既に一部の動画は非公開となっておりもう見ることができません。そのうちのひとつが "What's New in Core Bluetooth" です。
2024年のいま、2017年のWhat's Newなんてもう必要ないだろう、と思う人もいるかもしれません [1]。
が、Core Bluetoothのようなニッチなフレームワークにとっては、昔のWWDCの発表であれ、それが唯一の一次情報だったりするので、非常に貴重です。
特に、2017年の同セッションは、これまでのWWDCにおいて唯一L2CAPについて言及しているセッションであり、またMTUやEDLにも触れつつ、Core Bluetoothの通信速度に関して事細かに説明してくれているパートもあり [2]、
WWDC17 "What's New in Core Bluetooth" より引用
現在においても非常に有用なセッションです。
スライドは現在でも公開 されており、またトランスクリプトは以下リポジトリにvttファイルとして残されています:
本記事ではこれらを統合し、WWDC17の同セッションの中でも特に重要だと感じた「L2CAP channels」パートの内容をまとめます。
APIドキュメントのL2CAPに関する記述をすべて整理した下記記事と併せてご参照ください:
以下、文章、画像はWWDCの基本的に同セッションからの引用です。適宜要約したり、順序を並び替えたり、見出しを追加したりしています。また日本語訳だけだと伝わりにくいと思われる部分には原文も載せています。
L2CAPの概要
今年の新機能として、L2CAPチャンネルへのアクセスが可能になりました。
So, an L2CAP channel at the lowest level is just this stream of data between two devices, and it's actually the protocol that it's actually the protocol that we use under the covers for all communication between these devices.
最も低いレベルのL2CAPチャネルとは、2つのデバイス間のこのデータストリームそのものであり、実際には、これらのデバイス間のすべての通信で裏で使用されているプロトコルです。
So L2CAP Channels have been used on the platform.
L2CAPチャネルはプラットフォーム上で使用されてきました。
Since day one of Bluetooth this is the first time that we're opening up for your applications to directly talk over these channels.
L2CAPチャンネルは、Bluetoothの初日から使用されており、今回初めて、アプリケーションがこれらのチャンネルで直接会話できるようになりました。
It actually stands for the Logical Link Control and Adaptation Protocol, and the support for dynamically allocated connection or into channels is new for Bluetooth Core Spec 4.1.
L2CAPチャンネルはLogical Link Control and Adaptation Protocolの略で、動的に割り当てられるconnection-oriented channelsをサポートするもので、Bluetooth Core Spec 4.1の新機能です。
So unlike all the other interactions that you've done with your accessories before where you have to work through the GATT Database to get your data, L2CAP Channels allow you to open a side channel and directly read and write without any framing limitations, packet size limitations.
そのため、GATTデータベースを経由してデータを入手する必要がある、これまでのアクセサリーとのやり取りとは異なり、
L2CAPチャンネルは、サイドチャンネルを開き、フレームやパケットサイズの制限なしに、直接読み書きすることができます。
実装方法
セントラル側の実装
It's a direct way to talk between your device and your accessory.
So we think this API is very simple to use.
If you have already connected to a peripheral, all you have to do is call openL2CAPChannel and specify as the PSM, and you'll get a callback data openL2CAPChannel will hand you back the object that represents this channel.
これは、あなたのデバイスとアクセサリーの間で直接会話する方法です。
だから、このAPIはとてもシンプルに使えると思う。
すでにペリフェラルに接続している場合は、openL2CAPChannel
をコールしてPSMとして指定するだけだ。
PSM
So the PSM is a -- it's the Protocol Service Multiplexer but you should think of it as analogous to say TCP port.
PSMはプロトコル・サービス・マルチプレクサ(Protocol Service Multiplexer)だが、TCPポートと同じようなものだと考えてほしい。
It's just a number that you give to us that uniquely identifies the service you want to open on the peripheral side of the connection.
これは、接続のペリフェラル側で開きたいサービスを一意に識別するための番号です。
And what's interesting about this is that there are some profiles that are published by the Bluetooth SIG that have a hard coded PSM.
興味深いのは、Bluetooth SIGが公表しているプロファイルの中には、PSMがハードコードされているものがあるということです。
So if you're trying to do things like the Object Transfer Protocol, the PSM will be known to you even before you connect to the device.
そのため、Object Transfer Protocolなどを行おうとする場合、PSMはデバイスに接続する前からわかっていることになります。
But in every other case, the PSM is unique to the device you're talking to, which means it's locally assigned and can even be locally assigned and can even be reused by other applications.
しかし、それ以外のすべての場合において、PSMはあなたが話しているデバイスに固有であり、ローカルに割り当てられ、他のアプリケーションによって再利用されることさえあります。
So it's important that you discover what PSM to connect to before you try to open it.
What we've done to make this a little bit simpler is we're publishing a UUID that you can use and put within your service to help you specify what PSM to open that's associated with your CB service.
そのため、PSMに接続する前に、接続するPSMを特定することが重要です。
これを少し簡素化するために、CBService
に関連付けられたPSMを特定する際に役立つ、サービス内で使用できるUUIDを発行しています。
ペリフェラル側の実装
We're also opening L2CAP Channels if you're acting as a peripheral.
また、ペリフェラルとして動作する場合は、L2CAPチャンネルもオープンする。
So if you want to have a L2CAP Channel that's associated with your service, you can call publishL2CAPChannel and we will return you what PSM was assigned by the system in the callback peripheralManger didPublishL2CAPChannel.
そのため、自分のサービスに関連付けられているL2CAP Channelを持ちたい場合は、publishL2CAPChannel
を呼び出せば、コールバックの peripheralManger(_:didPublishL2CAPChannel:error)
で、システムによって割り当てられたPSMを返してくれる。
Another thing we've allowed is we allow you to specify whether your L2CAP Channel requires encryption or not.
So most of the time, the safe bet is to say yes, I want bet is to say yes, I want encryption.
It protects you from things like man-in-the-middle attacks, it protects you from things like people eavesdropping on the packets that you're sending between your two devices.
もう1つは、L2CAP Channelで暗号化が必要かどうかを指定できるようにしたことだ。
ほとんどの場合、安全なのはYesと言うことだ。
暗号化することで、中間者攻撃(man-in-the-middle attack)や、2つのデバイス間で送信されるパケットを盗聴されることを防ぐことができる。
But there are time when you might want to build more advanced types of authentication, like using public key cryptography you could build your own account system and protect your data that way.
しかし、より高度な認証システムを構築したい場合もあるでしょう。公開鍵暗号方式を使えば、独自のアカウントシステムを構築し、データを保護することができます。
Opening an L2CAP Channel
So let's go through an example of how you would actually negotiate an L2CAP Channel between two devices.
If you're acting as a peripheral, you would ask the system to publish an L2CAP Channel.
Again you get to specify whether this channel requires encryption or not.
In this case we're going to say true.
それでは、実際に2つのデバイス間でどのようにL2CAPチャネルをネゴシエートするのか、例を挙げて説明しよう。
ペリフェラルとして動作する場合、システムにL2CAP Channelの発行を依頼する。
このチャネルに暗号化が必要かどうかを指定する。
この場合はtrue
とする。
And when that's successful, you'll get a callback peripheralManager didPublishL2CAPChannel.
And as I mentioned, we'll tell you what PSM has been locally assigned for your service.
これが成功すると、peripheralManager(_:didPublishL2CAPChannel:error)
というコールバックが返ってくる。
そして、先ほども述べたように、あなたのサービスにローカルに割り当てられたPSMを伝えます。
So this is your opportunity to make the PSM known to incoming connections so that they can connections so that they can discover what channel to open that's associated with your service.
As a Central, you can read the PSM and that's all the information you need to actually open that channel.
So now you can call openL2CAPChannel with the PSM that you read from the remote device and you'll get the callback didOpenL2CAPChannel.
つまり、これは入ってくるコネクションにPSMを知らせる機会であり、コネクションがあなたのサービスに関連付けられているどのチャネルを開けばいいかを発見できるようにする。
セントラルとして、あなたはPSMを読むことができ、それはあなたが実際にそのチャネルを開くために必要なすべての情報です。
リモートデバイスから読み取った PSM を使って openL2CAPChannel
をコールすると、
didOpenL2CAPChannel
というコールバックが返ってくる。
So CB L2CAP Channel encapsulates all the information you need to know who you're talking to and how you can talk to it.
つまり、CBL2CAPChannel
は、誰とどのように話しているかを知るために必要なすべての情報をカプセル化する。
In this case we tell you the peer, which is either the central or the peripheral on the remote side of the connection.
We tell you what PSM was connected in case you have multiple services that you've published.
And then we just give you an InputStream and OutputStream.
この場合、ピア(接続のリモート側のセントラルまたはペリフェラル)をお知らせします。
複数のサービスを公開している場合は、どのPSMが接続されたかをお知らせします。
そして、InputStream
とOutputStream
をお知らせします。
Stream Events
We didn't want to build our own API and make you have to learn how to use a new Read Write API.
We didn't want you to have to adapt your code to deal adapt your code to deal specifically with Bluetooth connections.
If you already know how to deal with the socket and an InputStream and OutputStream, you can deal with an L2CAP Channel.
私たちは独自のAPIを構築し、新しいRead Write APIの使用方法を学んでもらうことを望んでいませんでした。
また、Bluetooth接続に特化したコードの変更をしてもらうことも望んでいませんでした。
ソケットやInputStream
、OutputStream
の使用方法をすでに理解している方であれば、L2CAPチャネルの使用方法も理解できるでしょう。
So we use all the same stream events that you would get off of, say, a socket after you're connected, and there's bytes available to be read.
You'll get the callback hasBytesAvailable.
If you're writing data and you fill all those queues, you get the same callback you would on a socket of hasSpaceAvailable.
We think this is really powerful because if you already have code that knows how to talk over other network interfaces like Ethernet or Wi-Fi.
That code can be directly adapted to run on top of L2CAP Channels.
つまり、接続が完了し、読み込み可能なバイトがある状態で、ソケットから取得するのと同じストリームイベントを使用する。
hasBytesAvailable
というコールバックが返ってくる。
データを書き込んでいて、それらのキューがすべて埋まったら、ソケットと同じコールバックhasSpaceAvailable
が返ってきます。
なぜなら、イーサネットやWi-Fiのような他のネットワーク・インターフェイスを介した通信方法を知っているコードがすでにある場合、そのコードをそのまま適応させることができるからだ。
そのコードをそのままL2CAP Channelsの上で実行することができる。
And when the channel has been closed, you get the same endEncountered.Event that you would get.
そして、チャネルが閉じられると、同じように endEncountered
イベントが発生する。
So after you've opened your connection, you can read data to that connection, you can write to it.
つまり、コネクションをオープンしたら、そのコネクションにデータを読み込んだり、書き込んだりすることができる。
Eventually when it's closed you get the endEncounterd.Event, and it can be closed for a couple of reasons.
最終的にそれが閉じられると、endEncountered
イベントが発行され、いくつかの理由で閉じられることがあります。
Closing Channels
So if the overall Bluetooth link So if the overall Bluetooth link is lost we'll tell you that the L2CAP Channel has been closed.
Bluetoothリンク全体が失われた場合、L2CAP Channelがクローズされたことを伝えます。
As the Central side, you can manually ask to close that connection.
セントラル側では、手動で接続を閉じるように要求することができます。
Now on the peripheral side, you can either un-publish the service or if you drop the object and allow it to be deallocated that's an implicit sign to us through Core Bluetooth that you're no longer interested.
ペリフェラル側では、サービスをアンパブリッシュするか、オブジェクトをドロップして割り当て解除を許可することで、Core Bluetoothを通して暗黙のうちに「もう興味がない」というサインを送ることができます。
That will also close the L2CAP Channel.
これにより、L2CAPチャネルも閉じられます。
いつL2CAPを使うべきか?
どのような場合にL2CAP Channelを使うべきか?
In general, if you're already doing well with GATT and your data model fits well into a GATT database, you should continue using that.
GATT makes it very simple to discover your data, to get quick updates.
You don't have to frame any of your data.
So keep using that if that worked for you.
一般的に、GATTでうまくいっており、データモデルがGATTデータベースにうまく適合している場合は、そのまま使い続けるべきです。 GATTは、データの発見や素早い更新を非常に簡単にします。 データをフレーム化する必要もない。 うまくいっている場合は、そのまま使い続けてください。
But if there are times where it was previously hard to make your data fit into the GATT database, data fit into the GATT database, either because you had more data that you could fit into a characteristic, or you're finding that GATT is kind of getting in the way, L2CAP Channels are a great opportunity to get the lowest overhead best performance when talking between your accessories.
しかし、以前はデータの特徴に適合させるために多くのデータが必要であったり、GATTが邪魔になっていたために、GATTデータベースにデータを適合させるのが困難であった場合、L2CAPチャンネルは、アクセサリー間の通信において、最低限のオーバーヘッドで最高のパフォーマンスを実現する素晴らしい機会となります。
And if you're doing large data transfers, say like a firmware update, L2CAP Channels are a good opportunity to help you get it there faster.
また、ファームウェアのアップデートなど、大容量のデータ転送を行う場合は、L2CAPチャンネルはより高速に転送できる良い機会となります。
And if you have a streaming protocol that's already defined somewhere that you want to run between your two devices, L2CAP Channels make that a really natural fit.
また、2つのデバイス間で実行したいストリーミングプロトコルがすでに定義されている場合は、L2CAPチャンネルはそれを自然に適合させることができます。
Wrap Up
If you're trying to do things like streaming protocols or transfer a large amount of data, L2CAP Channels are a great fit for that and we think that's a really powerful feature that's going to help you build even better accessories.
ストリーミングプロトコルや大量のデータ転送などを行おうとしている場合、L2CAPチャネルは最適です。これは、より優れたアクセサリーの構築に役立つ非常に強力な機能であると考えています。
Discussion