For the tests I was using WifiUPnPTestApp and I was adding service data into the services array with WifiP2pUpnpServiceInfo. The data sent via service lines was strings containing only number characters.
I was only using two Nexus 5 devices with these tests, one of them was having 5.1.0 Lollipop and the other one was having 4.4.4 KitKat firmware.
The data that can be sent with the API are defined in the API docs for WifiP2pUpnpServiceInfo.
From initial tests I concluded that the API does require the UUID and device to be set into it. The UUID also need to be in format defined for it, thus it cannot really be made any shorter. To be on safe side I also assumed that some parts of the API might also require the device string to have the correct formatting, i.e. to be in the form of ‘urn:schemas-upnp-org:device:DEVICE_NAME’. With these tests the DEVICE_NAME was set to be one character long to save up some space for the payload.
There appears to be also a requirement for the characters that can be used with any of the strings used with the API. The defined characters can be found from the API docs . Easiest way to be sure that only supported characters are used, would be to simply Base64 encode the payload strings, which again reduces the effective payload that can be sent over.
By default there are three lines which gets delivered on top of the services advertised:
- One line having just the UID
- One line having the UID and saying that its upnp rootdevice
- One line advertising the device line set for the service
Each line delivered separately to the callback, also each line added to the services array will be getting delivered separately to the callback.
Thus if the data would need to be combined, then there should be identifier included to determine which part the data is. In general it appear that last added line will be delivered first, indicating that there is a LIFO (Last in first out) buffer implemented for the UPnP advertisement sending in the API. But I would not recommend relying on the delivery order when combining the data send over with the API.
Do remember that with each separate line that is delivered, there is additional 43 byte header (for example: ‘uuid:6859dede-8574-59ab-9332-123456789011::’) added. This header will be counted in total bytes delivered and thus it will reduce the max payload we can deliver through this channel. And therefor if you want to deliver max amount of data, then the as much data as can be added in on service line, should definitely be added there.
The actual data that gets sent out from the device appears to be limited to some value less than 1K. With Lollipop tests I managed to get at max 946 bytes payload out (946 bytes +43 bytes of header = total string length = 988 bytes) in a single service line.
With KitKat the maximum data that can be delivered with one service line appears to be 188 bytes (231 -43 header), anything on top of that gets cut away. Then for maximum data you can have 4 full lines giving the payload maximum value of 752 bytes (4 x 188).
Do note that even when the KitKat device did cut any service line that was having more than 188 bytes of payload, it can see the service lines advertised by Lollipop device, even when the maximum of 946 bytes of data is used.
The maximum payload, as well as the max-line cutting appears to be handled by the LIFO buffer manager, and first it just checks the last line from the buffer and sees whether it first into the limits posed. And if it does not then noting gets sent out. If it fits then it’s added to be delivered to other devices. After the first line, it just checks next lines in the LIFO buffer until the length of already added lines + the new line would be too long, then it simply ignored the next line and anything after it.
There appears to be also some additional headers which are only visible internally, since if I want to see also the device line same time as I see my own data, I do need to reduce the size of the payload to 868 (78 bytes less), even when the length of the 1 character device name line is only 72 bytes (for example: ‘uuid:6859dede-8574-59ab-9332-123456789011::urn:schemas-upnp-org:device:A’).
Then if I also want to see the ‘One line having just the UID’ (41 bytes), and the root device line (58 bytes), then the max payload drops to 757 (189 bytes less than the max). So as with 1 line the reduction was 6 bytes, and with 3 lines it was 18, I would want to assume that each line adds firstly the 43 bytes of visible header, and then also 6 bytes of invisible header, thus actually reducing the max payload we can deliver through the channel for 49 bytes per line.
Additionally the LIFO buffer, as it is managed by the Wi-Fi Direct API, it’s also shared between different apps. Which effectively means that the app that its services added lasts to the API, will be the one that get them out, provided that they do fit into the limits posed.
The service lines added by other apps, will get out only if their size requirements along still fit, after the lines that do get added before them.
This means that the data delivery through this channel is not really reliable, since any other application can effectively turn off the discovery, and the application has no ways on knowing when that happens.