-
A while ago on Slack (where we unfortunately lost the history) we had a discussion on the APIs for the upcoming Bluetooth Audio service specifications. One such specification (VOCS) implementation was recently merged (#31893) with an API, which may not be optimal. What I would like to do here, is open the API discussion and use the VOCS implementation as a reference as how we should design this and some of the other upcoming service implementations. The API that was merged was based on the idea that we will have a shared API between server and client, and that the
One comment regarding this from @joerchan was that it was not clear when it was a client (remote) operation or when it was a server (local) operation, and his suggestion was to have something like
i.e using read/get and write/set to differentiate between client/remote and server/local operations. The biggest downside of this is that it will effectively double the size of the APIs as we will need two function for each action (one for each role). For VOCS it isn't that bad, but we will have other implementation (such as TBS/CCP) with 30+ functions that will effectively become 60+ for a single service. Another approach that I've considered myself is to get rid of the connection pointer in the API, and simply rely on the instance pointer, so something like:
As the instance is either a local instance (returned from init) or a remote instance (returned from doing discovery), but I don't feel like that will help with the confusion that @joerchan pointed out. A solution to that could be to expand the API to be
Which will return us to having a larger number of API functions. The point of this discussion is how we can design and API for these GATT services that makes sense for everyone.
Also keep in mind that some profiles/services for LE Audio is not public yet. We can freely discuss AICS, VOCS, VCS, VCP, TBS, CCP, MICS, MICP, MCS and MCP (see https://www.bluetooth.com/specifications/specs/) |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 11 replies
-
I fully see your point @Thalley. @joerchan proposal with a get/set for local and read/write for remote operations requires that this (get/set/read/write) is the convention all over the rest of the Bluetooth API which it is not. Take for example bt_gatt_attr_read. This also allows for a local connection point to do local database storing If we go with the bt_vocs_location_get(struct bt_vocs *inst), what would then happen if the function was supplied with an inst which was not local? To me, the most unambiguous is to allow the conn handle to be local as well, and in that way make it clear to the user where the action is taking place. And it is in line with the GATT API in zephyr as well, so it is not a new concept. |
Beta Was this translation helpful? Give feedback.
-
Frankly, I thought this was agreed and settled half a year ago. But let us see if we can reach a broader consensus this time. As for the proposed "shared" client/server API, that seems very workable to me. It is well documented that for the local interface, give a NULL pointer. So for using the API (writing code), this should be clear. For reading code, local/remote should be clear from context and the parameters given. (I.e., when "NULL" is given as the connection parameter, this is local use.) The doubling of the API is indeed significant, some of the services have a large number of characterstics. Media control is one of the large ones in this respect, the client header filer currently has around 33 function calls and 38 callbacks (OTC use included). The media player has 46 functions/callbacks. That being said, media control is the single module in le-audio that is written so that one side (the media player) may be only local (no Bluetooth). So here a local-only interface could possibly actually make sense for some cases. |
Beta Was this translation helpful? Give feedback.
-
Sorry for kicking the beehive on this one, I guess I didn't understand the full scope of this when we discussed this last time, or now when I made the comment on the VOCS PR. My understanding from the last discussion was that instead of having bt_vocs_server and bt_vocs_client API's we would put all of them under bt_vocs, and then the name would signal which role is using the API, since read/write is client, and notify is server. The main reason why I reacted to the To me it seems like there is just as many functions, with the difference being how many are exposed as public ones. And then you need to call them differently. If the argument for using the doubling of the APIs is to limit the amount of public APIs that is exposed to the application then that is OK with me. It is hard to see the scope of the APIs based on a single PR here and it appears to be quite a lot of these services. Now i've stated my reasoning I'll say that I'm happy to go with either suggestion now that I have a better understand of the reasoning behind these API decisions. |
Beta Was this translation helpful? Give feedback.
-
I think the general problem I see with this approach of creating services APIs as a kind of helper library is that it gives the impression that all service would be implemented at application layer, rather than in the stack itself or in a driver. Taking VOCS as example, the stack could implement it directly and just fetch the values for elsewhere, that way one wouldn't need any APIs for the service itself just the client procedures, well if there are any client procedures defined. For MCS and VCS I believe we may need to allow registration of external capabilties, much like bt_audio_capability, so that in itself is the API where the user can provide fields and callbacks to the stack in a pull style rather than expecting the upper layer to push individual fields since that makes the implementation much more predictable and probably easier to qualify different implementation as it is just a matter of changing the capabilities provider. |
Beta Was this translation helpful? Give feedback.
-
Another thing to consider is how writes to the services should be done. From #32785 (comment): From @Vudentz
From @Thalley
|
Beta Was this translation helpful? Give feedback.
-
Some thoughts on APIRequirements, or possible requirements
Or, put another way, like I thought for Media Control:
From talk with @cvinayak (hopefully I understood him correctly):
From talk with @Thalley:
So I propose a system along the lines of what is shown in https://github.com/asbjornsabo/zephyr-bt-sig/blob/api/subsys/bluetooth/host/audio/msc/api_proposal.svg Here, there is
A minimal sample header file for the "middle-man" module with some additional explanation is found in https://github.com/asbjornsabo/zephyr-bt-sig/blob/api/subsys/bluetooth/host/audio/mplc.h This allows multiple functionality instances, and decouples these from the stack. I think that in this proposal, we should be able to follow much of what Emil has been doing for the VCS/VOCS/AICS API, while at the same time adressing my concern for separating the server interface from the functionality and Luiz's wish to be able to handle things outside of the stack. |
Beta Was this translation helpful? Give feedback.
-
Closing as the API has been settled on. |
Beta Was this translation helpful? Give feedback.
Closing as the API has been settled on.