{"id":18188058,"url":"https://github.com/hypfer/fiio-bta30-protocol","last_synced_at":"2026-02-12T08:31:16.916Z","repository":{"id":70162514,"uuid":"494139998","full_name":"Hypfer/fiio-bta30-protocol","owner":"Hypfer","description":"Documentation on the BLE protocol of the FiiO BTA30 DAC \u0026 Bluetooth Transceiver","archived":false,"fork":false,"pushed_at":"2022-05-19T18:13:24.000Z","size":3,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-13T21:44:24.786Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hypfer.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"hypfer","ko_fi":"hypfer"}},"created_at":"2022-05-19T16:02:39.000Z","updated_at":"2024-05-11T12:50:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"f333cdd1-2bfa-4837-a044-635e2baa6770","html_url":"https://github.com/Hypfer/fiio-bta30-protocol","commit_stats":{"total_commits":1,"total_committers":1,"mean_commits":1.0,"dds":0.0,"last_synced_commit":"491d6656af350dece408b7852a272bf754e7eadc"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Hypfer/fiio-bta30-protocol","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypfer%2Ffiio-bta30-protocol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypfer%2Ffiio-bta30-protocol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypfer%2Ffiio-bta30-protocol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypfer%2Ffiio-bta30-protocol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hypfer","download_url":"https://codeload.github.com/Hypfer/fiio-bta30-protocol/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypfer%2Ffiio-bta30-protocol/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29361818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T01:03:07.613Z","status":"online","status_checked_at":"2026-02-12T02:00:06.911Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-03T02:04:30.488Z","updated_at":"2026-02-12T08:31:16.878Z","avatar_url":"https://github.com/Hypfer.png","language":null,"funding_links":["https://github.com/sponsors/hypfer","https://ko-fi.com/hypfer"],"categories":[],"sub_categories":[],"readme":"\n## Motivation\n\nThe FiiO BTA30 is a Hi-Fi-grade DAC and Bluetooth Transceiver, featuring USB-C for Data and Power, RCA analog output and\nalso SPDIF in and out via both TOSLINK and Coax. According to the marketing material, a Qualcomm CSR8675 Bluetooth Chip is used.\n\nWhile it does work out of the box, there are some additional tunables available via the official \"FiiO Control\" Android App.\nThese include things such as the power-on-behaviour, whether the output level should be locked or which codecs should be used.\n\nThe app itself works fine, however it is unclear how long it will stay that way given that it is an Android app.\nThus, here's some documentation on the protocol.\n\nThis may also be adaptable to other similar FiiO devices, however I only have a BTA 30.\n\n## Protocol\n\nThe FiiO BTA 30 uses Bluetooth Low Energy (BLE) for all its configuration needs. As with most BLE appliances,\nthe implementation could be described as _strange_.\n\nIt seems that all FiiO-specific functionality is just piggybacked on top of the generic `Qualcomm CSR102x OTAU` functionality,\nwhich is probably some sample code provided by Qualcomm and it was just easier that way? Who knows.\n\nSaid OTAU characteristic is documented by Qualcomm in a PDF named `csr102x_otau_overview.pdf`, which I won't mirror here\ndue to copyright concerns. At the time of writing, it is available for download off the official Qualcomm servers:\n[https://developer.qualcomm.com/qfile/34081/csr102x_otau_overview.pdf](https://developer.qualcomm.com/qfile/34081/csr102x_otau_overview.pdf)\n\nAs the name suggest, there also seems to be some over-the-air-firmware-update functionality available, however it seems like that doesn't apply to the BTA30 (yet?)\n\nFirware updates would likely be stored somewhere below `http://fiio-bluetooth.oss-cn-beijing.aliyuncs.com/`.\nThere currently (2022-05-19) is a subfolder named BTA30, however it doesn't seem to contain a new firmware image.\n\n### Characteristics\n\nWe have one service with UUID `00001100-d102-11e1-9b23-00025b00a5a5` named `CSR GAIA` according to the Qualcomm docs.\n\nThis service features three characteristics:\n\n1. `00001101-d102-11e1-9b23-00025b00a5a5` (`CSR GAIA Command Endpoint`)\n    Commands will be written to this characteristic\n\n2. `00001102-d102-11e1-9b23-00025b00a5a5` (`CSR GAIA Response Endpoint`)\n    Replies to commands will be provided via this characteristic as notifications.\n    It needs to be subscribed first before any commands are sent\n\n3. `00001103-d102-11e1-9b23-00025b00a5a5` (`CSR GAIA Data Endpoint`)\n    No idea what this does\n\n\n### Commands\n\n#### Requests\n\nCommand requests are written to the `CSR GAIA Command Endpoint` characteristic.\n\nThese consist of at least four bytes but may be longer if there is a payload.\n\nThe first 20 bits are a magic while the next 12 bits contain the command ID.\nAfter that, there may be 0-n bytes of payload.\n\n##### Examples\n\nLet's look at some examples to make this easier.\n\n###### No Payload\n\nThis is an example without any payload\n\n`00 0a 04 3d`\n\n- First, there's the magic: `0x000a0`\n- Then, there's the command: `0x43d`\n\nThat's it.\nCommand `0x43d` is the `GET_LED_OFF` command.\nOn success, you will get the following response: `00 0a 84 3d 00 01`.\nIf your LED_OFF setting is false, then the 0x01 at the end will of course be `0x00`.\n\n###### Payload\n\nHere's an example that features a payload:\n\n`00 0a 04 0b 01`\n\n- First, there's the magic: `0x000a0`\n- Then, there's the command: `0x40b`\n- Finally, there's the payload: `0x01`\n\nCommand `0x41c` is the `Set Boot Mode` command and `0x01` means true.\nOn success, you will get the following response: `00 0a 84 1c 00 01`.\n\n#### Replies\n\nCommand replies are provided via notifications of the `CSR GAIA Response Endpoint` characteristic.\n\nThese consist of at least five bytes but may be longer if there is a payload.\nThe first 20 bits are a magic while the next 12 bits contain the command ID.\nThis is followed by a single null byte. After that, there may be 0-n bytes of payload.\n\n##### Examples\n\nLet's look at some examples to make this easier.\n\n###### No Payload\n\nThis is an example without any payload:\n\n`00 0a 84 25 00`\n\n- First, there's the magic: `0x000a8`\n- Then, there's the command: `0x425`\n- Finally, there's the null byte `0x00`\n\nCommand `0x425` is the `Power Off` command, which just turns of the device.\nHence, there's no need for a payload. The reply confirms the successful receive of the command.\n\n###### Payload\n\nHere's an example that features a payload:\n\n`00 0a 84 1c 00 01`\n\n- First, there's the magic: `0x000a8`\n- Then, there's the command: `0x41c`\n- Then, there's the null byte `0x00`\n- Finally, there's the payload: `0x01`\n\nCommand `0x41c` is the `Boot Mode` command and `0x01` means true.\nThus, this message means that the BTA 30 will turn on as soon as it receives power.\nIf this was `0x00` you'd still have to manually press the power button.\n\n### List of Commands\n\nHere are all available commands. Some of them may be read-only. Others can be written\n\n#### Global Commands\n\n##### Version\n\n**Description:**\u003cbr/\u003e\nThe Device Version + Type\n\n**GET Command**:\u003cbr/\u003e\n0x418\n\n**Response**:\u003cbr/\u003e\n3 Byte\n\n1. Major Version\n2. Minor Version\n3. Device Type (Always `D4` for the BTA30)\n\n\n##### Current Connection Codec\n\n**Description:**\u003cbr/\u003e\nThe Codec used by the current connection\n\n**Command**:\u003cbr/\u003e\n0x416\n\n**Payload**:\u003cbr/\u003e\nOne Byte\n\nDecimal:\n- 0 = A2DP OFF\n- 1 = SBC\n- 3 = AAC\n- 5 = APTX\n- 7 = APTX HD\n- 10 = LDAC\n\n\n\n\n##### Boot Mode\n\n**Description:**\u003cbr/\u003e\nWhether the Device should turn on as soon as it receives power\n\n**GET Command**:\u003cbr/\u003e\n0x41C\n\n**SET Command**:\u003cbr/\u003e\n0x40B\n\n**Payload**:\u003cbr/\u003e\nEither `0x00` or `0x01`\n\n##### LED Mode\n\n**Description:**\u003cbr/\u003e\nWhether the Device LEDs should be on or off\n\n**GET Command**:\u003cbr/\u003e\n0x43D\n\n**SET Command**:\u003cbr/\u003e\n0x43E\n\n**Payload**:\u003cbr/\u003e\nEither `0x00` or `0x01`\n\n##### LED Pattern\n\n**Description:**\u003cbr/\u003e\nWhether the LED flashes red-green or red-blue during connection setup\n\n**GET Command**:\u003cbr/\u003e\n0x44A\n\n**SET Command**:\u003cbr/\u003e\n0x44B\n\n**Payload**:\u003cbr/\u003e\nEither `0x00` for red-green or `0x01` for blue-red\n\n\n##### TX LDAC Quality Setting\n\n**Description:**\u003cbr/\u003e\nFetch the current TX LDAC Quality Setting\n\n**GET Command**:\u003cbr/\u003e\n0x44C\n\n**SET Command**:\u003cbr/\u003e\n0x44D\n\n**Payload**:\u003cbr/\u003e\n1 Byte\n- Audio quality first (`0x01`)\n- Standard (`0x02`)\n- Connection first (`0x03`)\n- Adaptive (`0x04`)\n\n##### SPDIF Volume Adjustment Setting\n\n**Description:**\u003cbr/\u003e\nWhether the SPDIF Output level should be controlled by the volume knob\n\n**GET Command**:\u003cbr/\u003e\n0x452\n\n**SET Command**:\u003cbr/\u003e\n0x453\n\n**Payload**:\u003cbr/\u003e\nEither `0x00` or `0x01`\n\n##### Upsampling Setting\n\n**Description:**\u003cbr/\u003e\nWhether the DAC should upsample the audio data to 384KHz\n\n**GET Command**:\u003cbr/\u003e\n0x450\n\n**SET Command**:\u003cbr/\u003e\n0x451\n\n**Payload**:\u003cbr/\u003e\nEither `0x00` or `0x01`\n\n##### Volume Setting\n\n**Description:**\u003cbr/\u003e\nThe current volume setting.\nThis is usually controlled by the knob on the device.\n\n**GET Command**:\u003cbr/\u003e\n0x412\n\n**SET Command**:\u003cbr/\u003e\n0x402\n\n**Payload**:\u003cbr/\u003e\n1 Byte `0x00`-`0x3C`\nDecimal 0-60\n\n##### DAC Lowpass Setting\n\n**Description:**\u003cbr/\u003e\nThe current DAC lowpass setting\n\n**GET Command**:\u003cbr/\u003e\n0x411\n\n**SET Command**:\u003cbr/\u003e\n0x401\n\n**Payload**:\u003cbr/\u003e\n1 Byte\n- Sharp Roll-Off Filter (`0x00`)\n- Slow Roll-Off Filter (`0x01`)\n- Short Delay Sharp Roll-Off Filter (`0x02`)\n- Short Delay Slow Roll-Off Filter (`0x03`)\n\n##### Output Balance\n\n**Description:**\u003cbr/\u003e\nThe current balance setting.\n\nValues can be between L12 and R12 with 0 being R0 `0x0200`\n\n**GET Command**:\u003cbr/\u003e\n0x413\n\n**SET Command**:\u003cbr/\u003e\n0x403\n\n\n**Payload**:\u003cbr/\u003e\n2 Byte\n1. L (`0x01`) or R (`0x02`)\n2. 0-12 Decimal Left or Right (`0x00`-`0x0C`)\n\n\n##### Name\n\n**Description:**\u003cbr/\u003e\nThe bluetooth name advertised by the device. 30 Bytes UTF-8 max\n\n**GET Command**:\u003cbr/\u003e\n0x445\n\n**SET Command**:\u003cbr/\u003e\n0x446\n\n**Description**:\u003cbr/\u003e\nBecause the name can be up to 30 UTF-8 bytes long, this command behaves a bit differently from the others.\nOne `Set Name` command may consist of up to four writes. You may even use emoji\n\n###### Basic Example SET\n\nThis example contains the short name `Hallo` and therefore needs no splitting as it fits in a single message.\n\n`00 0a 04 46 ff 05 48 61 6c 6c 6f ff`\n\n- First, there's the magic: `0x000a0`\n- Then, there's the command: `0x446`\n- Then, there's the start of payload marker: `0xff`\n- Then, there's the length of the name payload: `0x05`\n- Then, there are the UTF-8 Bytes of `Hallo`: `0x48616c6c6f`\n- Finally, there's the end of payload marker: `0xff`\n\n###### Advanced example SET\n\nThis example contains the 30 character long name `KlausKlausKlausKlausKlausKlaus`, which was split into four messages.\n\n1. `00 0a 04 46 ff 1e 4b 6c 61 75 73 4b 6c 61` - `KlausKla`\n2. `00 0a 04 46 75 73 4b 6c 61 75 73 4b 6c 61` - `usKlausKla`\n2. `00 0a 04 46 75 73 4b 6c 61 75 73 4b 6c 61` - `usKlausKla`\n3. `00 0a 04 46 75 73 ff` - `us`\n\nIn this example, the `0x1e` represents the length of 30 characters.\n\n##### Example GET\n\nThe same logic applies to the get name response. Here, the name is `FiiO BTA30`.\n\n1. `00 0a 04 46 ff 0a 46 69 69 4f 20 42 54 41` - Length: 0x0a (10), `FiiO BTA`\n1. `00 0a 04 46 33 30 ff` - `30`\n\n\n#### Mode-dependant Commands\n\n##### Input Sources\n\n**Description:**\u003cbr/\u003e\nFetch/select which sources are enabled for the mode\n\n**GET Command**:\u003cbr/\u003e\n0x448\n\n**SET Command**:\u003cbr/\u003e\n0x449\n\n**GET Payload**:\u003cbr/\u003e\n1 Byte\n`0x01` for RX, `0x02` for TX\n\n**GET Response/SET Payload**:\u003cbr/\u003e\n2 Bytes\n1. `0x01` for RX, `0x02` for TX\n2. Settings\n    - USB (`0x01`)\n    - Coax (`0x02`)\n    - USB \u0026 Coax (`0x03`)\n\n##### GET Volume Mode\n\n**Description:**\u003cbr/\u003e\nFetch/select the volume mode setting for the mode\n\n**GET Command**:\u003cbr/\u003e\n0x44E\n\n**SET Command**:\u003cbr/\u003e\n0x44F\n\n**GET Payload**:\u003cbr/\u003e\n1 Byte\n`0x01` for RX, `0x02` for TX\n\n**GET Response/SET Payload**:\u003cbr/\u003e\n2 Bytes\n1. `0x01` for RX, `0x02` for TX\n2. Settings\n    - Adjustable (`0x01`)\n    - Fixed at 30% (`0x02`)\n    - Fixed at 50% (`0x03`)\n    - Fixed at 70% (`0x04`)\n    - Fixed at 100% (`0x05`)\n\n##### GET Enabled Codecs\n\n**Description:**\u003cbr/\u003e\nFetch/set the enabled codecs for the mode\nAPTX-LL seems to only be available in TX?\n\n**GET Command**:\u003cbr/\u003e\n0x417\n\n**GET Command**:\u003cbr/\u003e\n0x407\n\n**GET Payload**:\u003cbr/\u003e\n1 Byte\n`0x01` for RX, `0x02` for TX\n\n**GET Response/SET Payload**:\u003cbr/\u003e\n2 Bytes\n1. `0x01` for RX, `0x02` for TX\n2. Sum of supported codecs\n    - AAC (`2`)\n    - LDAC (`4`)\n    - APTX (`8`)\n    - APTX-LL (`16`)\n    - APTX-HD (`32`)\n\n#### Special SET-only commands\n\n##### Factory reset\n\n**Description:**\u003cbr/\u003e\nDoes a factory reset\n\n**Command**:\u003cbr/\u003e\n0x404\n\n**Response**:\u003cbr/\u003e\nNone\n\n##### Power Off\n\n**Description:**\u003cbr/\u003e\nTurns off the BTA30\n\n**Command**:\u003cbr/\u003e\n0x425\n\n**Response**:\u003cbr/\u003e\nNone\n\n##### Clear Pairing\n\n**Description:**\u003cbr/\u003e\nDelete all pairing information from the BTA30\n\n**Command**:\u003cbr/\u003e\n0x443\n\n**Response**:\u003cbr/\u003e\nNone\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypfer%2Ffiio-bta30-protocol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhypfer%2Ffiio-bta30-protocol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypfer%2Ffiio-bta30-protocol/lists"}