Bluetooth Audio Transceiver

Bluetooth Audio Transceiver is an application developed based on Common SDK. It has the capability of Bluetooth, Bluetooth Low Energy, and Audio. The host (external MCU) can communicate with Bluetooth Audio Transceiver through the UART interface. Before introducing the functions of the application, a few terms will first be defined:

  • ACI: Application Controller Interface, the communication interface between the ACI Host and Device.

  • ACI Device: Application Controller Interface Device, the chip that runs the Bluetooth Audio Transceiver application.

  • ACI Host: Application Controller Interface Host, the host can be an external MCU chip or PC, which must support the UART interface.

The objective of this ACI UART Transport Layer is to enable the use of the RTK Vendor Command set over a serial interface between two UARTs. The ACI Device provides common functions, such as power on, power off, factory reset, recording from the local MIC, local playback audio from ACI Host, HFP AG/HF, A2DP Source/Sink, etc.

These features are demonstrated in four different types of demo applications: Bluetooth Audio Transmitter, Bluetooth Audio Receiver, Bluetooth Audio Transceiver, Bluetooth Audio Transmitter MP3, and Bluetooth Audio Intergrated Transceiver. Later sections will detail the features supported by each scenario type and the flowcharts for implementing these features.

Bluetooth Audio Transmitter

The system block diagram shown below consists of 4 parts: Phone, ACI Host, ACI Device, Headset. Different modules use various interfaces to communicate with each other:

  • Phone <-> ACI Device: Communication with Bluetooth/Bluetooth Low Energy.

  • ACI Host <-> ACI Device: Communication with UART.

  • ACI Device <-> Headset: Communication with Bluetooth/Bluetooth Low Energy.

  • MIC is connected to the internal codec.

The ACI Host connects with the ACI Device via the UART interface. Through the RTK Command set, the ACI Host controls the ACI Device into pairing mode, as well as active scanning and pairing with the Headset. In this application, the ACI Device acts as a Bluetooth Low Energy Peripheral. It will advertise and accept Bluetooth Low Energy connect requests from the mobile phone, and the phone can control the ACI Device through the Bluetooth Low Energy connection. The audio data flow is identified by the blue line with arrows.

For the Bluetooth link with the Headset, ACI Device acts as the Source of A2DP or AG of HFP and can play the audio data from MIC, line-in, or I2S to the Headset through the A2DP or SCO link.

Bluetooth Audio Receiver

The system block diagram is shown as follows, consisting of 3 parts: Phone, ACI Host, ACI Device, different modules use various interfaces to communicate with each other:

  • Phone <-> ACI Device: Communication with Bluetooth/Bluetooth Low Energy.

  • ACI Host <-> ACI Device: Communication with UART.

  • ACI Device <-> Headset: Communication with Bluetooth.

  • MIC and SPK are connected to the internal codec.

In this application, ACI Device acts as Bluetooth Low Energy Peripheral, it will advertise and accept Bluetooth Low Energy connect requests from the mobile phone, and the phone can control ACI Device through Bluetooth Low Energy connection. The audio data flow is identified by the blue line with arrows.

For the Bluetooth link with the cell phone, ACI Device acts as the HF role of HFP and A2DP Sink role of A2DP, which can play music and handle phone calls.

Bluetooth Audio Transceiver

The system block diagram is shown as follows, which consists of 5 parts: Phone, ACI Host, ACI Device 1, ACI Device 2, Headset, different modules use various interfaces to communicate with each other:

  • Phone <-> ACI Device 1: Communication with Bluetooth/Bluetooth Low Energy.

  • ACI Host <-> ACI Device 1: Communication with UART.

  • ACI Host <-> ACI Device 2: Communication with UART.

  • ACI Device 1 <-> ACI Device 2: Communication with SPI and GPIO.

  • ACI Device 2 <-> Headset: Communication with Bluetooth/Bluetooth Low Energy.

ACI Device 1 supports A2DP Sink and HFP HF; ACI Device 2 supports A2DP Source and HFP AG. The audio data flow is identified by the blue line with arrows.

  • In A2DP scenario:

    • Audio data are routed as follows: Phone -> ACI Device 1 -> ACI Device 2 -> Headset.

  • In SCO scenario:

    • Downstream voice data are routed as follows: Phone -> ACI Device 1 -> ACI Device 2 -> Headset SPK.

    • Upstream voice data are routed as follows: Headset MIC -> ACI Device 2 -> ACI Device 1 -> Phone.


Bluetooth Audio Transmitter MP3

The system block diagram is shown as follows in the figure below:

The system block diagram is the same as bt_audio_transmitter. The only difference is that the audio data is from ACI Host. The audio data flow is identified by the blue line with arrows.

  • For the ACI Device itself, the audio data received from the ACI Host can not only be played out through the A2DP Source to the Headset but also through the local SPK, similarly, audio data sampled through the ACI Device’s MIC can also be sent to the ACI Host through the ACI.

  • For the Bluetooth link with the Headset, the ACI Device acts as the Source of A2DP and can play the audio data from ACI Host to the Headset through the A2DP link.


Bluetooth Audio Intergrated Transceiver

The system block diagram is shown as follows, which consists of 4 parts: Phone, ACI Host, ACI Device, Headset. different modules use various interfaces to communicate with each other:

  • Phone <-> ACI Device: Communication with Bluetooth;

  • ACI Host <-> ACI Device: Communication with UART;

  • ACI Device <-> Headset: Communication with Bluetooth.

ACI Device supports both A2DP Sink/Source role and HFP HF/AG role. As a feature of this application, ACI Device needs to be connected to Phone and Headset at the same time. The audio data flow is identified by the blue line with arrows.

Requirements

The sample supports the following development kits:

Hardware Platforms

Board Name

Build Target

RTL87x3E HDK

RTL87x3E EVB

bt_audio_trx_4M_lea_dual_bank0
bt_audio_trx_4M_lea_dual_bank1

RTL87x3D HDK

RTL87x3D EVB

bt_audio_trx_16M_lea_dual_bank0
bt_audio_trx_16M_lea_dual_bank1

RTL87x3EP HDK

RTL87x3EP EVB

bt_audio_trx_16M_lea_dual_bank0
bt_audio_trx_16M_lea_dual_bank1

When built for an xxx_4M_xxx or xxx_16M_xxx build target, the sample is configured to build and run with a 4M or 16M flash map.

To quickly set up the development environment, please refer to the detailed instructions provided in Quick Start.

DSP

There are 3 types of images for Common SDK, which are shown below. We just take RTL8763EAU as an example:

  • cs: Common SDK.

  • pipe: Audio Pipe.

  • lea: LE Audio.

  • ull: Ultra Low Latency.

DSP Image Type

Directory

cs_pipe_stereo

bin\rtl87x3e\8763EAU\4M\BANK0.

cs_lea_pipe_stereo

bin\rtl87x3e\8763EAU\4M\DSP_Image\cs_leaaudio_pipe_stereo.

cs_leaaudio_pipe_stereo_ull

bin\rtl87x3e\8763EAU\4M\DSP_Image\cs_leaaudio_pipe_stereo_ull.

The supported function list of each image is listed in the table below:

Function

cs_pipe_stereo

cs_lea_pipe_stereo

cs_leaaudio_pipe_stereo_ull

DSP Share 80K to MCU

Y

N

Y

DSP Voice SPK Algorithm

N

Y

N

LE Audio

N

Y

Y

BIS TX ULL

N

N

Y

CIS TX ULL

N

N

Y

Notification (VP & Ringtone)

Y

Y

N

Playback

Y

Y

N

Record Gain Control

Y

Y

N

Record

Y

Y

Y

Audio (A2DP)

Y

Y

N

Voice (HFP, 1 MIC)

Y

Y

N

Line-in

Y

Y

Y

Audio Pipe

Y

Y

Y

Local Playback

Y

Y

N

MP3 Decode

Y

Y

Y

Configurations

To understand the main function of Bluetooth Audio Transceiver, the application can be categorized into 5 scenarios, which are bt_audio_transmitter, bt_audio_receiver, bt_audio_transceiver, bt_audio_transmitter_mp3, and bt_audio_intergrated_transceiver.

As in the table below, the SDK has demo bins for providing these application scenarios and how to compile to generate these demo bins in the directory: release\board\evb\bt_audio_trx\mdk\rtl87x3e_bt_audio_trx.uvprojx.

Application Scenarios

Demo Bins

Macro Define in app_flags.h

bt_audio_transmitter

app_demo_bin\mdk\bt_audio_trx\bt_audio_transmitter

F_APP_BT_AUDIO_TRANSMITTER_DEMO_SUPPORT

bt_audio_receiver

app_demo_bin\mdk\bt_audio_trx\bt_audio_receiver

F_APP_BT_AUDIO_RECEIVER_DEMO_SUPPORT

bt_audio_transceiver

app_demo_bin\mdk\bt_audio_trx\bt_audio_transceiver

F_APP_BT_AUDIO_TRANSCEIVER_DEMO_SUPPORT

bt_audio_transmitter_mp3

app_demo_bin\mdk\bt_audio_trx\bt_audio_transmitter_mp3

F_APP_BT_AUDIO_TRANSMITTER_MP3_DEMO_SUPPORT

bt_audio_intergrated_transceiver

app_demo_bin\mdk\bt_audio_trx\bt_audio_intergrated_transceiver

F_APP_INTEGRATED_TRANSCEIVER

The directory paths of the above source codes are as follows:

  • bt_audio_transmitter: sample\bt_audio_trx\source_play.

  • bt_audio_receiver: sample\bt_audio_trx\bredr.

  • bt_audio_transceiver: sample\bt_audio_trx\transfer_path.

  • bt_audio_transmitter_mp3: sample\bt_audio_trx\music_playback.

  • bt_audio_intergrated_transceiver: sample\bt_audio_trx\source_play.

DSP Configuration

The supported function list of each image in DSPConfig Tool are listed in the table below:

DSPConfig Tool

Tab

Function Block

cs_pipe_stereo

cs_lea_pipe_stereo

cs_leaaudio_pipe_stereo_ull

Voice

Decode

NR

N

Y

N

HPF

N

Y

N

MB-DRC

N

Y

N

32KHz Process

N

Y

N

EQ

N

Y

N

Fade In/Out

N

Y

N

Comfort Noise

N

Y

N

Digital Gain

Y

Y

N

DAC

N

N

N

Encode

ADC

N

N

N

DC Remover

Y

Y

N

DSP Gain

Y

Y

N

AEC

Y

Y

N

Multi MIC

Y

Y

N

NR/AES

Y

Y

N

HPF

Y

Y

N

MB-DRC

Y

Y

N

EQ

Y

Y

N

32KHz Process

Y

Y

N

Fade In/Out

Y

Y

N

PostGain

Y

Y

N

HW Sidetone

Y

Y

N

Side Tone

Y

Y

N

Record

ADC

N

N

N

DC Remover

N

N

N

DSP Gain

N

N

N

AEC

N

N

N

Multi MIC

N

N

N

NR/AES

N

N

N

HPF

N

N

N

MB-DRC

N

N

N

EQ

N

N

N

32KHz Process

N

N

N

Fade In/Out

N

N

N

PostGain

Y

Y

N

Audio

MB-AGC

Y

Y

N

Parameter EQ

Y

Y

N

Audio Widening

Y

Y

N

Digital Gain

Y

Y

N

Transducer EQ

N

N

N

DAC

N

N

N

Line-in

ADC

N

N

N

MB-AGC

N

N

N

Parameter EQ

N

N

N

Audio Widening

N

N

N

Transducer EQ

N

N

N

DAC

N

N

N

Notification

Default SPK Gain for Ringtone

Y

Y

N

Default SPK Gain for VP

Y

Y

N

Building and Downloading

This sample can be found under sdk\board\evb\bt_audio_trx in SDK folder structure.

Take the project rtl87x3e_bt_audio_trx.uvprojx and demo bin bt_audio_transmitter as an example. To build and run the sample with Keil development environment, follow the steps listed below:

  1. Open the project rtl87x3e_bt_audio_trx.uvprojx.

  2. Set F_APP_BT_AUDIO_TRANSMITTER_DEMO_SUPPORT in app_flasg.h to 1, and other macros below shall be set to 0.

    /**
     *  NOTE: Only one demo support flag shall be set to 1.
     */
    #define F_APP_BT_AUDIO_TRANSMITTER_DEMO_SUPPORT         1
    #define F_APP_BT_AUDIO_RECEIVER_DEMO_SUPPORT            0
    #define F_APP_BT_AUDIO_TRANSCEIVER_DEMO_SUPPORT         0
    #define F_APP_BT_AUDIO_TRANSMITTER_MP3_DEMO_SUPPORT     0
    #define F_APP_CHARGE_CASE_DEMO_SUPPORT                  0
    #define F_APP_DASHBOARD_DEMO_SUPPORT                    0
    
  3. Choose the build target bt_audio_trx_4M_lea_dual_bank0.

  4. Build the target.

    After a successful build, the APP bin file bt_audio_trx_bank0_MP-v0.0.0.0-xxx.bin will be generated in the directory bin\rtl87x3e\flash_4M_dualbank\bank0.

  5. Download the generated APP bin bt_audio_trx_bank0_MP-v0.0.0.0-xxx.bin into EVB board.

  6. Press reset button on the EVB board.

Experimental Verification

After programming the application bin to the EVB board, testing can be done with a Bluetooth headset or a mobile phone, depending on the specific application type of the bin. The following sections introduce the message sequence charts and implementation steps of each application demo bin, which are divided into:

Message Sequence Charts

This chapter shows typical interactions between Application Controller Interface (ACI) commands and events. It focuses on the message sequence charts (MSCs) for the procedures specified in Code Flow. This chapter illustrates only the most useful scenarios; it does not cover all possible alternatives. In all message sequence charts, it is assumed that all events are not masked, so the Controller will not filter out any events. The sequence of messages in these message sequence charts is for illustrative purposes. The messages may be sent in a different order where allowed by the ACI. If any of these charts differ from the text in the ACI Parts, the text in those Parts overrides these charts.

Notation

The notation used in the message sequence charts consists of ovals, elongated hexagons, boxes, lines, and arrows. The vertical lines terminated on the top by a shadow box and at the bottom by a solid oval indicate a protocol entity that resides in a device. MSCs describe interactions between these entities and the states those entities may be in.

The following notations represent interactions and states:

Notation

Description

Oval

Defines the context for the message sequence chart.

Hexagon

Indicates a condition needed to start the transaction below this hexagon. The location and width of the Hexagon indicate which entity or entities make this decision.

Box

Replaces a group of transactions. May indicate a user action, or a procedure in the link layer.

Note

Gives an explanation of an element.

Alt/else

Performs the appropriate action based on the alternative condition.

Loop

Repeats the loop to perform some behavior.

Control Flow

Some message sequences are split into several charts. In these charts, numbers indicate normal or required ordering, and letters represent alternative paths. For example, Step 4 is after Step 3, and Step 5a could be executed instead of Step 5b.

Example MSC

The protocol entities represented in the example illustrate the interactions of two devices named A and B; each device includes a Host and a link layer entity in this example. Other MSCs in this chapter may show the interactions of more than two devices.

Forward Compatibility

Many of the message sequences in this part use ACI Commands or events that have enhanced or extended variants that were added to the specification later than the relevant sequence. Such variants can be related commands or events with different names or commands or events with multiple versions. In some instances, a Host is required to use the new variant rather than the one shown in the MSC. Even when this is not a requirement, Host implementers may prefer to use the newer variants.

In these circumstances, the MSCs have not been rewritten to use newer features but have been left unchanged. In general, the new commands and events will directly replace the old ones, but this is not always the case and readers should not assume it.

Basic Functions

This chapter introduces some basic features, which are supported in various application scenarios. This chapter describes how to use these functions and the flow for testing them, including the MSCs of the ACI Device and ACI Host interaction, and the commands used.

Power On/Off and Factory Reset

Power on, power off, and factory reset functions are introduced in this chapter.

  • Power on state: The execution of any function must ensure that the system is in the power on state.

  • Power off state: The APP layer will do the corresponding processing to make DSP enter a power off state. Since the power on state will enter DLPS mode automatically, the power off state cannot be set.

  • Factory reset: This function can clear Bluetooth pairing information and reset FTL information. This command needs to be executed once after downloading.

Power On

The chip needs to execute the power on command after downloading.

Note

Using ACI Host CLI test may require sending the mmi pwron command multiple times to wake up the chip. This problem will not exist when the ACI Host wakes up the chip through GPIO. When there is no task, the chip in power on state will enter DLPS mode automatically.

The ACI Host CLI CMD for power on is mmi pwron, the corresponding UART CMD packet and tool log are as follows:

Command

Parameters

ACI Host CLI CMD

CMD_MMI = 0x0004

action = MMI_DEV_POWER_ON(0x54)

mmi pwron

2023-01-05 17:40:36,041 INFO: input command: mmi pwron
2023-01-05 17:40:36,041 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 54] name: CMD_MMI
2023-01-05 17:40:36,042 INFO: Packet sendPacket: <<<send packet: AA 0F 04 00 04 00 00 54 95
2023-01-05 17:40:36,046 INFO: AciHostCLI continuously_read: >>>receive packet: AA 02 05 00 00 00 04 00 00 F5
2023-01-05 17:40:36,046 INFO: Parser eventParser: syncWord: AA,seqn: 02,len: 5,opcode: 0000,params: [04 00 00], check_sum: F5
2023-01-05 17:40:36,046 INFO: Parser eventParser: event name: APP_APP_EVENT_ACK
2023-01-05 17:40:36,047 INFO: Parser eventParser: event_id: [04 00]
2023-01-05 17:40:36,047 INFO: Parser eventParser: status: [00]

The chip that has executed the power on command will actively report APP_EVENT_DEVICE_STATE is powered on after reset. The corresponding event packet and tool log are as follows:

Event

Parameters

APP_EVENT_DEVICE_STATE = 0x0007

state = APP_DEVICE_STATE_ON(1)

2023-01-05 17:40:36,078 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 03 00 07 00 01 F2
2023-01-05 17:40:36,078 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 3,opcode: 0007,params: [01], check_sum: F2
2023-01-05 17:40:36,079 INFO: Parser eventParser: event name: APP_EVENT_DEVICE_STATE
2023-01-05 17:40:36,079 INFO: Parser eventParser: device_state: [01]
2023-01-05 17:40:36,080 INFO: Packet sendPacket: <<<send packet: AA 10 05 00 00 00 07 00 00 E4

The corresponding flow chart is as follows:

Power Off

After executing the power off command, the APP layer will do the corresponding processing to make the enter the power down state. The ACI Host CLI CMD for power off is mmi pwroff, the corresponding UART CMD packet and tool log are as follows:

Command

Parameters

ACI Host CLI CMD

CMD_MMI = 0x0004

action = MMI_DEV_POWER_OFF(0x56)

mmi pwroff

2023-01-05 17:42:08,000 INFO: input command: mmi pwroff
2023-01-05 17:42:08,000 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 56] name: CMD_MMI
2023-01-05 17:42:08,001 INFO: Packet sendPacket: <<<send packet: AA 11 04 00 04 00 00 56 91
2023-01-05 17:42:08,013 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 04 00 00 F3
2023-01-05 17:42:08,014 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [04 00 00], check_sum: F3
2023-01-05 17:42:08,014 INFO: Parser eventParser: event name: APP_EVENT_ACK
2023-01-05 17:42:08,014 INFO: Parser eventParser: event_id: [04 00]
2023-01-05 17:42:08,014 INFO: Parser eventParser: status: [00]

The chip will return APP_EVENT_DEVICE_STATE with APP_DEVICE_STATE_OFF_ING to indicate the start of the power off preparation procedure. When the power off preparation procedure is completed, it will report the event of APP_EVENT_DEVICE_STATE with APP_DEVICE_STATE_OFF. The corresponding UART event packet and tool log are as follows:

Event

Parameters

APP_EVENT_DEVICE_STATE = 0x0007

state = APP_DEVICE_STATE_OFF_ING(2)

APP_EVENT_DEVICE_STATE = 0x0007

state = APP_DEVICE_STATE_OFF(0)

2023-01-05 17:42:08,014 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 03 00 07 00 02 EF
2023-01-05 17:42:08,015 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 3,opcode: 0007,params: [02], check_sum: EF
2023-01-05 17:42:08,015 INFO: Parser eventParser: event name: APP_EVENT_DEVICE_STATE
2023-01-05 17:42:08,015 INFO: Parser eventParser: device_state: [02]
2023-01-05 17:42:08,016 INFO: Packet sendPacket: <<<send packet: AA 12 05 00 00 00 07 00 00 E2
2023-01-05 17:42:09,500 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 03 00 07 00 00 F0
2023-01-05 17:42:09,500 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 3,opcode: 0007,params: [00], check_sum: F0
2023-01-05 17:42:09,501 INFO: Parser eventParser: event name: APP_EVENT_DEVICE_STATE
2023-01-05 17:42:09,501 INFO: Parser eventParser: device_state: [00]
2023-01-05 17:42:09,501 INFO: Packet sendPacket: <<<send packet: AA 13 05 00 00 00 07 00 00 E1
2023-01-05 17:42:10,395 ERROR: gap in packets, between 6 and 1 packet before: [170, 6, 3, 0, 7, 0, 0, 240] packet after: [170, 1, 2, 0, 32, 9, 212]
2023-01-05 17:42:10,396 INFO: AciHostCLI continuously_read: >>>receive packet: AA 01 02 00 20 09 D4
2023-01-05 17:42:10,396 INFO: Parser eventParser: syncWord: AA,seqn: 01,len: 2,opcode: 0920,params: [], check_sum: D4
2023-01-05 17:42:10,396 INFO: Parser eventParser: event name: EVENT_BT_READY
2023-01-05 17:42:10,397 INFO: Packet sendPacket: <<<send packet: AA 14 05 00 00 00 20 09 00 BE

The corresponding flow chart is as follows:

Factory Reset

Note

Before executing the factory reset command, it is necessary to ensure that the device is in a power on state. Only after the factory reset is executed, the device can enter DLPS mode. As a result, it needs to be executed once after downloading.

After executing the factory reset command, the device will enter the power off state first, and then enter the power on state automatically.

The ACI Host CLI CMD for factory reset is mmi freset, the corresponding UART CMD packet and tool log are as follows:

Command

Parameters

ACI Host CLI CMD

CMD_MMI = 0x0004

action = MMI_DEV_FACTORY_RESET(0x58)

mmi freset

After the factory reset, the chip will restore from the device state before the factory reset executes.

2023-01-05 17:50:34,629 INFO: input command: mmi freset
2023-01-05 17:50:34,630 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 58] name: CMD_MMI
2023-01-05 17:50:34,631 INFO: Packet sendPacket: <<<send packet: AA 1E 04 00 04 00 00 58 82
2023-01-05 17:50:34,641 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 04 00 00 F3
2023-01-05 17:50:34,642 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [04 00 00], check_sum: F3
2023-01-05 17:50:34,642 INFO: Parser eventParser: event name: APP_EVENT_ACK
2023-01-05 17:50:34,642 INFO: Parser eventParser: event_id: [04 00]
2023-01-05 17:50:34,643 INFO: Parser eventParser: status: [00]
2023-01-05 17:50:34,643 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 03 00 07 00 02 EF
2023-01-05 17:50:34,643 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 3,opcode: 0007,params: [02], check_sum: EF
2023-01-05 17:50:34,644 INFO: Parser eventParser: event name: APP_EVENT_DEVICE_STATE
2023-01-05 17:50:34,644 INFO: Parser eventParser: device_state: [02]
2023-01-05 17:50:34,645 INFO: Packet sendPacket: <<<send packet: AA 1F 05 00 00 00 07 00 00 D5
2023-01-05 17:50:35,153 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 03 00 07 00 00 F0
2023-01-05 17:50:35,154 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 3,opcode: 0007,params: [00], check_sum: F0
2023-01-05 17:50:35,154 INFO: Parser eventParser: event name: APP_EVENT_DEVICE_STATE
2023-01-05 17:50:35,155 INFO: Parser eventParser: device_state: [00]
2023-01-05 17:50:35,155 INFO: Packet sendPacket: <<<send packet: AA 20 05 00 00 00 07 00 00 D4
2023-01-05 17:50:35,675 INFO: AciHostCLI continuously_read: >>>receive packet: AA 01 02 00 20 09 D4
2023-01-05 17:50:35,675 INFO: Parser eventParser: syncWord: AA,seqn: 01,len: 2,opcode: 0920,params: [], check_sum: D4
2023-01-05 17:50:35,675 INFO: Parser eventParser: event name: EVENT_BT_READY
2023-01-05 17:50:35,676 INFO: Packet sendPacket: <<<send packet: AA 07 05 00 00 00 20 09 00 CB

The corresponding flow chart is as follows:

Connection and Linkback Function

This chapter introduces the functions of connecting to phone and connecting to BUD.

Connect to Phone

The function of connecting to the phone is implemented by sending ACI Host CLI CMD.

ACI Host CLI Test: Connect to Phone

Command

Parameters

ACI Host CLI CMD

Description

CMD_XM_SET_MODE = 0x0030

device_mode = BT_DEVICE_MODE_IDLE(0)

mode idle

BR/EDR radio in undiscoverable and unconnectable mode.

CMD_XM_SET_MODE = 0x0030

device_mode =
BT_DEVICE_MODE_DISCOVERABLE(1)

mode inq_scan

BR/EDR radio in discoverable mode.

CMD_XM_SET_MODE = 0x0030

device_mode =
BT_DEVICE_MODE_CONNECTABLE(2)

mode page_scan

BR/EDR radio in connectable mode.

CMD_XM_SET_MODE = 0x0030

device_mode =
BT_DEVICE_MODE_DISCOVERABLE_CONNECTABLE(3)

mode all_enable

BR/EDR radio in discoverable and connectable mode.

CMD_BT_CREATE_CONNECTION = 0x0002

profile_mask, bd_addr

connect phone_sample

It chooses device to connect by inquiry scan result by index, no UART packet.

CMD_XM_USER_CFM_REQ = 0x8013

true = 0x01

btcfm t

Confirm connect request.

When using the connect phone_sample, the bd_addr parameter needs to be changed to the address of the phone.

  1. ACI Host CLI test: Device enters discoverable and connectable mode.

    2023-04-21 17:17:51,030 INFO: input command: mode all_enable
    2023-04-21 17:17:51,031 INFO: Parser cmdParser: cmd opcode: 0030 param: [03] name: CMD_XM_SET_MODE
    2023-04-21 17:17:51,031 INFO: Packet sendPacket: <<<send packet: AA 09 03 00 30 00 03 C1
    2023-04-21 17:17:51,037 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 30 00 00 C7
    2023-04-21 17:17:51,039 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [30 00 00], check_sum: C7
    2023-04-21 17:17:51,044 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-21 17:17:51,045 INFO: Parser eventParser: event_id: [30 00]
    2023-04-21 17:17:51,047 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Pair/connect with phone_sample.

    2023-04-21 17:20:32,106 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 08 00 25 09 41 AF 7B 6C 32 20 9C
    2023-04-21 17:20:32,108 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 8,opcode: 0925,params: [41 AF 7B 6C 32 20], check_sum: 9C
    2023-04-21 17:20:32,108 INFO: Parser eventParser: event name: APP_EVENT_BR_PAIRING_REQ
    2023-04-21 17:20:32,109 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:32,111 INFO: Packet sendPacket: <<<send packet: AA 08 05 00 00 00 25 09 00 C5
    2023-04-21 17:20:32,155 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 0C 00 14 00 01 00 AF 7B 6C 32 20 00 00 00 F1
    2023-04-21 17:20:32,156 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 12,opcode: 0014,params: [01 00 AF 7B 6C 32 20 00 00 00], check_sum: F1
    2023-04-21 17:20:32,158 INFO: Parser eventParser: event name: APP_EVENT_BR_LINK_STATUS
    2023-04-21 17:20:32,165 INFO: Parser eventParser: link_status: [01]
    2023-04-21 17:20:32,166 INFO: Parser eventParser: bd_addr: [00 AF 7B 6C 32 20]
    2023-04-21 17:20:32,167 INFO: Packet sendPacket: <<<send packet: AA 09 05 00 00 00 14 00 00 DE
    2023-04-21 17:20:32,170 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 31 00 09 00 00 41 AF 7B 6C 32 20 47 61 6C 61 78 79 20 41 34 30 73 00 00 00 00 00 00 00 00
    2023-04-21 17:20:32,171 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 49,opcode: 0009,params: [00 41 AF 7B 6C 32 20 47 61 6C 61 78 79 20 41 34 30 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00], check_sum: F8
    2023-04-21 17:20:32,172 INFO: Parser eventParser: event name: APP_EVENT_BR_REMOTE_NAME
    2023-04-21 17:20:32,172 INFO: Parser eventParser: cause: [00]
    2023-04-21 17:20:32,173 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:32,174 INFO: Parser eventParser: name: [47 61 6C 61 78 79 20 41 34 30 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
    2023-04-21 17:20:32,177 INFO: Parser eventParser:  remote_name: Galaxy A40s
    2023-04-21 17:20:32,181 INFO: Packet sendPacket: <<<send packet: AA 0A 05 00 00 00 09 00 00 E8
    2023-04-21 17:20:32,378 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 0C 00 26 09 AC C9 07 00 41 AF 7B 6C 32 20 18
    2023-04-21 17:20:32,379 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 12,opcode: 0926,params: [AC C9 07 00 41 AF 7B 6C 32 20], check_sum: 18
    2023-04-21 17:20:32,381 INFO: Parser eventParser: event name: APP_EVENT_BR_SSP_NUMERIC_VALUE
    2023-04-21 17:20:32,382 INFO: Parser eventParser: display_val: [AC C9 07 00]
    2023-04-21 17:20:32,383 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:32,384 INFO: Packet sendPacket: <<<send packet: AA 0B 05 00 00 00 26 09 00 C1
    2023-04-21 17:20:32,394 INFO: AciHostCLI continuously_read: >>>receive packet: AA 09 0D 00 00 88 41 AF 7B 6C 32 20 AC C9 07 00 00 BD
    2023-04-21 17:20:32,395 INFO: Parser eventParser: syncWord: AA,seqn: 09,len: 13,opcode: 8800,params: [41 AF 7B 6C 32 20 AC C9 07 00 00], check_sum: BD
    2023-04-21 17:20:32,397 INFO: Parser eventParser: event name: EVENT_XM_USER_CONFIRMATION_REQ
    2023-04-21 17:20:32,401 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:32,402 INFO: Parser eventParser: display_val: [AC C9 07 00]
    2023-04-21 17:20:32,403 INFO: Packet sendPacket: <<<send packet: AA 0C 05 00 00 00 00 88 00 67
    
  3. ACI Host CLI test: Confirm connection request.

    2023-04-21 17:20:38,347 INFO: input command: btcfm t
    2023-04-21 17:20:38,348 INFO: Parser cmdParser: cmd opcode: 8013 param: [00 01] name: CMD_XM_USER_CFM_REQ
    2023-04-21 17:20:38,348 INFO: Packet sendPacket: <<<send packet: AA 0D 04 00 13 80 00 01 5B
    2023-04-21 17:20:38,366 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0A 05 00 00 00 13 80 00 5E
    2023-04-21 17:20:38,369 INFO: Parser eventParser: syncWord: AA,seqn: 0A,len: 5,opcode: 0000,params: [13 80 00], check_sum: 5E
    2023-04-21 17:20:38,371 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-21 17:20:38,374 INFO: Parser eventParser: event_id: [13 80]
    2023-04-21 17:20:38,378 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Connection successful.

    2023-04-21 17:20:39,741 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0B 0A 00 03 00 04 41 AF 7B 6C 32 20 01 BA
    2023-04-21 17:20:39,742 INFO: Parser eventParser: syncWord: AA,seqn: 0B,len: 10,opcode: 0003,params: [04 41 AF 7B 6C 32 20 01], check_sum: BA
    2023-04-21 17:20:39,743 INFO: Parser eventParser: event name: APP_EVENT_PROFILE_CONN_STATUS
    2023-04-21 17:20:39,743 INFO: Parser eventParser: profile: [04]
    2023-04-21 17:20:39,743 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:39,744 INFO: Parser eventParser: others: [01]
    2023-04-21 17:20:39,744 INFO: Packet sendPacket: <<<send packet: AA 0E 05 00 00 00 03 00 00 EA
    2023-04-21 17:20:39,949 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0C 09 00 03 00 01 41 AF 7B 6C 32 20 BE
    2023-04-21 17:20:39,950 INFO: Parser eventParser: syncWord: AA,seqn: 0C,len: 9,opcode: 0003,params: [01 41 AF 7B 6C 32 20], check_sum: BE
    2023-04-21 17:20:39,953 INFO: Parser eventParser: event name: APP_EVENT_PROFILE_CONN_STATUS
    2023-04-21 17:20:39,954 INFO: Parser eventParser: profile: [01]
    2023-04-21 17:20:39,966 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:39,968 INFO: Parser eventParser: others: []
    2023-04-21 17:20:39,970 INFO: Packet sendPacket: <<<send packet: AA 0F 05 00 00 00 03 00 00 E9
    2023-04-21 17:20:44,039 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0D 09 00 03 00 02 41 AF 7B 6C 32 20 BC
    2023-04-21 17:20:44,040 INFO: Parser eventParser: syncWord: AA,seqn: 0D,len: 9,opcode: 0003,params: [02 41 AF 7B 6C 32 20], check_sum: BC
    2023-04-21 17:20:44,041 INFO: Parser eventParser: event name: APP_EVENT_PROFILE_CONN_STATUS
    2023-04-21 17:20:44,042 INFO: Parser eventParser: profile: [02]
    2023-04-21 17:20:44,043 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2023-04-21 17:20:44,044 INFO: Parser eventParser: others: []
    2023-04-21 17:20:44,045 INFO: Packet sendPacket: <<<send packet: AA 10 05 00 00 00 03 00 00 E8
    
Connect to BUD

The function of connecting to BUD is implemented by sending ACI Host CLI CMD.

ACI Host CLI Test: Connect to BUD

Command

Parameters

ACI Host CLI CMD

Description

CMD_XM_SET_MODE = 0x0030

device_mode = BT_DEVICE_MODE_IDLE(0)

mode idle

BR/EDR radio in undiscoverable and unconnectable mode.

CMD_XM_SET_MODE = 0x0030

device_mode = BT_DEVICE_MODE_DISCOVERABLE(1)

mode inq_scan

BR/EDR radio in discoverable mode.

CMD_XM_SET_MODE = 0x0030

device_mode = BT_DEVICE_MODE_CONNECTABLE(2)

mode page_scan

BR/EDR radio in connectable mode.

CMD_XM_SET_MODE = 0x0030

device_mode = BT_DEVICE_MODE_DISCOVERABLE_CONNECTABLE(3)

mode all_enable

BR/EDR radio in discoverable and connectable mode.

CMD_BT_CREATE_CONNECTION = 0x0002

profile_mask, bd_addr

connect device

It chooses a device to connect by the inquiry scan result by an index, no UART packet.

CMD_INQUIRY = 0x0321

0x00

inquiry start

Start inquiry.

CMD_BT_CREATE_CONNECTION = 0x0002

None

connect idx

Show devices that can be connected.

CMD_XM_USER_CFM_REQ = 0x8013

true = 0x01

btcfm t

Confirm connect request.

When using the connect headset_sample, the parameter of bd_addr needs to be changed to the address of the BUD.

  1. ACI Host CLI test: Connect to BUD with specific address directly.

    2023-04-23 19:07:07,166 INFO: input command: connect headset_sample
    2023-04-23 19:07:07,170 INFO: Parser cmdParser: cmd opcode: 0002 param: [07 01 00 00 DD CC BB AA 22 12] name: CMD_BT_CREATE_CONNECTION
    2023-04-23 19:07:07,171 INFO: Packet sendPacket: <<<send packet: AA 09 0C 00 02 00 07 01 00 00 DD CC BB AA 22 12 9F
    2023-04-23 19:07:07,183 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 05 00 00 00 02 00 00 F2
    2023-04-23 19:07:07,186 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 5,opcode: 0000,params: [02 00 00], check_sum: F2
    2023-04-23 19:07:07,192 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-23 19:07:07,197 INFO: Parser eventParser: event_id: [02 00]
    2023-04-23 19:07:07,206 INFO: Parser eventParser: status: [00]
    

    In addition to direct connection, BUD can also be connected through the inquiry process.

  2. ACI Host CLI test: BUDs inquiry start.

    2023-04-21 17:26:01,020 INFO: input command: inquiry start
    2023-04-21 17:26:01,021 INFO: Parser cmdParser: cmd opcode: 0321 param: [00 08] name: CMD_INQUIRY
    2023-04-21 17:26:01,021 INFO: Packet sendPacket: <<<send packet: AA 2C 04 00 21 03 00 08 A4
    2023-04-21 17:26:01,027 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 21 03 00 D2
    2023-04-21 17:26:01,028 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [21 03 00], check_sum: D2
    2023-04-21 17:26:01,031 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-21 17:26:01,032 INFO: Parser eventParser: event_id: [21 03]
    2023-04-21 17:26:01,036 INFO: Parser eventParser: status: [00]
    2023-04-21 17:26:01,037 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 03 00 23 09 01 CA
    2023-04-21 17:26:01,037 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 3,opcode: 0923,params: [01], check_sum: CA
    2023-04-21 17:26:01,037 INFO: Parser eventParser: event name: APP_EVENT_BR_INQUIRY_STATE
    2023-04-21 17:26:01,038 INFO: Parser eventParser: inquiry_state: [01]
    2023-04-21 17:26:01,038 INFO: Packet sendPacket: <<<send packet: AA 2D 05 00 00 00 23 09 00 A2
    
  3. ACI Host CLI test: BUDs inquired.

    2023-04-21 17:26:25,514 INFO: AciHostCLI continuously_read: >>>receive packet: AA 09 35 00 29 09 B0 EC 33 E7 50 70 04 84 24 00 0D 4A 42 4C 20 57 41 56 45 20 46 4C 45 58 00 00
    2023-04-21 17:26:25,515 INFO: Parser eventParser: syncWord: AA,seqn: 09,len: 53,opcode: 0929,params: [B0 EC 33 E7 50 70 04 84 24 00 0D 4A 42 4C 20 57 41 56 45 20 46 4C 45 58 00 00 00 00 00 00 00 00], check_sum: E7
    2023-04-21 17:26:25,518 INFO: Parser eventParser: event name: APP_EVENT_BR_INQUIRY_RESULT
    2023-04-21 17:26:25,519 INFO: Parser eventParser: bd_addr: [B0 EC 33 E7 50 70]
    2023-04-21 17:26:25,520 INFO: Parser eventParser: cod: [04 84 24 00]
    2023-04-21 17:26:25,520 INFO: Parser eventParser: name_len: [0D]
    2023-04-21 17:26:25,521 INFO: Parser eventParser: name: [4A 42 4C 20 57 41 56 45 20 46 4C 45 58 00 00 00 00 00 00 00]
    2023-04-21 17:26:25,521 INFO: Parser eventParser: name: JBL WAVE FLEX
    2023-04-21 17:26:25,521 INFO: Packet sendPacket: <<<send packet: AA 30 05 00 00 00 29 09 00 99
    
  4. ACI Host CLI test: Show the device index of BUDs, and enter the index of the device to be connected.

    For example, in the following log, input 1 then enter.

    connect idx
    2023-04-21 17:33:24,158 INFO: Parser cmdParser: device index: 1 bd_addr: B0 EC 33 E7 50 70 cod: 04 84 24 00, name: JBL WAVE FLEX
    1
    
  5. ACI Host CLI test: Confirm connection request.

    Input btcfm t after the event EVENT_XM_USER_CONFIRMATION_REQ.

    2023-04-21 17:33:39,021 INFO: Parser eventParser: event name: EVENT_XM_USER_CONFIRMATION_REQ
    2023-04-21 17:33:39,021 INFO: Parser eventParser: bd_addr: [B0 EC 33 E7 50 70]
    2023-04-21 17:33:39,021 INFO: Parser eventParser: display_val: [31 E2 01 00]
    2023-04-21 17:33:39,021 INFO: Packet sendPacket: <<<send packet: AA 35 05 00 00 00 00 88 00 3E
    btcfm t
    2023-04-21 17:33:41,984 INFO: input command: btcfm t
    2023-04-21 17:33:41,985 INFO: Parser cmdParser: cmd opcode: 8013 param: [00 01] name: CMD_XM_USER_CFM_REQ
    2023-04-21 17:33:41,985 INFO: Packet sendPacket: <<<send packet: AA 36 04 00 13 80 00 01 32
    2023-04-21 17:33:41,991 INFO: AciHostCLI continuously_read: >>>receive packet: AA 33 05 00 00 00 13 80 00 35
    2023-04-21 17:33:41,993 INFO: Parser eventParser: syncWord: AA,seqn: 33,len: 5,opcode: 0000,params: [13 80 00], check_sum: 35
    2023-04-21 17:33:41,996 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-21 17:33:42,000 INFO: Parser eventParser: event_id: [13 80]
    2023-04-21 17:33:42,001 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test: Connect success and linkback.

    The following protocols are established by default: A2DP (0x01), AVRCP (0x02), and HFP (0x04).

    2023-04-21 17:55:49,697 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 09 00 03 00 01 B0 EC 33 E7 50 70 6C
    2023-04-21 17:55:49,699 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 9,opcode: 0003,params: [01 B0 EC 33 E7 50 70], check_sum: 6C
    2023-04-21 17:55:49,699 INFO: Parser eventParser: event name: APP_EVENT_PROFILE_CONN_STATUS
    2023-04-21 17:55:49,700 INFO: Parser eventParser: profile: [01]
    2023-04-21 17:55:49,701 INFO: Parser eventParser: bd_addr: [B0 EC 33 E7 50 70]
    2023-04-21 17:55:49,702 INFO: Parser eventParser: others: []
    2023-04-21 17:55:49,703 INFO: Packet sendPacket: <<<send packet: AA 29 05 00 00 00 03 00 00 CF
    2023-04-21 17:55:49,921 INFO: AciHostCLI continuously_read: >>>receive packet: AA 12 09 00 24 09 00 B0 EC 33 E7 50 70 42
    2023-04-21 17:55:49,921 INFO: Parser eventParser: syncWord: AA,seqn: 12,len: 9,opcode: 0924,params: [00 B0 EC 33 E7 50 70], check_sum: 42
    2023-04-21 17:55:49,923 INFO: Parser eventParser: event name: EVENT_SERVICES_SEARCH_STATE
    2023-04-21 17:55:49,924 INFO: Packet sendPacket: <<<send packet: AA 2A 05 00 00 00 24 09 00 A4
    2023-04-21 17:55:50,033 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 09 00 03 00 02 B0 EC 33 E7 50 70 69
    2023-04-21 17:55:50,035 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 9,opcode: 0003,params: [02 B0 EC 33 E7 50 70], check_sum: 69
    2023-04-21 17:55:50,040 INFO: Parser eventParser: event name: APP_EVENT_PROFILE_CONN_STATUS
    2023-04-21 17:55:50,042 INFO: Parser eventParser: profile: [02]
    2023-04-21 17:55:50,042 INFO: Parser eventParser: bd_addr: [B0 EC 33 E7 50 70]
    2023-04-21 17:55:50,043 INFO: Parser eventParser: others: []
    2023-04-21 17:55:50,043 INFO: Packet sendPacket: <<<send packet: AA 2B 05 00 00 00 03 00 00 CD
    2023-04-21 17:55:50,256 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 09 00 24 09 00 B0 EC 33 E7 50 70 40
    2023-04-21 17:55:50,260 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 9,opcode: 0924,params: [00 B0 EC 33 E7 50 70], check_sum: 40
    2023-04-21 17:55:50,262 INFO: Parser eventParser: event name: EVENT_SERVICES_SEARCH_STATE
    2023-04-21 17:55:50,268 INFO: Packet sendPacket: <<<send packet: AA 2C 05 00 00 00 24 09 00 A2
    2023-04-21 17:55:50,527 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 03 00 36 03 00 AF
    2023-04-21 17:55:50,528 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 3,opcode: 0336,params: [00], check_sum: AF
    2023-04-21 17:55:50,530 INFO: Packet sendPacket: <<<send packet: AA 2D 05 00 00 00 36 03 00 95
    2023-04-21 17:55:50,560 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 0A 00 03 00 04 B0 EC 33 E7 50 70 01 62
    2023-04-21 17:55:50,561 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 10,opcode: 0003,params: [04 B0 EC 33 E7 50 70 01], check_sum: 62
    2023-04-21 17:55:50,565 INFO: Parser eventParser: event name: APP_EVENT_PROFILE_CONN_STATUS
    2023-04-21 17:55:50,572 INFO: Parser eventParser: profile: [04]
    2023-04-21 17:55:50,574 INFO: Parser eventParser: bd_addr: [B0 EC 33 E7 50 70]
    2023-04-21 17:55:50,574 INFO: Parser eventParser: others: [01]
    2023-04-21 17:55:50,574 INFO: Packet sendPacket: <<<send packet: AA 2E 05 00 00 00 03 00 00 CA
    
  7. ACI Host CLI test: Linkback to ACI Device.

    Input mode page_scan to enter connectable mode. In the scenario that needs BUD linkback, please make BUD enters pairing mode, ACI Device will be connected with BUD automatically.

    2023-04-23 19:24:06,535 INFO: input command: mode page_scan
    2023-04-23 19:24:06,538 INFO: Parser cmdParser: cmd opcode: 0030 param: [02] name: CMD_XM_SET_MODE
    2023-04-23 19:24:06,544 INFO: Packet sendPacket: <<<send packet: AA 0C 03 00 30 00 02 BF
    2023-04-23 19:24:06,553 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0A 05 00 00 00 30 00 00 C1
    2023-04-23 19:24:06,565 INFO: Parser eventParser: syncWord: AA,seqn: 0A,len: 5,opcode: 0000,params: [30 00 00], check_sum: C1
    2023-04-23 19:24:06,576 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-23 19:24:06,585 INFO: Parser eventParser: event_id: [30 00]
    2023-04-23 19:24:06,589 INFO: Parser eventParser: status: [00]
    

Bluetooth Low Energy Function

The ACI Device can act as a Central, scanning surrounding advertisements and initiating connections, and can also operate as a Peripheral, broadcasting and accepting connections.

For the Central role, it typically uses the following commands.

Command

Parameters

ACI Host CLI
CMD

Description

CMD_LE_START_SCAN = 0x0103

local_addr_type, phys, filter_policy, filter_duplicates, scan_type_1M, scan_interval_1M, scan_window_1M, scan_type_Coded, scan_interval_Coded, scan_window_Coded,

le start_scan

Start scanning.

CMD_LE_STOP_SCAN = 0x0104

None

le stop_scan

Stop scanning.

CMD_LE_CREATE_CONN = 0x010E

None

le conn_idx

Show scan list and enter device index to initiate a connection.

CMD_LE_CREATE_CONN = 0x010E

init_phys, remote_bd_type, remote_bd[6], local_bd_type, scan_timeout

connect_sample

Initiate a connection to the specific device.

CMD_LE_START_PAIR = 0x0109

link_id

le start_pair_dev1

Pair with the specific device.

For the Peripheral role, these commands are commonly required.

Command

Parameters

ACI Host CLI
CMD

Description

CMD_XM_LE_ADV_CREATE = 0x804B

adv_data(arbitrary value), adv_prop, interval_min, interval_max, owner_addr_type, owner_addr, peer_addr_type, peer_addr, adv_data_len, adv_data, scan_rsp_len, scan_rsp

le adv_create

Create LE ADV with params.

CMD_XM_LE_START_ADVERTISING = 0x8040

adv_interval

le advstart

Start LE ADV with a handle.

CMD_XM_LE_STOP_ADVERTISING = 0x8041

adv_interval

le advstop

Stop LE ADV with a handle.

CMD_XM_LE_ADV_DATA_UPDATE = 0x8044

adv_handle, adv_len, adv_data

le adv_data

Update ADV data for preset LE ADV.

CMD_XM_LE_SCAN_RSP_DATA_UPDATE = 0x8045

adv_handle, scan_rsp_len = 0x001F, scan_rsp

le scan_rsp_data

Update scan rsp for preset LE ADV.

CMD_XM_LE_ADV_INTVAL_UPDATE = 0x8046

adv_handle, adv_interval = 0x0320

le adv500ms

It chooses the device to connect with inquiry scan result by an index, no UART packet.

CMD_XM_LE_USER_CFM_REQ = 0x8049

link_id, action = true

lecfm t

Accept pairing request.

CMD_XM_LE_USER_CFM_REQ = 0x8049

link_id, action = false

lecfm f

Reject pairing request.

Once a connection is established, connection parameters can be updated, data can be transferred, and the connection can be disconnected among other operations.

Command

Parameters

ACI Host CLI
CMD

Description

CMD_XM_LE_DISC = 0x8042

app_link_id

le disconn

Disconnect phone with profile and address.

CMD_XM_LE_CONN_PARAM_UPDATE = 0x8043

app_link_id, conn_interval = 0x0050, latency = 0x0000, supervision_tout = 0x01F4

le conn_param

ConnInterval is 0x50 * 1.25 = 100ms,
latency = 0, supTimeout = 0x1F4 * 10ms = 5s.

CMD_XM_LE_ATT_GET_MTU = 0x8047

app_link_id

le mtu

Get the MTU for the le link with app_link_id.

CMD_LE_DATA_TRANSFER = 0x0102

app_link_id, pkt_type=PKT_TYPE_SINGLE(0x00), total_len, pkt_len, payload

le send1

An example for GATT service data transfer.

Additionally, the ACI Device supports features such as the use of a white list, a resolving list, and resolution capabilities.

Command

Parameters

ACI Host CLI
CMD

Description

CMD_LE_MODIFY_WHITELIST = 0x0161

opcode = GAP_WHITE_LIST_OP_CLEAR

whitelist clr_sample

Clear the white list.

CMD_LE_MODIFY_WHITELIST = 0x0161

opcode = GAP_WHITE_LIST_OP_ADD,
bd_addr

whitelist add_sample

Add a device to white list.

CMD_LE_MODIFY_WHITELIST = 0x0161

opcode = GAP_WHITE_LIST_OP_REMOVE,
bd_addr

whitelist rmv_sample

Remove a device from white list.

CMD_LE_MODIFY_WHITELIST_BY_IDX= 0x0162

opcode, device_idx

whitelist_id add_idx0

Add the first device stored in the bond list to the white list.

CMD_LE_MODIFY_WHITELIST_BY_IDX= 0x0162

opcode, device_idx

whitelist_id rmv_idx0

Remove the first device stored in the bond list from the white list.

CMD_LE_MODIFY_RESOLVELIST_BY_IDX= 0x0163

opcode, device_idx

resolvlist_id add_idx0

Add the first device stored in the bond list to the resolving list.

CMD_LE_MODIFY_RESOLVELIST_BY_IDX= 0x0163

opcode, device_idx

resolvlist_id rmv_idx0

Remove the first device stored in the bond list from the resolving list.

CMD_LE_SET_RESOLUTION = 0x0164

operation

le_resolution enable/le_resolution disable

Enable/disable resolution.

ACI Host CLI Test: Advertising

Start advertising with le adv_create and le advstart. Meanwhile, be sure that EVB is in power on mode.

le adv_create
2023-04-25 15:13:40,814 INFO: input command: le adv_create
2023-04-25 15:13:40,816 INFO: Parser cmdParser: cmd opcode: 804B param: [00 13 20 00 20 00 01 59 27 EF 53 9D FC 01 11 33 11 66 55 66 0A 00 03 16 95 FE 05 09 41 41 41 41] name: CMD_XM_LE_ADV_CREATE
2023-04-25 15:13:40,818 INFO: Packet sendPacket: <<<send packet: AA 01 2A 00 4B 80 00 13 20 00 20 00 01 59 27 EF 53 9D FC 01 11 33 11 66 55 66 0A 00 03 16 95 FE
2023-04-25 15:13:40,831 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 4B 80 00 6C
2023-04-25 15:13:40,838 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [4B 80 00], check_sum: 6C
2023-04-25 15:13:40,840 INFO: Parser eventParser: event name: APP_EVENT_ACK
2023-04-25 15:13:40,841 INFO: Parser eventParser: event_id: [4B 80]
2023-04-25 15:13:40,843 INFO: Parser eventParser: status: [00]
2023-04-25 15:13:40,844 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 03 00 08 81 00 70
2023-04-25 15:13:40,845 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 3,opcode: 8108,params: [00], check_sum: 70
2023-04-25 15:13:40,846 INFO: Parser eventParser: event name: EVENT_XM_LE_ADV_CREATED
2023-04-25 15:13:40,847 INFO: Parser eventParser: handle: [00]
2023-04-25 15:13:40,853 INFO: Packet sendPacket: <<<send packet: AA 02 05 00 00 00 08 81 00 70
le advstart
2023-04-25 16:57:57,670 INFO: input command: le advstart
2023-04-25 16:57:57,671 INFO: Parser cmdParser: cmd opcode: 8040 param: [00 78 00] name: CMD_XM_LE_START_ADVERTISING
2023-04-25 16:57:57,672 INFO: Packet sendPacket: <<<send packet: AA 1B 05 00 40 80 00 78 00 E7
2023-04-25 16:57:57,684 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0E 05 00 40 80 00 01 00 6B
2023-04-25 16:57:57,685 INFO: Parser eventParser: syncWord: AA,seqn: 0E,len: 5,opcode: 8040,params: [00 01 00], check_sum: 6B
2023-04-25 16:57:57,686 INFO: Parser eventParser: event name: EVENT_XM_LE_ADV_STATE
2023-04-25 16:57:57,686 INFO: Parser eventParser: adv_state: [00]
2023-04-25 16:57:57,687 INFO: Parser eventParser: stop_cause: [01]
2023-04-25 16:57:57,687 INFO: Packet sendPacket: <<<send packet: AA 1C 05 00 00 00 40 80 00 5E
2023-04-25 16:57:57,700 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0F 05 00 00 00 40 80 00 6B
2023-04-25 16:57:57,701 INFO: Parser eventParser: syncWord: AA,seqn: 0F,len: 5,opcode: 0000,params: [40 80 00], check_sum: 6B
2023-04-25 16:57:57,702 INFO: Parser eventParser: event name: APP_EVENT_ACK
2023-04-25 16:57:57,703 INFO: Parser eventParser: event_id: [40 80]
2023-04-25 16:57:57,703 INFO: Parser eventParser: status: [00]
ACI Host CLI Test: Connection Establishment

If a Central device (such as a mobile phone) establishes a connection with the ACI Device (operating as a Peripheral), or if the ACI Device (operating as a Central) establishes a connection with a Peripheral device (such as a headphone), the ACI Device will report the APP_EVENT_LE_CONNECTED.

2023-04-25 16:58:35,969 INFO: AciHostCLI continuously_read: >>>receive packet: AA 10 05 00 40 80 00 00 02 68
2023-04-25 16:58:35,969 INFO: Parser eventParser: syncWord: AA,seqn: 10,len: 5,opcode: 8100,params: [00 00 02], check_sum: 68
2023-04-25 16:58:35,970 INFO: Parser eventParser: event name: EVENT_XM_LE_ADV_STATE
2023-04-25 16:58:35,970 INFO: Parser eventParser: adv_state: [00]
2023-04-25 16:58:35,971 INFO: Parser eventParser: stop_cause: [00]
2023-04-25 16:58:35,971 INFO: Packet sendPacket: <<<send packet: AA 1D 05 00 00 00 00 81 00 5D
2023-04-25 16:58:35,985 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 03 00 00 01 00 EB
2023-04-25 16:58:35,985 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 3,opcode: 0100,params: [00], check_sum: EB
2023-04-25 16:58:35,986 INFO: Parser eventParser: event name: APP_EVENT_LE_CONNECTED
2023-04-25 16:58:35,986 INFO: Parser eventParser: link_id: [00]
2023-04-25 16:58:35,987 INFO: Packet sendPacket: <<<send packet: AA 1E 05 00 00 00 00 01 00 DC
2023-04-25 16:58:36,001 INFO: AciHostCLI continuously_read: >>>receive packet: AA 12 14 00 03 81 02 00 0D 00 02 01 D3 27 0A 2B 27 53 24 00 00 00 F4 01 82
2023-04-25 16:58:36,002 INFO: Parser eventParser: syncWord: AA,seqn: 12,len: 20,opcode: 8103,params: [02 00 0D 00 02 01 D3 27 0A 2B 27 53 24 00 00 00 F4 01], check_sum: 82
2023-04-25 16:58:36,002 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_STATE
2023-04-25 16:58:36,002 INFO: Parser eventParser: link_state: [02]
2023-04-25 16:58:36,003 INFO: Parser eventParser: app_link_id: [00]
2023-04-25 16:58:36,003 INFO: Parser eventParser: conn_handle: [0D 00]
2023-04-25 16:58:36,004 INFO: Parser eventParser: role: [02]
2023-04-25 16:58:36,577 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 0A 00 04 81 00 00 06 00 00 00 F4 01 62
2023-04-25 16:58:36,578 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 10,opcode: 8104,params: [00 00 06 00 00 00 F4 01], check_sum: 62
2023-04-25 16:58:36,579 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
2023-04-25 16:58:36,579 INFO: Parser eventParser: app_link_id: [00]
2023-04-25 16:58:36,580 INFO: Parser eventParser: res: [00]
2023-04-25 16:58:36,580 INFO: Parser eventParser: connInterval: [06 00]
2023-04-25 16:58:36,581 INFO: Parser eventParser: connLatency: [00 00]
2023-04-25 16:58:36,581 INFO: Parser eventParser: supTimeout: [F4 01]
2023-04-25 16:58:36,581 INFO: Packet sendPacket: <<<send packet: AA 21 05 00 00 00 04 81 00 55
2023-04-25 16:58:36,880 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 0A 00 04 81 00 00 24 00 00 00 F4 01 43
2023-04-25 16:58:36,881 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 10,opcode: 8104,params: [00 00 24 00 00 00 F4 01], check_sum: 43
2023-04-25 16:58:36,882 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
2023-04-25 16:58:36,882 INFO: Parser eventParser: app_link_id: [00]
2023-04-25 16:58:36,883 INFO: Parser eventParser: res: [00]
2023-04-25 16:58:36,883 INFO: Parser eventParser: connInterval: [24 00]
2023-04-25 16:58:36,883 INFO: Parser eventParser: connLatency: [00 00]
2023-04-25 16:58:36,884 INFO: Parser eventParser: supTimeout: [F4 01]
2023-04-25 16:58:36,885 INFO: Packet sendPacket: <<<send packet: AA 22 05 00 00 00 04 81 00 54
ACI Host CLI Test: Data Transfer

Phone should subscript notification with UUID 0xFD04. If pairing needed (EVENT_XM_LE_USER_CONFIRMATION_REQ), input lecfm t to confirm the pairing authorization.

lecfm t
2023-04-25 17:15:25,084 INFO: input command: lecfm t
2023-04-25 17:15:25,085 INFO: Parser cmdParser: cmd opcode: 8049 param: [00 01] name: CMD_XM_LE_USER_CFM_REQ
2023-04-25 17:15:25,086 INFO: Packet sendPacket: <<<send packet: AA 13 04 00 49 80 00 01 5E
2023-04-25 17:15:25,091 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0F 05 00 00 00 49 80 00 62
2023-04-25 17:15:25,093 INFO: Parser eventParser: syncWord: AA,seqn: 0F,len: 5,opcode: 0000,params: [49 80 00], check_sum: 62
2023-04-25 17:15:25,096 INFO: Parser eventParser: event name: APP_EVENT_ACK
2023-04-25 17:15:25,097 INFO: Parser eventParser: event_id: [49 80]
2023-04-25 17:15:25,097 INFO: Parser eventParser: status: [00]
2023-04-25 17:15:28,494 INFO: AciHostCLI continuously_read: >>>receive packet: AA 10 0B 00 02 01 00 00 00 22 75 9A C6 3D 50 5E
2023-04-25 17:15:28,495 INFO: Parser eventParser: syncWord: AA,seqn: 10,len: 11,opcode: 0102,params: [00 00 00 22 75 9A C6 3D 50], check_sum: 5E
2023-04-25 17:15:28,496 INFO: Parser eventParser: event name: APP_EVENT_LE_PAIR_STATUS
2023-04-25 17:15:28,496 INFO: Parser eventParser: link_id: [00]
2023-04-25 17:15:28,497 INFO: Parser eventParser: cause: [00 00]
2023-04-25 17:15:28,497 INFO: Parser eventParser: resolved_addr: [22 75 9A C6 3D 50]
2023-04-25 17:15:28,498 INFO: Packet sendPacket: <<<send packet: AA 14 05 00 00 00 02 01 00 E4
2023-04-25 17:15:29,070 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 0B 00 06 30 0D 00 04 00 00 02 00 02 00 99
2023-04-25 17:15:29,071 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 11,opcode: 3006,params: [0D 00 04 00 00 02 00 02 00], check_sum: 99
2023-04-25 17:15:29,072 INFO: Packet sendPacket: <<<send packet: AA 15 05 00 00 00 06 30 00 B0

Then le send1 can send data 0x01 0x34 0x56.

le send1
2023-04-25 17:05:50,644 INFO: input command: le send1
2023-04-25 17:05:50,645 INFO: Parser cmdParser: cmd opcode: 0102 param: [00 00 03 00 03 00 01 34 56] name: CMD_LE_DATA_TRANSFER
2023-04-25 17:05:50,646 INFO: Packet sendPacket: <<<send packet: AA 31 0B 00 02 01 00 00 03 00 03 00 01 34 56 30
2023-04-25 17:05:50,659 INFO: AciHostCLI continuously_read: >>>receive packet: AA 24 05 00 00 00 02 01 00 D4
2023-04-25 17:05:50,660 INFO: Parser eventParser: syncWord: AA,seqn: 24,len: 5,opcode: 0000,params: [02 01 00], check_sum: D4
2023-04-25 17:05:50,660 INFO: Parser eventParser: event name: APP_EVENT_ACK
2023-04-25 17:05:50,661 INFO: Parser eventParser: event_id: [02 01]
2023-04-25 17:05:50,661 INFO: Parser eventParser: status: [00]
ACI Host CLI Test: Scan Devices

The ACI Device currently supports two scan commands: CMD_LE_START_SCAN and CMD_LEA_SCAN. These are used to scan all LE devices and devices that support LE Audio respectively. This chapter introduces the CMD_LE_START_SCAN command. For information on the CMD_LEA_SCAN command, please refer to chapter Initiator General ACI Host CLI Test. Please note, after scanning the devices, both commands report information through the EVENT_LE_AUDIO_SCAN_INFO event.

2024-05-20 10:34:10,712 INFO: input command: le start_scan
2024-05-20 10:34:10,713 INFO: Parser cmdParser: cmd opcode: 0103 param: [00 01 00 01 01 90 01 C8 00 01 90 01 C8 00] name: CMD_LE_START_SCAN
2024-05-20 10:34:10,713 INFO: Packet sendPacket: <<<send packet: AA 0A 10 00 03 01 00 01 00 01 01 90 01 C8 00 01 90 01 C8 00 2C
2024-05-20 10:34:10,793 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 03 01 00 F4
2024-05-20 10:34:10,793 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [03 01 00], check_sum: F4
2024-05-20 10:34:10,794 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 10:34:10,794 INFO: Parser eventParser: event_id: [03 01]
2024-05-20 10:34:10,796 INFO: Parser eventParser: status: [00]
2024-05-20 10:34:10,825 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 34 00 40 01 13 00 01 0A B2 8E 26 D5 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2024-05-20 10:34:10,826 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 52,opcode: 0140,params: [13 00 01 0A B2 8E 26 D5 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00], check_sum: C6
2024-05-20 10:34:10,827 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
2024-05-20 10:34:10,828 INFO: Parser eventParser: event_type: [13 00]
2024-05-20 10:34:10,828 INFO: Parser eventParser: addr_type: [01]
2024-05-20 10:34:10,829 INFO: Parser eventParser: addr: [0A B2 8E 26 D5 68]
2024-05-20 10:34:10,830 INFO: Parser eventParser: name_len: [00]
2024-05-20 10:34:10,830 INFO: Parser eventParser: name: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
2024-05-20 10:34:10,831 INFO: Parser eventParser: name:
2024-05-20 10:34:10,831 INFO: Packet sendPacket: <<<send packet: AA 0B 05 00 00 00 40 01 00 AF
2024-05-20 10:34:10,841 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 34 00 40 01 10 00 01 10 EF E9 32 1D C9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2024-05-20 10:34:10,842 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 52,opcode: 0140,params: [10 00 01 10 EF E9 32 1D C9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00], check_sum: 75
2024-05-20 10:34:10,843 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
2024-05-20 10:34:10,843 INFO: Parser eventParser: event_type: [10 00]
2024-05-20 10:34:10,844 INFO: Parser eventParser: addr_type: [01]
2024-05-20 10:34:10,847 INFO: Parser eventParser: addr: [10 EF E9 32 1D C9]
2024-05-20 10:34:10,848 INFO: Parser eventParser: name_len: [00]
2024-05-20 10:34:10,849 INFO: Parser eventParser: name: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
2024-05-20 10:34:10,849 INFO: Parser eventParser: name:
2024-05-20 10:34:10,851 INFO: Packet sendPacket: <<<send packet: AA 0C 05 00 00 00 40 01 00 AE
2024-05-20 10:34:10,857 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 34 00 40 01 10 00 01 01 53 93 7A F1 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2024-05-20 10:34:10,857 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 52,opcode: 0140,params: [10 00 01 01 53 93 7A F1 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00], check_sum: 1E
2024-05-20 10:34:10,858 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
2024-05-20 10:34:10,859 INFO: Parser eventParser: event_type: [10 00]
2024-05-20 10:34:10,860 INFO: Parser eventParser: addr_type: [01]
2024-05-20 10:34:10,860 INFO: Parser eventParser: addr: [01 53 93 7A F1 04]
2024-05-20 10:34:10,861 INFO: Parser eventParser: name_len: [00]
2024-05-20 10:34:10,861 INFO: Parser eventParser: name: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
2024-05-20 10:34:10,862 INFO: Parser eventParser: name:
2024-05-20 10:34:10,862 INFO: Packet sendPacket: <<<send packet: AA 0D 05 00 00 00 40 01 00 AD
2024-05-20 10:34:10,873 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 34 00 40 01 10 00 01 1F 86 5A 27 51 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2024-05-20 10:34:10,874 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 52,opcode: 0140,params: [10 00 01 1F 86 5A 27 51 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00], check_sum: C8
2024-05-20 10:34:10,874 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
2024-05-20 10:34:10,875 INFO: Parser eventParser: event_type: [10 00]
2024-05-20 10:34:10,876 INFO: Parser eventParser: addr_type: [01]
2024-05-20 10:34:10,876 INFO: Parser eventParser: addr: [1F 86 5A 27 51 34]
2024-05-20 10:34:10,877 INFO: Parser eventParser: name_len: [00]
2024-05-20 10:34:10,877 INFO: Parser eventParser: name: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
2024-05-20 10:34:10,878 INFO: Parser eventParser: name:
2024-05-20 10:34:10,879 INFO: Packet sendPacket: <<<send packet: AA 0E 05 00 00 00 40 01 00 AC
2024-05-20 10:34:10,889 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 34 00 40 01 01 00 00 01 23 15 DD AA DD 0F 38 37 37 33 45 53 4C 5F 64 61 6E 6E 69 5F 52 00
2024-05-20 10:34:10,890 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 52,opcode: 0140,params: [01 00 00 01 23 15 DD AA DD 0F 38 37 37 33 45 53 4C 5F 64 61 6E 6E 69 5F 52 00 00 00 00 00 00 00], check_sum: FF
2024-05-20 10:34:10,890 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
2024-05-20 10:34:10,891 INFO: Parser eventParser: event_type: [01 00]
2024-05-20 10:34:10,892 INFO: Parser eventParser: addr_type: [00]
2024-05-20 10:34:10,893 INFO: Parser eventParser: addr: [01 23 15 DD AA DD]
2024-05-20 10:34:10,894 INFO: Parser eventParser: name_len: [0F]
2024-05-20 10:34:10,895 INFO: Parser eventParser: name: [38 37 37 33 45 53 4C 5F 64 61 6E 6E 69 5F 52 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
2024-05-20 10:34:10,895 INFO: Parser eventParser: name: 8773ESL_danni_R
ACI Host CLI Test: Initiate Connection

By entering the le conn_idx command, it is possible to list all scanned devices on the ACI Host CLI Tool. After entering the index of the device to connect with, the ACI Device will initiate a connection with that device, as well as automatically pair and discover services. The initiation of a connection is actually triggered through the CMD_LE_CREATE_CONN command.

2024-05-20 10:34:22,119 INFO: input command: le conn_idx
2024-05-20 10:34:22,119 INFO: Parser cmdParser: device index: 0 addr_type 1 bd_addr: 0A B2 8E 26 D5 68 , name:
2024-05-20 10:34:22,120 INFO: Parser cmdParser: device index: 1 addr_type 1 bd_addr: 10 EF E9 32 1D C9 , name:
2024-05-20 10:34:22,120 INFO: Parser cmdParser: device index: 2 addr_type 1 bd_addr: 01 53 93 7A F1 04 , name:
2024-05-20 10:34:22,121 INFO: Parser cmdParser: device index: 3 addr_type 1 bd_addr: 1F 86 5A 27 51 34 , name:
2024-05-20 10:34:22,122 INFO: Parser cmdParser: device index: 4 addr_type 0 bd_addr: 01 23 15 DD AA DD , name: 8773ESL_danni_R

2024-05-20 10:34:43,692 INFO: Parser cmdParser: input dev_index: 4
2024-05-20 10:34:43,693 INFO: Parser cmdParser: cmd opcode: 010E param: [03 00 01 23 15 DD AA DD 00 E8 03] name: CMD_LE_CREATE_CONN
2024-05-20 10:34:43,694 INFO: Packet sendPacket: <<<send packet: AA AB 0D 00 0E 01 03 00 01 23 15 DD AA DD 00 E8 03 AE
2024-05-20 10:34:44,109 INFO: AciHostCLI continuously_read: >>>receive packet: AA D4 05 00 00 00 0E 01 00 18
2024-05-20 10:34:44,110 INFO: Parser eventParser: syncWord: AA,seqn: D4,len: 5,opcode: 0000,params: [0E 01 00], check_sum: 18
2024-05-20 10:34:44,110 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 10:34:44,111 INFO: Parser eventParser: event_id: [0E 01]
2024-05-20 10:34:44,111 INFO: Parser eventParser: status: [00]
2024-05-20 10:34:44,125 INFO: AciHostCLI continuously_read: >>>receive packet: AA D5 05 00 07 01 00 02 02 1A
2024-05-20 10:34:44,128 INFO: Parser eventParser: syncWord: AA,seqn: D5,len: 5,opcode: 0107,params: [00 02 02], check_sum: 1A
2024-05-20 10:34:44,131 INFO: Parser eventParser: event name: EVENT_LE_PHY_UPD
2024-05-20 10:34:44,134 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:44,135 INFO: Parser eventParser: tx_phy: [02]
2024-05-20 10:34:44,135 INFO: Parser eventParser: rx_phy: [02]
2024-05-20 10:34:44,136 INFO: Packet sendPacket: <<<send packet: AA AC 05 00 00 00 07 01 00 47
2024-05-20 10:34:44,141 INFO: AciHostCLI continuously_read: >>>receive packet: AA D6 03 00 00 01 00 26
2024-05-20 10:34:44,144 INFO: Parser eventParser: syncWord: AA,seqn: D6,len: 3,opcode: 0100,params: [00], check_sum: 26
2024-05-20 10:34:44,145 INFO: Parser eventParser: event name: APP_EVENT_LE_CONNECTED
2024-05-20 10:34:44,146 INFO: Parser eventParser: link_id: [00]
2024-05-20 10:34:44,146 INFO: Packet sendPacket: <<<send packet: AA AD 05 00 00 00 00 01 00 4D
2024-05-20 10:34:44,157 INFO: AciHostCLI continuously_read: >>>receive packet: AA D7 14 00 43 80 02 00 05 00 01 00 01 23 15 DD AA DD 18 00 00 00 F4 01 A0
2024-05-20 10:34:44,159 INFO: Parser eventParser: syncWord: AA,seqn: D7,len: 20,opcode: 8043,params: [02 00 05 00 01 00 01 23 15 DD AA DD 18 00 00 00 F4 01], check_sum: A0
2024-05-20 10:34:44,161 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_STATE
2024-05-20 10:34:44,162 INFO: Parser eventParser: link_state: [02]
2024-05-20 10:34:44,163 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:44,166 INFO: Parser eventParser: conn_handle: [05 00]
2024-05-20 10:34:44,167 INFO: Parser eventParser: role: [01]
2024-05-20 10:34:44,167 INFO: Parser eventParser: remote addr type: [00]
2024-05-20 10:34:44,168 INFO: Parser eventParser: remote addr: [01 23 15 DD AA DD]
2024-05-20 10:34:44,168 INFO: Parser eventParser: connInterval: [18 00]
2024-05-20 10:34:44,170 INFO: Parser eventParser: connLatency: [00 00]
2024-05-20 10:34:44,171 INFO: Parser eventParser: supTimeout: [F4 01]
2024-05-20 10:34:44,174 INFO: Packet sendPacket: <<<send packet: AA AE 05 00 00 00 43 80 00 8A
2024-05-20 10:34:44,189 INFO: AciHostCLI continuously_read: >>>receive packet: AA D8 05 00 41 80 00 F4 00 6E
2024-05-20 10:34:44,191 INFO: Parser eventParser: syncWord: AA,seqn: D8,len: 5,opcode: 8041,params: [00 F4 00], check_sum: 6E
2024-05-20 10:34:44,194 INFO: Parser eventParser: event name: EVENT_XM_LE_MTU
2024-05-20 10:34:44,196 INFO: Parser eventParser: mtu_size: [00 F4]
2024-05-20 10:34:44,200 INFO: Packet sendPacket: <<<send packet: AA AF 05 00 00 00 41 80 00 8B
2024-05-20 10:34:44,237 INFO: AciHostCLI continuously_read: >>>receive packet: AA D9 0B 00 06 01 00 FB 00 28 04 FB 00 28 04 C7
2024-05-20 10:34:44,238 INFO: Parser eventParser: syncWord: AA,seqn: D9,len: 11,opcode: 0106,params: [00 FB 00 28 04 FB 00 28 04], check_sum: C7
2024-05-20 10:34:44,244 INFO: Parser eventParser: event name: EVENT_LE_SET_DATA_LEN
2024-05-20 10:34:44,245 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:44,246 INFO: Parser eventParser: max_tx_octets: [FB 00]
2024-05-20 10:34:44,246 INFO: Parser eventParser: max_tx_time: [28 04]
2024-05-20 10:34:44,247 INFO: Parser eventParser: max_rx_octets: [FB 00]
2024-05-20 10:34:44,248 INFO: Parser eventParser: max_rx_time: [28 04]
2024-05-20 10:34:44,249 INFO: Packet sendPacket: <<<send packet: AA B0 05 00 00 00 06 01 00 44
2024-05-20 10:34:44,540 INFO: AciHostCLI continuously_read: >>>receive packet: AA DA 0A 00 44 80 00 00 18 00 0F 00 F4 01 3C
2024-05-20 10:34:44,541 INFO: Parser eventParser: syncWord: AA,seqn: DA,len: 10,opcode: 8044,params: [00 00 18 00 0F 00 F4 01], check_sum: 3C
2024-05-20 10:34:44,543 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
2024-05-20 10:34:44,548 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:44,549 INFO: Parser eventParser: res: [00]
2024-05-20 10:34:44,550 INFO: Parser eventParser: connInterval: [18 00]
2024-05-20 10:34:44,550 INFO: Parser eventParser: connLatency: [0F 00]
2024-05-20 10:34:44,551 INFO: Parser eventParser: supTimeout: [F4 01]
2024-05-20 10:34:44,552 INFO: Packet sendPacket: <<<send packet: AA B1 05 00 00 00 44 80 00 86
2024-05-20 10:34:45,690 INFO: AciHostCLI continuously_read: >>>receive packet: AA DB 0B 00 02 01 00 00 00 01 23 15 DD AA DD 7A
2024-05-20 10:34:45,691 INFO: Parser eventParser: syncWord: AA,seqn: DB,len: 11,opcode: 0102,params: [00 00 00 01 23 15 DD AA DD], check_sum: 7A
2024-05-20 10:34:45,693 INFO: Parser eventParser: event name: APP_EVENT_LE_PAIR_STATUS
2024-05-20 10:34:45,696 INFO: Parser eventParser: link_id: [00]
2024-05-20 10:34:45,697 INFO: Parser eventParser: cause: [00 00]
2024-05-20 10:34:45,698 INFO: Parser eventParser: resolved_addr: [01 23 15 DD AA DD]
2024-05-20 10:34:45,698 INFO: Packet sendPacket: <<<send packet: AA B2 05 00 00 00 02 01 00 46
2024-05-20 10:34:46,473 INFO: AciHostCLI continuously_read: >>>receive packet: AA DC 0A 00 44 80 00 00 06 00 00 00 F4 01 5B
2024-05-20 10:34:46,475 INFO: Parser eventParser: syncWord: AA,seqn: DC,len: 10,opcode: 8044,params: [00 00 06 00 00 00 F4 01], check_sum: 5B
2024-05-20 10:34:46,476 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
2024-05-20 10:34:46,480 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:46,481 INFO: Parser eventParser: res: [00]
2024-05-20 10:34:46,482 INFO: Parser eventParser: connInterval: [06 00]
2024-05-20 10:34:46,484 INFO: Parser eventParser: connLatency: [00 00]
2024-05-20 10:34:46,484 INFO: Parser eventParser: supTimeout: [F4 01]
2024-05-20 10:34:46,485 INFO: Packet sendPacket: <<<send packet: AA B3 05 00 00 00 44 80 00 84
2024-05-20 10:34:46,888 INFO: AciHostCLI continuously_read: >>>receive packet: AA DD 04 00 10 01 00 00 0E
2024-05-20 10:34:46,889 INFO: Parser eventParser: syncWord: AA,seqn: DD,len: 4,opcode: 0110,params: [00 00], check_sum: 0E
2024-05-20 10:34:46,891 INFO: Parser eventParser: event name: EVENT_ANCS_REGISTER_COMPLETE
2024-05-20 10:34:46,895 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:46,895 INFO: Parser eventParser: result: [00]
2024-05-20 10:34:46,896 INFO: Packet sendPacket: <<<send packet: AA B4 05 00 00 00 10 01 00 36
2024-05-20 10:34:47,000 INFO: AciHostCLI continuously_read: >>>receive packet: AA DE 0A 00 44 80 00 00 18 00 00 00 F4 01 47
2024-05-20 10:34:47,001 INFO: Parser eventParser: syncWord: AA,seqn: DE,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: 47
2024-05-20 10:34:47,002 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
2024-05-20 10:34:47,006 INFO: Parser eventParser: app_link_id: [00]
2024-05-20 10:34:47,006 INFO: Parser eventParser: res: [00]
2024-05-20 10:34:47,007 INFO: Parser eventParser: connInterval: [18 00]
2024-05-20 10:34:47,007 INFO: Parser eventParser: connLatency: [00 00]
2024-05-20 10:34:47,009 INFO: Parser eventParser: supTimeout: [F4 01]
2024-05-20 10:34:47,010 INFO: Packet sendPacket: <<<send packet: AA B5 05 00 00 00 44 80 00 82
ACI Host CLI Test: Operate White List

Using the white list, the ACI Device can only receive broadcasts from devices in the white list, or only establish connections with devices in the white list. The CMD_LE_MODIFY_WHITELIST command allows adding or removing specific devices to and from the white list, and to clear the white list. The CMD_LE_MODIFY_WHITELIST_BY_IDX command allows adding the device with the specified index in the bond list to the white list, or removing it from the white list.

Note

These commands shall not be used when: Any advertising filter policy uses the white list and advertising is enabled, the scanning filter policy uses the white list and scanning is enabled, or the initiator filter policy uses the white list and an HCI_LE_Create_Connection or HCI_LE_Extended_Create_Connection command is outstanding.

2024-05-20 10:37:01,539 INFO: input command: whitelist_id add_idx0
2024-05-20 10:37:01,539 INFO: Parser cmdParser: cmd opcode: 0162 param: [01 00] name: CMD_LE_MODIFY_WIHITLIST_BY_IDX
2024-05-20 10:37:01,540 INFO: Packet sendPacket: <<<send packet: AA 01 04 00 62 01 01 00 97
2024-05-20 10:37:01,561 INFO: AciHostCLI continuously_read: >>>receive packet: AA E6 05 00 00 00 62 01 00 B2
2024-05-20 10:37:01,563 INFO: Parser eventParser: syncWord: AA,seqn: E6,len: 5,opcode: 0000,params: [62 01 00], check_sum: B2
2024-05-20 10:37:01,564 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 10:37:01,564 INFO: Parser eventParser: event_id: [62 01]
2024-05-20 10:37:01,565 INFO: Parser eventParser: status: [00]
2024-05-20 10:37:09,630 INFO: input command: whitelist_id rmv_idx0
2024-05-20 10:37:09,631 INFO: Parser cmdParser: cmd opcode: 0162 param: [02 00] name: CMD_LE_MODIFY_WIHITLIST_BY_IDX
2024-05-20 10:37:09,632 INFO: Packet sendPacket: <<<send packet: AA 02 04 00 62 01 02 00 95
2024-05-20 10:37:09,711 WARNING: AciHostCLI retrans: retransmit command whitelist_id rmv_idx0 due to ack timeout! retry: 1
2024-05-20 10:37:09,712 INFO: Packet sendPacket: <<<send packet: AA 02 04 00 62 01 02 00 95
2024-05-20 10:37:09,723 INFO: AciHostCLI continuously_read: >>>receive packet: AA E7 05 00 00 00 62 01 00 B1
2024-05-20 10:37:09,724 INFO: Parser eventParser: syncWord: AA,seqn: E7,len: 5,opcode: 0000,params: [62 01 00], check_sum: B1
2024-05-20 10:37:09,725 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 10:37:09,725 INFO: Parser eventParser: event_id: [62 01]
2024-05-20 10:37:09,726 INFO: Parser eventParser: status: [00]
ACI Host CLI Test: Operate Resolving List

Similar to the white list, if the device needs to use the link layer privacy mechanism, a resolving list needs to be stored on the Controller. Using CMD_LE_MODIFY_RESOLVELIST_BY_IDX, device with specified indexe in the bond list can be added to or removed from the resolving list, and the entire resolving list can be cleared.

To enable/disable resolution of resolvable private addresses in the Controller, please use the command CMD_LE_SET_RESOLUTION.

Note

These commands shall not be used when:

  • Advertising (other than periodic advertising) is enabled.

  • Scanning is enabled.

  • HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or HCI_LE_Periodic_Advertising_Create_Sync command is outstanding.

2024-05-20 14:02:09,954 INFO: input command: resolvlist_id add_idx0
2024-05-20 14:02:09,955 INFO: Parser cmdParser: cmd opcode: 0163 param: [01 00] name: CMD_LE_MODIFY_RESOLVELIST_BY_IDX
2024-05-20 14:02:09,956 INFO: Packet sendPacket: <<<send packet: AA 01 04 00 63 01 01 00 96
2024-05-20 14:02:10,028 WARNING: AciHostCLI retrans: retransmit command resolvlist_id add_idx0 due to ack timeout! retry: 1
2024-05-20 14:02:10,029 INFO: Packet sendPacket: <<<send packet: AA 01 04 00 63 01 01 00 96
2024-05-20 14:02:10,042 INFO: AciHostCLI continuously_read: >>>receive packet: AA EC 05 00 00 00 63 01 00 AB
2024-05-20 14:02:10,043 INFO: Parser eventParser: syncWord: AA,seqn: EC,len: 5,opcode: 0000,params: [63 01 00], check_sum: AB
2024-05-20 14:02:10,043 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 14:02:10,044 INFO: Parser eventParser: event_id: [63 01]
2024-05-20 14:02:10,044 INFO: Parser eventParser: status: [00]
2024-05-20 14:02:18,897 INFO: input command: le_resolution enable
2024-05-20 14:02:18,897 INFO: Parser cmdParser: cmd opcode: 0164 param: [01] name: CMD_LE_SET_RESOLUTION
2024-05-20 14:02:18,898 INFO: Packet sendPacket: <<<send packet: AA 02 03 00 64 01 01 95
2024-05-20 14:02:18,973 WARNING: AciHostCLI retrans: retransmit command le_resolution enable due to ack timeout! retry: 1
2024-05-20 14:02:18,974 INFO: Packet sendPacket: <<<send packet: AA 02 03 00 64 01 01 95
2024-05-20 14:02:18,987 INFO: AciHostCLI continuously_read: >>>receive packet: AA ED 05 00 00 00 64 01 00 A9
2024-05-20 14:02:18,987 INFO: Parser eventParser: syncWord: AA,seqn: ED,len: 5,opcode: 0000,params: [64 01 00], check_sum: A9
2024-05-20 14:02:18,988 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 14:02:18,988 INFO: Parser eventParser: event_id: [64 01]
2024-05-20 14:02:18,989 INFO: Parser eventParser: status: [00]
2024-05-20 14:02:22,360 INFO: input command: le_resolution disable
2024-05-20 14:02:22,361 INFO: Parser cmdParser: cmd opcode: 0164 param: [00] name: CMD_LE_SET_RESOLUTION
2024-05-20 14:02:22,362 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 64 01 00 95
2024-05-20 14:02:22,433 WARNING: AciHostCLI retrans: retransmit command le_resolution disable due to ack timeout! retry: 1
2024-05-20 14:02:22,434 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 64 01 00 95
2024-05-20 14:02:22,453 INFO: AciHostCLI continuously_read: >>>receive packet: AA EE 05 00 00 00 64 01 00 A8
2024-05-20 14:02:22,454 INFO: Parser eventParser: syncWord: AA,seqn: EE,len: 5,opcode: 0000,params: [64 01 00], check_sum: A8
2024-05-20 14:02:22,454 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 14:02:22,455 INFO: Parser eventParser: event_id: [64 01]
2024-05-20 14:02:22,455 INFO: Parser eventParser: status: [00]
2024-05-20 14:02:30,731 INFO: input command: resolvlist_id rmv_idx0
2024-05-20 14:02:30,732 INFO: Parser cmdParser: cmd opcode: 0163 param: [02 00] name: CMD_LE_MODIFY_RESOLVELIST_BY_IDX
2024-05-20 14:02:30,733 INFO: Packet sendPacket: <<<send packet: AA 04 04 00 63 01 02 00 92
2024-05-20 14:02:30,806 WARNING: AciHostCLI retrans: retransmit command resolvlist_id rmv_idx0 due to ack timeout! retry: 1
2024-05-20 14:02:30,807 INFO: Packet sendPacket: <<<send packet: AA 04 04 00 63 01 02 00 92
2024-05-20 14:02:30,824 INFO: AciHostCLI continuously_read: >>>receive packet: AA EF 05 00 00 00 63 01 00 A8
2024-05-20 14:02:30,824 INFO: Parser eventParser: syncWord: AA,seqn: EF,len: 5,opcode: 0000,params: [63 01 00], check_sum: A8
2024-05-20 14:02:30,825 INFO: Parser eventParser: event name: APP_EVENT_ACK
2024-05-20 14:02:30,825 INFO: Parser eventParser: event_id: [63 01]
2024-05-20 14:02:30,825 INFO: Parser eventParser: status: [00]

Record Function

Bluetooth Audio Transceiver application supports the recording of many audio formats such as PCM, mSBC, SBC, and OPUS. Before using, please configure MIC 1 on the EVB and connect an external MIC.

Record process:

ACI Host CLI Test

The ACI Host CLI CMD for recording are rc start and rc stop, and the corresponding UART CMD packet.

Command

Parameters

ACI Host CLI CMD

CMD_XM_START_RECORD = 0x8082

type = AUDIO_FORMAT_TYPE_PCM(0), sample_rate = 0x00003E80, frame_len = 0x0400, chann_num 1, bit_width = 0x10

rc start_pcm

CMD_XM_STOP_RECORD = 0x8503

None

rc stop

  1. ACI Host CLI test: Start recording PCM.

    An example of recording PCM is provided here. Please refer to ACI_CMD_XM_START_RECORD for recording more formats.

    2023-04-03 17:12:12,558 INFO: input command: rc start_pcm
    2023-04-03 17:12:12,559 INFO: Parser cmdParser: cmd opcode: 8082 param: [00 80 3E 00 00 00 04 01 10] name: CMD_XM_START_RECORD
    2023-04-03 17:12:12,560 INFO: Packet sendPacket: <<<send packet: AA 01 0B 00 02 85 00 80 3E 00 00 00 04 01 10 9A
    2023-04-03 17:12:12,572 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 02 85 00 71
    2023-04-03 17:12:12,577 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [02 85 00], check_sum: 71
    2023-04-03 17:12:12,578 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-03 17:12:12,579 INFO: Parser eventParser: event_id: [02 85]
    2023-04-03 17:12:12,579 INFO: Parser eventParser: status: [00]
    2023-04-03 17:12:12,849 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 02 04 02 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    2023-04-03 17:12:12,850 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 1026,opcode: 8082,params: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00], check_sum: B1
    2023-04-03 17:12:12,850 INFO: Parser eventParser: event name: EVENT_XM_RECORDING_DATA
    2023-04-03 17:12:12,878 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 02 04 02 85 FD FF F8 FF F2 FF F3 FF F5 FF F2 FF F2 FF F3 FF EE FF ED FF FE FF 08 00 01 00
    2023-04-03 17:12:12,879 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 1026,opcode: 8082,params: [FD FF F8 FF F2 FF F3 FF F5 FF F2 FF F2 FF F3 FF EE FF ED FF FE FF 08 00 01 00 06 00 1B 00 27 00], check_sum: 9E
    2023-04-03 17:12:12,880 INFO: Parser eventParser: event name: EVENT_XM_RECORDING_DATA
    
  2. ACI Host CLI test: Stop recording.

    2023-04-03 17:12:12,558 INFO: input command: rc stop
    2023-04-03 17:14:52,717 INFO: Parser cmdParser: cmd opcode: 8503 param: [] name: CMD_XM_STOP_RECORD
    2023-04-03 17:14:52,718 INFO: Packet sendPacket: <<<send packet: AA 02 02 00 03 85 74
    2023-04-03 17:14:52,725 INFO: AciHostCLI continuously_read: >>>receive packet: AA BF 05 00 00 00 03 85 00 B4
    2023-04-03 17:14:52,730 INFO: Parser eventParser: syncWord: AA,seqn: BF,len: 5,opcode: 0000,params: [03 85 00], check_sum: B4
    2023-04-03 17:14:52,731 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-03 17:14:52,732 INFO: Parser eventParser: event_id: [03 85]
    2023-04-03 17:14:52,733 INFO: Parser eventParser: status: [00]
    

LE Audio Function

The current version of Bluetooth Audio Transceiver application includes support for LE Audio functionality. LE Audio typically utilizes BIS or CIS to transmit audio data. In the present version, BIS has been implemented. Please note that the LE Audio module only offers protocol and data pathway. Users need to supply data to the LE Audio module by either the transparent transmission module A2DP Transparent Transmission (BIS Output) or the recording module, enabling the transmission of ISO audio data to external devices.

LE Audio Initiator

Initiator, which is described in CAP SPEC, always operates in CAP Unicast Client role, BAP Broadcast Source role, BAP Scan Assistant role, or CCP Call Control Server role.

Initiator General ACI Host CLI Test

For CIS, it is necessary to establish an LE link, whereas for BIS, it is not mandatory. This chapter delineates the process of establishing an LE link with devices supporting LE Audio Acceptor.

To scan nearby devices supporting LE Audio, ACI Host sends the CMD_LEA_SCAN to enable the scan procedure. The current scan results can be displayed by entering the le conn_idx command. If the device expected to be connected is a stereo headset, directly input the serial number of the headset to establish the connection and complete the pairing. If the device to be connected is a pair of RWS BUDS, input the serial number of either the left or right BUD, and Bluetooth Audio Transceiver application will establish connections for both BUDS simultaneously. Upon completion of the LE Audio-related service discovery, Bluetooth Audio Transceiver application will report the EVENT_LE_AUDIO_BAP_DISCOVERY_DONE event.

Command

Parameters

ACI Host CLI CMD

CMD_LEA_SCAN(0x3023)

action = start(0x00)

lea_scan start

CMD_LEA_SCAN(0x3023)

action = stop(0x01)

lea_scan stop

LE Audio connection process:

  1. ACI Host CLI test: Start scanning LE Audio devices.

    2023-07-17 15:59:35,770 INFO: input command: lea_scan start
    2023-07-17 15:59:35,771 INFO: Parser cmdParser: cmd opcode: 3023 param: [00] name: CMD_LEA_SCAN
    2023-07-17 15:59:35,771 INFO: Packet sendPacket: <<<send packet: AA 04 03 00 23 30 00 A6
    2023-07-17 15:59:35,779 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 23 30 00 A4
    2023-07-17 15:59:35,783 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [23 30 00], check_sum: A4
    2023-07-17 15:59:35,784 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 15:59:35,784 INFO: Parser eventParser: event_id: [23 30]
    2023-07-17 15:59:35,786 INFO: Parser eventParser: status: [00]
    2023-07-17 15:59:39,470 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 34 00 0B 01 01 00 01 61 6C 0D 97 48 E0 12 38 37 36 33 45 46 4C 5F 35 76 5F 52 28 6D 73 62
    2023-07-17 15:59:39,470 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 52,opcode: 010B,params: [01 00 01 61 6C 0D 97 48 E0 12 38 37 36 33 45 46 4C 5F 35 76 5F 52 28 6D 73 62 63 29 00 00 00 00], check_sum: AE
    2023-07-17 15:59:39,471 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
    2023-07-17 15:59:39,471 INFO: Parser eventParser: event_type: [01 00]
    2023-07-17 15:59:39,472 INFO: Parser eventParser: addr_type: [01]
    2023-07-17 15:59:39,472 INFO: Parser eventParser: addr: [61 6C 0D 97 48 E0]
    2023-07-17 15:59:39,472 INFO: Parser eventParser: name_len: [12]
    2023-07-17 15:59:39,473 INFO: Parser eventParser: name: [38 37 36 33 45 46 4C 5F 35 76 5F 52 28 6D 73 62 63 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
    2023-07-17 15:59:39,473 INFO: Parser eventParser: name: 8763EFL_5v_R(msbc)
    2023-07-17 15:59:39,474 INFO: Packet sendPacket: <<<send packet: AA 05 05 00 00 00 0B 01 00 EA
    2023-07-17 15:59:39,709 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 34 00 0B 01 01 00 01 A0 DE 13 53 C0 F1 12 38 37 36 33 45 46 4C 5F 35 76 5F 4C 28 6D 73 62
    2023-07-17 15:59:39,710 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 52,opcode: 010B,params: [01 00 01 A0 DE 13 53 C0 F1 12 38 37 36 33 45 46 4C 5F 35 76 5F 4C 28 6D 73 62 63 29 00 00 00 00], check_sum: B7
    2023-07-17 15:59:39,711 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
    2023-07-17 15:59:39,711 INFO: Parser eventParser: event_type: [01 00]
    2023-07-17 15:59:39,712 INFO: Parser eventParser: addr_type: [01]
    2023-07-17 15:59:39,712 INFO: Parser eventParser: addr: [A0 DE 13 53 C0 F1]
    2023-07-17 15:59:39,713 INFO: Parser eventParser: name_len: [12]
    2023-07-17 15:59:39,713 INFO: Parser eventParser: name: [38 37 36 33 45 46 4C 5F 35 76 5F 4C 28 6D 73 62 63 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
    2023-07-17 15:59:39,714 INFO: Parser eventParser: name: 8763EFL_5v_L(msbc)
    2023-07-17 15:59:39,714 INFO: Packet sendPacket: <<<send packet: AA 06 05 00 00 00 0B 01 00 E9
    
  2. ACI Host CLI test: Stop scanning and showing results.

    2023-07-17 15:59:49,718 INFO: input command: lea_scan stop
    2023-07-17 15:59:49,719 INFO: Parser cmdParser: cmd opcode: 3023 param: [01] name: CMD_LEA_SCAN
    2023-07-17 15:59:49,719 INFO: Packet sendPacket: <<<send packet: AA 07 03 00 23 30 01 A2
    2023-07-17 15:59:49,726 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 05 00 00 00 23 30 00 A1
    2023-07-17 15:59:49,727 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 5,opcode: 0000,params: [23 30 00], check_sum: A1
    2023-07-17 15:59:49,730 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 15:59:49,731 INFO: Parser eventParser: event_id: [23 30]
    2023-07-17 15:59:49,732 INFO: Parser eventParser: status: [00]
    2023-07-17 15:59:52,770 INFO: input command: le conn_idx
    2023-07-17 15:59:52,770 INFO: Parser cmdParser: device index: 0 addr_type 1 bd_addr: 61 6C 0D 97 48 E0 , name: 8763EFL_5v_R(msbc)
    2023-07-17 15:59:52,771 INFO: Parser cmdParser: device index: 1 addr_type 1 bd_addr: A0 DE 13 53 C0 F1 , name: 8763EFL_5v_L(msbc)
    
  3. ACI Host CLI test: Input the device index to initiate the connection procedure.

    2023-07-17 15:59:58,755 INFO: Parser cmdParser: input dev_index: 0
    2023-07-17 15:59:58,756 INFO: Parser cmdParser: cmd opcode: 010E param: [03 01 61 6C 0D 97 48 E0 00 E8 03] name: CMD_LE_CREATE_CONN
    2023-07-17 15:59:58,756 INFO: Packet sendPacket: <<<send packet: AA 08 0D 00 0E 01 03 01 61 6C 0D 97 48 E0 00 E8 03 54
    2023-07-17 15:59:58,774 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 05 00 00 00 0E 01 00 E4
    2023-07-17 15:59:58,775 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 5,opcode: 0000,params: [0E 01 00], check_sum: E4
    2023-07-17 15:59:58,776 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 15:59:58,779 INFO: Parser eventParser: event_id: [0E 01]
    2023-07-17 15:59:58,780 INFO: Parser eventParser: status: [00]
    2023-07-17 15:59:58,798 INFO: AciHostCLI continuously_read: >>>receive packet: AA 09 05 00 07 01 00 02 02 E6
    2023-07-17 15:59:58,799 INFO: Parser eventParser: syncWord: AA,seqn: 09,len: 5,opcode: 0107,params: [00 02 02], check_sum: E6
    2023-07-17 15:59:58,799 INFO: Parser eventParser: event name: EVENT_LE_PHY_UPD
    2023-07-17 15:59:58,800 INFO: Parser eventParser: app_link_id: [00]
    2023-07-17 15:59:58,800 INFO: Parser eventParser: tx_phy: [02]
    2023-07-17 15:59:58,801 INFO: Parser eventParser: rx_phy: [02]
    2023-07-17 15:59:58,801 INFO: Packet sendPacket: <<<send packet: AA 09 05 00 00 00 07 01 00 EA
    2023-07-17 15:59:58,814 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0A 03 00 00 01 00 F2
    2023-07-17 15:59:58,814 INFO: Parser eventParser: syncWord: AA,seqn: 0A,len: 3,opcode: 0100,params: [00], check_sum: F2
    2023-07-17 15:59:58,815 INFO: Parser eventParser: event name: APP_EVENT_LE_CONNECTED
    2023-07-17 15:59:58,815 INFO: Parser eventParser: link_id: [00]
    2023-07-17 15:59:58,816 INFO: Packet sendPacket: <<<send packet: AA 0A 05 00 00 00 00 01 00 F0
    2023-07-17 15:59:58,830 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0B 14 00 43 80 02 00 05 00 01 01 61 6C 0D 97 48 E0 20 00 00 00 E8 03 71
    2023-07-17 15:59:58,831 INFO: Parser eventParser: syncWord: AA,seqn: 0B,len: 20,opcode: 8043,params: [02 00 05 00 01 01 61 6C 0D 97 48 E0 20 00 00 00 E8 03], check_sum: 71
    2023-07-17 15:59:58,831 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_STATE
    2023-07-17 15:59:58,832 INFO: Parser eventParser: link_state: [02]
    2023-07-17 15:59:58,832 INFO: Parser eventParser: app_link_id: [00]
    2023-07-17 15:59:58,833 INFO: Parser eventParser: conn_handle: [05 00]
    2023-07-17 15:59:58,833 INFO: Parser eventParser: role: [01]
    2023-07-17 15:59:58,834 INFO: Parser eventParser: remote addr type: [01]
    2023-07-17 15:59:58,834 INFO: Parser eventParser: remote addr: [61 6C 0D 97 48 E0]
    2023-07-17 15:59:58,834 INFO: Parser eventParser: connInterval: [20 00]
    2023-07-17 15:59:58,835 INFO: Parser eventParser: connLatency: [00 00]
    2023-07-17 15:59:58,835 INFO: Parser eventParser: supTimeout: [E8 03]
    2023-07-17 15:59:58,835 INFO: Packet sendPacket: <<<send packet: AA 0B 05 00 00 00 43 80 00 2D
    2023-07-17 15:59:58,845 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0C 05 00 41 80 00 F4 00 3A
    2023-07-17 15:59:58,846 INFO: Parser eventParser: syncWord: AA,seqn: 0C,len: 5,opcode: 8041,params: [00 F4 00], check_sum: 3A
    2023-07-17 15:59:58,847 INFO: Parser eventParser: event name: EVENT_XM_LE_MTU
    2023-07-17 15:59:58,847 INFO: Parser eventParser: mtu_size: [00 F4]
    2023-07-17 15:59:58,848 INFO: Packet sendPacket: <<<send packet: AA 0C 05 00 00 00 41 80 00 2E
    2023-07-17 16:00:00,299 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0D 0B 00 02 01 00 00 00 00 00 00 00 00 00 E5
    2023-07-17 16:00:00,300 INFO: Parser eventParser: syncWord: AA,seqn: 0D,len: 11,opcode: 0102,params: [00 00 00 00 00 00 00 00 00], check_sum: E5
    2023-07-17 16:00:00,301 INFO: Parser eventParser: event name: APP_EVENT_LE_PAIR_STATUS
    2023-07-17 16:00:00,301 INFO: Parser eventParser: link_id: [00]
    2023-07-17 16:00:00,302 INFO: Parser eventParser: cause: [00 00]
    2023-07-17 16:00:00,302 INFO: Parser eventParser: resolved_addr: [00 00 00 00 00 00]
    2023-07-17 16:00:00,303 INFO: Packet sendPacket: <<<send packet: AA 0D 05 00 00 00 02 01 00 EB
    2023-07-17 16:00:05,108 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0E 34 00 0B 01 01 00 01 A0 DE 13 53 C0 F1 12 38 37 36 33 45 46 4C 5F 35 76 5F 4C 28 6D 73 62
    2023-07-17 16:00:05,108 INFO: Parser eventParser: syncWord: AA,seqn: 0E,len: 52,opcode: 010B,params: [01 00 01 A0 DE 13 53 C0 F1 12 38 37 36 33 45 46 4C 5F 35 76 5F 4C 28 6D 73 62 63 29 00 00 00 00], check_sum: AF
    2023-07-17 16:00:05,109 INFO: Parser eventParser: event name: APP_EVENT_LE_AUDIO_SCAN_INFO
    2023-07-17 16:00:05,109 INFO: Parser eventParser: event_type: [01 00]
    2023-07-17 16:00:05,110 INFO: Parser eventParser: addr_type: [01]
    2023-07-17 16:00:05,110 INFO: Parser eventParser: addr: [A0 DE 13 53 C0 F1]
    2023-07-17 16:00:05,111 INFO: Parser eventParser: name_len: [12]
    2023-07-17 16:00:05,112 INFO: Parser eventParser: name: [38 37 36 33 45 46 4C 5F 35 76 5F 4C 28 6D 73 62 63 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
    2023-07-17 16:00:05,112 INFO: Parser eventParser: name: 8763EFL_5v_L(msbc)
    2023-07-17 16:00:05,113 INFO: Packet sendPacket: <<<send packet: AA 0E 05 00 00 00 0B 01 00 E1
    2023-07-17 16:00:05,155 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0F 05 00 07 01 01 02 02 DF
    2023-07-17 16:00:05,156 INFO: Parser eventParser: syncWord: AA,seqn: 0F,len: 5,opcode: 0107,params: [01 02 02], check_sum: DF
    2023-07-17 16:00:05,156 INFO: Parser eventParser: event name: EVENT_LE_PHY_UPD
    2023-07-17 16:00:05,157 INFO: Parser eventParser: app_link_id: [01]
    2023-07-17 16:00:05,157 INFO: Parser eventParser: tx_phy: [02]
    2023-07-17 16:00:05,158 INFO: Parser eventParser: rx_phy: [02]
    2023-07-17 16:00:05,158 INFO: Packet sendPacket: <<<send packet: AA 0F 05 00 00 00 07 01 00 E4
    2023-07-17 16:00:05,171 INFO: AciHostCLI continuously_read: >>>receive packet: AA 10 03 00 00 01 01 EB
    2023-07-17 16:00:05,172 INFO: Parser eventParser: syncWord: AA,seqn: 10,len: 3,opcode: 0100,params: [01], check_sum: EB
    2023-07-17 16:00:05,173 INFO: Parser eventParser: event name: APP_EVENT_LE_CONNECTED
    2023-07-17 16:00:05,173 INFO: Parser eventParser: link_id: [01]
    2023-07-17 16:00:05,174 INFO: Packet sendPacket: <<<send packet: AA 10 05 00 00 00 00 01 00 EA
    2023-07-17 16:00:05,187 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 14 00 43 80 02 01 06 00 01 01 A0 DE 13 53 C0 F1 64 00 00 00 F4 01 1F
    2023-07-17 16:00:05,188 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 20,opcode: 8043,params: [02 01 06 00 01 01 A0 DE 13 53 C0 F1 64 00 00 00 F4 01], check_sum: 1F
    2023-07-17 16:00:05,189 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_STATE
    2023-07-17 16:00:05,189 INFO: Parser eventParser: link_state: [02]
    2023-07-17 16:00:05,190 INFO: Parser eventParser: app_link_id: [01]
    2023-07-17 16:00:05,190 INFO: Parser eventParser: conn_handle: [06 00]
    2023-07-17 16:00:05,191 INFO: Parser eventParser: role: [01]
    2023-07-17 16:00:05,191 INFO: Parser eventParser: remote addr type: [01]
    2023-07-17 16:00:05,191 INFO: Parser eventParser: remote addr: [A0 DE 13 53 C0 F1]
    2023-07-17 16:00:05,192 INFO: Parser eventParser: connInterval: [64 00]
    2023-07-17 16:00:05,192 INFO: Parser eventParser: connLatency: [00 00]
    2023-07-17 16:00:05,193 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-07-17 16:00:05,193 INFO: Packet sendPacket: <<<send packet: AA 11 05 00 00 00 43 80 00 27
    2023-07-17 16:00:05,203 INFO: AciHostCLI continuously_read: >>>receive packet: AA 12 03 00 0D 01 00 DD
    2023-07-17 16:00:05,204 INFO: Parser eventParser: syncWord: AA,seqn: 12,len: 3,opcode: 010D,params: [00], check_sum: DD
    2023-07-17 16:00:05,204 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_DISCOVERY_DONE
    2023-07-17 16:00:05,204 INFO: Parser eventParser: link_id: [00]
    2023-07-17 16:00:05,205 INFO: Packet sendPacket: <<<send packet: AA 12 05 00 00 00 0D 01 00 DB
    2023-07-17 16:00:05,331 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 05 00 41 80 01 F4 20 30
    2023-07-17 16:00:05,332 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 5,opcode: 8041,params: [01 F4 00], check_sum: 32
    2023-07-17 16:00:05,333 INFO: Parser eventParser: event name: EVENT_XM_LE_MTU
    2023-07-17 16:00:05,333 INFO: Parser eventParser: mtu_size: [01 F4]
    2023-07-17 16:00:05,334 INFO: Packet sendPacket: <<<send packet: AA 13 05 00 00 00 41 80 00 27
    2023-07-17 16:00:07,584 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 0B 00 02 01 01 00 00 00 00 00 00 00 00 DD
    2023-07-17 16:00:07,584 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 11,opcode: 0102,params: [01 00 00 00 00 00 00 00 00], check_sum: DD
    2023-07-17 16:00:07,585 INFO: Parser eventParser: event name: APP_EVENT_LE_PAIR_STATUS
    2023-07-17 16:00:07,586 INFO: Parser eventParser: link_id: [01]
    2023-07-17 16:00:07,586 INFO: Parser eventParser: cause: [00 00]
    2023-07-17 16:00:07,587 INFO: Parser eventParser: resolved_addr: [00 00 00 00 00 00]
    2023-07-17 16:00:07,587 INFO: Packet sendPacket: <<<send packet: AA 14 05 00 00 00 02 01 00 E4
    2023-07-17 16:00:22,950 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 03 00 0D 01 01 D9
    2023-07-17 16:00:22,951 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 3,opcode: 010D,params: [01], check_sum: D9
    2023-07-17 16:00:22,952 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_DISCOVERY_DONE
    2023-07-17 16:00:22,952 INFO: Parser eventParser: link_id: [01]
    2023-07-17 16:00:22,952 INFO: Packet sendPacket: <<<send packet: AA 15 05 00 00 00 0D 01 00 D8
    
BIS Initiator Introduction

BIS, which stands for Broadcast Isochronous Channel, is a communication channel utilized in the context of LE Audio. It is responsible for transmitting audio data wirelessly. BIS is designed to support high-quality audio streaming, allowing the transfer of synchronized audio content from a source device (as broadcast source role) to multiple recipient devices simultaneously.

BIS Initiator ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 1
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 48k_1bis

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_16_2(16k)
BIS num = 1
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 16k_1bis

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 2
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 48k_2bis

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_16_2(16k)
BIS num = 2
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 16k_2bis

CMD_LEA_BSRC_START(0x3221)

None

bsrcstart x

CMD_LEA_BSRC_STOP(0x3022)

release = true

bsrcstop release

CMD_LEA_BSRC_STOP(0x3022)

release = false

bsrcstop hold

The ACI Host CLI CMD for BIS are CMD_LEA_BSRC_INIT, CMD_LEA_BSRC_START, and CMD_LEA_BSRC_STOP. CMD_LEA_BSRC_INIT is used to initialize the parameters related to BIS, including codec type, BIS number, encryption mode, ULL mode (Ultra Low Latency mode), and PD (Presentation Delay). The PD parameter is only effective when ULL mode is enabled. When ULL mode is activated, the following parameters are specifically used when creating BIG: Packing = Interleaved, Max Transport Latency = 10 ms, RTN = 2. Additionally, the DSP would periodically fetch the anchor point to capture data at more precise time intervals, aiming for lower and more stable latency. CMD_LEA_BSRC_START is used to activate BIS, while CMD_LEA_BSRC_STOP is used to stop BIS.

  1. ACI Host CLI test: Initialize BIS.

    2023-05-31 10:25:21,803 INFO: input command: bsrcinit 48k_2bis
    2023-05-31 10:25:21,803 INFO: Parser cmdParser: cmd opcode: 3020 param: [0D 02 00 01 10 27] name: CMD_LEA_BSRC_INIT
    2023-05-31 10:25:21,803 INFO: Packet sendPacket: <<<send packet: AA 0C 07 00 20 30 0D 02 00 01 10 27 11
    2023-05-31 10:25:21,834 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 20 30 00 C6
    2023-05-31 10:25:21,834 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [20 30 00], check_sum: C6
    2023-05-31 10:25:21,834 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:25:21,834 INFO: Parser eventParser: event_id: [20 30]
    2023-05-31 10:25:21,834 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Start BIS.

    2023-05-31 10:25:36,368 INFO: input command: bsrcstart x
    2023-05-31 10:25:36,368 INFO: Parser cmdParser: cmd opcode: 3021 param: [] name: CMD_LEA_BSRC_START
    2023-05-31 10:25:36,368 INFO: Packet sendPacket: <<<send packet: AA 0D 02 00 21 30 BE
    2023-05-31 10:25:36,388 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 21 30 00 C4
    2023-05-31 10:25:36,388 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [21 30 00], check_sum: C4
    2023-05-31 10:25:36,388 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:25:36,388 INFO: Parser eventParser: event_id: [21 30]
    2023-05-31 10:25:36,388 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Stop BIS.

    2023-05-31 10:25:50,472 INFO: input command: bsrcstop release
    2023-05-31 10:25:50,472 INFO: Parser cmdParser: cmd opcode: 3022 param: [01] name: CMD_LEA_BSRC_STOP
    2023-05-31 10:25:50,472 INFO: Packet sendPacket: <<<send packet: AA 0E 03 00 22 30 01 BA
    2023-05-31 10:25:50,512 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 22 30 00 C2
    2023-05-31 10:25:50,512 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [22 30 00], check_sum: C2
    2023-05-31 10:25:50,522 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:25:50,522 INFO: Parser eventParser: event_id: [22 30]
    2023-05-31 10:25:50,522 INFO: Parser eventParser: status: [00]
    
CIS Initiator Introduction

CIS, which stands for Connected Isochronous Stream, is an audio stream utilized in the context of LE Audio. Unlike BIS, an ACL link must always be present during the life of a CIS.

CIS Initiator ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_SCAN = 0x3023

type = APP_LEA_SCAN_START(0)

lea_scan start

CMD_LEA_SCAN(0x3023)

type = APP_LEA_SCAN_STOP(1)

lea_scan stop

CMD_LEA_CIS_START_MEDIA(0x3024)

group_idx = 0

cis_media start_group_idx_0

CMD_LEA_CIS_START_MEDIA(0x3024)

group_idx = 1

cis_media start_group_idx_1

CMD_LEA_CIS_START_CONVERSATION(0x3031)

group_idx = 0

cis_conversation start_group_idx_0

CMD_LEA_CIS_START_CONVERSATION(0x3031)

group_idx = 1

cis_conversation start_group_idx_1

CMD_LEA_CIS_STOP_STREAM(0x3025)

group_idx = 0, release = false

cis_stream stop_group_idx_0

CMD_LEA_CIS_STOP_STREAM(0x3025)

group_idx = 0, release = true

cis_stream release_group_idx_0

CMD_LEA_CIS_STOP_STREAM(0x3025)

group_idx = 1, release = false

cis_stream stop_group_idx_1

CMD_LEA_CIS_STOP_STREAM(0x3025)

group_idx = 1, release = true

cis_stream release_group_idx_1

For CIS, it is necessary to establish an LE link. Please refer to Initiator General ACI Host CLI Test for connection procedure.

  1. ACI Host CLI test: Start media stream.

    2023-12-08 16:23:42,137 INFO: input command: cis_media start_group_idx_0
    2023-12-08 16:23:42,137 INFO: Parser cmdParser: cmd opcode: 3024 param: [00] name: CMD_LEA_CIS_START_MEDIA
    2023-12-08 16:23:42,137 INFO: Packet sendPacket: <<<send packet: AA 13 03 00 24 30 00 96
    2023-12-08 16:23:42,213 WARNING: AciHostCLI retrans: retransmit command cis_media start_group_idx_0 due to ack timeout! retry: 1
    2023-12-08 16:23:42,213 INFO: Packet sendPacket: <<<send packet: AA 13 03 00 24 30 00 96
    2023-12-08 16:23:42,233 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 05 00 00 00 24 30 00 93
    2023-12-08 16:23:42,233 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 5,opcode: 0000,params: [24 30 00], check_sum: 93
    2023-12-08 16:23:42,233 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-12-08 16:23:42,233 INFO: Parser eventParser: event_id: [24 30]
    2023-12-08 16:23:42,233 INFO: Parser eventParser: status: [00]
    2023-12-08 16:23:42,233 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 07 00 41 01 D0 E7 2C 00 01 BE
    2023-12-08 16:23:42,233 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 7,opcode: 0141,params: [D0 E7 2C 00 01], check_sum: BE
    2023-12-08 16:23:42,237 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:23:42,237 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:23:42,237 INFO: Parser eventParser: state: [01]
    2023-12-08 16:23:42,237 INFO: Packet sendPacket: <<<send packet: AA 14 05 00 00 00 41 01 00 A5
    2023-12-08 16:23:42,249 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 07 00 41 01 D0 E7 2C 00 03 BB
    2023-12-08 16:23:42,249 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 7,opcode: 0141,params: [D0 E7 2C 00 03], check_sum: BB
    2023-12-08 16:23:42,249 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:23:42,249 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:23:42,249 INFO: Parser eventParser: state: [03]
    2023-12-08 16:23:42,249 INFO: Packet sendPacket: <<<send packet: AA 15 05 00 00 00 41 01 00 A4
    2023-12-08 16:23:42,616 INFO: AciHostCLI continuously_read: >>>receive packet: AA 17 0A 00 44 80 00 00 18 00 00 00 F4 01 0E
    2023-12-08 16:23:42,616 INFO: Parser eventParser: syncWord: AA,seqn: 17,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: 0E
    2023-12-08 16:23:42,616 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-12-08 16:23:42,616 INFO: Parser eventParser: app_link_id: [00]
    2023-12-08 16:23:42,616 INFO: Parser eventParser: res: [00]
    2023-12-08 16:23:42,616 INFO: Parser eventParser: connInterval: [18 00]
    2023-12-08 16:23:42,620 INFO: Parser eventParser: connLatency: [00 00]
    2023-12-08 16:23:42,620 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-12-08 16:23:42,620 INFO: Packet sendPacket: <<<send packet: AA 16 05 00 00 00 44 80 00 21
    2023-12-08 16:23:42,952 INFO: AciHostCLI continuously_read: >>>receive packet: AA 18 0A 00 44 80 00 00 20 00 00 00 F4 01 05
    2023-12-08 16:23:42,952 INFO: Parser eventParser: syncWord: AA,seqn: 18,len: 10,opcode: 8044,params: [00 00 20 00 00 00 F4 01], check_sum: 05
    2023-12-08 16:23:42,952 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-12-08 16:23:42,952 INFO: Parser eventParser: app_link_id: [00]
    2023-12-08 16:23:42,952 INFO: Parser eventParser: res: [00]
    2023-12-08 16:23:42,952 INFO: Parser eventParser: connInterval: [20 00]
    2023-12-08 16:23:42,956 INFO: Parser eventParser: connLatency: [00 00]
    2023-12-08 16:23:42,956 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-12-08 16:23:42,956 INFO: Packet sendPacket: <<<send packet: AA 17 05 00 00 00 44 80 00 20
    2023-12-08 16:23:43,685 INFO: AciHostCLI continuously_read: >>>receive packet: AA 19 07 00 41 01 D0 E7 2C 00 04 B7
    2023-12-08 16:23:43,685 INFO: Parser eventParser: syncWord: AA,seqn: 19,len: 7,opcode: 0141,params: [D0 E7 2C 00 04], check_sum: B7
    2023-12-08 16:23:43,685 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:23:43,685 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:23:43,685 INFO: Parser eventParser: state: [04]
    2023-12-08 16:23:43,689 INFO: Packet sendPacket: <<<send packet: AA 18 05 00 00 00 41 01 00 A1
    
  2. ACI Host CLI test: Stop media stream.

    2023-12-08 16:23:53,705 INFO: input command: cis_stream stop_group_idx_0
    2023-12-08 16:23:53,705 INFO: Parser cmdParser: cmd opcode: 3025 param: [00 00] name: CMD_LEA_CIS_STOP_STREAM
    2023-12-08 16:23:53,705 INFO: Packet sendPacket: <<<send packet: AA 19 04 00 25 30 00 00 8E
    2023-12-08 16:23:53,713 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1A 05 00 00 00 25 30 00 8C
    2023-12-08 16:23:53,713 INFO: Parser eventParser: syncWord: AA,seqn: 1A,len: 5,opcode: 0000,params: [25 30 00], check_sum: 8C
    2023-12-08 16:23:53,717 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-12-08 16:23:53,717 INFO: Parser eventParser: event_id: [25 30]
    2023-12-08 16:23:53,717 INFO: Parser eventParser: status: [00]
    2023-12-08 16:23:53,717 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1B 07 00 41 01 D0 E7 2C 00 06 B3
    2023-12-08 16:23:53,717 INFO: Parser eventParser: syncWord: AA,seqn: 1B,len: 7,opcode: 0141,params: [D0 E7 2C 00 06], check_sum: B3
    2023-12-08 16:23:53,717 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:23:53,717 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:23:53,721 INFO: Parser eventParser: state: [06]
    2023-12-08 16:23:53,721 INFO: Packet sendPacket: <<<send packet: AA 1A 05 00 00 00 41 01 00 9F
    2023-12-08 16:23:53,807 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1C 07 00 41 01 D0 E7 2C 00 02 B6
    2023-12-08 16:23:53,811 INFO: Parser eventParser: syncWord: AA,seqn: 1C,len: 7,opcode: 0141,params: [D0 E7 2C 00 02], check_sum: B6
    2023-12-08 16:23:53,811 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:23:53,811 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:23:53,811 INFO: Parser eventParser: state: [02]
    2023-12-08 16:23:53,811 INFO: Packet sendPacket: <<<send packet: AA 1B 05 00 00 00 41 01 00 9E
    
  3. ACI Host CLI test: Release media stream.

    2023-12-08 16:24:02,218 INFO: input command: cis_stream release_group_idx_0
    2023-12-08 16:24:02,218 INFO: Parser cmdParser: cmd opcode: 3025 param: [00 01] name: CMD_LEA_CIS_STOP_STREAM
    2023-12-08 16:24:02,218 INFO: Packet sendPacket: <<<send packet: AA 1C 04 00 25 30 00 01 8A
    2023-12-08 16:24:02,242 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1D 05 00 00 00 25 30 00 89
    2023-12-08 16:24:02,242 INFO: Parser eventParser: syncWord: AA,seqn: 1D,len: 5,opcode: 0000,params: [25 30 00], check_sum: 89
    2023-12-08 16:24:02,242 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-12-08 16:24:02,242 INFO: Parser eventParser: event_id: [25 30]
    2023-12-08 16:24:02,242 INFO: Parser eventParser: status: [00]
    2023-12-08 16:24:02,242 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E 07 00 41 01 D0 E7 2C 00 07 AF
    2023-12-08 16:24:02,242 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 7,opcode: 0141,params: [D0 E7 2C 00 07], check_sum: AF
    2023-12-08 16:24:02,242 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:02,246 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:02,246 INFO: Parser eventParser: state: [07]
    2023-12-08 16:24:02,246 INFO: Packet sendPacket: <<<send packet: AA 1D 05 00 00 00 41 01 00 9C
    2023-12-08 16:24:02,400 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 07 00 41 01 D0 E7 2C 00 01 B4
    2023-12-08 16:24:02,400 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 7,opcode: 0141,params: [D0 E7 2C 00 01], check_sum: B4
    2023-12-08 16:24:02,400 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:02,400 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:02,400 INFO: Parser eventParser: state: [01]
    2023-12-08 16:24:02,404 INFO: Packet sendPacket: <<<send packet: AA 1E 05 00 00 00 41 01 00 9B
    2023-12-08 16:24:02,751 INFO: AciHostCLI continuously_read: >>>receive packet: AA 20 0A 00 44 80 00 00 18 00 00 00 F4 01 05
    2023-12-08 16:24:02,751 INFO: Parser eventParser: syncWord: AA,seqn: 20,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: 05
    2023-12-08 16:24:02,751 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-12-08 16:24:02,751 INFO: Parser eventParser: app_link_id: [00]
    2023-12-08 16:24:02,751 INFO: Parser eventParser: res: [00]
    2023-12-08 16:24:02,755 INFO: Parser eventParser: connInterval: [18 00]
    2023-12-08 16:24:02,755 INFO: Parser eventParser: connLatency: [00 00]
    2023-12-08 16:24:02,755 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-12-08 16:24:02,755 INFO: Packet sendPacket: <<<send packet: AA 1F 05 00 00 00 44 80 00 18
    
  4. ACI Host CLI test: Start stream conversation.

    2023-12-08 16:24:11,884 INFO: input command: cis_conversation start_group_idx_0
    2023-12-08 16:24:11,884 INFO: Parser cmdParser: cmd opcode: 3031 param: [00] name: CMD_LEA_CIS_START_CONVERSATION
    2023-12-08 16:24:11,884 INFO: Packet sendPacket: <<<send packet: AA 20 03 00 31 30 00 7C
    2023-12-08 16:24:11,900 INFO: AciHostCLI continuously_read: >>>receive packet: AA 21 05 00 00 00 31 30 00 79
    2023-12-08 16:24:11,900 INFO: Parser eventParser: syncWord: AA,seqn: 21,len: 5,opcode: 0000,params: [31 30 00], check_sum: 79
    2023-12-08 16:24:11,900 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-12-08 16:24:11,904 INFO: Parser eventParser: event_id: [31 30]
    2023-12-08 16:24:11,904 INFO: Parser eventParser: status: [00]
    2023-12-08 16:24:11,904 INFO: AciHostCLI continuously_read: >>>receive packet: AA 22 07 00 41 01 D0 E7 2C 00 01 B1
    2023-12-08 16:24:11,904 INFO: Parser eventParser: syncWord: AA,seqn: 22,len: 7,opcode: 0141,params: [D0 E7 2C 00 01], check_sum: B1
    2023-12-08 16:24:11,908 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:11,908 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:11,908 INFO: Parser eventParser: state: [01]
    2023-12-08 16:24:11,908 INFO: Packet sendPacket: <<<send packet: AA 21 05 00 00 00 41 01 00 98
    2023-12-08 16:24:11,916 INFO: AciHostCLI continuously_read: >>>receive packet: AA 23 07 00 41 01 D0 E7 2C 00 03 AE
    2023-12-08 16:24:11,916 INFO: Parser eventParser: syncWord: AA,seqn: 23,len: 7,opcode: 0141,params: [D0 E7 2C 00 03], check_sum: AE
    2023-12-08 16:24:11,916 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:11,920 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:11,920 INFO: Parser eventParser: state: [03]
    2023-12-08 16:24:11,920 INFO: Packet sendPacket: <<<send packet: AA 22 05 00 00 00 41 01 00 97
    2023-12-08 16:24:12,557 INFO: AciHostCLI continuously_read: >>>receive packet: AA 24 0A 00 44 80 00 00 18 00 00 00 F4 01 01
    2023-12-08 16:24:12,557 INFO: Parser eventParser: syncWord: AA,seqn: 24,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: 01
    2023-12-08 16:24:12,557 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-12-08 16:24:12,557 INFO: Parser eventParser: app_link_id: [00]
    2023-12-08 16:24:12,561 INFO: Parser eventParser: res: [00]
    2023-12-08 16:24:12,561 INFO: Parser eventParser: connInterval: [18 00]
    2023-12-08 16:24:12,561 INFO: Parser eventParser: connLatency: [00 00]
    2023-12-08 16:24:12,561 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-12-08 16:24:12,561 INFO: Packet sendPacket: <<<send packet: AA 23 05 00 00 00 44 80 00 14
    2023-12-08 16:24:12,921 INFO: AciHostCLI continuously_read: >>>receive packet: AA 25 07 00 41 01 D0 E7 2C 00 04 AB
    2023-12-08 16:24:12,925 INFO: Parser eventParser: syncWord: AA,seqn: 25,len: 7,opcode: 0141,params: [D0 E7 2C 00 04], check_sum: AB
    2023-12-08 16:24:12,925 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:12,925 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:12,925 INFO: Parser eventParser: state: [04]
    2023-12-08 16:24:12,925 INFO: Packet sendPacket: <<<send packet: AA 24 05 00 00 00 41 01 00 95
    
  5. ACI Host CLI test: Stop stream conversation.

    2023-12-08 16:24:18,072 INFO: input command: cis_stream stop_group_idx_0
    2023-12-08 16:24:18,072 INFO: Parser cmdParser: cmd opcode: 3025 param: [00 00] name: CMD_LEA_CIS_STOP_STREAM
    2023-12-08 16:24:18,072 INFO: Packet sendPacket: <<<send packet: AA 25 04 00 25 30 00 00 82
    2023-12-08 16:24:18,080 INFO: AciHostCLI continuously_read: >>>receive packet: AA 26 05 00 00 00 25 30 00 80
    2023-12-08 16:24:18,084 INFO: Parser eventParser: syncWord: AA,seqn: 26,len: 5,opcode: 0000,params: [25 30 00], check_sum: 80
    2023-12-08 16:24:18,084 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-12-08 16:24:18,084 INFO: Parser eventParser: event_id: [25 30]
    2023-12-08 16:24:18,084 INFO: Parser eventParser: status: [00]
    2023-12-08 16:24:18,084 INFO: AciHostCLI continuously_read: >>>receive packet: AA 27 07 00 41 01 D0 E7 2C 00 06 A7
    2023-12-08 16:24:18,084 INFO: Parser eventParser: syncWord: AA,seqn: 27,len: 7,opcode: 0141,params: [D0 E7 2C 00 06], check_sum: A7
    2023-12-08 16:24:18,084 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:18,084 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:18,088 INFO: Parser eventParser: state: [06]
    2023-12-08 16:24:18,088 INFO: Packet sendPacket: <<<send packet: AA 26 05 00 00 00 41 01 00 93
    2023-12-08 16:24:18,254 INFO: AciHostCLI continuously_read: >>>receive packet: AA 28 07 00 41 01 D0 E7 2C 00 02 AA
    2023-12-08 16:24:18,258 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 7,opcode: 0141,params: [D0 E7 2C 00 02], check_sum: AA
    2023-12-08 16:24:18,258 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:18,258 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:18,258 INFO: Parser eventParser: state: [02]
    2023-12-08 16:24:18,258 INFO: Packet sendPacket: <<<send packet: AA 27 05 00 00 00 41 01 00 92
    
  6. ACI Host CLI test: Release stream conversation.

    2023-12-08 16:24:23,562 INFO: input command: cis_stream release_group_idx_0
    2023-12-08 16:24:23,562 INFO: Parser cmdParser: cmd opcode: 3025 param: [00 01] name: CMD_LEA_CIS_STOP_STREAM
    2023-12-08 16:24:23,562 INFO: Packet sendPacket: <<<send packet: AA 28 04 00 25 30 00 01 7E
    2023-12-08 16:24:23,574 INFO: AciHostCLI continuously_read: >>>receive packet: AA 29 05 00 00 00 25 30 00 7D
    2023-12-08 16:24:23,574 INFO: Parser eventParser: syncWord: AA,seqn: 29,len: 5,opcode: 0000,params: [25 30 00], check_sum: 7D
    2023-12-08 16:24:23,574 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-12-08 16:24:23,574 INFO: Parser eventParser: event_id: [25 30]
    2023-12-08 16:24:23,574 INFO: Parser eventParser: status: [00]
    2023-12-08 16:24:23,574 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2A 07 00 41 01 D0 E7 2C 00 07 A3
    2023-12-08 16:24:23,578 INFO: Parser eventParser: syncWord: AA,seqn: 2A,len: 7,opcode: 0141,params: [D0 E7 2C 00 07], check_sum: A3
    2023-12-08 16:24:23,578 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:23,578 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:23,578 INFO: Parser eventParser: state: [07]
    2023-12-08 16:24:23,578 INFO: Packet sendPacket: <<<send packet: AA 29 05 00 00 00 41 01 00 90
    2023-12-08 16:24:23,718 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2B 07 00 41 01 D0 E7 2C 00 01 A8
    2023-12-08 16:24:23,718 INFO: Parser eventParser: syncWord: AA,seqn: 2B,len: 7,opcode: 0141,params: [D0 E7 2C 00 01], check_sum: A8
    2023-12-08 16:24:23,718 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-12-08 16:24:23,718 INFO: Parser eventParser: group_handle: [D0 E7 2C 00]
    2023-12-08 16:24:23,718 INFO: Parser eventParser: state: [01]
    2023-12-08 16:24:23,718 INFO: Packet sendPacket: <<<send packet: AA 2A 05 00 00 00 41 01 00 8F
    2023-12-08 16:24:23,956 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2C 0A 00 44 80 00 00 18 00 00 00 F4 01 F9
    2023-12-08 16:24:23,960 INFO: Parser eventParser: syncWord: AA,seqn: 2C,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: F9
    2023-12-08 16:24:23,960 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-12-08 16:24:23,960 INFO: Parser eventParser: app_link_id: [00]
    2023-12-08 16:24:23,960 INFO: Parser eventParser: res: [00]
    2023-12-08 16:24:23,960 INFO: Parser eventParser: connInterval: [18 00]
    2023-12-08 16:24:23,960 INFO: Parser eventParser: connLatency: [00 00]
    2023-12-08 16:24:23,964 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-12-08 16:24:23,964 INFO: Packet sendPacket: <<<send packet: AA 2B 05 00 00 00 44 80 00 0C
    
LE Audio Acceptor
Acceptor Introduction

Acceptor, which is described in the CAP SPEC, always operates in the BAP Unicast Server role, BAP Broadcast Sink role, BAP Scan Delegator role, VCP Volume Renderer Role, MICP MIC Device role, or CCP Call Control Client role.

Acceptor General ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_ADV_START(0x3250)

None

lea_adv_start

CMD_LEA_ADV_STOP(0x3251)

None

lea_adv_stop

The ACI Host CLI commands for Acceptor are CMD_LEA_ADV_START and CMD_LEA_ADV_STOP.

CMD_LEA_ADV_START is used to start LE Audio advertising and be able to be connected by the Initiator which supports CIS.

CMD_LEA_ADV_STOP is used to stop LE Audio advertising and the Initiator cannot scan the Acceptor.

  1. ACI Host CLI test: Start LE Audio Advertising.

    2023-07-27 11:07:56,017 INFO: input command: lea_adv_start x
    2023-07-27 11:07:56,018 INFO: Parser cmdParser: cmd opcode: 3250 param: [] name: CMD_LEA_ADV_START
    2023-07-27 11:07:56,019 INFO: Packet sendPacket: <<<send packet: AA 01 02 00 50 32 7B
    2023-07-27 11:07:56,029 INFO: AciHostCLI continuously_read: >>>receive packet: AA 02 05 00 00 00 50 32 00 77
    2023-07-27 11:07:56,036 INFO: Parser eventParser: syncWord: AA,seqn: 02,len: 5,opcode: 0000,params: [50 32 00], check_sum: 77
    2023-07-27 11:07:56,044 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 11:07:56,046 INFO: Parser eventParser: event_id: [50 32]
    2023-07-27 11:07:56,047 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Stop LE Audio Advertising.

    2023-07-27 11:08:38,865 INFO: input command: lea_adv_stop x
    2023-07-27 11:08:38,865 INFO: Parser cmdParser: cmd opcode: 3251 param: [] name: CMD_LEA_ADV_STOP
    2023-07-27 11:08:38,868 INFO: Packet sendPacket: <<<send packet: AA 09 02 00 51 32 72
    2023-07-27 11:08:38,883 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0A 05 00 00 00 51 32 00 6E
    2023-07-27 11:08:38,889 INFO: Parser eventParser: syncWord: AA,seqn: 0A,len: 5,opcode: 0000,params: [51 32 00], check_sum: 6E
    2023-07-27 11:08:38,892 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 11:08:38,895 INFO: Parser eventParser: event_id: [51 32]
    2023-07-27 11:08:38,897 INFO: Parser eventParser: status: [00]
    
BIS Acceptor Introduction

BIS Acceptor, subdivision according to CAP role of the Acceptor, availability in variety broadcast scenarios. Besides being used for receiving Broadcast Isochronous Streams, it can also support scanning for Broadcast Audio Streams autonomously or delegate the scanning to a Commander.

BIS Acceptor ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_SYNC_INIT(0x3254)

bis_mode = random
bis_policy = sink
addr = NULL

bis_sync_init random

CMD_LEA_SYNC_INIT(0x3254)

bis_mode = spec
bis_policy = sink
addr = {0x03:0x22:0x56:0x77:0x03:0x15}

bis_sync_init spec

CMD_LEA_SYNC_INIT(0x3254)

bis_mode = random
bis_policy = delegator
addr = NULL

bis_sync_init delegator

CMD_LEA_SYNC(0x3255)

sync = true

bis_sync start

CMD_LEA_SYNC(0x3255)

sync = false

bis_sync stop

The ACI Host CLI CMD for BIS are CMD_LEA_SYNC_INIT, CMD_LEA_SYNC. CMD_LEA_BSRC_INIT is used to initialize the BIS parameters, including BIS role, BIS mode, the addr need to sync and only used in SPEC mode.

CMD_LEA_SYNC is used to sync the broadcast audio stream.

  1. ACI Host CLI test: BIS sync init.

    2023-08-04 19:00:22,584 INFO: input command: bis_sync_init random
    2023-08-04 19:00:22,584 INFO: Parser cmdParser: cmd opcode: 3254 param: [02 00 00 00 00 00 00 00] name: CMD_LEA_SYNC_INIT
    2023-08-04 19:00:22,584 INFO: Packet sendPacket: <<<send packet: AA 04 0A 00 54 32 02 00 00 00 00 00 00 00 6A
    2023-08-04 19:00:22,604 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 54 32 00 71
    2023-08-04 19:00:22,609 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [54 32 00], check_sum: 71
    2023-08-04 19:00:22,614 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-08-04 19:00:22,614 INFO: Parser eventParser: event_id: [54 32]
    2023-08-04 19:00:22,628 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: BIS sync start.

    2023-08-04 19:00:29,694 INFO: input command: bis_sync start
    2023-08-04 19:00:29,694 INFO: Parser cmdParser: cmd opcode: 3255 param: [00] name: CMD_LEA_SYNC
    2023-08-04 19:00:29,694 INFO: Packet sendPacket: <<<send packet: AA 05 03 00 55 32 00 71
    2023-08-04 19:00:29,714 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 55 32 00 6F
    2023-08-04 19:00:29,724 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [55 32 00], check_sum: 6F
    2023-08-04 19:00:29,724 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-08-04 19:00:29,724 INFO: Parser eventParser: event_id: [55 32]
    2023-08-04 19:00:29,724 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: BIS sync stop.

    2023-08-04 19:01:02,725 INFO: input command: bis_sync stop
    2023-08-04 19:01:02,725 INFO: Parser cmdParser: cmd opcode: 3255 param: [01] name: CMD_LEA_SYNC
    2023-08-04 19:01:02,725 INFO: Packet sendPacket: <<<send packet: AA 06 03 00 55 32 01 6F
    2023-08-04 19:01:02,745 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 05 00 00 00 55 32 00 6E
    2023-08-04 19:01:02,745 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 5,opcode: 0000,params: [55 32 00], check_sum: 6E
    2023-08-04 19:01:02,745 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-08-04 19:01:02,745 INFO: Parser eventParser: event_id: [55 32]
    2023-08-04 19:01:02,755 INFO: Parser eventParser: status: [00]
    
CIS Acceptor Introduction

CIS, which stands for Unicast Isochronous Channel, is a logical transport for connected devices that allows sending and receiving isochronous data. For a CIS, an acknowledgment protocol is available to increase packet delivery dependability. This chapter describes how to use the CIS Acceptor and can be connected to remote devices. Actually, the CIS Acceptor can control the remote device’s music player and telephone call by MCP and CCP profiles. It will notify VCS audio volume to Initiator when local volume or SPK mute/unmute changes.

CIS Acceptor ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x00

lea_call_cp accept

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x01

lea_call_cp terminate

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x02

lea_call_cp local_hold

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x03

lea_call_cp local_retrieve

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x04

lea_call_cp originate

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x05

lea_call_cp join

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x01

lea_media_cp play

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x02

lea_media_cp pause

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x03

lea_media_cp fast_rewind

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x04

lea_media_cp fast_forward

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x05

lea_media_cp stop

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x30

lea_media_cp previous_track

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x31

lea_media_cp next_track

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x00

lea_vcs vol_up

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x01

lea_vcs vol_down

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x02

lea_vcs spk_mute

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x03

lea_vcs spk_unmute

The ACI Host CLI CMD for CIS Acceptor is CMD_LEA_CCP_CALL_CP, CMD_LEA_MCP_MEDIA_CP and CMD_LEA_VCS_SET:

  • CMD_LEA_CCP_CALL_CP is used to control the remote device’s telephone call when they are connected to LE Audio. And it can send accept, terminate, local hold, local retrieve, originate and join commands by CCP profile.

  • CMD_LEA_MCP_MEDIA_CP is used to control the remote device’s active music player when they are connected to LE Audio. And it can send play, pause, stop, fast rewind, fast forward, previous track, and next track commands by the MCP profile.

  • CMD_LEA_VCS_SET is used to change the volume of the local device’s audio and the CIS Acceptor will notify the VCS audio volume state to the remote device.

  1. ACI Host CLI test: CCP accept.

    2023-07-27 14:16:42,829 INFO: input command: lea_call_cp accept
    2023-07-27 14:16:42,830 INFO: Parser cmdParser: cmd opcode: 3252 param: [00 00] name: CMD_LEA_CCP_CALL_CP
    2023-07-27 14:16:42,831 INFO: Packet sendPacket: <<<send packet: AA 17 04 00 52 32 00 00 60
    2023-07-27 14:16:42,849 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0B 05 00 00 00 52 32 00 6B
    2023-07-27 14:16:42,858 INFO: Parser eventParser: syncWord: AA,seqn: 0B,len: 5,opcode: 0000,params: [52 32 00], check_sum: 6B
    2023-07-27 14:16:42,862 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 14:16:42,865 INFO: Parser eventParser: event_id: [52 32]
    2023-07-27 14:16:42,867 INFO: Parser eventParser: status: [00]
    2023-07-27 14:16:44,691 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E 04 00 52 32 00 04 56
    2023-07-27 14:16:44,692 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 4,opcode: 3252,params: [00 04], check_sum: 56
    2023-07-27 14:16:44,694 INFO: Packet sendPacket: <<<send packet: AA 0B 05 00 00 00 52 32 00 6C
    
  2. ACI Host CLI test: CCP terminate.

    2023-07-27 14:17:24,536 INFO: input command: lea_call_cp terminate
    2023-07-27 14:17:24,536 INFO: Parser cmdParser: cmd opcode: 3252 param: [00 01] name: CMD_LEA_CCP_CALL_CP
    2023-07-27 14:17:24,537 INFO: Packet sendPacket: <<<send packet: AA 1A 04 00 52 32 00 01 5D
    2023-07-27 14:17:24,556 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0E 05 00 00 00 52 32 00 69
    2023-07-27 14:17:24,559 INFO: Parser eventParser: syncWord: AA,seqn: 0E,len: 5,opcode: 0000,params: [52 32 00], check_sum: 69
    2023-07-27 14:17:24,560 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 14:17:24,561 INFO: Parser eventParser: event_id: [52 32]
    2023-07-27 14:17:24,562 INFO: Parser eventParser: status: [00]
    2023-07-27 14:17:26,922 INFO: AciHostCLI continuously_read: >>>receive packet: AA 20 04 00 52 32 00 00 58
    2023-07-27 14:17:26,923 INFO: Parser eventParser: syncWord: AA,seqn: 20,len: 4,opcode: 3252,params: [00 00], check_sum: 58
    2023-07-27 14:17:26,924 INFO: Packet sendPacket: <<<send packet: AA 0D 05 00 00 00 52 32 00 6A
    
  3. ACI Host CLI test: CCP local hold.

    2023-07-27 14:17:00,880 INFO: input command: lea_call_cp local_hold
    2023-07-27 14:17:00,880 INFO: Parser cmdParser: cmd opcode: 3252 param: [00 02] name: CMD_LEA_CCP_CALL_CP
    2023-07-27 14:17:00,882 INFO: Packet sendPacket: <<<send packet: AA 18 04 00 52 32 00 02 5E
    2023-07-27 14:17:00,903 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0C 05 00 00 00 52 32 00 6B
    2023-07-27 14:17:00,909 INFO: Parser eventParser: syncWord: AA,seqn: 0C,len: 5,opcode: 0000,params: [52 32 00], check_sum: 6B
    2023-07-27 14:17:00,918 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 14:17:00,920 INFO: Parser eventParser: event_id: [52 32]
    2023-07-27 14:17:00,921 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: CCP local retrieve.

    2023-07-27 14:17:08,153 INFO: input command: lea_call_cp local_retrieve
    2023-07-27 14:17:08,154 INFO: Parser cmdParser: cmd opcode: 3252 param: [00 03] name: CMD_LEA_CCP_CALL_CP
    2023-07-27 14:17:08,155 INFO: Packet sendPacket: <<<send packet: AA 19 04 00 52 32 00 03 5C
    2023-07-27 14:17:08,172 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0D 05 00 00 00 52 32 00 6A
    2023-07-27 14:17:08,176 INFO: Parser eventParser: syncWord: AA,seqn: 0D,len: 5,opcode: 0000,params: [52 32 00], check_sum: 6A
    2023-07-27 14:17:08,178 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 14:17:08,184 INFO: Parser eventParser: event_id: [52 32]
    2023-07-27 14:17:08,186 INFO: Parser eventParser: status: [00]
    
  5. ACI Host CLI test: CCP originate.

  6. ACI Host CLI test: CCP join.

  7. ACI Host CLI test: MCP play.

    2023-07-27 12:00:52,509 INFO: input command: lea_media_cp play
    2023-07-27 12:00:52,510 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 01] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:00:52,511 INFO: Packet sendPacket: <<<send packet: AA 01 04 00 53 32 00 01 75
    2023-07-27 12:00:52,531 INFO: AciHostCLI continuously_read: >>>receive packet: AA 25 05 00 00 00 53 32 00 51
    2023-07-27 12:00:52,535 INFO: Parser eventParser: syncWord: AA,seqn: 25,len: 5,opcode: 0000,params: [53 32 00], check_sum: 51
    2023-07-27 12:00:52,542 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:00:52,544 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:00:52,546 INFO: Parser eventParser: status: [00]
    2023-07-27 12:00:52,570 INFO: AciHostCLI continuously_read: >>>receive packet: AA 26 04 00 53 32 00 01 50
    2023-07-27 12:00:52,572 INFO: Parser eventParser: syncWord: AA,seqn: 26,len: 4,opcode: 3253,params: [00 01], check_sum: 50
    2023-07-27 12:00:52,573 INFO: Packet sendPacket: <<<send packet: AA 02 05 00 00 00 53 32 00 74
    
  8. ACI Host CLI test: MCP pause.

    2023-07-27 12:04:41,402 INFO: input command: lea_media_cp pause
    2023-07-27 12:04:41,403 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 02] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:04:41,404 INFO: Packet sendPacket: <<<send packet: AA 03 04 00 53 32 00 02 72
    2023-07-27 12:04:41,417 INFO: AciHostCLI continuously_read: >>>receive packet: AA 27 05 00 00 00 53 32 00 4F
    2023-07-27 12:04:41,419 INFO: Parser eventParser: syncWord: AA,seqn: 27,len: 5,opcode: 0000,params: [53 32 00], check_sum: 4F
    2023-07-27 12:04:41,426 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:04:41,428 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:04:41,429 INFO: Parser eventParser: status: [00]
    2023-07-27 12:04:41,497 INFO: AciHostCLI continuously_read: >>>receive packet: AA 28 04 00 53 32 00 02 4D
    2023-07-27 12:04:41,498 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 4,opcode: 3253,params: [00 02], check_sum: 4D
    2023-07-27 12:04:41,499 INFO: Packet sendPacket: <<<send packet: AA 04 05 00 00 00 53 32 00 72
    
  9. ACI Host CLI test: MCP fast rewind.

    2023-07-27 12:05:01,473 INFO: input command: lea_media_cp fast_rewind
    2023-07-27 12:05:01,474 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 03] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:05:01,476 INFO: Packet sendPacket: <<<send packet: AA 05 04 00 53 32 00 03 6F
    2023-07-27 12:05:01,497 INFO: AciHostCLI continuously_read: >>>receive packet: AA 29 05 00 00 00 53 32 00 4D
    2023-07-27 12:05:01,500 INFO: Parser eventParser: syncWord: AA,seqn: 29,len: 5,opcode: 0000,params: [53 32 00], check_sum: 4D
    2023-07-27 12:05:01,501 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:05:01,504 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:05:01,505 INFO: Parser eventParser: status: [00]
    2023-07-27 12:05:01,573 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2A 04 00 53 32 00 03 4A
    2023-07-27 12:05:01,574 INFO: Parser eventParser: syncWord: AA,seqn: 2A,len: 4,opcode: 3253,params: [00 03], check_sum: 4A
    2023-07-27 12:05:01,575 INFO: Packet sendPacket: <<<send packet: AA 06 05 00 00 00 53 32 00 70
    
  10. ACI Host CLI test: MCP fast forward.

    2023-07-27 12:05:17,450 INFO: input command: lea_media_cp fast_forward
    2023-07-27 12:05:17,450 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 04] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:05:17,452 INFO: Packet sendPacket: <<<send packet: AA 07 04 00 53 32 00 04 6C
    2023-07-27 12:05:17,463 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2B 05 00 00 00 53 32 00 4B
    2023-07-27 12:05:17,470 INFO: Parser eventParser: syncWord: AA,seqn: 2B,len: 5,opcode: 0000,params: [53 32 00], check_sum: 4B
    2023-07-27 12:05:17,471 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:05:17,473 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:05:17,473 INFO: Parser eventParser: status: [00]
    2023-07-27 12:05:17,620 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2C 04 00 53 32 00 03 48
    2023-07-27 12:05:17,621 INFO: Parser eventParser: syncWord: AA,seqn: 2C,len: 4,opcode: 3253,params: [00 01], check_sum: 48
    2023-07-27 12:05:17,622 INFO: Packet sendPacket: <<<send packet: AA 08 05 00 00 00 53 32 00 6E
    
  11. ACI Host CLI test: MCP stop.

    2023-07-27 12:07:08,855 INFO: input command: lea_media_cp stop
    2023-07-27 12:07:08,856 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 05] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:07:08,857 INFO: Packet sendPacket: <<<send packet: AA 1A 04 00 53 32 00 05 58
    2023-07-27 12:07:08,874 INFO: AciHostCLI continuously_read: >>>receive packet: AA 3E 05 00 00 00 53 32 00 38
    2023-07-27 12:07:08,876 INFO: Parser eventParser: syncWord: AA,seqn: 3E,len: 5,opcode: 0000,params: [53 32 00], check_sum: 38
    2023-07-27 12:07:08,878 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:07:08,880 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:07:08,881 INFO: Parser eventParser: status: [00]
    2023-07-27 12:07:11,332 INFO: AciHostCLI continuously_read: >>>receive packet: AA 3F 04 00 53 32 00 02 36
    2023-07-27 12:07:11,334 INFO: Parser eventParser: syncWord: AA,seqn: 3F,len: 4,opcode: 3253,params: [00 02], check_sum: 36
    2023-07-27 12:07:11,336 INFO: Packet sendPacket: <<<send packet: AA 1B 05 00 00 00 53 32 00 5B
    
  12. ACI Host CLI test: MCP previous track.

    2023-07-27 12:07:54,069 INFO: input command: lea_media_cp previous_track
    2023-07-27 12:07:54,070 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 30] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:07:54,072 INFO: Packet sendPacket: <<<send packet: AA 1F 04 00 53 32 00 30 28
    2023-07-27 12:07:54,094 INFO: AciHostCLI continuously_read: >>>receive packet: AA 43 05 00 00 00 53 32 00 33
    2023-07-27 12:07:54,097 INFO: Parser eventParser: syncWord: AA,seqn: 43,len: 5,opcode: 0000,params: [53 32 00], check_sum: 33
    2023-07-27 12:07:54,099 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:07:54,100 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:07:54,101 INFO: Parser eventParser: status: [00]
    
  13. ACI Host CLI test: MCP next track.

    2023-07-27 12:08:05,519 INFO: input command: lea_media_cp next_track
    2023-07-27 12:08:05,519 INFO: Parser cmdParser: cmd opcode: 3253 param: [00 31] name: CMD_LEA_MCP_MEDIA_CP
    2023-07-27 12:08:05,520 INFO: Packet sendPacket: <<<send packet: AA 20 04 00 53 32 00 31 26
    2023-07-27 12:08:05,540 INFO: AciHostCLI continuously_read: >>>receive packet: AA 44 05 00 00 00 53 32 00 32
    2023-07-27 12:08:05,543 INFO: Parser eventParser: syncWord: AA,seqn: 44,len: 5,opcode: 0000,params: [53 32 00], check_sum: 32
    2023-07-27 12:08:05,543 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-27 12:08:05,544 INFO: Parser eventParser: event_id: [53 32]
    2023-07-27 12:08:05,545 INFO: Parser eventParser: status: [00]
    
  14. ACI Host CLI test: VCS volume up.

    2024-02-28 15:31:52,825 INFO: input command: lea_vcs vol_up
    2024-02-28 15:31:52,827 INFO: Parser cmdParser: cmd opcode: 3256 param: [00 00] name: CMD_LEA_VCS_SET_CP
    2024-02-28 15:31:52,829 INFO: Packet sendPacket: <<<send packet: AA 26 04 00 56 32 00 00 4E
    2024-02-28 15:31:52,852 INFO: AciHostCLI continuously_read: >>>receive packet: AA 25 03 00 20 00 01 B7
    2024-02-28 15:31:52,856 INFO: Parser eventParser: syncWord: AA,seqn: 25,len: 3,opcode: 0020,params: [01], check_sum: B7
    2024-02-28 15:31:52,859 INFO: Parser eventParser: event name: EVENT_AUDIO_VOL_CHANGE
    2024-02-28 15:31:52,872 INFO: Packet sendPacket: <<<send packet: AA 27 05 00 00 00 20 00 00 B4
    2024-02-28 15:31:52,882 INFO: AciHostCLI continuously_read: >>>receive packet: AA 26 05 00 00 00 56 32 00 4D
    2024-02-28 15:31:52,885 INFO: Parser eventParser: syncWord: AA,seqn: 26,len: 5,opcode: 0000,params: [56 32 00], check_sum: 4D
    2024-02-28 15:31:52,887 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-02-28 15:31:52,889 INFO: Parser eventParser: event_id: [56 32]
    2024-02-28 15:31:52,891 INFO: Parser eventParser: status: [00]
    
  15. ACI Host CLI test: VCS volume down.

    2024-02-28 15:31:46,154 INFO: input command: lea_vcs vol_down
    2024-02-28 15:31:46,156 INFO: Parser cmdParser: cmd opcode: 3256 param: [00 01] name: CMD_LEA_VCS_SET_CP
    2024-02-28 15:31:46,158 INFO: Packet sendPacket: <<<send packet: AA 23 04 00 56 32 00 01 50
    2024-02-28 15:31:46,173 INFO: AciHostCLI continuously_read: >>>receive packet: AA 22 03 00 20 00 04 B7
    2024-02-28 15:31:46,176 INFO: Parser eventParser: syncWord: AA,seqn: 22,len: 3,opcode: 0020,params: [04], check_sum: B7
    2024-02-28 15:31:46,180 INFO: Parser eventParser: event name: EVENT_AUDIO_VOL_CHANGE
    2024-02-28 15:31:46,182 INFO: Packet sendPacket: <<<send packet: AA 24 05 00 00 00 20 00 00 B7
    2024-02-28 15:31:46,188 INFO: AciHostCLI continuously_read: >>>receive packet: AA 23 05 00 00 00 56 32 00 50
    2024-02-28 15:31:46,190 INFO: Parser eventParser: syncWord: AA,seqn: 23,len: 5,opcode: 0000,params: [56 32 00], check_sum: 50
    2024-02-28 15:31:46,191 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-02-28 15:31:46,193 INFO: Parser eventParser: event_id: [56 32]
    2024-02-28 15:31:46,194 INFO: Parser eventParser: status: [00]
    
  16. ACI Host CLI test: VCS SPK mute.

    2024-02-28 15:32:02,346 INFO: input command: lea_vcs spk_mute
    2024-02-28 15:32:02,346 INFO: Parser cmdParser: cmd opcode: 3256 param: [00 02] name: CMD_LEA_VCS_SET_CP
    2024-02-28 15:32:02,348 INFO: Packet sendPacket: <<<send packet: AA 2F 04 00 56 32 00 02 43
    2024-02-28 15:32:02,371 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2F 05 00 00 00 56 32 00 44
    2024-02-28 15:32:02,373 INFO: Parser eventParser: syncWord: AA,seqn: 2F,len: 5,opcode: 0000,params: [56 32 00], check_sum: 44
    2024-02-28 15:32:02,375 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-02-28 15:32:02,377 INFO: Parser eventParser: event_id: [56 32]
    2024-02-28 15:32:02,378 INFO: Parser eventParser: status: [00]
    
  17. ACI Host CLI test: VCS SPK unmute.

    2024-02-28 15:32:06,691 INFO: input command: lea_vcs spk_unmute
    2024-02-28 15:32:06,692 INFO: Parser cmdParser: cmd opcode: 3256 param: [00 03] name: CMD_LEA_VCS_SET_CP
    2024-02-28 15:32:06,695 INFO: Packet sendPacket: <<<send packet: AA 30 04 00 56 32 00 03 41
    2024-02-28 15:32:06,720 INFO: AciHostCLI continuously_read: >>>receive packet: AA 30 05 00 00 00 56 32 00 43
    2024-02-28 15:32:06,726 INFO: Parser eventParser: syncWord: AA,seqn: 30,len: 5,opcode: 0000,params: [56 32 00], check_sum: 43
    2024-02-28 15:32:06,729 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-02-28 15:32:06,732 INFO: Parser eventParser: event_id: [56 32]
    2024-02-28 15:32:06,738 INFO: Parser eventParser: status: [00]
    

Bluetooth Audio Transmitter

This chapter introduces the functionality of the bt_audio_transmitter application scenario. This functionality is enabled by opening the macro definition F_APP_BT_AUDIO_TRANSMITTER_DEMO_SUPPORT in app_flags.h. This chapter describes how to use these functions and the flow of how to test them, including the MSCs of the ACI Device and ACI Host interaction, and the commands used by ACI Host.

Source Play Function

Based on the scenario introduced in Bluetooth Audio Transmitter, Bluetooth Audio Transceiver application supports source play function, which can transmit MIC, line-in, USB, SD card signal to BUDs through HFP, A2DP or BIS/CIS. These input and output methods can be combined in various ways by set_route_in CMD and set_route_out CMD. This chapter presents three combinations as examples:

MIC Source Play

Before using, configure MIC 1 on the EVB and connect an external MIC. After connecting the MIC and starting the recording, the recorded data will be sent to the connected BUD via HFP. The MIC source playback process is:

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = mic(0x01, 0x00)

set_route_in mic

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = hfp_ag(0x02)

set_route_out hfp_ag

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the MIC input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set HFP output route, sends CMD_SRC_PLAY_ROUTE_IN_START or CMD_SRC_PLAY_ROUTE_IN_STOP to start or stop the MIC input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START or CMD_SRC_PLAY_ROUTE_OUT_STOP to start or stop the HFP output route.

  1. ACI Host CLI test: Connect ACI Device to BUD.

    Please refer to Connect to BUD.

  2. ACI Host CLI test: Input set_route_in mic.

    2023-04-18 18:35:04,933 INFO: input command: set_route_in mic
    2023-04-18 18:35:04,933 INFO: Parser cmdParser: cmd opcode: 3300 param: [01 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-04-18 18:35:04,934 INFO: Packet sendPacket: <<<send packet: AA 10 03 00 00 33 01 00 B9
    2023-04-18 18:35:04,956 INFO: AciHostCLI continuously_read: >>>receive packet: AA 10 05 00 00 00 00 33 00 B8
    2023-04-18 18:35:04,963 INFO: Parser eventParser: syncWord: AA,seqn: 10,len: 5,opcode: 0000,params: [00 33 00], check_sum: B8
    2023-04-18 18:35:04,966 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:35:04,983 INFO: Parser eventParser: event_id: [00 33]
    2023-04-18 18:35:04,986 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input set_route_out hfp_ag.

    2023-04-18 18:35:18,259 INFO: input command: set_route_out hfp_ag
    2023-04-18 18:35:18,260 INFO: Parser cmdParser: cmd opcode: 3302 param: [02] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-04-18 18:35:18,262 INFO: Packet sendPacket: <<<send packet: AA 11 03 00 02 33 02 B5
    2023-04-18 18:35:18,279 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 05 00 00 00 02 33 00 B5
    2023-04-18 18:35:18,284 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 5,opcode: 0000,params: [02 33 00], check_sum: B5
    2023-04-18 18:35:18,285 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:35:18,286 INFO: Parser eventParser: event_id: [02 33]
    2023-04-18 18:35:18,287 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Input route_out start.

    2023-04-18 18:35:29,323 INFO: input command: route_out start
    2023-04-18 18:35:29,324 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-04-18 18:35:29,326 INFO: Packet sendPacket: <<<send packet: AA 12 02 00 06 33 B3
    2023-04-18 18:35:29,338 INFO: AciHostCLI continuously_read: >>>receive packet: AA 12 05 00 00 00 06 33 00 B0
    2023-04-18 18:35:29,339 INFO: Parser eventParser: syncWord: AA,seqn: 12,len: 5,opcode: 0000,params: [06 33 00], check_sum: B0
    2023-04-18 18:35:29,347 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:35:29,351 INFO: Parser eventParser: event_id: [06 33]
    2023-04-18 18:35:29,353 INFO: Parser eventParser: status: [00]
    2023-04-18 18:35:29,539 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 04 00 38 03 00 02 AC
    2023-04-18 18:35:29,540 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 4,opcode: 0338,params: [00 02], check_sum: AC
    2023-04-18 18:35:29,542 INFO: Packet sendPacket: <<<send packet: AA 13 05 00 00 00 38 03 00 AD
    2023-04-18 18:35:29,555 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 04 00 00 03 00 01 E4
    2023-04-18 18:35:29,556 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 4,opcode: 0300,params: [00 01], check_sum: E4
    2023-04-18 18:35:29,557 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2023-04-18 18:35:29,561 INFO: Parser eventParser: app_link_id: [00]
    2023-04-18 18:35:29,563 INFO: Parser eventParser: state: [01]
    2023-04-18 18:35:29,565 INFO: Packet sendPacket: <<<send packet: AA 14 05 00 00 00 00 03 00 E4
    
  5. ACI Host CLI test: Input route_in start.

    2023-04-18 18:35:43,561 INFO: input command: route_in start
    2023-04-18 18:35:43,562 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-04-18 18:35:43,563 INFO: Packet sendPacket: <<<send packet: AA 15 02 00 04 33 B2
    2023-04-18 18:35:43,597 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 05 00 00 00 04 33 00 AF
    2023-04-18 18:35:43,610 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 5,opcode: 0000,params: [04 33 00], check_sum: AF
    2023-04-18 18:35:43,612 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:35:43,614 INFO: Parser eventParser: event_id: [04 33]
    2023-04-18 18:35:43,615 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test: Input route_in stop.

    2023-04-18 18:36:05,128 INFO: input command: route_in stop
    2023-04-18 18:36:05,128 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-04-18 18:36:05,130 INFO: Packet sendPacket: <<<send packet: AA 16 02 00 05 33 B0
    2023-04-18 18:36:05,145 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 05 00 00 00 05 33 00 AD
    2023-04-18 18:36:05,166 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 5,opcode: 0000,params: [05 33 00], check_sum: AD
    2023-04-18 18:36:05,167 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:36:05,168 INFO: Parser eventParser: event_id: [05 33]
    2023-04-18 18:36:05,170 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test: Input route_out stop.

    2023-04-18 18:36:32,207 INFO: input command: route_out stop
    2023-04-18 18:36:32,208 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-04-18 18:36:32,210 INFO: Packet sendPacket: <<<send packet: AA 18 02 00 07 33 AC
    2023-04-18 18:36:32,221 INFO: AciHostCLI continuously_read: >>>receive packet: AA 18 05 00 00 00 07 33 00 A9
    2023-04-18 18:36:32,227 INFO: Parser eventParser: syncWord: AA,seqn: 18,len: 5,opcode: 0000,params: [07 33 00], check_sum: A9
    2023-04-18 18:36:32,230 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:36:32,232 INFO: Parser eventParser: event_id: [07 33]
    2023-04-18 18:36:32,233 INFO: Parser eventParser: status: [00]
    2023-04-18 18:36:32,285 INFO: AciHostCLI continuously_read: >>>receive packet: AA 19 04 00 00 03 00 00 E0
    2023-04-18 18:36:32,286 INFO: Parser eventParser: syncWord: AA,seqn: 19,len: 4,opcode: 0300,params: [00 00], check_sum: E0
    2023-04-18 18:36:32,287 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2023-04-18 18:36:32,288 INFO: Parser eventParser: app_link_id: [00]
    2023-04-18 18:36:32,288 INFO: Parser eventParser: state: [00]
    2023-04-18 18:36:32,290 INFO: Packet sendPacket: <<<send packet: AA 19 05 00 00 00 00 03 00 DF
    
Line-in Source Play (A2DP Output)

Before using, please configure MIC 2 on the EVB and connect to PC through line-in. After line-in is connected and music on PC is started, the music data will be sent to the connected BUD through A2DP.

Line-in source play (A2DP output) process:

ACI Host CLI Test

The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the line-in input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set A2DP output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the line-in input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP to start or stop the A2DP output route.

Command

Parameters

ACI Host CLI CMD

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = linein(0x02, 0x00)

set_route_in linein

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = a2dp(0x01)

set_route_out a2dp

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

  1. ACI Host CLI test: Connect ACI Device to BUD.

    Please refer to Connect to BUD.

  2. ACI Host CLI test: Input set_route_in line-in.

    2023-04-18 18:37:54,643 INFO: input command: set_route_in linein
    2023-04-18 18:37:54,643 INFO: Parser cmdParser: cmd opcode: 3300 param: [02 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-04-18 18:37:54,645 INFO: Packet sendPacket: <<<send packet: AA 29 03 00 00 33 02 00 9F
    2023-04-18 18:37:54,658 INFO: AciHostCLI continuously_read: >>>receive packet: AA 10 05 00 00 00 00 33 00 B8
    2023-04-18 18:37:54,663 INFO: Parser eventParser: syncWord: AA,seqn: 10,len: 5,opcode: 0000,params: [00 33 00], check_sum: B8
    2023-04-18 18:37:54,667 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:37:54,670 INFO: Parser eventParser: event_id: [00 33]
    2023-04-18 18:37:54,672 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input set_route_out a2dp.

    2023-04-18 18:38:07,087 INFO: input command: set_route_out a2dp
    2023-04-18 18:38:07,088 INFO: Parser cmdParser: cmd opcode: 3302 param: [01] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-04-18 18:38:07,090 INFO: Packet sendPacket: <<<send packet: AA 2A 03 00 02 33 01 9D
    2023-04-18 18:38:07,101 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 05 00 00 00 02 33 00 B5
    2023-04-18 18:38:07,113 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 5,opcode: 0000,params: [02 33 00], check_sum: B5
    2023-04-18 18:38:07,116 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:38:07,116 INFO: Parser eventParser: event_id: [02 33]
    2023-04-18 18:38:07,117 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Input route_out start.

    2023-04-18 18:38:23,684 INFO: input command: route_out start
    2023-04-18 18:38:23,685 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-04-18 18:38:23,685 INFO: Packet sendPacket: <<<send packet: AA 2B 02 00 06 33 9A
    2023-04-18 18:38:23,699 INFO: AciHostCLI continuously_read: >>>receive packet: AA 12 05 00 00 00 06 33 00 B0
    2023-04-18 18:38:23,702 INFO: Parser eventParser: syncWord: AA,seqn: 12,len: 5,opcode: 0000,params: [06 33 00], check_sum: B0
    2023-04-18 18:38:23,708 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:38:23,708 INFO: Parser eventParser: event_id: [06 33]
    2023-04-18 18:38:23,709 INFO: Parser eventParser: status: [00]
    
  5. ACI Host CLI test: Input route_in start.

    2023-04-18 18:38:26,773 INFO: input command: route_in start
    2023-04-18 18:38:26,774 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-04-18 18:38:26,775 INFO: Packet sendPacket: <<<send packet: AA 2C 02 00 04 33 9B
    2023-04-18 18:38:26,796 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 05 00 00 00 04 33 00 B1
    2023-04-18 18:38:26,798 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 5,opcode: 0000,params: [04 33 00], check_sum: B1
    2023-04-18 18:38:26,798 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:38:26,799 INFO: Parser eventParser: event_id: [04 33]
    2023-04-18 18:38:26,800 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test: Input route_in stop.

    2023-04-18 18:39:21,706 INFO: input command: route_in stop
    2023-04-18 18:39:21,707 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-04-18 18:39:21,708 INFO: Packet sendPacket: <<<send packet: AA 2D 02 00 05 33 99
    2023-04-18 18:39:21,712 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 05 00 00 00 05 33 00 AF
    2023-04-18 18:39:21,719 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 5,opcode: 0000,params: [05 33 00], check_sum: AF
    2023-04-18 18:39:21,723 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:39:21,723 INFO: Parser eventParser: event_id: [05 33]
    2023-04-18 18:39:21,726 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test: Input route_out stop.

    2023-04-18 18:39:44,974 INFO: input command: route_out stop
    2023-04-18 18:39:44,974 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-04-18 18:39:44,976 INFO: Packet sendPacket: <<<send packet: AA 2F 02 00 07 33 95
    2023-04-18 18:39:45,044 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 05 00 00 00 07 33 00 AB
    2023-04-18 18:39:45,046 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 5,opcode: 0000,params: [07 33 00], check_sum: AB
    2023-04-18 18:39:45,047 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-18 18:39:45,052 INFO: Parser eventParser: event_id: [07 33]
    2023-04-18 18:39:45,055 INFO: Parser eventParser: status: [00]
    
Line-in Source Play (BIS Output)

Before using, please configure MIC 2 on the EVB and connect to PC through line-in. After line-in is connected and music on the PC is started, the music data could be sent to the BUD(s) through BIS.

BIS supports configuring codec type (48k/16k), BIS number (1 BIS containing dual-channel data or 2 BIS containing separate L and R channel data), ULL mode (E2E Latency < 30ms), and other parameters. For details, please refer to ACI_CMD_LEA_BSRC_INIT.

Line-in source play (BIS Output) process:

ACI Host CLI Test

When using BIS as output path, it is necessary to initialize BIS first through CMD_LEA_BSRC_INIT. The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the line-in input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set BIS output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the line-in input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP (other than CMD_LEA_BSRC_START/STOP) to start or stop the BIS output route.

Command

Parameters

ACI Host CLI CMD

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 2
encryption = false
ull_mode = false
pd = 0x2710

bsrcinit 48k_2bis

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = linein(0x02, 0x00)

set_route_in linein

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = BIS(0x03)

set_route_out bis

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

  1. ACI Host CLI test: Initialize BIS.

    2023-05-31 10:25:21,803 INFO: input command: bsrcinit 48k_2bis
    2023-05-31 10:25:21,803 INFO: Parser cmdParser: cmd opcode: 3020 param: [0D 02 00 01 10 27] name: CMD_LEA_BSRC_INIT
    2023-05-31 10:25:21,803 INFO: Packet sendPacket: <<<send packet: AA 0C 07 00 20 30 0D 02 00 01 10 27 11
    2023-05-31 10:25:21,834 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 20 30 00 C6
    2023-05-31 10:25:21,834 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [20 30 00], check_sum: C6
    2023-05-31 10:25:21,834 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:25:21,834 INFO: Parser eventParser: event_id: [20 30]
    2023-05-31 10:25:21,834 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Input set_route_out bis.

    2023-05-31 10:24:33,516 INFO: input command: set_route_out bis
    2023-05-31 10:24:33,516 INFO: Parser cmdParser: cmd opcode: 3302 param: [03] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-05-31 10:24:33,526 INFO: Packet sendPacket: <<<send packet: AA 04 03 00 02 33 03 C1
    2023-05-31 10:24:33,546 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 02 33 00 C2
    2023-05-31 10:24:33,546 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [02 33 00], check_sum: C2
    2023-05-31 10:24:33,546 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:24:33,546 INFO: Parser eventParser: event_id: [02 33]
    2023-05-31 10:24:33,546 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input set_route_in line-in.

    2023-05-31 10:24:36,385 INFO: input command: set_route_in linein
    2023-05-31 10:24:36,385 INFO: Parser cmdParser: cmd opcode: 3300 param: [02 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-05-31 10:24:36,385 INFO: Packet sendPacket: <<<send packet: AA 05 03 00 00 33 02 00 C3
    2023-05-31 10:24:36,405 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 00 33 00 C3
    2023-05-31 10:24:36,405 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [00 33 00], check_sum: C3
    2023-05-31 10:24:36,405 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:24:36,405 INFO: Parser eventParser: event_id: [00 33]
    2023-05-31 10:24:36,415 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Input route_out start.

    2023-05-31 10:24:39,606 INFO: input command: route_out start
    2023-05-31 10:24:39,616 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-05-31 10:24:39,616 INFO: Packet sendPacket: <<<send packet: AA 06 02 00 06 33 BF
    2023-05-31 10:24:39,626 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 05 00 00 00 06 33 00 BC
    2023-05-31 10:24:39,626 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 5,opcode: 0000,params: [06 33 00], check_sum: BC
    2023-05-31 10:24:39,626 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:24:39,626 INFO: Parser eventParser: event_id: [06 33]
    2023-05-31 10:24:39,626 INFO: Parser eventParser: status: [00]
    
  5. ACI Host CLI test: Input route_in start.

    2023-05-31 10:24:42,685 INFO: input command: route_in start
    2023-05-31 10:24:42,695 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-05-31 10:24:42,695 INFO: Packet sendPacket: <<<send packet: AA 07 02 00 04 33 C0
    2023-05-31 10:24:42,755 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 05 00 00 00 04 33 00 BD
    2023-05-31 10:24:42,755 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 5,opcode: 0000,params: [04 33 00], check_sum: BD
    2023-05-31 10:24:42,755 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:24:42,755 INFO: Parser eventParser: event_id: [04 33]
    2023-05-31 10:24:42,755 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test: Input route_in stop.

    2023-05-31 10:24:50,746 INFO: input command: route_in stop
    2023-05-31 10:24:50,746 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-05-31 10:24:50,746 INFO: Packet sendPacket: <<<send packet: AA 08 02 00 05 33 BE
    2023-05-31 10:24:50,766 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 05 00 00 00 05 33 00 BB
    2023-05-31 10:24:50,766 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 5,opcode: 0000,params: [05 33 00], check_sum: BB
    2023-05-31 10:24:50,766 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:24:50,766 INFO: Parser eventParser: event_id: [05 33]
    2023-05-31 10:24:50,766 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test: Input route_out stop.

    2023-05-31 10:25:04,644 INFO: input command: route_out stop
    2023-05-31 10:25:04,644 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-05-31 10:25:04,644 INFO: Packet sendPacket: <<<send packet: AA 09 02 00 07 33 BB
    2023-05-31 10:25:04,664 INFO: AciHostCLI continuously_read: >>>receive packet: AA 09 05 00 00 00 07 33 00 B8
    2023-05-31 10:25:04,664 INFO: Parser eventParser: syncWord: AA,seqn: 09,len: 5,opcode: 0000,params: [07 33 00], check_sum: B8
    2023-05-31 10:25:04,674 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 10:25:04,674 INFO: Parser eventParser: event_id: [07 33]
    2023-05-31 10:25:04,674 INFO: Parser eventParser: status: [00]
    
Line-in Source Play (CIS Output)

Before using, please configure MIC 2 on the EVB and connect to PC through line-in. After line-in is connected and music on PC is started, the music data can be sent to the connected BUD(s) through CIS.

In this scenario, CIS supports only the downlink direction of the datapath. The codec type is determined through negotiation (refer to app_lea_ini_select_media_prefer_codec()). In ULL mode (configured through the CMD_LEA_CIS_ULL_MODE command, and E2E Latency < 30ms), 48_1 is preferred, while in non-ULL mode, 48_6 takes precedence.

CIS connection process: Please refer to ACI Host CLI Test: Advertising.

Line-in source play (CIS Output) process:

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = linein(0x02, 0x00)

set_route_in linein

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = cis(0x04)

set_route_out cis

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

For CIS, it is necessary to establish an LE link. Please refer to Initiator General ACI Host CLI Test for connection procedure.

The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the line-in input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set CIS output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the line-in input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP to start or stop the CIS output route.

  1. ACI Host CLI test: Input set_route_in line-in.

    2023-07-17 16:00:30,147 INFO: input command: set_route_in linein
    2023-07-17 16:00:30,147 INFO: Parser cmdParser: cmd opcode: 3300 param: [02 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-07-17 16:00:30,148 INFO: Packet sendPacket: <<<send packet: AA 16 03 00 00 33 02 00 B2
    2023-07-17 16:00:30,154 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 05 00 00 00 00 33 00 B2
    2023-07-17 16:00:30,155 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 5,opcode: 0000,params: [00 33 00], check_sum: B2
    2023-07-17 16:00:30,158 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 16:00:30,159 INFO: Parser eventParser: event_id: [00 33]
    2023-07-17 16:00:30,160 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Input set_route_out cis.

    2023-07-17 16:00:34,130 INFO: input command: set_route_out cis
    2023-07-17 16:00:34,130 INFO: Parser cmdParser: cmd opcode: 3302 param: [04] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-07-17 16:00:34,131 INFO: Packet sendPacket: <<<send packet: AA 17 03 00 02 33 04 AD
    2023-07-17 16:00:34,148 INFO: AciHostCLI continuously_read: >>>receive packet: AA 17 05 00 00 00 02 33 00 AF
    2023-07-17 16:00:34,149 INFO: Parser eventParser: syncWord: AA,seqn: 17,len: 5,opcode: 0000,params: [02 33 00], check_sum: AF
    2023-07-17 16:00:34,149 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 16:00:34,150 INFO: Parser eventParser: event_id: [02 33]
    2023-07-17 16:00:34,150 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input route_out start and the BAP state will transition to state 4 (AUDIO_STREAM_STATE_STREAMING).

    2023-07-17 16:00:37,182 INFO: input command: route_out start
    2023-07-17 16:00:37,182 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-07-17 16:00:37,183 INFO: Packet sendPacket: <<<send packet: AA 18 02 00 06 33 AD
    2023-07-17 16:00:37,199 INFO: AciHostCLI continuously_read: >>>receive packet: AA 18 05 00 00 00 06 33 00 AA
    2023-07-17 16:00:37,199 INFO: Parser eventParser: syncWord: AA,seqn: 18,len: 5,opcode: 0000,params: [06 33 00], check_sum: AA
    2023-07-17 16:00:37,200 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 16:00:37,201 INFO: Parser eventParser: event_id: [06 33]
    2023-07-17 16:00:37,201 INFO: Parser eventParser: status: [00]
    2023-07-17 16:00:37,202 INFO: AciHostCLI continuously_read: >>>receive packet: AA 19 07 00 0C 01 90 B3 2C 00 01 63
    2023-07-17 16:00:37,202 INFO: Parser eventParser: syncWord: AA,seqn: 19,len: 7,opcode: 010C,params: [90 B3 2C 00 01], check_sum: 63
    2023-07-17 16:00:37,203 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-07-17 16:00:37,203 INFO: Parser eventParser: group_handle: [90 B3 2C 00]
    2023-07-17 16:00:37,203 INFO: Parser eventParser: state: [01]
    2023-07-17 16:00:37,204 INFO: Packet sendPacket: <<<send packet: AA 19 05 00 00 00 0C 01 00 D5
    2023-07-17 16:00:37,215 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1A 07 00 0C 01 90 B3 2C 00 03 60
    2023-07-17 16:00:37,215 INFO: Parser eventParser: syncWord: AA,seqn: 1A,len: 7,opcode: 010C,params: [90 B3 2C 00 03], check_sum: 60
    2023-07-17 16:00:37,216 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-07-17 16:00:37,216 INFO: Parser eventParser: group_handle: [90 B3 2C 00]
    2023-07-17 16:00:37,217 INFO: Parser eventParser: state: [03]
    2023-07-17 16:00:37,217 INFO: Packet sendPacket: <<<send packet: AA 1A 05 00 00 00 0C 01 00 D4
    2023-07-17 16:00:38,365 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1B 0A 00 44 80 00 00 24 00 00 00 E8 03 08
    2023-07-17 16:00:38,366 INFO: Parser eventParser: syncWord: AA,seqn: 1B,len: 10,opcode: 8044,params: [00 00 24 00 00 00 E8 03], check_sum: 08
    2023-07-17 16:00:38,367 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-07-17 16:00:38,367 INFO: Parser eventParser: app_link_id: [00]
    2023-07-17 16:00:38,367 INFO: Parser eventParser: res: [00]
    2023-07-17 16:00:38,368 INFO: Parser eventParser: connInterval: [24 00]
    2023-07-17 16:00:38,368 INFO: Parser eventParser: connLatency: [00 00]
    2023-07-17 16:00:38,369 INFO: Parser eventParser: supTimeout: [E8 03]
    2023-07-17 16:00:38,370 INFO: Packet sendPacket: <<<send packet: AA 1B 05 00 00 00 44 80 00 1C
    2023-07-17 16:00:39,595 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1C 0A 00 44 80 01 00 6C 00 00 00 F4 01 B4
    2023-07-17 16:00:39,596 INFO: Parser eventParser: syncWord: AA,seqn: 1C,len: 10,opcode: 8044,params: [01 00 6C 00 00 00 F4 01], check_sum: B4
    2023-07-17 16:00:39,596 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-07-17 16:00:39,597 INFO: Parser eventParser: app_link_id: [01]
    2023-07-17 16:00:39,597 INFO: Parser eventParser: res: [00]
    2023-07-17 16:00:39,597 INFO: Parser eventParser: connInterval: [6C 00]
    2023-07-17 16:00:39,598 INFO: Parser eventParser: connLatency: [00 00]
    2023-07-17 16:00:39,598 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-07-17 16:00:39,599 INFO: Packet sendPacket: <<<send packet: AA 1C 05 00 00 00 44 80 00 1B
    2023-07-17 16:00:41,000 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1D 0A 00 44 80 01 00 24 00 00 00 F4 01 FB
    2023-07-17 16:00:41,001 INFO: Parser eventParser: syncWord: AA,seqn: 1D,len: 10,opcode: 8044,params: [01 00 24 00 00 00 F4 01], check_sum: FB
    2023-07-17 16:00:41,002 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2023-07-17 16:00:41,002 INFO: Parser eventParser: app_link_id: [01]
    2023-07-17 16:00:41,003 INFO: Parser eventParser: res: [00]
    2023-07-17 16:00:41,003 INFO: Parser eventParser: connInterval: [24 00]
    2023-07-17 16:00:41,003 INFO: Parser eventParser: connLatency: [00 00]
    2023-07-17 16:00:41,004 INFO: Parser eventParser: supTimeout: [F4 01]
    2023-07-17 16:00:41,004 INFO: Packet sendPacket: <<<send packet: AA 1D 05 00 00 00 44 80 00 1A
    2023-07-17 16:00:41,448 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E 07 00 0C 01 90 B3 2C 00 04 5B
    2023-07-17 16:00:41,449 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 7,opcode: 010C,params: [90 B3 2C 00 04], check_sum: 5B
    2023-07-17 16:00:41,449 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-07-17 16:00:41,450 INFO: Parser eventParser: group_handle: [90 B3 2C 00]
    2023-07-17 16:00:41,451 INFO: Parser eventParser: state: [04]
    2023-07-17 16:00:41,451 INFO: Packet sendPacket: <<<send packet: AA 1E 05 00 00 00 0C 01 00 D0
    
  4. ACI Host CLI test: Input route_in start.

    2023-07-17 16:00:45,813 INFO: input command: route_in start
    2023-07-17 16:00:45,814 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-07-17 16:00:45,814 INFO: Packet sendPacket: <<<send packet: AA 1F 02 00 04 33 A8
    2023-07-17 16:00:45,873 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 05 00 00 00 04 33 00 A5
    2023-07-17 16:00:45,874 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 5,opcode: 0000,params: [04 33 00], check_sum: A5
    2023-07-17 16:00:45,874 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 16:00:45,875 INFO: Parser eventParser: event_id: [04 33]
    2023-07-17 16:00:45,875 INFO: Parser eventParser: status: [00]
    
  5. ACI Host CLI test: Input route_out stop, and the BAP state will transition to state 1 (AUDIO_STREAM_STATE_IDLE_CONFIGURED).

    2023-07-17 16:07:29,020 INFO: input command: route_out stop
    2023-07-17 16:07:29,020 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-07-17 16:07:29,021 INFO: Packet sendPacket: <<<send packet: AA 01 02 00 07 33 C3
    2023-07-17 16:07:29,041 INFO: AciHostCLI continuously_read: >>>receive packet: AA 20 05 00 00 00 07 33 00 A1
    2023-07-17 16:07:29,042 INFO: Parser eventParser: syncWord: AA,seqn: 20,len: 5,opcode: 0000,params: [07 33 00], check_sum: A1
    2023-07-17 16:07:29,043 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 16:07:29,043 INFO: Parser eventParser: event_id: [07 33]
    2023-07-17 16:07:29,044 INFO: Parser eventParser: status: [00]
    2023-07-17 16:07:29,044 INFO: AciHostCLI continuously_read: >>>receive packet: AA 21 07 00 0C 01 90 B3 2C 00 07 55
    2023-07-17 16:07:29,045 INFO: Parser eventParser: syncWord: AA,seqn: 21,len: 7,opcode: 010C,params: [90 B3 2C 00 07], check_sum: 55
    2023-07-17 16:07:29,045 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-07-17 16:07:29,045 INFO: Parser eventParser: group_handle: [90 B3 2C 00]
    2023-07-17 16:07:29,046 INFO: Parser eventParser: state: [07]
    2023-07-17 16:07:29,046 INFO: Packet sendPacket: <<<send packet: AA 02 05 00 00 00 0C 01 00 EC
    2023-07-17 16:07:29,265 INFO: AciHostCLI continuously_read: >>>receive packet: AA 22 07 00 0C 01 90 B3 2C 00 01 5A
    2023-07-17 16:07:29,265 INFO: Parser eventParser: syncWord: AA,seqn: 22,len: 7,opcode: 010C,params: [90 B3 2C 00 01], check_sum: 5A
    2023-07-17 16:07:29,266 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2023-07-17 16:07:29,266 INFO: Parser eventParser: group_handle: [90 B3 2C 00]
    2023-07-17 16:07:29,267 INFO: Parser eventParser: state: [01]
    2023-07-17 16:07:29,267 INFO: Packet sendPacket: <<<send packet: AA 03 05 00 00 00 0C 01 00 EB
    
  6. ACI Host CLI test: Input route_in stop.

    2023-07-17 16:07:33,327 INFO: input command: route_in stop
    2023-07-17 16:07:33,327 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-07-17 16:07:33,328 INFO: Packet sendPacket: <<<send packet: AA 04 02 00 05 33 C2
    2023-07-17 16:07:33,338 INFO: AciHostCLI continuously_read: >>>receive packet: AA 23 05 00 00 00 05 33 00 A0
    2023-07-17 16:07:33,339 INFO: Parser eventParser: syncWord: AA,seqn: 23,len: 5,opcode: 0000,params: [05 33 00], check_sum: A0
    2023-07-17 16:07:33,340 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-17 16:07:33,340 INFO: Parser eventParser: event_id: [05 33]
    2023-07-17 16:07:33,341 INFO: Parser eventParser: status: [00]
    
USB Source Play (BIS Output)

Before using, please connect EVB to PC through USB, select EVB as the audio device. After USB cable is connected and music on PC is started, the music data could be sent to the BUD(s) through BIS.

BIS supports configuring codec type (48k/16k), BIS number (1 BIS containing dual-channel data or 2 BIS containing separate L and R channel data), ULL mode (E2E Latency < 30ms), and other parameters. For details, please refer to ACI_CMD_LEA_BSRC_INIT.

USB source play (BIS Output) process:

ACI Host CLI Test

When using BIS as the output path, it is necessary to initialize BIS firstly through CMD_LEA_BSRC_INIT. The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the USB input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set BIS output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the USB input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP (other than CMD_LEA_BSRC_START/STOP) to start or stop the BIS output route.

Command

Parameters

ACI Host CLI CMD

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 2
encryption = false
ull_mode = false
pd = 0x2710

bsrcinit 48k_2bis

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = usb_ds(0x03, 0x01)

set_route_in usb_ds

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = bis(0x03)

set_route_out bis

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

  1. ACI Host CLI test: Initialize BIS.

    2023-09-13 10:35:17,929 INFO: input command: bsrcinit 48k_2bis
    2023-09-13 10:35:17,930 INFO: Parser cmdParser: cmd opcode: 3020 param: [0B 02 00 00 10 27] name: CMD_LEA_BSRC_INIT
    2023-09-13 10:35:17,931 INFO: Packet sendPacket: <<<send packet: AA 09 08 00 20 30 0B 02 00 00 10 27 5B
    2023-09-13 10:35:17,940 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 20 30 00 A7
    2023-09-13 10:35:17,943 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [20 30 00], check_sum: A7
    2023-09-13 10:35:17,944 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 10:35:17,944 INFO: Parser eventParser: event_id: [20 30]
    2023-09-13 10:35:17,945 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Input set_route_out bis.

    2023-09-13 10:35:30,605 INFO: input command: set_route_out bis
    2023-09-13 10:35:30,605 INFO: Parser cmdParser: cmd opcode: 3302 param: [03] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-09-13 10:35:30,606 INFO: Packet sendPacket: <<<send packet: AA 0B 03 00 02 33 03 BA
    2023-09-13 10:35:30,617 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 05 00 00 00 02 33 00 C0
    2023-09-13 10:35:30,617 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 5,opcode: 0000,params: [02 33 00], check_sum: C0
    2023-09-13 10:35:30,618 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 10:35:30,620 INFO: Parser eventParser: event_id: [02 33]
    2023-09-13 10:35:30,620 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input set_route_in usb.

    2023-09-13 10:35:27,473 INFO: input command: set_route_in usb
    2023-09-13 10:35:27,473 INFO: Parser cmdParser: cmd opcode: 3300 param: [03 01] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-09-13 10:35:27,474 INFO: Packet sendPacket: <<<send packet: AA 0A 03 00 00 33 03 01 BD
    2023-09-13 10:35:27,485 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 00 33 00 C3
    2023-09-13 10:35:27,487 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [00 33 00], check_sum: C3
    2023-09-13 10:35:27,488 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 10:35:27,489 INFO: Parser eventParser: event_id: [00 33]
    2023-09-13 10:35:27,490 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Input route_out start.

    2023-09-13 10:35:33,528 INFO: input command: route_out start
    2023-09-13 10:35:33,529 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-09-13 10:35:33,529 INFO: Packet sendPacket: <<<send packet: AA 0C 02 00 06 33 B9
    2023-09-13 10:35:33,539 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 05 00 00 00 06 33 00 BB
    2023-09-13 10:35:33,546 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 5,opcode: 0000,params: [06 33 00], check_sum: BB
    2023-09-13 10:35:33,546 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 10:35:33,547 INFO: Parser eventParser: event_id: [06 33]
    2023-09-13 10:35:33,548 INFO: Parser eventParser: status: [00]
    
  5. ACI Host CLI test: Input route_in start.

    2023-09-13 10:35:35,952 INFO: input command: route_in start
    2023-09-13 10:35:35,952 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-09-13 10:35:35,953 INFO: Packet sendPacket: <<<send packet: AA 0D 02 00 04 33 BA
    2023-09-13 10:35:35,962 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 05 00 00 00 04 33 00 BC
    2023-09-13 10:35:35,965 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 5,opcode: 0000,params: [04 33 00], check_sum: BC
    2023-09-13 10:35:35,966 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 10:35:35,966 INFO: Parser eventParser: event_id: [04 33]
    2023-09-13 10:35:35,967 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test: Input route_in stop.

    2023-09-13 11:24:27,143 INFO: input command: route_in stop
    2023-09-13 11:24:27,143 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-09-13 11:24:27,143 INFO: Packet sendPacket: <<<send packet: AA 0E 02 00 05 33 B8
    2023-09-13 11:24:27,152 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 05 00 00 00 05 33 00 BB
    2023-09-13 11:24:27,157 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 5,opcode: 0000,params: [05 33 00], check_sum: BB
    2023-09-13 11:24:27,157 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 11:24:27,158 INFO: Parser eventParser: event_id: [05 33]
    2023-09-13 11:24:27,159 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test: Input route_out stop.

    2023-09-13 11:23:57,789 INFO: input command: route_out stop
    2023-09-13 11:23:57,789 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-09-13 11:23:57,790 INFO: Packet sendPacket: <<<send packet: AA 0B 02 00 07 33 B9
    2023-09-13 11:23:57,798 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 07 33 00 BC
    2023-09-13 11:23:57,803 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [07 33 00], check_sum: BC
    2023-09-13 11:23:57,804 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-09-13 11:23:57,804 INFO: Parser eventParser: event_id: [07 33]
    2023-09-13 11:23:57,805 INFO: Parser eventParser: status: [00]
    
USB Source Play (CIS Output)

Before using, please connect EVB to PC through USB, select EVB as the audio device. After USB cable is connected and music on PC is started, the music data could be sent to the BUD(s) through CIS.

In this scenario, CIS only sets up the downlink direction of the datapath. The codec type is determined through negotiation (refer to app_lea_ini_select_media_prefer_codec()). In ULL mode (configured through the CMD_LEA_CIS_ULL_MODE command, and E2E Latency < 30ms), 48_1 is preferred, while in non-ULL mode, 48_6 takes precedence.

CIS connection process: Please refer to ACI Host CLI Test: Advertising.

USB source play (CIS Output) process:

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_SCAN(0x3023)

action = start(0x00)

lea_scan start

CMD_LEA_SCAN(0x3023)

action = stop(0x01)

lea_scan stop

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = usb_ds(0x03, 0x01)

set_route_in usb_ds

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = cis(0x04)

set_route_out cis

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

For CIS, it is necessary to establish an LE link. Please refer to Initiator General ACI Host CLI Test for connection procedure.

  1. ACI Host CLI test: Input set_route_in usb_ds.

    2024-01-23 17:19:23,499 INFO: input command: set_route_in usb_ds
    2024-01-23 17:19:23,500 INFO: Parser cmdParser: cmd opcode: 3300 param: [03 01] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2024-01-23 17:19:23,501 INFO: Packet sendPacket: <<<send packet: AA 29 04 00 00 33 03 01 9C
    2024-01-23 17:19:23,514 INFO: AciHostCLI continuously_read: >>>receive packet: AA 23 05 00 00 00 00 33 00 A5
    2024-01-23 17:19:23,515 INFO: Parser eventParser: syncWord: AA,seqn: 23,len: 5,opcode: 0000,params: [00 33 00], check_sum: A5
    2024-01-23 17:19:23,515 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:23,516 INFO: Parser eventParser: event_id: [00 33]
    2024-01-23 17:19:23,516 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Input set_route_out cis.

    2024-01-23 17:19:25,989 INFO: input command: set_route_out cis
    2024-01-23 17:19:25,990 INFO: Parser cmdParser: cmd opcode: 3302 param: [04] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2024-01-23 17:19:25,991 INFO: Packet sendPacket: <<<send packet: AA 2A 03 00 02 33 04 9A
    2024-01-23 17:19:26,003 INFO: AciHostCLI continuously_read: >>>receive packet: AA 24 05 00 00 00 02 33 00 A2
    2024-01-23 17:19:26,007 INFO: Parser eventParser: syncWord: AA,seqn: 24,len: 5,opcode: 0000,params: [02 33 00], check_sum: A2
    2024-01-23 17:19:26,009 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:26,009 INFO: Parser eventParser: event_id: [02 33]
    2024-01-23 17:19:26,010 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input route_out start.

    2024-01-23 17:19:27,670 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2024-01-23 17:19:27,671 INFO: Packet sendPacket: <<<send packet: AA 2B 02 00 06 33 9A
    2024-01-23 17:19:27,679 INFO: AciHostCLI continuously_read: >>>receive packet: AA 25 05 00 00 00 06 33 00 9D
    2024-01-23 17:19:27,679 INFO: Parser eventParser: syncWord: AA,seqn: 25,len: 5,opcode: 0000,params: [06 33 00], check_sum: 9D
    2024-01-23 17:19:27,680 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:27,681 INFO: Parser eventParser: event_id: [06 33]
    2024-01-23 17:19:27,682 INFO: Parser eventParser: status: [00]
    2024-01-23 17:19:27,685 INFO: AciHostCLI continuously_read: >>>receive packet: AA 26 07 00 41 01 A8 E1 2C 00 01 DB
    2024-01-23 17:19:27,686 INFO: Parser eventParser: syncWord: AA,seqn: 26,len: 7,opcode: 0141,params: [A8 E1 2C 00 01], check_sum: DB
    2024-01-23 17:19:27,686 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:27,687 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:27,687 INFO: Parser eventParser: state: [01]
    2024-01-23 17:19:27,690 INFO: Packet sendPacket: <<<send packet: AA 2C 05 00 00 00 41 01 00 8D
    2024-01-23 17:19:27,694 INFO: AciHostCLI continuously_read: >>>receive packet: AA 27 07 00 41 01 A8 E1 2C 00 03 D8
    2024-01-23 17:19:27,695 INFO: Parser eventParser: syncWord: AA,seqn: 27,len: 7,opcode: 0141,params: [A8 E1 2C 00 03], check_sum: D8
    2024-01-23 17:19:27,698 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:27,699 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:27,699 INFO: Parser eventParser: state: [03]
    2024-01-23 17:19:27,700 INFO: Packet sendPacket: <<<send packet: AA 2D 05 00 00 00 41 01 00 8C
    2024-01-23 17:19:28,092 INFO: AciHostCLI continuously_read: >>>receive packet: AA 28 0A 00 44 80 00 00 18 00 00 00 F4 01 FD
    2024-01-23 17:19:28,093 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: FD
    2024-01-23 17:19:28,093 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2024-01-23 17:19:28,094 INFO: Parser eventParser: app_link_id: [00]
    2024-01-23 17:19:28,095 INFO: Parser eventParser: res: [00]
    2024-01-23 17:19:28,096 INFO: Parser eventParser: connInterval: [18 00]
    2024-01-23 17:19:28,096 INFO: Parser eventParser: connLatency: [00 00]
    2024-01-23 17:19:28,097 INFO: Parser eventParser: supTimeout: [F4 01]
    2024-01-23 17:19:28,097 INFO: Packet sendPacket: <<<send packet: AA 2E 05 00 00 00 44 80 00 09
    2024-01-23 17:19:28,411 INFO: AciHostCLI continuously_read: >>>receive packet: AA 29 0A 00 44 80 00 00 20 00 00 00 F4 01 F4
    2024-01-23 17:19:28,412 INFO: Parser eventParser: syncWord: AA,seqn: 29,len: 10,opcode: 8044,params: [00 00 20 00 00 00 F4 01], check_sum: F4
    2024-01-23 17:19:28,415 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2024-01-23 17:19:28,415 INFO: Parser eventParser: app_link_id: [00]
    2024-01-23 17:19:28,416 INFO: Parser eventParser: res: [00]
    2024-01-23 17:19:28,416 INFO: Parser eventParser: connInterval: [20 00]
    2024-01-23 17:19:28,417 INFO: Parser eventParser: connLatency: [00 00]
    2024-01-23 17:19:28,417 INFO: Parser eventParser: supTimeout: [F4 01]
    2024-01-23 17:19:28,418 INFO: Packet sendPacket: <<<send packet: AA 2F 05 00 00 00 44 80 00 08
    2024-01-23 17:19:28,811 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2A 07 00 41 01 A8 E1 2C 00 04 D4
    2024-01-23 17:19:28,811 INFO: Parser eventParser: syncWord: AA,seqn: 2A,len: 7,opcode: 0141,params: [A8 E1 2C 00 04], check_sum: D4
    2024-01-23 17:19:28,812 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:28,812 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:28,814 INFO: Parser eventParser: state: [04]
    2024-01-23 17:19:28,815 INFO: Packet sendPacket: <<<send packet: AA 30 05 00 00 00 41 01 00 89
    
  4. ACI Host CLI test: Input route_in start.

    2024-01-23 17:19:30,390 INFO: input command: route_in start
    2024-01-23 17:19:30,390 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2024-01-23 17:19:30,391 INFO: Packet sendPacket: <<<send packet: AA 31 02 00 04 33 96
    2024-01-23 17:19:30,422 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2B 05 00 00 00 04 33 00 99
    2024-01-23 17:19:30,423 INFO: Parser eventParser: syncWord: AA,seqn: 2B,len: 5,opcode: 0000,params: [04 33 00], check_sum: 99
    2024-01-23 17:19:30,425 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:30,427 INFO: Parser eventParser: event_id: [04 33]
    2024-01-23 17:19:30,431 INFO: Parser eventParser: status: [00]
    
  5. ACI Host CLI test: Input route_out stop.

    2024-01-23 17:19:35,613 INFO: input command: route_out stop
    2024-01-23 17:19:35,613 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2024-01-23 17:19:35,614 INFO: Packet sendPacket: <<<send packet: AA 32 02 00 07 33 92
    2024-01-23 17:19:35,622 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2C 05 00 00 00 07 33 00 95
    2024-01-23 17:19:35,623 INFO: Parser eventParser: syncWord: AA,seqn: 2C,len: 5,opcode: 0000,params: [07 33 00], check_sum: 95
    2024-01-23 17:19:35,626 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:35,627 INFO: Parser eventParser: event_id: [07 33]
    2024-01-23 17:19:35,628 INFO: Parser eventParser: status: [00]
    2024-01-23 17:19:35,629 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2D 07 00 41 01 A8 E1 2C 00 07 CE
    2024-01-23 17:19:35,629 INFO: Parser eventParser: syncWord: AA,seqn: 2D,len: 7,opcode: 0141,params: [A8 E1 2C 00 07], check_sum: CE
    2024-01-23 17:19:35,630 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:35,633 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:35,634 INFO: Parser eventParser: state: [07]
    2024-01-23 17:19:35,635 INFO: Packet sendPacket: <<<send packet: AA 33 05 00 00 00 41 01 00 86
    2024-01-23 17:19:35,814 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2E 07 00 41 01 A8 E1 2C 00 01 D3
    2024-01-23 17:19:35,815 INFO: Parser eventParser: syncWord: AA,seqn: 2E,len: 7,opcode: 0141,params: [A8 E1 2C 00 01], check_sum: D3
    2024-01-23 17:19:35,816 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:35,820 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:35,821 INFO: Parser eventParser: state: [01]
    2024-01-23 17:19:35,823 INFO: Packet sendPacket: <<<send packet: AA 34 05 00 00 00 41 01 00 85
    2024-01-23 17:19:36,132 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2F 0A 00 44 80 00 00 18 00 00 00 F4 01 F6
    2024-01-23 17:19:36,134 INFO: Parser eventParser: syncWord: AA,seqn: 2F,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: F6
    2024-01-23 17:19:36,134 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2024-01-23 17:19:36,135 INFO: Parser eventParser: app_link_id: [00]
    2024-01-23 17:19:36,135 INFO: Parser eventParser: res: [00]
    2024-01-23 17:19:36,136 INFO: Parser eventParser: connInterval: [18 00]
    2024-01-23 17:19:36,137 INFO: Parser eventParser: connLatency: [00 00]
    2024-01-23 17:19:36,137 INFO: Parser eventParser: supTimeout: [F4 01]
    2024-01-23 17:19:36,138 INFO: Packet sendPacket: <<<send packet: AA 35 05 00 00 00 44 80 00 02
    
  6. ACI Host CLI test: Input route_in stop.

    2024-01-23 17:19:37,889 INFO: input command: route_in stop
    2024-01-23 17:19:37,890 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2024-01-23 17:19:37,890 INFO: Packet sendPacket: <<<send packet: AA 36 02 00 05 33 90
    2024-01-23 17:19:37,904 INFO: AciHostCLI continuously_read: >>>receive packet: AA 30 05 00 00 00 05 33 00 93
    2024-01-23 17:19:37,904 INFO: Parser eventParser: syncWord: AA,seqn: 30,len: 5,opcode: 0000,params: [05 33 00], check_sum: 93
    2024-01-23 17:19:37,905 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:37,905 INFO: Parser eventParser: event_id: [05 33]
    2024-01-23 17:19:37,906 INFO: Parser eventParser: status: [00]
    
USB Source Play (CIS Input and Output)

Before using, please connect the EVB and PC through USB and select the EVB as the audio device. Once the USB cable is connected, calls or simultaneous recording and playing of music can be initiated on the PC. The USB downstream data, transferred to the EVB, can be sent to BUD(s) through the CIS, and the data received from the BUD(s) through CIS can be transmitted upstream to the PC through USB.

In this scenario, CIS will set up both downlink and uplink directions of the datapaths. The codec type is determined through negotiation (refer to app_lea_ini_select_conversation_prefer_codec()), and 16_2 is preferred.

CIS connection process: Please refer to ACI Host CLI Test: Advertising.

USB source play (CIS Input and Output) process:

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_SCAN(0x3023)

action = start(0x00)

lea_scan start

CMD_LEA_SCAN(0x3023)

action = stop(0x01)

lea_scan stop

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = usb_ds_us(0x03, 0x03)

set_route_in usb_ds_us

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = cis(0x04)

set_route_out cis

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

For CIS, it is necessary to establish an LE link. Please refer to Initiator General ACI Host CLI Test for the connection procedure.

In addition, in the CIS input and output mode, it is necessary to establish a call using call control commands (such as incoming call and accept call) before initiating start CIS.

  1. ACI Host CLI test: Input set_route_in usb_ds_us.

    2024-01-23 17:18:40,848 INFO: input command: set_route_in usb_ds_us
    2024-01-23 17:18:40,849 INFO: Parser cmdParser: cmd opcode: 3300 param: [03 03] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2024-01-23 17:18:40,850 INFO: Packet sendPacket: <<<send packet: AA 19 04 00 00 33 03 03 AA
    2024-01-23 17:18:40,857 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 05 00 00 00 00 33 00 B5
    2024-01-23 17:18:40,858 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 5,opcode: 0000,params: [00 33 00], check_sum: B5
    2024-01-23 17:18:40,860 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:18:40,863 INFO: Parser eventParser: event_id: [00 33]
    2024-01-23 17:18:40,866 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Input set_route_out cis.

    2024-01-23 17:18:42,952 INFO: input command: set_route_out cis
    2024-01-23 17:18:42,952 INFO: Parser cmdParser: cmd opcode: 3302 param: [04] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2024-01-23 17:18:42,953 INFO: Packet sendPacket: <<<send packet: AA 1A 03 00 02 33 04 AA
    2024-01-23 17:18:42,960 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 05 00 00 00 02 33 00 B2
    2024-01-23 17:18:42,961 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 5,opcode: 0000,params: [02 33 00], check_sum: B2
    2024-01-23 17:18:42,962 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:18:42,966 INFO: Parser eventParser: event_id: [02 33]
    2024-01-23 17:18:42,968 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Call control procedure (incoming call and accept call).

    2024-01-23 17:18:54,685 INFO: input command: ccp_action incomingcall
    2024-01-23 17:18:54,686 INFO: Parser cmdParser: cmd opcode: 3032 param: [05 00] name: CMD_LEA_CCP_ACTION
    2024-01-23 17:18:54,687 INFO: Packet sendPacket: <<<send packet: AA 1B 04 00 32 30 05 00 7A
    2024-01-23 17:18:54,701 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 03 00 48 01 01 9E
    2024-01-23 17:18:54,701 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 3,opcode: 0148,params: [01], check_sum: 9E
    2024-01-23 17:18:54,702 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_CCP_CREATE_CALL
    2024-01-23 17:18:54,702 INFO: Parser eventParser: call_index: [01]
    2024-01-23 17:18:54,703 INFO: Packet sendPacket: <<<send packet: AA 1C 05 00 00 00 48 01 00 96
    2024-01-23 17:18:54,717 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 05 00 00 00 32 30 00 83
    2024-01-23 17:18:54,718 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 5,opcode: 0000,params: [32 30 00], check_sum: 83
    2024-01-23 17:18:54,718 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:18:54,719 INFO: Parser eventParser: event_id: [32 30]
    2024-01-23 17:18:54,719 INFO: Parser eventParser: status: [00]
    2024-01-23 17:18:56,312 INFO: input command: ccp_action accept1
    2024-01-23 17:18:56,313 INFO: Parser cmdParser: cmd opcode: 3032 param: [14 01] name: CMD_LEA_CCP_ACTION
    2024-01-23 17:18:56,314 INFO: Packet sendPacket: <<<send packet: AA 1D 04 00 32 30 14 01 68
    2024-01-23 17:18:56,329 INFO: AciHostCLI continuously_read: >>>receive packet: AA 17 05 00 00 00 32 30 00 82
    2024-01-23 17:18:56,330 INFO: Parser eventParser: syncWord: AA,seqn: 17,len: 5,opcode: 0000,params: [32 30 00], check_sum: 82
    2024-01-23 17:18:56,332 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:18:56,333 INFO: Parser eventParser: event_id: [32 30]
    2024-01-23 17:18:56,333 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Input route_out start.

    2024-01-23 17:19:06,596 INFO: input command: route_out start
    2024-01-23 17:19:06,597 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2024-01-23 17:19:06,598 INFO: Packet sendPacket: <<<send packet: AA 1E 02 00 06 33 A7
    2024-01-23 17:19:06,619 INFO: AciHostCLI continuously_read: >>>receive packet: AA 18 05 00 00 00 06 33 00 AA
    2024-01-23 17:19:06,620 INFO: Parser eventParser: syncWord: AA,seqn: 18,len: 5,opcode: 0000,params: [06 33 00], check_sum: AA
    2024-01-23 17:19:06,620 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:06,621 INFO: Parser eventParser: event_id: [06 33]
    2024-01-23 17:19:06,621 INFO: Parser eventParser: status: [00]
    2024-01-23 17:19:06,622 INFO: AciHostCLI continuously_read: >>>receive packet: AA 19 07 00 41 01 A8 E1 2C 00 01 E8
    2024-01-23 17:19:06,622 INFO: Parser eventParser: syncWord: AA,seqn: 19,len: 7,opcode: 0141,params: [A8 E1 2C 00 01], check_sum: E8
    2024-01-23 17:19:06,623 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:06,624 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:06,625 INFO: Parser eventParser: state: [01]
    2024-01-23 17:19:06,626 INFO: Packet sendPacket: <<<send packet: AA 1F 05 00 00 00 41 01 00 9A
    2024-01-23 17:19:06,635 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1A 07 00 41 01 A8 E1 2C 00 03 E5
    2024-01-23 17:19:06,636 INFO: Parser eventParser: syncWord: AA,seqn: 1A,len: 7,opcode: 0141,params: [A8 E1 2C 00 03], check_sum: E5
    2024-01-23 17:19:06,637 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:06,638 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:06,639 INFO: Parser eventParser: state: [03]
    2024-01-23 17:19:06,640 INFO: Packet sendPacket: <<<send packet: AA 20 05 00 00 00 41 01 00 99
    2024-01-23 17:19:07,002 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1B 0A 00 44 80 00 00 18 00 00 00 F4 01 0A
    2024-01-23 17:19:07,003 INFO: Parser eventParser: syncWord: AA,seqn: 1B,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: 0A
    2024-01-23 17:19:07,006 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2024-01-23 17:19:07,009 INFO: Parser eventParser: app_link_id: [00]
    2024-01-23 17:19:07,010 INFO: Parser eventParser: res: [00]
    2024-01-23 17:19:07,011 INFO: Parser eventParser: connInterval: [18 00]
    2024-01-23 17:19:07,011 INFO: Parser eventParser: connLatency: [00 00]
    2024-01-23 17:19:07,012 INFO: Parser eventParser: supTimeout: [F4 01]
    2024-01-23 17:19:07,013 INFO: Packet sendPacket: <<<send packet: AA 21 05 00 00 00 44 80 00 16
    2024-01-23 17:19:07,257 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1C 07 00 41 01 A8 E1 2C 00 04 E2
    2024-01-23 17:19:07,258 INFO: Parser eventParser: syncWord: AA,seqn: 1C,len: 7,opcode: 0141,params: [A8 E1 2C 00 04], check_sum: E2
    2024-01-23 17:19:07,259 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:07,260 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:07,261 INFO: Parser eventParser: state: [04]
    2024-01-23 17:19:07,263 INFO: Packet sendPacket: <<<send packet: AA 22 05 00 00 00 41 01 00 97
    
  5. ACI Host CLI test: Input route_in start.

    2024-01-23 17:19:08,892 INFO: input command: route_in start
    2024-01-23 17:19:08,893 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2024-01-23 17:19:08,894 INFO: Packet sendPacket: <<<send packet: AA 23 02 00 04 33 A4
    2024-01-23 17:19:08,948 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1D 05 00 00 00 04 33 00 A7
    2024-01-23 17:19:08,948 INFO: Parser eventParser: syncWord: AA,seqn: 1D,len: 5,opcode: 0000,params: [04 33 00], check_sum: A7
    2024-01-23 17:19:08,949 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:08,949 INFO: Parser eventParser: event_id: [04 33]
    2024-01-23 17:19:08,950 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test: Input route_out stop.

    2024-01-23 17:19:15,611 INFO: input command: route_out stop
    2024-01-23 17:19:15,612 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2024-01-23 17:19:15,613 INFO: Packet sendPacket: <<<send packet: AA 24 02 00 07 33 A0
    2024-01-23 17:19:15,633 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E 05 00 00 00 07 33 00 A3
    2024-01-23 17:19:15,634 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 5,opcode: 0000,params: [07 33 00], check_sum: A3
    2024-01-23 17:19:15,634 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:15,635 INFO: Parser eventParser: event_id: [07 33]
    2024-01-23 17:19:15,636 INFO: Parser eventParser: status: [00]
    2024-01-23 17:19:15,636 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 07 00 41 01 A8 E1 2C 00 07 DC
    2024-01-23 17:19:15,637 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 7,opcode: 0141,params: [A8 E1 2C 00 07], check_sum: DC
    2024-01-23 17:19:15,637 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:15,639 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:15,639 INFO: Parser eventParser: state: [07]
    2024-01-23 17:19:15,640 INFO: Packet sendPacket: <<<send packet: AA 25 05 00 00 00 41 01 00 94
    2024-01-23 17:19:15,808 INFO: AciHostCLI continuously_read: >>>receive packet: AA 20 07 00 41 01 A8 E1 2C 00 01 E1
    2024-01-23 17:19:15,809 INFO: Parser eventParser: syncWord: AA,seqn: 20,len: 7,opcode: 0141,params: [A8 E1 2C 00 01], check_sum: E1
    2024-01-23 17:19:15,810 INFO: Parser eventParser: event name: EVENT_LE_AUDIO_BAP_STATE
    2024-01-23 17:19:15,811 INFO: Parser eventParser: group_handle: [A8 E1 2C 00]
    2024-01-23 17:19:15,811 INFO: Parser eventParser: state: [01]
    2024-01-23 17:19:15,812 INFO: Packet sendPacket: <<<send packet: AA 26 05 00 00 00 41 01 00 93
    2024-01-23 17:19:16,032 INFO: AciHostCLI continuously_read: >>>receive packet: AA 21 0A 00 44 80 00 00 18 00 00 00 F4 01 04
    2024-01-23 17:19:16,033 INFO: Parser eventParser: syncWord: AA,seqn: 21,len: 10,opcode: 8044,params: [00 00 18 00 00 00 F4 01], check_sum: 04
    2024-01-23 17:19:16,034 INFO: Parser eventParser: event name: EVENT_XM_LE_CON_PARAM
    2024-01-23 17:19:16,035 INFO: Parser eventParser: app_link_id: [00]
    2024-01-23 17:19:16,038 INFO: Parser eventParser: res: [00]
    2024-01-23 17:19:16,039 INFO: Parser eventParser: connInterval: [18 00]
    2024-01-23 17:19:16,040 INFO: Parser eventParser: connLatency: [00 00]
    2024-01-23 17:19:16,041 INFO: Parser eventParser: supTimeout: [F4 01]
    2024-01-23 17:19:16,041 INFO: Packet sendPacket: <<<send packet: AA 27 05 00 00 00 44 80 00 10
    
  7. ACI Host CLI test: Input route_in stop.

    2024-01-23 17:19:17,316 INFO: input command: route_in stop
    2024-01-23 17:19:17,317 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2024-01-23 17:19:17,318 INFO: Packet sendPacket: <<<send packet: AA 28 02 00 05 33 9E
    2024-01-23 17:19:17,326 INFO: AciHostCLI continuously_read: >>>receive packet: AA 22 05 00 00 00 05 33 00 A1
    2024-01-23 17:19:17,327 INFO: Parser eventParser: syncWord: AA,seqn: 22,len: 5,opcode: 0000,params: [05 33 00], check_sum: A1
    2024-01-23 17:19:17,331 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-01-23 17:19:17,334 INFO: Parser eventParser: event_id: [05 33]
    2024-01-23 17:19:17,336 INFO: Parser eventParser: status: [00]
    
SD Card Source Play

Before using, please rework the LDO on SD card slot of EVB. Please create a folder named audio under the root directory and place the file named 8kbps_8kHz.mp3 in it. Then, insert the SD card into the corresponding card slot.

Note

DSP bin under release bin\bank0 should be downloaded.

After the SD card is inserted, the SD card source play can be started. SD card source play process:

ACI Host CLI Test

The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to the ACI Device to set the SD card input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set the local output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the SD card input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP to start or stop the local output route.

Command

Parameters

ACI Host CLI CMD

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = sd_card(0x04, 0x00)

set_route_in sd_card

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = local(0x05)

set_route_out local

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

  1. ACI Host CLI test: Insert SD card to EVB.

  2. ACI Host CLI test: Input set_route_in sd_card.

    2023-11-08 15:34:24,936 INFO: input command: set_route_in sd_card
    2023-11-08 15:34:24,936 INFO: Parser cmdParser: cmd opcode: 3300 param: [04 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-11-08 15:34:24,937 INFO: Packet sendPacket: <<<send packet: AA 03 04 00 00 33 04 00 C2
    2023-11-08 15:34:24,945 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 00 33 02 C3
    2023-11-08 15:34:24,946 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [00 33 02], check_sum: C3
    2023-11-08 15:34:24,947 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-08 15:34:24,947 INFO: Parser eventParser: event_id: [00 33]
    2023-11-08 15:34:24,947 INFO: Parser eventParser: status: [02]
    
  3. ACI Host CLI test: Input set_route_out local.

    2023-11-08 15:35:32,279 INFO: input command: set_route_out local
    2023-11-08 15:35:32,280 INFO: Parser cmdParser: cmd opcode: 3302 param: [05] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-11-08 15:35:32,280 INFO: Packet sendPacket: <<<send packet: AA 04 03 00 02 33 05 BF
    2023-11-08 15:35:32,368 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 02 33 02 C0
    2023-11-08 15:35:32,368 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [02 33 02], check_sum: C0
    2023-11-08 15:35:32,369 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-08 15:35:32,369 INFO: Parser eventParser: event_id: [02 33]
    2023-11-08 15:35:32,369 INFO: Parser eventParser: status: [02]
    
  4. ACI Host CLI test: Input route_out start.

    2023-11-08 15:36:03,687 INFO: input command: route_out start
    2023-11-08 15:36:03,687 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-11-08 15:36:03,688 INFO: Packet sendPacket: <<<send packet: AA 05 02 00 06 33 C0
    2023-11-08 15:36:03,834 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 06 33 02 BB
    2023-11-08 15:36:03,835 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [06 33 02], check_sum: BB
    2023-11-08 15:36:03,835 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-08 15:36:03,835 INFO: Parser eventParser: event_id: [06 33]
    2023-11-08 15:36:03,835 INFO: Parser eventParser: status: [02]
    
  5. ACI Host CLI test: Input route_in start.

    2023-11-08 15:36:52,159 INFO: input command: route_in start
    2023-11-08 15:36:52,159 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-11-08 15:36:52,160 INFO: Packet sendPacket: <<<send packet: AA 01 02 00 04 33 C6
    2023-11-08 15:36:52,165 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 05 00 00 00 04 33 02 BC
    2023-11-08 15:36:52,166 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 5,opcode: 0000,params: [04 33 02], check_sum: BC
    2023-11-08 15:36:52,169 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-08 15:36:52,171 INFO: Parser eventParser: event_id: [04 33]
    2023-11-08 15:36:52,171 INFO: Parser eventParser: status: [02]
    
  6. ACI Host CLI test: Input route_out stop.

    2023-11-08 15:37:08,533 INFO: input command: route_out stop
    2023-11-08 15:37:08,534 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-11-08 15:37:08,534 INFO: Packet sendPacket: <<<send packet: AA 03 02 00 07 33 C1
    2023-11-08 15:37:08,542 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 05 00 00 00 07 33 02 B7
    2023-11-08 15:37:08,543 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 5,opcode: 0000,params: [07 33 02], check_sum: B7
    2023-11-08 15:37:08,544 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-08 15:37:08,544 INFO: Parser eventParser: event_id: [07 33]
    2023-11-08 15:37:08,544 INFO: Parser eventParser: status: [02]
    
  7. ACI Host CLI test: Input route_in stop.

    2023-11-08 15:37:23,015 INFO: input command: route_in stop
    2023-11-08 15:37:23,015 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-11-08 15:37:23,015 INFO: Packet sendPacket: <<<send packet: AA 05 02 00 05 33 C1
    2023-11-08 15:37:23,023 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0A 05 00 00 00 05 33 02 B7
    2023-11-08 15:37:23,028 INFO: Parser eventParser: syncWord: AA,seqn: 0A,len: 5,opcode: 0000,params: [05 33 02], check_sum: B7
    2023-11-08 15:37:23,029 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-08 15:37:23,030 INFO: Parser eventParser: event_id: [05 33]
    2023-11-08 15:37:23,030 INFO: Parser eventParser: status: [02]
    
SD Card Source Play(BIS/CIS Output)

Before using, please make preparations as described in SD Card Source Play. The music data could be sent to the BUD(s) through BIS.

Note

DSP bin under release bin\DSP_Image\cs_leaaudio_pipe_stereo should be downloaded.

After SD card is inserted, the SD card source play can be started. SD card source play process:

ACI Host CLI Test

When using BIS as output path, it is necessary to initialize BIS firstly through CMD_LEA_BSRC_INIT. The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the SD card input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set BIS/CIS output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the SD card input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP to start or stop the BIS output route.

Command

Parameters

ACI Host CLI CMD

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 2
encryption = false
ull_mode = false
pd = 0x2710

bsrcinit 48k_2bis

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = sd_card(0x04, 0x00)

set_route_in sd_card

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = bis(0x03)

set_route_out bis

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = cis(0x04)

set_route_out cis

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

For CIS, it is necessary to establish an LE link. Please refer to Initiator General ACI Host CLI Test for connection procedure.

  1. ACI Host CLI test: Insert SD card to EVB.

  2. ACI Host CLI test: Initialize BIS.

    2023-11-09 11:27:18,506 INFO: input command: bsrcinit 48k_2bis
    2023-11-09 11:27:18,507 INFO: Parser cmdParser: cmd opcode: 3020 param: [0B 02 00 00 10 27] name: CMD_LEA_BSRC_INIT
    2023-11-09 11:27:18,507 INFO: Packet sendPacket: <<<send packet: AA 02 08 00 20 30 0B 02 00 00 10 27 62
    2023-11-09 11:27:18,585 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0C 05 00 00 00 20 30 00 9F
    2023-11-09 11:27:18,585 INFO: Parser eventParser: syncWord: AA,seqn: 0C,len: 5,opcode: 0000,params: [20 30 00], check_sum: 9F
    2023-11-09 11:27:18,586 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:27:18,586 INFO: Parser eventParser: event_id: [20 30]
    2023-11-09 11:27:18,586 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Input set_route_out bis/cis.

    If choose BIS:

    2023-11-09 11:28:14,714 INFO: input command: set_route_out bis
    2023-11-09 11:28:14,715 INFO: Parser cmdParser: cmd opcode: 3302 param: [03] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-11-09 11:28:14,715 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 02 33 03 C2
    2023-11-09 11:28:14,725 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0D 05 00 00 00 02 33 02 B7
    2023-11-09 11:28:14,727 INFO: Parser eventParser: syncWord: AA,seqn: 0D,len: 5,opcode: 0000,params: [02 33 02], check_sum: B7
    2023-11-09 11:28:14,727 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:28:14,727 INFO: Parser eventParser: event_id: [02 33]
    2023-11-09 11:28:14,727 INFO: Parser eventParser: status: [02]
    

    If choose CIS:

    2023-11-10 10:27:00,869 INFO: input command: set_route_out cis
    2023-11-10 10:27:00,870 INFO: Parser cmdParser: cmd opcode: 3302 param: [04] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2023-11-10 10:27:00,870 INFO: Packet sendPacket: <<<send packet: AA 0F 03 00 02 33 04 B5
    2023-11-10 10:27:00,876 INFO: AciHostCLI continuously_read: >>>receive packet: AA 19 05 00 00 00 02 33 02 AB
    2023-11-10 10:27:00,876 INFO: Parser eventParser: syncWord: AA,seqn: 19,len: 5,opcode: 0000,params: [02 33 02], check_sum: AB
    2023-11-10 10:27:00,876 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-10 10:27:00,877 INFO: Parser eventParser: event_id: [02 33]
    2023-11-10 10:27:00,879 INFO: Parser eventParser: status: [02]
    
  4. ACI Host CLI test: Input set_route_in sd_card.

    2023-11-09 11:28:32,673 INFO: input command: set_route_in sd_card
    2023-11-09 11:28:32,674 INFO: Parser cmdParser: cmd opcode: 3300 param: [04 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2023-11-09 11:28:32,676 INFO: Packet sendPacket: <<<send packet: AA 05 04 00 00 33 04 00 C0
    2023-11-09 11:28:32,751 INFO: AciHostCLI continuously_read: >>>receive packet: AA 0F 05 00 00 00 00 33 02 B7
    2023-11-09 11:28:32,751 INFO: Parser eventParser: syncWord: AA,seqn: 0F,len: 5,opcode: 0000,params: [00 33 02], check_sum: B7
    2023-11-09 11:28:32,751 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:28:32,751 INFO: Parser eventParser: event_id: [00 33]
    2023-11-09 11:28:32,752 INFO: Parser eventParser: status: [02]
    
  5. ACI Host CLI test: Input route_out start.

    2023-11-09 11:28:51,593 INFO: input command: route_out start
    2023-11-09 11:28:51,594 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2023-11-09 11:28:51,594 INFO: Packet sendPacket: <<<send packet: AA 07 02 00 06 33 BE
    2023-11-09 11:28:51,607 INFO: AciHostCLI continuously_read: >>>receive packet: AA 11 05 00 00 00 06 33 02 AF
    2023-11-09 11:28:51,608 INFO: Parser eventParser: syncWord: AA,seqn: 11,len: 5,opcode: 0000,params: [06 33 02], check_sum: AF
    2023-11-09 11:28:51,608 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:28:51,608 INFO: Parser eventParser: event_id: [06 33]
    2023-11-09 11:28:51,608 INFO: Parser eventParser: status: [02]
    
  6. ACI Host CLI test: Input route_in start.

    2023-11-09 11:29:17,530 INFO: input command: route_in start
    2023-11-09 11:29:17,530 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2023-11-09 11:29:17,531 INFO: Packet sendPacket: <<<send packet: AA 09 02 00 04 33 BE
    2023-11-09 11:29:17,545 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 05 00 00 00 04 33 02 AF
    2023-11-09 11:29:17,545 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 5,opcode: 0000,params: [04 33 02], check_sum: AF
    2023-11-09 11:29:17,545 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:29:17,545 INFO: Parser eventParser: event_id: [04 33]
    2023-11-09 11:29:17,546 INFO: Parser eventParser: status: [02]
    
  7. ACI Host CLI test: Input route_out stop.

    2023-11-09 11:29:45,331 INFO: input command: route_out stop
    2023-11-09 11:29:45,332 INFO: Parser cmdParser: cmd opcode: 3307 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_STOP
    2023-11-09 11:29:45,332 INFO: Packet sendPacket: <<<send packet: AA 0B 02 00 07 33 B9
    2023-11-09 11:29:45,338 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 05 00 00 00 07 33 02 AA
    2023-11-09 11:29:45,343 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 5,opcode: 0000,params: [07 33 02], check_sum: AA
    2023-11-09 11:29:45,343 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:29:45,344 INFO: Parser eventParser: event_id: [07 33]
    2023-11-09 11:29:45,346 INFO: Parser eventParser: status: [02]
    
  8. ACI Host CLI test: Input route_in stop.

    2023-11-09 11:29:56,073 INFO: input command: route_in stop
    2023-11-09 11:29:56,074 INFO: Parser cmdParser: cmd opcode: 3305 param: [] name: CMD_SRC_PLAY_ROUTE_IN_STOP
    2023-11-09 11:29:56,074 INFO: Packet sendPacket: <<<send packet: AA 0D 02 00 05 33 B9
    2023-11-09 11:29:56,115 INFO: AciHostCLI continuously_read: >>>receive packet: AA 17 05 00 00 00 05 33 02 AA
    2023-11-09 11:29:56,116 INFO: Parser eventParser: syncWord: AA,seqn: 17,len: 5,opcode: 0000,params: [05 33 02], check_sum: AA
    2023-11-09 11:29:56,116 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-11-09 11:29:56,118 INFO: Parser eventParser: event_id: [05 33]
    2023-11-09 11:29:56,118 INFO: Parser eventParser: status: [02]
    

Bluetooth Audio Receiver

This chapter introduces the functionality of the bt_audio_receiver application scenario. This functionality is enabled by opening the macro definition F_APP_BT_AUDIO_RECEIVER_DEMO_SUPPORT in app_flags.h. This chapter describes how to use these functions and the flow of how to test them, including the MSCs of the ACI Device and ACI Host interaction, and the commands used by ACI Host.

HFP Function

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

Description

CMD_MMI = 0x0004

action = MMI_HF_ANSWER_CALL(0x0003)

mmi answer

Answer an incoming call.

CMD_MMI = 0x0004

action = MMI_HF_REJECT_CALL(0x0004)

mmi reject

Reject an incoming call.

CMD_BT_HFP_DIAL_WITH_NUMBER = 0x001B

number = {…}

call 10086

HFP dial with number ‘10086’.

MAP Function

Based on the scenario introduced in Connect to Phone, MAP can be used to combine the messaging capabilities of a messaging server device and the user interface capabilities of a client device for browsing, reading, and sending messages.

Before using the MAP function, it is necessary to enable ‘Message access’ on Android devices, and enable ‘Show Notifications’ on iOS devices.

MAP process:

As introduced in the figure, after the MAP connection is established, the device will set a folder to root\telecom\msg. The parameters of CMD_MAP_GET_MESSAGE need to be set according to the handle value of the specific message in the message list.

ACI Host CLI Test

The ACI Host uses CMD_MAP_CONNECT with a status parameter to the ACI Device to establish a MAP connection, uses CMD_MAP_GET_FOLDER_LISTING, CMD_MAP_GET_MESSAGE_LISTING, and CMD_MAP_GET_MESSAGE to get folders and messages, and uses CMD_MAP_REG_MSG_NOTIFICATION to register message notifications.

Command

Parameters

ACI Host CLI CMD

CMD_MAP_CONNECT(0x3801)

action = map_connect

map connect

CMD_MAP_GET_FOLDER_LISTING(0x3802)

action = get_folder_list(0x0A)

map get folder list

CMD_MAP_DISCONNECT(0x3803)

action = map_disconnect

map disconnect

CMD_MAP_GET_MESSAGE_LISTING(0x3805)

action = get_msg_list(0x0A)

map get msg list

CMD_MAP_REG_MSG_NOTIFICATION(0x3809)

action = reg_msg_note(0x01)

map reg msg note

CMD_MAP_GET_MESSAGE(0x380A)

action = get_msg(handle_length, handle)

map get msg

CMD_MAP_PUSH_MESSAGE(0x3810)

action = push_msg(msg_length,msg)

map push msg

  1. ACI Host CLI test: Connect ACI Device to Phone.

    Please refer to Connect to Phone.

  2. ACI Host CLI test: MAP connect.

    2023-03-08 14:40:07,573 INFO: input command: map connect
    2023-03-08 14:40:07,574 INFO: Parser cmdParser: cmd opcode: 3801 param: [] name: CMD_MAP_CONNECT
    2023-03-08 14:40:07,575 INFO: Packet sendPacket: <<<send packet: AA 1B 02 00 01 38 AA
    2023-03-08 14:40:07,579 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1B 05 00 00 00 01 38 00 A7
    2023-03-08 14:40:07,579 INFO: Parser eventParser: syncWord: AA,seqn: 1B,len: 5,opcode: 0000,params: [01 38 00], check_sum: A7
    2023-03-08 14:40:07,580 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 14:40:07,580 INFO: Parser eventParser: event_id: [01 38]
    2023-03-08 14:40:07,580 INFO: Parser eventParser: status: [00]
    2023-03-08 14:40:07,804 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1C 09 00 24 09 00 41 AF 7B 6C 32 20 85
    2023-03-08 14:40:07,804 INFO: Parser eventParser: syncWord: AA,seqn: 1C,len: 9,opcode: 0924,params: [00 41 AF 7B 6C 32 20], check_sum: 85
    2023-03-08 14:40:07,806 INFO: Parser eventParser: event name: EVENT_SERVICES_SEARCH_STATE
    2023-03-08 14:40:07,807 INFO: Packet sendPacket: <<<send packet: AA 1C 05 00 00 00 24 09 00 B2
    
  3. ACI Host CLI test: MAP get folder list.

    2023-03-08 14:40:32,790 INFO: input command: map get_folder_list
    2023-03-08 14:40:32,791 INFO: Parser cmdParser: cmd opcode: 3802 param: [0A 00] name: CMD_MAP_GET_FOLDER_LISTING
    2023-03-08 14:40:32,792 INFO: Packet sendPacket: <<<send packet: AA 1D 04 00 02 38 0A 00 9B
    2023-03-08 14:40:32,803 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1D 05 00 00 00 02 38 00 A4
    2023-03-08 14:40:32,804 INFO: Parser eventParser: syncWord: AA,seqn: 1D,len: 5,opcode: 0000,params: [02 38 00], check_sum: A4
    2023-03-08 14:40:32,804 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 14:40:32,804 INFO: Parser eventParser: event_id: [02 38]
    2023-03-08 14:40:32,805 INFO: Parser eventParser: status: [00]
    2023-03-08 14:40:33,208 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E FA 00 04 38 3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E 3D 27 31 2E 30 27 20 65 6E 63 6F 64 69
    2023-03-08 14:40:33,209 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 250,opcode: 3804,params: [3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E 3D 27 31 2E 30 27 20 65 6E 63 6F 64 69 6E 67 3D 27 75 74], check_sum: C3
    2023-03-08 14:40:33,210 INFO: Packet sendPacket: <<<send packet: AA 1E 05 00 00 00 04 38 00 A1
    
  4. ACI Host CLI test: MAP get message list.

    2023-03-08 14:41:04,092 INFO: input command: map get_msg_list
    2023-03-08 14:41:04,093 INFO: Parser cmdParser: cmd opcode: 3805 param: [0A 00] name: CMD_MAP_GET_MESSAGE_LISTING
    2023-03-08 14:41:04,095 INFO: Packet sendPacket: <<<send packet: AA 1F 04 00 05 38 0A 00 96
    2023-03-08 14:41:04,108 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 05 00 00 00 05 38 00 9F
    2023-03-08 14:41:04,109 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 5,opcode: 0000,params: [05 38 00], check_sum: 9F
    2023-03-08 14:41:04,109 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 14:41:04,109 INFO: Parser eventParser: event_id: [05 38]
    2023-03-08 14:41:04,110 INFO: Parser eventParser: status: [00]
    2023-03-08 14:41:05,232 INFO: AciHostCLI continuously_read: >>>receive packet: AA 20 CA 03 06 38 3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E 3D 27 31 2E 30 27 20 65 6E 63 6F 64 69
    2023-03-08 14:41:05,232 INFO: Parser eventParser: syncWord: AA,seqn: 20,len: 970,opcode: 3806,params: [3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E 3D 27 31 2E 30 27 20 65 6E 63 6F 64 69 6E 67 3D 27 75 74], check_sum: 6B
    2023-03-08 14:41:05,234 INFO: Packet sendPacket: <<<send packet: AA 20 05 00 00 00 06 38 00 9D
    2023-03-08 14:41:05,267 INFO: AciHostCLI continuously_read: >>>receive packet: AA 21 CA 03 06 38 31 34 36 31 32 22 20 73 65 6E 64 65 72 5F 61 64 64 72 65 73 73 69 6E 67 3D 22
    2023-03-08 14:41:05,268 INFO: Parser eventParser: syncWord: AA,seqn: 21,len: 970,opcode: 3806,params: [31 34 36 31 32 22 20 73 65 6E 64 65 72 5F 61 64 64 72 65 73 73 69 6E 67 3D 22 31 30 36 35 39 31], check_sum: 3E
    2023-03-08 14:41:05,269 INFO: Packet sendPacket: <<<send packet: AA 21 05 00 00 00 06 38 00 9C
    2023-03-08 14:41:05,378 INFO: AciHostCLI continuously_read: >>>receive packet: AA 22 CA 03 06 38 3D 22 6E 6F 22 20 70 72 6F 74 65 63 74 65 64 3D 22 6E 6F 22 20 2F 3E 0A 20 20
    2023-03-08 14:41:05,379 INFO: Parser eventParser: syncWord: AA,seqn: 22,len: 970,opcode: 3806,params: [3D 22 6E 6F 22 20 70 72 6F 74 65 63 74 65 64 3D 22 6E 6F 22 20 2F 3E 0A 20 20 20 20 3C 6D 73 67], check_sum: D5
    2023-03-08 14:41:05,381 INFO: Packet sendPacket: <<<send packet: AA 22 05 00 00 00 06 38 00 9B
    2023-03-08 14:41:05,401 INFO: AciHostCLI continuously_read: >>>receive packet: AA 23 B6 03 07 38 65 6E 64 65 72 5F 61 64 64 72 65 73 73 69 6E 67 3D 22 31 30 36 35 39 33 31 31
    2023-03-08 14:41:05,403 INFO: Parser eventParser: syncWord: AA,seqn: 23,len: 950,opcode: 3807,params: [65 6E 64 65 72 5F 61 64 64 72 65 73 73 69 6E 67 3D 22 31 30 36 35 39 33 31 31 31 33 22 20 72 65], check_sum: 10
    2023-03-08 14:41:05,405 INFO: Packet sendPacket: <<<send packet: AA 23 05 00 00 00 07 38 00 99
    
  5. ACI Host CLI test: MAP get message.

    2023-03-08 14:41:34,092 INFO: input command: map get_msg
    2023-03-08 14:41:34,093 INFO: Parser cmdParser: cmd opcode: 380A param: [22 00 30 00 30 00 34 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 42 00] name: CMD_MAP_GET_MESSAGE
    2023-03-08 14:41:34,093 INFO: Packet sendPacket: <<<send packet: AA 24 24 00 0A 38 22 00 30 00 30 00 34 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00 30 00
    2023-03-08 14:41:34,107 INFO: AciHostCLI continuously_read: >>>receive packet: AA 24 05 00 00 00 0A 38 00 95
    2023-03-08 14:41:34,108 INFO: Parser eventParser: syncWord: AA,seqn: 24,len: 5,opcode: 0000,params: [0A 38 00], check_sum: 95
    2023-03-08 14:41:34,108 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 14:41:34,108 INFO: Parser eventParser: event_id: [0A 38]
    2023-03-08 14:41:34,108 INFO: Parser eventParser: status: [00]
    2023-03-08 14:41:34,460 INFO: AciHostCLI continuously_read: >>>receive packet: AA 25 1B 01 0C 38 42 45 47 49 4E 3A 42 4D 53 47 0D 0A 56 45 52 53 49 4F 4E 3A 31 2E 30 0D 0A 53
    2023-03-08 14:41:34,460 INFO: Parser eventParser: syncWord: AA,seqn: 25,len: 283,opcode: 380C,params: [42 45 47 49 4E 3A 42 4D 53 47 0D 0A 56 45 52 53 49 4F 4E 3A 31 2E 30 0D 0A 53 54 41 54 55 53 3A], check_sum: 62
    2023-03-08 14:41:34,461 INFO: Packet sendPacket: <<<send packet: AA 25 05 00 00 00 0C 38 00 92
    
  6. ACI Host CLI test: MAP register notification.

    2023-03-08 14:43:32,651 INFO: input command: map reg_msg_note
    2023-03-08 14:43:32,653 INFO: Parser cmdParser: cmd opcode: 3809 param: [01] name: CMD_MAP_REG_MSG_NOTIFICATION
    2023-03-08 14:43:32,654 INFO: Packet sendPacket: <<<send packet: AA 05 03 00 09 38 01 B6
    2023-03-08 14:43:32,672 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2A 05 00 00 00 09 38 00 90
    2023-03-08 14:43:32,673 INFO: Parser eventParser: syncWord: AA,seqn: 2A,len: 5,opcode: 0000,params: [09 38 00], check_sum: 90
    2023-03-08 14:43:32,673 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 14:43:32,674 INFO: Parser eventParser: event_id: [09 38]
    2023-03-08 14:43:32,674 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test: MAP push message.

    2023-03-08 14:42:49,284 INFO: input command: map push_msg
    2023-03-08 14:42:49,287 INFO: Parser cmdParser: cmd opcode: 3810 param: [F8 00 42 45 47 49 4E 3A 42 4D 53 47 0D 0A 56 45 52 53 49 4F 4E 3A 31 2E 30 0D 0A 53 54 41 54 55] name: CMD_MAP_PUSH_MESSAGE
    2023-03-08 14:42:49,289 INFO: Packet sendPacket: <<<send packet: AA 03 FC 00 10 38 F8 00 42 45 47 49 4E 3A 42 4D 53 47 0D 0A 56 45 52 53 49 4F 4E 3A 31 2E 30 0D
    2023-03-08 14:42:49,296 INFO: AciHostCLI continuously_read: >>>receive packet: AA 28 05 00 00 00 10 38 00 8B
    2023-03-08 14:42:49,296 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 5,opcode: 0000,params: [10 38 00], check_sum: 8B
    2023-03-08 14:42:49,296 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 14:42:49,297 INFO: Parser eventParser: event_id: [10 38]
    2023-03-08 14:42:49,297 INFO: Parser eventParser: status: [00]
    
  8. ACI Host CLI test: MAP disconnect.

    2023-03-08 19:15:22,350 INFO: input command: map disconnect
    2023-03-08 19:15:22,353 INFO: Parser cmdParser: cmd opcode: 3803 param: [] name: CMD_MAP_DISCONNECT
    2023-03-08 19:15:22,354 INFO: Packet sendPacket: <<<send packet: AA 39 02 00 03 38 8A
    2023-03-08 19:15:22,368 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2E 05 00 00 00 03 38 00 92
    2023-03-08 19:15:22,371 INFO: Parser eventParser: syncWord: AA,seqn: 2E,len: 5,opcode: 0000,params: [03 38 00], check_sum: 92
    2023-03-08 19:15:22,373 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-08 19:15:22,373 INFO: Parser eventParser: event_id: [03 38]
    2023-03-08 19:15:22,374 INFO: Parser eventParser: status: [00]
    

PBAP Function

Based on the scenario introduced in Connect to Phone, PBAP can be used to pull phone book objects and combined call history from the server device.

Before using the PBAP function, Android phones need to open ‘Contact access’, and iOS phones need to open ‘Sync Contacts’.

PBAP process:

As introduced in the figure, after the PBAP connection is established, the device will set a folder to root\telecom\pb. The folder will be set to root\telecom\cch when the device uses CMD_PBAP_DOWNLOAD with download_cch action.

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_PBAP_DOWNLOAD(0x0420)

action = download_all(0x03)

pbap download_all

CMD_PBAP_DOWNLOAD(0x0420)

action = download_PB(0x04)

pbap download_PB

CMD_PBAP_DOWNLOAD(0x0420)

action = download_cch(0x05)

pbap download_cch

CMD_PBAP_CONNECT(0x0423)

action = pbap_connect

pbap connect

CMD_PBAP_DISCONNECT(0x0426)

action = pbap_disconnect

pbap disconnect

The ACI Host uses CMD_PBAP_CONNECT to ACI Device to establish PBAP connection, and uses CMD_PBAP_DOWNLOAD to get phonebook and call history.

  1. ACI Host CLI test: Connect ACI Device to Phone.

    Please refer to Connect to Phone.

  2. ACI Host CLI test: PBAP connect.

    2023-03-09 16:53:57,753 INFO: input command: pbap connect
    2023-03-09 16:53:57,753 INFO: Parser cmdParser: cmd opcode: 0423 param: [] name: CMD_PBAP_CONNECT
    2023-03-09 16:53:57,754 INFO: Packet sendPacket: <<<send packet: AA 44 02 00 23 04 83
    2023-03-09 16:53:57,762 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E 05 00 00 00 23 04 00 A6
    2023-03-09 16:53:57,763 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 5,opcode: 0000,params: [23 04 00], check_sum: A6
    2023-03-09 16:53:57,763 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-09 16:53:57,763 INFO: Parser eventParser: event_id: [23 04]
    2023-03-09 16:53:57,763 INFO: Parser eventParser: status: [00]
    2023-03-09 16:53:58,003 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 09 00 24 09 00 41 AF 7B 6C 32 20 82
    2023-03-09 16:53:58,003 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 9,opcode: 0924,params: [00 41 AF 7B 6C 32 20], check_sum: 82
    2023-03-09 16:53:58,004 INFO: Parser eventParser: event name: EVENT_SERVICES_SEARCH_STATE
    2023-03-09 16:53:58,004 INFO: Packet sendPacket: <<<send packet: AA 45 05 00 00 00 24 09 00 89
    
  3. ACI Host CLI test: PBAP download_PB.

    2023-03-09 16:54:40,282 INFO: input command: pbap download_PB
    2023-03-09 16:54:40,283 INFO: Parser cmdParser: cmd opcode: 0420 param: [04] name: CMD_PBAP_DOWNLOAD
    2023-03-09 16:54:40,283 INFO: Packet sendPacket: <<<send packet: AA 05 03 00 20 04 04 C0
    2023-03-09 16:54:40,298 INFO: AciHostCLI continuously_read: >>>receive packet: AA 24 05 00 00 00 20 04 00 A3
    2023-03-09 16:54:40,299 INFO: Parser eventParser: syncWord: AA,seqn: 24,len: 5,opcode: 0000,params: [20 04 00], check_sum: A3
    2023-03-09 16:54:40,299 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-09 16:54:40,299 INFO: Parser eventParser: event_id: [20 04]
    2023-03-09 16:54:40,299 INFO: Parser eventParser: status: [00]
    2023-03-09 16:54:40,426 INFO: AciHostCLI continuously_read: >>>receive packet: AA 25 13 00 02 05 07 02 00 00 00 02 00 C0 F8 EF 2C 41 AF 7B 6C 32 20 BA
    2023-03-09 16:54:40,427 INFO: Parser eventParser: syncWord: AA,seqn: 25,len: 19,opcode: 0502,params: [07 02 00 00 00 02 00 C0 F8 EF 2C 41 AF 7B 6C 32 20], check_sum: BA
    2023-03-09 16:54:40,427 INFO: Parser eventParser: event name: EVENT_PBAP_DOWNLOAD_START
    2023-03-09 16:54:40,428 INFO: Packet sendPacket: <<<send packet: AA 06 05 00 00 00 02 05 00 EE
    2023-03-09 16:54:40,633 INFO: AciHostCLI continuously_read: >>>receive packet: AA 26 66 00 00 05 62 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31
    2023-03-09 16:54:40,634 INFO: Parser eventParser: syncWord: AA,seqn: 26,len: 102,opcode: 0500,params: [62 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31 0D 0A 46 4E 3B 43], check_sum: B9
    2023-03-09 16:54:40,635 INFO: Parser eventParser: event name: EVENT_PBAP_REPORT_DATA
    2023-03-09 16:54:40,635 INFO: Packet sendPacket: <<<send packet: AA 07 05 00 00 00 00 05 00 EF
    2023-03-09 16:54:40,652 INFO: AciHostCLI continuously_read: >>>receive packet: AA 27 43 00 00 05 3F 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31
    2023-03-09 16:54:40,668 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 9,opcode: 0503,params: [07 41 AF 7B 6C 32 20], check_sum: 97
    2023-03-09 16:54:40,669 INFO: Parser eventParser: event name: EVENT_PBAP_DOWNLOAD_CMPL
    2023-03-09 16:54:40,669 INFO: Packet sendPacket: <<<send packet: AA 09 05 00 00 00 03 05 00 EA
    
  4. ACI Host CLI test: PBAP download_cch.

    2023-03-09 16:55:19,105 INFO: input command: pbap download_cch
    2023-03-09 16:55:19,106 INFO: Parser cmdParser: cmd opcode: 0420 param: [05] name: CMD_PBAP_DOWNLOAD
    2023-03-09 16:55:19,107 INFO: Packet sendPacket: <<<send packet: AA 0D 03 00 20 04 05 B7
    2023-03-09 16:55:19,124 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2C 05 00 00 00 20 04 00 9B
    2023-03-09 16:55:19,124 INFO: Parser eventParser: syncWord: AA,seqn: 2C,len: 5,opcode: 0000,params: [20 04 00], check_sum: 9B
    2023-03-09 16:55:19,125 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-09 16:55:19,125 INFO: Parser eventParser: event_id: [20 04]
    2023-03-09 16:55:19,125 INFO: Parser eventParser: status: [00]
    2023-03-09 16:55:19,524 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2D 13 00 02 05 04 2C 01 00 00 2C 01 B7 B8 C4 2C 41 AF 7B 6C 32 20 D3
    2023-03-09 16:55:19,525 INFO: Parser eventParser: syncWord: AA,seqn: 2D,len: 19,opcode: 0502,params: [04 2C 01 00 00 2C 01 B7 B8 C4 2C 41 AF 7B 6C 32 20], check_sum: D3
    2023-03-09 16:55:19,526 INFO: Parser eventParser: event name: EVENT_PBAP_DOWNLOAD_START
    2023-03-09 16:55:19,526 INFO: Packet sendPacket: <<<send packet: AA 0E 05 00 00 00 02 05 00 E6
    2023-03-09 16:55:20,158 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2E 76 00 00 05 72 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31
    2023-03-09 16:55:20,159 INFO: Parser eventParser: syncWord: AA,seqn: 2E,len: 118,opcode: 0500,params: [72 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31 0D 0A 46 4E 3A 0D], check_sum: A4
    2023-03-09 16:55:20,159 INFO: Parser eventParser: event name: EVENT_PBAP_REPORT_DATA
    2023-03-09 16:55:20,160 INFO: Packet sendPacket: <<<send packet: AA 0F 05 00 00 00 00 05 00 E7
    2023-03-09 16:55:20,177 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2F 76 00 00 05 72 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31
    2023-03-09 16:55:20,177 INFO: Parser eventParser: syncWord: AA,seqn: 2F,len: 118,opcode: 0500,params: [72 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31 0D 0A 46 4E 3A 0D], check_sum: 94
    2023-03-09 16:55:20,178 INFO: Parser eventParser: event name: EVENT_PBAP_REPORT_DATA
    2023-03-09 16:55:20,178 INFO: Packet sendPacket: <<<send packet: AA 10 05 00 00 00 00 05 00 E6
    
    //PBAP keeps reporting data ...
    
    2023-03-09 16:55:40,239 INFO: AciHostCLI continuously_read: >>>receive packet: AA 7B 09 00 03 05 04 41 AF 7B 6C 32 20 47
    2023-03-09 16:55:40,240 INFO: Parser eventParser: syncWord: AA,seqn: 7B,len: 9,opcode: 0503,params: [04 41 AF 7B 6C 32 20], check_sum: 47
    2023-03-09 16:55:40,240 INFO: Parser eventParser: event name: EVENT_PBAP_DOWNLOAD_CMPL
    2023-03-09 16:55:40,240 INFO: Packet sendPacket: <<<send packet: AA 5B 05 00 00 00 03 05 00 98
    
  5. ACI Host CLI test: PBAP download_all.

    2023-03-09 16:56:56,241 INFO: input command: pbap download_all
    2023-03-09 16:56:56,242 INFO: Parser cmdParser: cmd opcode: 0420 param: [03] name: CMD_PBAP_DOWNLOAD
    2023-03-09 16:56:56,242 INFO: Packet sendPacket: <<<send packet: AA 5C 03 00 20 04 03 6A
    2023-03-09 16:56:56,262 INFO: AciHostCLI continuously_read: >>>receive packet: AA 7C 05 00 00 00 20 04 00 4B
    2023-03-09 16:56:56,263 INFO: Parser eventParser: syncWord: AA,seqn: 7C,len: 5,opcode: 0000,params: [20 04 00], check_sum: 4B
    2023-03-09 16:56:56,264 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-09 16:56:56,265 INFO: Parser eventParser: event_id: [20 04]
    2023-03-09 16:56:56,265 INFO: Parser eventParser: status: [00]
    2023-03-09 16:56:56,821 INFO: AciHostCLI continuously_read: >>>receive packet: AA 7D 13 00 02 05 07 02 00 00 00 02 00 6A 08 C5 2C 41 AF 7B 6C 32 20 D2
    2023-03-09 16:56:56,822 INFO: Parser eventParser: syncWord: AA,seqn: 7D,len: 19,opcode: 0502,params: [07 02 00 00 00 02 00 6A 08 C5 2C 41 AF 7B 6C 32 20], check_sum: D2
    2023-03-09 16:56:56,822 INFO: Parser eventParser: event name: EVENT_PBAP_DOWNLOAD_START
    2023-03-09 16:56:56,822 INFO: Packet sendPacket: <<<send packet: AA 5D 05 00 00 00 02 05 00 97
    2023-03-09 16:56:57,027 INFO: AciHostCLI continuously_read: >>>receive packet: AA 7E 66 00 00 05 62 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31
    2023-03-09 16:56:57,028 INFO: Parser eventParser: syncWord: AA,seqn: 7E,len: 102,opcode: 0500,params: [62 00 42 45 47 49 4E 3A 56 43 41 52 44 0D 0A 56 45 52 53 49 4F 4E 3A 32 2E 31 0D 0A 46 4E 3B 43], check_sum: 61
    2023-03-09 16:56:57,028 INFO: Parser eventParser: event name: EVENT_PBAP_REPORT_DATA
    2023-03-09 16:56:57,029 INFO: Packet sendPacket: <<<send packet: AA 5E 05 00 00 00 00 05 00 98
    
    //PBAP keep reporting data ...
    
    2023-03-09 16:57:18,438 INFO: AciHostCLI continuously_read: >>>receive packet: AA D2 09 00 03 05 04 41 AF 7B 6C 32 20 F0
    2023-03-09 16:57:18,438 INFO: Parser eventParser: syncWord: AA,seqn: D2,len: 9,opcode: 0503,params: [04 41 AF 7B 6C 32 20], check_sum: F0
    2023-03-09 16:57:18,438 INFO: Parser eventParser: event name: EVENT_PBAP_DOWNLOAD_CMPL
    2023-03-09 16:57:18,439 INFO: Packet sendPacket: <<<send packet: AA B1 05 00 00 00 03 05 00 42
    
  6. ACI Host CLI test: PBAP disconnect.

    2023-03-09 17:33:30,246 INFO: input command: pbap disconnect
    2023-03-09 17:33:30,247 INFO: Parser cmdParser: cmd opcode: 0426 param: [] name: CMD_PBAP_DISCONNECT
    2023-03-09 17:33:30,248 INFO: Packet sendPacket: <<<send packet: AA 38 02 00 26 04 8C
    2023-03-09 17:33:30,265 INFO: AciHostCLI continuously_read: >>>receive packet: AA 38 05 00 00 00 26 04 00 89
    2023-03-09 17:33:30,265 INFO: Parser eventParser: syncWord: AA,seqn: 38,len: 5,opcode: 0000,params: [26 04 00], check_sum: 89
    2023-03-09 17:33:30,266 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-09 17:33:30,266 INFO: Parser eventParser: event_id: [26 04]
    2023-03-09 17:33:30,266 INFO: Parser eventParser: status: [00]
    2023-03-09 17:33:30,361 INFO: AciHostCLI continuously_read: >>>receive packet: AA 39 0B 00 04 00 40 41 AF 7B 6C 32 20 00 00 4F
    2023-03-09 17:33:30,361 INFO: Parser eventParser: syncWord: AA,seqn: 39,len: 11,opcode: 0004,params: [40 41 AF 7B 6C 32 20 00 00], check_sum: 4F
    2023-03-09 17:33:30,362 INFO: Parser eventParser: event name: EVENT_DISCONNECT_STATUS
    2023-03-09 17:33:30,362 INFO: Parser eventParser: link_id: [40]
    2023-03-09 17:33:30,362 INFO: Parser eventParser: profile: [41]
    2023-03-09 17:33:30,362 INFO: Parser eventParser: bd_addr: [AF 7B 6C 32 20 00]
    2023-03-09 17:33:30,362 INFO: Parser eventParser: cause: [00]
    2023-03-09 17:33:30,363 INFO: Packet sendPacket: <<<send packet: AA 39 05 00 00 00 04 00 00 BE
    

CIS Acceptor Function

Firstly, CIS Acceptor needs to start LE Audio advertising, and then CIS Initiator can scan and connect it. After the LE Audio link is connected, CIS Acceptor can control remote media player and telephone call.

CIS Acceptor connection process:

CIS Acceptor media/call control process:

ACI Host CLI Test

Command

Parameters

ACI Host CLI CMD

CMD_LEA_ADV_START(0x3250)

lea_adv_start

CMD_LEA_ADV_STOP

None

lea_adv_stop

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x00

lea_call_cp accept

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x01

lea_call_cp terminate

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x02

lea_call_cp local_hold

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x03

lea_call_cp local_retrieve

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x04

lea_call_cp originate

CMD_LEA_CCP_CALL_CP

conn_id=0
call_cp=0x05

lea_call_cp join

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x01

lea_media_cp play

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x02

lea_media_cp pause

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x03

lea_media_cp fast_rewind

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x04

lea_media_cp fast_forward

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x05

lea_media_cp stop

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x30

lea_media_cp previous_track

CMD_LEA_MCP_MEDIA_CP

conn_id=0
media_cp=0x31

lea_media_cp next_track

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x00

lea_vcs vol_up

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x01

lea_vcs vol_down

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x02

lea_vcs spk_mute

CMD_LEA_VCS_SET

conn_id=0
vol_type=0x03

lea_vcs spk_unmute

For detailed information, please refer to CIS Acceptor ACI Host CLI Test.

BIS Acceptor Function

If an assistant exists, the sink could connect with an assistant and ask the assistant to assist it for scanning and get the extended advertising and periodic advertising info. If the assistant doesn’t exist, the sink needs to sync the source autonomously.

BIS sync establish process:

ACI Host CLI Test

Please refer to LE Audio Acceptor.

Bluetooth Audio Transceiver

This chapter introduces the functionality of the bt_audio_transceiver application scenario. This functionality is enabled by opening the macro definition F_APP_BT_AUDIO_TRANSCEIVER_DEMO_SUPPORT in app_flags.h. This chapter describes how to use these functions and the flow of how to test them, including the MSCs of the ACI Device and ACI Host interaction, and the commands used by ACI Host.

A2DP Transparent Transmission (A2DP Output)

Two typical application scenarios are introduced in chapter Bluetooth Audio Transceiver. Based on the A2DP scenario, A2DP data can be transferred from the Phone, through ACI Device 1 and ACI Device 2, to the Headset. This function is called A2DP Transparent Transmission.

A2DP Transparent Transmission process:

ACI Device 1 and ACI Device 2 transmit data through SPI. The SPI role of ACI Device 1 is master and that of ACI Device 2 is the slave. Please set flag F_APP_SPI_ROLE_MASTER on ACI Device 1 and set flag F_APP_SPI_ROLE_SLAVE on ACI Device 2 to enable SPI before building the application.

The AVDTP data format between Phone and ACI Device 1 may be different from that between ACI Device 2 and Headset. To solve this mismatch, the Audio Pipe is introduced on ACI Device 2 to convert the format in the route of Phone -> ACI Device 1 to that in the route of ACI Device 2 -> Headset.

ACI Host CLI Test

Before using the function, the hardware environment needs to be configured.

Bluetooth address modification: Use the MCUConfig Tool to modify the Bluetooth address of ACI Device 2 to make it different from ACI Device 1.

SPI wiring preparation: The recommended connection is P0_0(SPI_SCK), P1_0(SPI_MOSI), P0_1(SPI_MISO), P1_1(SPI_CS), P2_1(PIN_GPIO) and GND of ACI Device 1 and ACI Device 2. Developers can connect according to the pin settings in board.h.

The play route of Device 2 should be configured to A2DP Source through CMD_A2DP_XMIT_SET_ROUTE_OUT. The ACI Host sends CMD_A2DP_XMIT_ROUTE_OUT_CTRL with status param to ACI Device 2 to start or stop processing and sending data to Headset. The corresponding UART CMD packet and tool log are as follows:

Command

Parameters

ACI Host CLI CMD

CMD_A2DP_XMIT_SET_ROUTE_OUT(0x3223)

action = XMIT_PLAY_ROUTE_A2DP_SRC(0)

a2dpxmitroute a2dpsrc

CMD_A2DP_XMIT_ROUTE_OUT_CTRL(0x3220)

action = XMIT_PLAY_STATE_START(0)

a2dpxmitctrl start

CMD_A2DP_XMIT_ROUTE_OUT_CTRL(0x3220)

action = XMIT_PLAY_STATE_IDLE(1)

a2dpxmitctrl stop

  1. ACI Host CLI test (ACI Device 2): Initiate ACI Device 2 as SPI slave.

    2023-05-15 14:53:17,075 INFO: input command: spiinit slave
    2023-05-15 14:53:17,075 INFO: Parser cmdParser: cmd opcode: 3020 param: [01] name: CMD_SPI_INIT
    2023-05-15 14:53:17,076 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 20 30 01 C8
    2023-05-15 14:53:17,082 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 20 30 00 C7
    2023-05-15 14:53:17,083 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [20 30 00], check_sum: C7
    2023-05-15 14:53:17,086 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:53:17,087 INFO: Parser eventParser: event_id: [20 30]
    2023-05-15 14:53:17,087 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test (ACI Device 1): Initiate ACI Device 1 as SPI master.

    2023-05-15 14:53:20,655 INFO: input command: spiinit master
    2023-05-15 14:53:20,655 INFO: Parser cmdParser: cmd opcode: 3100 param: [00] name: CMD_SPI_INIT
    2023-05-15 14:53:20,656 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 20 30 00 C9
    2023-05-15 14:53:20,670 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 20 30 00 C7
    2023-05-15 14:53:20,671 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [20 30 00], check_sum: C7
    2023-05-15 14:53:20,671 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:53:20,672 INFO: Parser eventParser: event_id: [20 30]
    2023-05-15 14:53:20,672 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test (ACI Device 1): Connect ACI Device 1 to Phone.

    Please refer to Connect to Phone.

  4. ACI Host CLI test (ACI Device 2): Connect Headset to ACI Device 2.

    Please refer to Connect to BUD.

  5. Phone starts to play music.

  6. ACI Host CLI test (ACI Device 2): Start or stop transmitting data to Headset.

    Use CMD a2dpxmitroute a2dpsrc to configure the output data route to A2DP Source, and input a2dpxmitctrl start to let the Headset get incoming music data from the Phone, input a2dpxmitctrl stop, no data will be transmitted to the Headset, music will stop.

    2023-05-15 14:53:58,736 INFO: input command: a2dpxmitroute a2dpsrc
    2023-05-15 14:53:58,737 INFO: Parser cmdParser: cmd opcode: 3223 param: [00] name: CMD_A2DP_XMIT_SET_ROUTE_OUT
    2023-05-15 14:53:58,737 INFO: Packet sendPacket: <<<send packet: AA 12 03 00 23 32 00 B5
    2023-05-15 14:53:58,748 INFO: AciHostCLI continuously_read: >>>receive packet: AA 12 05 00 00 00 23 32 00 B3
    2023-05-15 14:53:58,749 INFO: Parser eventParser: syncWord: AA,seqn: 12,len: 5,opcode: 0000,params: [23 32 00], check_sum: B3
    2023-05-15 14:53:58,749 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:53:58,750 INFO: Parser eventParser: event_id: [23 32]
    2023-05-15 14:53:58,750 INFO: Parser eventParser: status: [00]
    
    2023-05-15 14:54:01,482 INFO: input command: a2dpxmitctrl start
    2023-05-15 14:54:01,483 INFO: Parser cmdParser: cmd opcode: 3220 param: [00] name: CMD_A2DP_XMIT_ROUTE_OUT_CTRL
    2023-05-15 14:54:01,483 INFO: Packet sendPacket: <<<send packet: AA 13 03 00 20 32 00 B7
    2023-05-15 14:54:01,499 INFO: AciHostCLI continuously_read: >>>receive packet: AA 13 05 00 00 00 20 32 00 B5
    2023-05-15 14:54:01,499 INFO: Parser eventParser: syncWord: AA,seqn: 13,len: 5,opcode: 0000,params: [20 32 00], check_sum: B5
    2023-05-15 14:54:01,500 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:54:01,500 INFO: Parser eventParser: event_id: [20 32]
    2023-05-15 14:54:01,501 INFO: Parser eventParser: status: [00]
    
    2023-05-15 14:54:11,089 INFO: input command: a2dpxmitctrl stop
    2023-05-15 14:54:11,089 INFO: Parser cmdParser: cmd opcode: 3220 param: [01] name: CMD_A2DP_XMIT_ROUTE_OUT_CTRL
    2023-05-15 14:54:11,090 INFO: Packet sendPacket: <<<send packet: AA 14 03 00 20 32 01 B5
    2023-05-15 14:54:11,097 INFO: AciHostCLI continuously_read: >>>receive packet: AA 14 05 00 00 00 20 32 00 B4
    2023-05-15 14:54:11,101 INFO: Parser eventParser: syncWord: AA,seqn: 14,len: 5,opcode: 0000,params: [20 32 00], check_sum: B4
    2023-05-15 14:54:11,103 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:54:11,104 INFO: Parser eventParser: event_id: [20 32]
    2023-05-15 14:54:11,104 INFO: Parser eventParser: status: [00]
    

A2DP Transparent Transmission (BIS Output)

LE Audio is a new Bluetooth wireless standard for transmitting audio. LE Audio operates on the Bluetooth Low Energy radio, which is different from Classic Audio (like A2DP or HFP) operates on the Bluetooth Classic radio. LE Audio transmits stream through BIS (Broadcast Isochronous Streams) or CIS (Connected Isochronous Streams). Currently, Bluetooth Audio Transceiver application supports broadcasting audio through BIS.

As a broadcaster, the audio data for broadcasting is necessary. Based on the typical A2DP scenario (refer to Bluetooth Audio Transceiver), we use the AVDTP data received from the Phone by ACI Device 1 as the raw data for ACI Device 2. The received AVDTP data would be converted to LC3 format supported by LE Audio through the Audio Pipe. On ACI Device 2, a BIG with 1 or 2 BIS would be set up and broadcast the converted LC3 data externally. The topology is shown in the figure below.

Before enabling the broadcast source feature, please ensure that the LE isochronous function and PA function are enabled in MCUConfig Tool, and at least 1 BIG, 2 BIS and 1 PA are set up.

Broadcast Source process:

ACI Host CLI Test

The ACI Host sends CMD_LEA_BSRC_INIT to ACI Device 2 to configure the codec type, BIS number and encryption mode. The play route of Device 2 should be configured to BIS through CMD_A2DP_XMIT_SET_ROUTE_OUT and the ACI Host sends CMD_A2DP_XMIT_ROUTE_OUT_CTRL with status param to ACI Device 2 to start or stop processing and sending data to Headset.

Command

Parameters

ACI Host CLI CMD

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 1
encryption = true
ull_mode = true
pd = 0x2710

bsrcinit 48k_1bis

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_16_2(16k)
BIS num = 1
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 16k_1bis

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_48_4(48k)
BIS num = 2
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 48k_2bis

CMD_LEA_BSRC_INIT(0x3020)

codec type = CODEC_CFG_ITEM_16_2(16k)
BIS num = 2
encryption = false
ull_mode = true
pd = 0x2710

bsrcinit 16k_2bis

CMD_A2DP_XMIT_SET_ROUTE_OUT(0x3223)

action = XMIT_PLAY_ROUTE_A2DP_SRC(0)

a2dpxmitroute bis

CMD_A2DP_XMIT_ROUTE_OUT_CTRL(0x3220)

action = XMIT_PLAY_STATE_START(0)

a2dpxmitctrl start

CMD_A2DP_XMIT_ROUTE_OUT_CTRL(0x3220)

action = XMIT_PLAY_STATE_IDLE(1)

a2dpxmitctrl stop

The corresponding UART CMD packet and tool log are as follows:

  1. ACI Host CLI test (ACI Device 2): Initiate ACI Device 2 as SPI slave.

    2023-05-15 14:53:17,075 INFO: input command: spiinit slave
    2023-05-15 14:53:17,075 INFO: Parser cmdParser: cmd opcode: 3100 param: [01] name: CMD_SPI_INIT
    2023-05-15 14:53:17,076 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 20 30 01 C8
    2023-05-15 14:53:17,082 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 20 30 00 C7
    2023-05-15 14:53:17,083 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [20 30 00], check_sum: C7
    2023-05-15 14:53:17,086 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:53:17,087 INFO: Parser eventParser: event_id: [20 30]
    2023-05-15 14:53:17,087 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test (ACI Device 1): Initiate ACI Device 1 as SPI master.

    2023-05-15 14:53:20,655 INFO: input command: spiinit master
    2023-05-15 14:53:20,655 INFO: Parser cmdParser: cmd opcode: 3100 param: [00] name: CMD_SPI_INIT
    2023-05-15 14:53:20,656 INFO: Packet sendPacket: <<<send packet: AA 03 03 00 20 30 00 C9
    2023-05-15 14:53:20,670 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 20 30 00 C7
    2023-05-15 14:53:20,671 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [20 30 00], check_sum: C7
    2023-05-15 14:53:20,671 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:53:20,672 INFO: Parser eventParser: event_id: [20 30]
    2023-05-15 14:53:20,672 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test (ACI Device 2): Initiate broadcast source.

    2023-05-15 14:53:25,753 INFO: input command: bsrcinit 48k_1bis
    2023-05-15 14:53:25,753 INFO: Parser cmdParser: cmd opcode: 3020 param: [0D 01 00 01 10 27] name: CMD_LEA_BSRC_INIT
    2023-05-15 14:53:25,754 INFO: Packet sendPacket: <<<send packet: AA 04 05 00 20 30 0D 01 00 01 10 27 B7
    2023-05-15 14:53:25,766 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 20 30 00 C5
    2023-05-15 14:53:25,767 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [20 30 00], check_sum: C5
    2023-05-15 14:53:25,768 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:53:25,768 INFO: Parser eventParser: event_id: [20 30]
    2023-05-15 14:53:25,769 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test (ACI Device 1): Connect ACI Device 1 to Phone.

    Please refer to Connect to Phone.

    Use CMD a2dpxmitroute bis to config the output data route to BIS, and input a2dpxmitctrl start to let Headset to get incoming music data from the Phone. If you input a2dpxmitctrl stop, no data will be transmitted to Headset, music will stop.

  5. ACI Host CLI test (ACI Device 1): Start streaming.

    2023-05-15 14:54:16,535 INFO: input command: a2dpxmitroute bis
    2023-05-15 14:54:16,535 INFO: Parser cmdParser: cmd opcode: 3223 param: [01] name: CMD_A2DP_XMIT_SET_ROUTE_OUT
    2023-05-15 14:54:16,536 INFO: Packet sendPacket: <<<send packet: AA 15 03 00 23 32 01 B1
    2023-05-15 14:54:16,549 INFO: AciHostCLI continuously_read: >>>receive packet: AA 15 05 00 00 00 23 32 00 B0
    2023-05-15 14:54:16,550 INFO: Parser eventParser: syncWord: AA,seqn: 15,len: 5,opcode: 0000,params: [23 32 00], check_sum: B0
    2023-05-15 14:54:16,551 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:54:16,551 INFO: Parser eventParser: event_id: [23 32]
    2023-05-15 14:54:16,552 INFO: Parser eventParser: status: [00]
    
  6. ACI Host CLI test (ACI Device 1): Start streaming.

    2023-05-15 14:54:26,384 INFO: input command: a2dpxmitctrl start
    2023-05-15 14:54:26,384 INFO: Parser cmdParser: cmd opcode: 3220 param: [00] name: CMD_A2DP_XMIT_ROUTE_OUT_CTRL
    2023-05-15 14:54:26,385 INFO: Packet sendPacket: <<<send packet: AA 16 03 00 20 32 00 B4
    2023-05-15 14:54:26,402 INFO: AciHostCLI continuously_read: >>>receive packet: AA 16 05 00 00 00 20 32 00 B2
    2023-05-15 14:54:26,403 INFO: Parser eventParser: syncWord: AA,seqn: 16,len: 5,opcode: 0000,params: [20 32 00], check_sum: B2
    2023-05-15 14:54:26,404 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:54:26,404 INFO: Parser eventParser: event_id: [20 32]
    2023-05-15 14:54:26,404 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test (ACI Device 1): Stop streaming.

    2023-05-15 14:54:48,305 INFO: input command: a2dpxmitctrl stop
    2023-05-15 14:54:48,305 INFO: Parser cmdParser: cmd opcode: 3220 param: [01] name: CMD_A2DP_XMIT_ROUTE_OUT_CTRL
    2023-05-15 14:54:48,306 INFO: Packet sendPacket: <<<send packet: AA 17 03 00 20 32 01 B2
    2023-05-15 14:54:48,314 INFO: AciHostCLI continuously_read: >>>receive packet: AA 17 05 00 00 00 20 32 00 B1
    2023-05-15 14:54:48,316 INFO: Parser eventParser: syncWord: AA,seqn: 17,len: 5,opcode: 0000,params: [20 32 00], check_sum: B1
    2023-05-15 14:54:48,319 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-15 14:54:48,320 INFO: Parser eventParser: event_id: [20 32]
    2023-05-15 14:54:48,321 INFO: Parser eventParser: status: [00]
    

HFP Transparent Transmission

Based on the SCO scenario introduced in chapter Bluetooth Audio Transceiver, HFP transparent transmission can be realized by transmitting SCO data from the Phone, through ACI Device 1 and ACI Device 2, to the Headset.

ACI Device 1 and ACI Device 2 transmit data through SPI. The SPI role of ACI Device 1 is master and that of ACI Device 2 is the slave. Similar to 6.1.1, please set the flag F_APP_SPI_ROLE_MASTER on ACI Device 1 and set the flag F_APP_SPI_ROLE_SLAVE on ACI Device 2 before building.

HFP Transparent Transmission process:

In addition, the operations of answering, hanging up, muting MIC, increasing or decreasing SPK volume can be realized only by host.

HFP Transparent Transmission host control process:

ACI Host CLI Test (HFP Transfer)

Before using the function, the hardware environment needs to be configured.

Bluetooth address modification: Use MCUConfig Tool to modify the Bluetooth address of ACI Device 2 to make it different from ACI Device 1.

SPI wiring preparation: The recommended connection is P0_0(SPI_SCK), P1_0(SPI_MOSI), P0_1(SPI_MISO), P1_1(SPI_CS), P2_1(PIN_GPIO) and GND of ACI Device 1 and ACI Device 2. Developers can connect according to the pin settings in board.h.

The ACI Host sends SPI_AG_SCO_CONNECT with status param to ACI Device 2 to connect the SCO link between ACI Device 2 and the Headset to send data. Correspondingly, the ACI Host sends SPI_AG_SCO_DISCONNECT to ACI Device 2 to disconnect the SCO link between ACI Device 2 and the Headset. The ACI Host CLI commands are hfpag conn and hfpag disconn. If the phone supports outband ringtone, commands such as hfpag call_incoming, hfpag call_answer and hfpag call_terminate are required to make the Headset simulate playing/stopping the ringtone and dropping calls.

The corresponding UART CMD packet and tool log are as follows:

Command

Parameters

ACI Host CLI CMD

CMD_HFP_AG_CONNECT_SCO(0x0480)

action = SPI_AG_SCO_CONNECT(0)

hfpag conn_0

CMD_HFP_AG_DISCONNECT_SCO(0x0481)

action = SPI_AG_SCO_DISCONNECT(0)

hfpag disconn_0

CMD_HFP_AG_CALL_INCOMING(0x0482)

action = NOTIFY_INCOMING_CALL(0)

hfpag call_incoming

CMD_HFP_AG_CALL_ANSWER(0x0483)

action = ANSWER_INCOMING_CALL(0)

hfpag call_answer

CMD_HFP_AG_CALL_TERMINATE(0x0484)

action = TERMINATE_CALL(0)

hfpag call_terminate

CMD_HFP_AG_MIC_GAIN_LEVEL_SET(0x0488)

action = MIC_MUTE(0x00)

hfpag mic_mute

CMD_HFP_AG_MIC_GAIN_LEVEL_SET(0x0488)

action = MIC_UNMUTE(0x0A)

hfpag mic_unmute

CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET(0x0489)

action = SPK_VOL_DOWN(0x00)

hfpag spk_vol_up

CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET(0x0489)

action = SPK_VOL_UP(0x00)

hfpag spk_vol_down

CMD_MMI(0x0004)

action = ANSWER_CALL(0x03)

mmi answer_call

CMD_MMI(0x0004)

action = REJECT_CALL(0x04)

mmi reject_call

CMD_MMI(0x0004)

action = END_CALL(0x05)

mmi end_active_call

  1. ACI Host CLI test (ACI Device 2): Initiate ACI Device 2 as SPI slave.

    Please refer to ACI Host CLI Test.

  2. ACI Host CLI test (ACI Device 1): Initiate ACI Device 1 as SPI master.

    Please refer to ACI Host CLI Test.

  3. ACI Host CLI test (ACI Device 1): Connect ACI Device 1 to Phone.

    Please refer to Connect to Phone.

  4. ACI Host CLI test (ACI Device 2): Connect Headset to ACI Device 2.

    Please refer to Connect to BUD.

  5. Call the Phone connected to ACI Device 1.

  6. ACI Host CLI test (ACI Device 2): Connect or disconnect the SCO link between ACI Device 2 and Headset.

    If input hfpag conn_0, the Headset will be able to hear incoming sounds from the Phone MIC and make calls, if input hfpag disconn_0, Headset will disconnect the SCO.

    2023-03-06 14:34:07,113 INFO: input command: hfpag conn_0
    2023-03-06 14:34:07,115 INFO: Parser cmdParser: cmd opcode: 0480 param: [00] name: CMD_HFP_AG_CONNECT_SCO
    2023-03-06 14:34:07,116 INFO: Packet sendPacket: <<<send packet: AA 10 03 00 80 04 00 E4
    2023-03-06 14:34:07,129 INFO: AciHostCLI continuously_read: >>>receive packet: AA 10 05 00 00 00 80 04 00 E2
    2023-03-06 14:34:07,129 INFO: Parser eventParser: syncWord: AA,seqn: 10,len: 5,opcode: 0000,params: [80 04 00], check_sum: E2
    2023-03-06 14:34:07,130 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-06 14:34:07,130 INFO: Parser eventParser: event_id: [80 04]
    2023-03-06 14:34:07,130 INFO: Parser eventParser: status: [00]
    
    2023-03-06 16:44:30,416 INFO: input command: hfpag disconn_0
    2023-03-06 16:44:30,419 INFO: Parser cmdParser: cmd opcode: 0481 param: [00] name: CMD_HFP_AG_DISCONNECT_SCO
    2023-03-06 16:44:30,422 INFO: Packet sendPacket: <<<send packet: AA 1C 03 00 81 04 00 D7
    2023-03-06 16:44:30,426 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1C 05 00 00 00 81 04 00 D5
    2023-03-06 16:44:30,427 INFO: Parser eventParser: syncWord: AA,seqn: 1C,len: 5,opcode: 0000,params: [81 04 00], check_sum: D5
    2023-03-06 16:44:30,427 INFO: Parser eventParser: event name: EVENT_ACK
    2023-03-06 16:44:30,427 INFO: Parser eventParser: event_id: [81 04]
    2023-03-06 16:44:30,428 INFO: Parser eventParser: status: [00]
    

    If the phone supports outband ringtones, ACI Device 2 should perform the following operations when the phone receives a call:

  7. ACI Host CLI test (ACI Device 2): Make Headset play ring to simulate incoming call.

    2023-05-17 09:46:17,157 INFO: input command: hfpag call_incoming
    2023-05-17 09:46:17,158 INFO: Parser cmdParser: cmd opcode: 0482 param: [00 81] name: CMD_HFP_AG_CALL_INCOMING
    2023-05-17 09:46:17,159 INFO: Packet sendPacket: <<<send packet: AA 27 04 00 82 04 00 81 49
    2023-05-17 09:46:17,169 INFO: AciHostCLI continuously_read: >>>receive packet: AA 27 04 00 35 03 00 01 9C
    2023-05-17 09:46:17,172 INFO: Parser eventParser: syncWord: AA,seqn: 27,len: 4,opcode: 0335,params: [00 01], check_sum: 9C
    2023-05-17 09:46:17,174 INFO: Packet sendPacket: <<<send packet: AA 28 05 00 00 00 35 03 00 9B
    2023-05-17 09:46:17,184 INFO: AciHostCLI continuously_read: >>>receive packet: AA 28 05 00 00 00 82 04 00 C8
    2023-05-17 09:46:17,185 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 5,opcode: 0000,params: [82 04 00], check_sum: C8
    2023-05-17 09:46:17,186 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-17 09:46:17,186 INFO: Parser eventParser: event_id: [82 04]
    2023-05-17 09:46:17,186 INFO: Parser eventParser: status: [00]
    
  8. Pick up Phone call.

  9. ACI Host CLI test (ACI Device 2): Answer Phone call.

    2023-05-17 09:46:34,693 INFO: input command: hfpag call_answer
    2023-05-17 09:46:34,693 INFO: Parser cmdParser: cmd opcode: 0483 param: [00] name: CMD_HFP_AG_CALL_ANSWER
    2023-05-17 09:46:34,694 INFO: Packet sendPacket: <<<send packet: AA 29 03 00 83 04 00 C8
    2023-05-17 09:46:34,712 INFO: AciHostCLI continuously_read: >>>receive packet: AA 29 04 00 35 03 00 03 98
    2023-05-17 09:46:34,717 INFO: Parser eventParser: syncWord: AA,seqn: 29,len: 4,opcode: 0335,params: [00 03], check_sum: 98
    2023-05-17 09:46:34,719 INFO: Packet sendPacket: <<<send packet: AA 2A 05 00 00 00 35 03 00 99
    2023-05-17 09:46:34,728 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2A 05 00 00 00 83 04 00 C5
    2023-05-17 09:46:34,728 INFO: Parser eventParser: syncWord: AA,seqn: 2A,len: 5,opcode: 0000,params: [83 04 00], check_sum: C5
    2023-05-17 09:46:34,729 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-17 09:46:34,729 INFO: Parser eventParser: event_id: [83 04]
    2023-05-17 09:46:34,730 INFO: Parser eventParser: status: [00]
    2023-05-17 09:46:35,895 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2B 04 00 38 03 00 02 94
    2023-05-17 09:46:35,897 INFO: Parser eventParser: syncWord: AA,seqn: 2B,len: 4,opcode: 0338,params: [00 02], check_sum: 94
    2023-05-17 09:46:35,901 INFO: Packet sendPacket: <<<send packet: AA 2B 05 00 00 00 38 03 00 95
    2023-05-17 09:46:35,911 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2C 04 00 00 03 00 01 CC
    2023-05-17 09:46:35,912 INFO: Parser eventParser: syncWord: AA,seqn: 2C,len: 4,opcode: 0300,params: [00 01], check_sum: CC
    2023-05-17 09:46:35,913 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2023-05-17 09:46:35,914 INFO: Parser eventParser: app_link_id: [00]
    2023-05-17 09:46:35,914 INFO: Parser eventParser: state: [01]
    2023-05-17 09:46:35,915 INFO: Packet sendPacket: <<<send packet: AA 2C 05 00 00 00 00 03 00 CC
    
  10. Hang up Phone call.

  11. ACI Host CLI test (ACI Device 2): Notify Headset that Phone call is terminated.

    2023-05-17 09:47:02,069 INFO: input command: hfpag call_terminate
    2023-05-17 09:47:02,069 INFO: Parser cmdParser: cmd opcode: 0484 param: [00] name: CMD_HFP_AG_CALL_TERMINATE
    2023-05-17 09:47:02,070 INFO: Packet sendPacket: <<<send packet: AA 2D 03 00 84 04 00 C3
    2023-05-17 09:47:02,076 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2D 04 00 35 03 00 00 97
    2023-05-17 09:47:02,077 INFO: Parser eventParser: syncWord: AA,seqn: 2D,len: 4,opcode: 0335,params: [00 00], check_sum: 97
    2023-05-17 09:47:02,082 INFO: Packet sendPacket: <<<send packet: AA 2E 05 00 00 00 35 03 00 95
    2023-05-17 09:47:02,091 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2E 05 00 00 00 84 04 00 C0
    2023-05-17 09:47:02,094 INFO: Parser eventParser: syncWord: AA,seqn: 2E,len: 5,opcode: 0000,params: [84 04 00], check_sum: C0
    2023-05-17 09:47:02,095 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-17 09:47:02,095 INFO: Parser eventParser: event_id: [84 04]
    2023-05-17 09:47:02,096 INFO: Parser eventParser: status: [00]
    

    If only host control is used, the following operations need to be performed:

  12. ACI Host CLI test (ACI Device 1): Answer call.

    2023-05-31 14:46:35,990 INFO: input command: mmi answer_call
    2023-05-31 14:46:35,990 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 03] name: CMD_MMI
    2023-05-31 14:46:35,991 INFO: Packet sendPacket: <<<send packet: AA 01 04 00 04 00 00 03 F4
    2023-05-31 14:46:36,009 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 05 00 00 00 04 00 00 F4
    2023-05-31 14:46:36,011 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 5,opcode: 0000,params: [04 00 00], check_sum: F4
    2023-05-31 14:46:36,012 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 14:46:36,013 INFO: Parser eventParser: event_id: [04 00]
    2023-05-31 14:46:36,013 INFO: Parser eventParser: status: [00]
    
  13. ACI Host CLI test (ACI Device 1): Reject call.

    2023-05-31 16:06:51,592 INFO: input command: mmi reject_call
    2023-05-31 16:06:51,596 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 04] name: CMD_MMI
    2023-05-31 16:06:51,598 INFO: Packet sendPacket: <<<send packet: AA 02 04 00 04 00 00 04 F2
    2023-05-31 16:06:51,613 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 04 00 00 F3
    2023-05-31 16:06:51,614 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [04 00 00], check_sum: F3
    2023-05-31 16:06:51,615 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 16:06:51,615 INFO: Parser eventParser: event_id: [04 00]
    2023-05-31 16:06:51,616 INFO: Parser eventParser: status: [00]
    
  14. ACI Host CLI test (ACI Device 2): Mute MIC.

    2023-05-31 16:20:02,818 INFO: input command: hfpag mic_mute
    2023-05-31 16:20:02,819 INFO: Parser cmdParser: cmd opcode: 0488 param: [00 00] name: CMD_HFP_AG_MIC_GAIN_LEVEL_SET
    2023-05-31 16:20:02,819 INFO: Packet sendPacket: <<<send packet: AA 03 04 00 88 04 00 00 E8
    2023-05-31 16:20:02,827 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 05 00 00 00 88 04 00 E5
    2023-05-31 16:20:02,830 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 5,opcode: 0000,params: [88 04 00], check_sum: E5
    2023-05-31 16:20:02,831 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 16:20:02,832 INFO: Parser eventParser: event_id: [88 04]
    2023-05-31 16:20:02,832 INFO: Parser eventParser: status: [00]
    
  15. ACI Host CLI test (ACI Device 2): Unmute MIC.

    2023-05-31 16:21:04,073 INFO: input command: hfpag mic_unmute
    2023-05-31 16:21:04,073 INFO: Parser cmdParser: cmd opcode: 0488 param: [00 0A] name: CMD_HFP_AG_MIC_GAIN_LEVEL_SET
    2023-05-31 16:21:04,074 INFO: Packet sendPacket: <<<send packet: AA 04 04 00 88 04 00 0A DD
    2023-05-31 16:21:04,080 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 05 00 00 00 88 04 00 E4
    2023-05-31 16:21:04,082 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 5,opcode: 0000,params: [88 04 00], check_sum: E4
    2023-05-31 16:21:04,089 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 16:21:04,090 INFO: Parser eventParser: event_id: [88 04]
    2023-05-31 16:21:04,091 INFO: Parser eventParser: status: [00]
    
  16. ACI Host CLI test (ACI Device 2): SPK volume up.

    2023-05-31 17:09:29,143 INFO: input command: hfpag spk_vol_up
    2023-05-31 17:09:29,144 INFO: Parser cmdParser: cmd opcode: 0489 param: [00 0A] name: CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET
    2023-05-31 17:09:29,146 INFO: Packet sendPacket: <<<send packet: AA 05 04 00 89 04 00 0A DB
    2023-05-31 17:09:29,158 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 05 00 00 00 89 04 00 E2
    2023-05-31 17:09:29,159 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 5,opcode: 0000,params: [89 04 00], check_sum: E2
    2023-05-31 17:09:29,160 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 17:09:29,160 INFO: Parser eventParser: event_id: [89 04]
    2023-05-31 17:09:29,161 INFO: Parser eventParser: status: [00]
    
  17. ACI Host CLI test (ACI Device 2): SPK volume down.

    2023-05-31 17:10:32,765 INFO: input command: hfpag spk_vol_down
    2023-05-31 17:10:32,766 INFO: Parser cmdParser: cmd opcode: 0489 param: [00 00] name: CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET
    2023-05-31 17:10:32,767 INFO: Packet sendPacket: <<<send packet: AA 06 04 00 89 04 00 00 E4
    2023-05-31 17:10:32,780 INFO: AciHostCLI continuously_read: >>>receive packet: AA 08 05 00 00 00 89 04 00 E1
    2023-05-31 17:10:32,794 INFO: Parser eventParser: syncWord: AA,seqn: 08,len: 5,opcode: 0000,params: [89 04 00], check_sum: E1
    2023-05-31 17:10:32,795 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 17:10:32,795 INFO: Parser eventParser: event_id: [89 04]
    2023-05-31 17:10:32,796 INFO: Parser eventParser: status: [00]
    
  18. ACI Host CLI test (ACI Device 1): End call.

    2023-05-31 17:17:47,759 INFO: input command: mmi end_active_call
    2023-05-31 17:17:47,759 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 05] name: CMD_MMI
    2023-05-31 17:17:47,760 INFO: Packet sendPacket: <<<send packet: AA 07 04 00 04 00 00 05 EC
    2023-05-31 17:17:47,774 INFO: AciHostCLI continuously_read: >>>receive packet: AA 09 05 00 00 00 04 00 00 EE
    2023-05-31 17:17:47,787 INFO: Parser eventParser: syncWord: AA,seqn: 09,len: 5,opcode: 0000,params: [04 00 00], check_sum: EE
    2023-05-31 17:17:47,787 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-05-31 17:17:47,788 INFO: Parser eventParser: event_id: [04 00]
    2023-05-31 17:17:47,788 INFO: Parser eventParser: status: [00]
    

Bluetooth Audio Transmitter MP3

This chapter introduces the functionality of the bt_audio_transmitter_mp3 application scenario. This functionality is enabled by opening the macro definition F_APP_BT_AUDIO_TRANSMITTER_MP3_DEMO_SUPPORT in app_flags.h. This chapter describes how to use these functions and the flow of how to test them, including the MSCs of the ACI Device and ACI Host interaction, and the commands used by ACI Host.

Music Play Function

The interactive process of music playing is analyzed in this chapter, the format of music playing is MP3.

Prerequisites

Music playing process:

  1. ACI Host CLI test: Session open.

    The ACI Host sends CMD_XM_MUSIC command with MUSIC_SESSION_OPEN to start the music-playing process. The ACI Host CLI CMD for starting music playing is music open, the corresponding UART CMD packet and tool log are as follows:

    Command

    Parameters

    ACI Host CLI CMD

    CMD_XM_MUSIC = 0x8080

    type = MUSIC_SESSION_OPEN(0), seq = 0

    music open

    2023-01-12 14:08:20,013 INFO: input command: music open
    2023-01-12 14:08:20,014 INFO: Parser cmdParser: cmd opcode: 8080 param: [00 00] name: CMD_XM_MUSIC
    2023-01-12 14:08:20,014 INFO: Packet sendPacket: <<<send packet: AA 04 04 00 80 80 00 00 73
    2023-01-12 14:08:20,026 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 80 80 00 72
    2023-01-12 14:08:20,027 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [80 80 00], check_sum: 72
    2023-01-12 14:08:20,028 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-01-12 14:08:20,029 INFO: Parser eventParser: event_id: [80 80]
    2023-01-12 14:08:20,030 INFO: Parser eventParser: status: [00]
    
  2. ACI Host CLI test: Session send xxx frame.

    ACI Device requests the first music data frame through EVENT_XM_MUSIC_REQ_FRAME. Afterward, ACI Device will continue to request music data frames through EVENT_APP_EVENT_ACK(0x0000) with status CMD_SET_STATUS_MUSIC_REQ(8).

    2023-01-12 14:08:20,030 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 02 00 00 85 74
    2023-01-12 14:08:20,031 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 2,opcode: 8500,params: [], check_sum: 74
    2023-01-12 14:08:20,031 INFO: Parser eventParser: event name: EVENT_XM_MUSIC_REQ_FRAME
    2023-01-12 14:08:20,032 INFO: Packet sendPacket: <<<send packet: AA 05 05 00 00 00 00 85 00 71
    2023-01-12 14:08:20,032 INFO: Music get_data: 00000000: 49 44 33 03 00 00 00 00 00 52 54 50 45 32 00 00 00 07 00 00 00 A4 FD A4 4F A7 BB 54 49 54 32 00
    2023-01-12 14:08:20,033 INFO: Parser cmdParser: cmd opcode: 8080 param: [05 00 49 44 33 03 00 00 00 00 00 52 54 50 45 32 00 00 00 07 00 00 00 A4 FD A4 4F A7 BB 54 49 54] name: CMD_XM_MUSIC
    2023-01-12 14:08:20,036 INFO: Packet sendPacket: <<<send packet: AA 06 04 02 00 85 05 00 49 44 33 03 00 00 00 00 00 52 54 50 45 32 00 00 00 07 00 00 00 A4 FD A4
    2023-01-12 14:08:20,042 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 05 00 00 00 00 80 80 68
    2023-01-12 14:08:20,043 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 5,opcode: 0000,params: [80 80 08], check_sum: 68
    2023-01-12 14:08:20,043 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-01-12 14:08:20,044 INFO: Parser eventParser: event_id: [80 80]
    2023-01-12 14:08:20,044 INFO: Parser eventParser: status: [08]
    
  3. ACI Host CLI test: Session close.

    The ACI Host sends Session Close to end the music playing process normally. The ACI Host CLI CMD for stopping music playing is music close, the corresponding UART CMD packet and tool log are as follows:

    Command

    Parameters

    ACI Host CLI CMD

    CMD_XM_MUSIC = 0x8080

    type = MUSIC_SESSION_CLOSE(4), seq = 0

    music close

    2023-01-12 14:19:04,386 INFO: Parser cmdParser: cmd opcode: 8080 param: [04 00] name: CMD_XM_MUSIC
    2023-01-12 14:19:04,386 INFO: Packet sendPacket: <<<send packet: AA 90 04 00 80 80 04 00 E3
    2023-01-12 14:19:04,398 INFO: AciHostCLI continuously_read: >>>receive packet: AA 3F 05 00 00 00 80 80 00 37
    2023-01-12 14:19:04,399 INFO: Parser eventParser: syncWord: AA,seqn: 3F,len: 5,opcode: 0000,params: [80 80 00], check_sum: 37
    2023-01-12 14:19:04,400 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-01-12 14:19:04,400 INFO: Parser eventParser: event_id: [80 80]
    2023-01-12 14:19:04,400 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Session abort.

    If the ACK status is not CMD_SET_STATUS_COMPLETE(0) or CMD_SET_STATUS_MUSIC_REQ(8) during playback, the ACI Host will send Session Abort to stop the music playing process immediately. The ACI Host CLI CMD for stopping music playing is music abort, the corresponding UART CMD packet and tool log are as follows:

    Command

    Parameters

    ACI Host CLI CMD

    CMD_XM_MUSIC = 0x8080

    type = MUSIC_SESSION_ABORT(3), seq = 0

    music abort

    2023-01-12 14:24:17,764 INFO: input command: music abort
    2023-01-12 14:24:17,765 INFO: Parser cmdParser: cmd opcode: 8080 param: [03 00] name: CMD_XM_MUSIC
    2023-01-12 14:24:17,765 INFO: Packet sendPacket: <<<send packet: AA 31 04 00 00 85 03 00 43
    2023-01-12 14:24:17,774 INFO: AciHostCLI continuously_read: >>>receive packet: AA 71 0A 00 0B 00 00 00 00 00 00 00 00 00 7A
    2023-01-12 14:24:17,774 INFO: Parser eventParser: syncWord: AA,seqn: 71,len: 10,opcode: 000B,params: [00 00 00 00 00 00 00 00], check_sum: 7A
    2023-01-12 14:24:17,775 INFO: Parser eventParser: event name: EVENT_PLAYER_STATUS
    2023-01-12 14:24:17,775 INFO: Parser eventParser: bd_addr: [00 00 00 00 00 00]
    2023-01-12 14:24:17,775 INFO: Parser eventParser: play_status: [00]
    2023-01-12 14:24:17,776 INFO: Parser eventParser: play_mode: [00]
    2023-01-12 14:24:17,776 INFO: Packet sendPacket: <<<send packet: AA 32 05 00 00 00 0B 00 00 BE
    2023-01-12 14:24:17,790 INFO: AciHostCLI continuously_read: >>>receive packet: AA 72 05 00 00 00 00 85 00 04
    2023-01-12 14:24:17,790 INFO: Parser eventParser: syncWord: AA,seqn: 72,len: 5,opcode: 0000,params: [00 85 00], check_sum: 04
    2023-01-12 14:24:17,791 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-01-12 14:24:17,791 INFO: Parser eventParser: event_id: [00 85]
    2023-01-12 14:24:17,791 INFO: Parser eventParser: status: [00]
    
ACI Host CLI Test

The played music directory is tool\AciHostCLI-Common_SDK\music.

Local Playback

Command

Parameters

ACI Host CLI CMD

Description

CMD_XM_MMI = 0x8004

action = XM_MMI_MODE_LOCAL_PLAY(1)

xmmi local

Switch to local playback mode for music play.

  1. Connect and configure a SPK to EVB.

  2. ACI Host CLI test: Enter local playback mode.

    Input xmmi local.

    2023-04-23 18:48:59,335 INFO: input command: xmmi local
    2023-04-23 18:48:59,337 INFO: Parser cmdParser: cmd opcode: 8004 param: [01] name: CMD_XM_MMI
    2023-04-23 18:48:59,338 INFO: Packet sendPacket: <<<send packet: AA 01 03 00 04 80 01 77
    2023-04-23 18:48:59,342 INFO: AciHostCLI continuously_read: >>>receive packet: AA 57 05 00 00 00 04 80 00 20
    2023-04-23 18:48:59,355 INFO: Parser eventParser: syncWord: AA,seqn: 57,len: 5,opcode: 0000,params: [04 80 00], check_sum: 20
    2023-04-23 18:48:59,357 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-23 18:48:59,360 INFO: Parser eventParser: event_id: [04 80]
    2023-04-23 18:48:59,367 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Music open.

    Input music open, then the played music can be heard from SPK.

  4. ACI Host CLI test: Music close.

    Input music close, then the played music will be stopped.

A2DP Source Playback

Command

Parameters

ACI Host CLI CMD

Description

CMD_XM_MMI = 0x8004

action = XM_MMI_MODE_A2DP_SOURCE(2)

xmmi source

Switch to A2DP Source mode for music play.

  1. ACI Host CLI test: Connect ACI Device to BUD.

    Please refer to Connect to BUD.

  2. ACI Host CLI test: Enter A2DP Source playback mode.

    Input xmmi source.

    2023-04-23 18:50:20,276 INFO: input command: xmmi source
    2023-04-23 18:50:20,278 INFO: Parser cmdParser: cmd opcode: 8004 param: [02] name: CMD_XM_MMI
    2023-04-23 18:50:20,280 INFO: Packet sendPacket: <<<send packet: AA 02 03 00 04 80 02 75
    2023-04-23 18:50:20,281 INFO: AciHostCLI continuously_read: >>>receive packet: AA 58 05 00 00 00 04 80 00 1F
    2023-04-23 18:50:20,301 INFO: Parser eventParser: syncWord: AA,seqn: 58,len: 5,opcode: 0000,params: [04 80 00], check_sum: 1F
    2023-04-23 18:50:20,316 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-04-23 18:50:20,323 INFO: Parser eventParser: event_id: [04 80]
    2023-04-23 18:50:20,326 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: Music open.

    Input music open, then the played music can be heard from BUD.

  4. ACI Host CLI test: Music close.

    Input music close, then the played music will be stopped.

Bluetooth Audio Intergrated Transceiver

This chapter introduces the functionality of the bt_audio_intergrated_transceiver application scenario. This functionality is enabled by opening the macro definition F_APP_BT_AUDIO_TRANSCEIVER_DEMO_SUPPORT and F_APP_INTEGRATED_TRANSCEIVER in app_flags.h. This chapter describes how to use these functions and the flow of how to test them, including the MSCs of the ACI Device and ACI Host interaction, and the commands used by ACI Host.

A2DP Intergrated Transceiver Transmission (A2DP Output)

Two typical transmit scenarios are introduced in chapter Bluetooth Audio Intergrated Transceiver. Based on the A2DP transmission, A2DP data can be transferred from the Phone, through ACI Device to the Headset.

A2DP intergrated transceiver transmission process:

Before using the function, please config the BR/EDR link numbers in ‘System Configuration’ by MCUConfig Tool.

AciHostCLI Test

The ACI Host sends CMD_SRC_PLAY_SET_SRC_ROUTE to ACI Device to set the A2DP input route, sends CMD_SRC_PLAY_SET_PLAY_ROUTE to set A2DP output route, sends CMD_SRC_PLAY_ROUTE_IN_START/STOP to start or stop the A2DP input route, and sends CMD_SRC_PLAY_ROUTE_OUT_START/STOP to start or stop the A2DP output route.

Command

Parameters

ACI Host CLI CMD

CMD_SRC_PLAY_SET_SRC_ROUTE(0x3300)

action = a2dp(0x07, 0x00)

set_route_in a2dp

CMD_SRC_PLAY_SET_PLAY_ROUTE(0x3302)

action = a2dp(0x01)

set_route_out a2dp

CMD_SRC_PLAY_ROUTE_IN_START(0x3304)

None

route_in start

CMD_SRC_PLAY_ROUTE_IN_STOP(0x3305)

None

route_in stop

CMD_SRC_PLAY_ROUTE_OUT_START(0x3306)

None

route_out start

CMD_SRC_PLAY_ROUTE_OUT_STOP(0x3307)

None

route_out stop

  1. ACI Host CLI test: Connect ACI Device to Phone.

    Please refer to Connect to Phone.

  2. ACI Host CLI test: Connect ACI Device to BUD.

    Please refer to Connect to BUD.

  3. ACI Host CLI test: Input set_route_in a2dp.

    2024-10-30 14:43:09,715 INFO:  input command: set_route_in a2dp 
    2024-10-30 14:43:09,716 INFO: Parser cmdParser: cmd opcode: 3300 param: [07 00] name: CMD_SRC_PLAY_SET_SRC_ROUTE
    2024-10-30 14:43:09,716 INFO: Packet sendPacket: <<<send packet: AA 54 04 00 00 33 07 00 6E
    2024-10-30 14:43:09,788 WARNING: AciHostCLI retrans: retransmit command set_route_in a2dp due to ack timeout! retry: 1
    2024-10-30 14:43:09,789 INFO: Packet sendPacket: <<<send packet: AA 54 04 00 00 33 07 00 6E
    2024-10-30 14:43:09,803 INFO: AciHostCLI continuously_read: >>>receive packet: AA 4A 05 00 00 00 00 33 00 7E
    2024-10-30 14:43:09,804 INFO: Parser eventParser: syncWord: AA,seqn: 4A,len: 5,opcode: 0000,params: [00 33 00], check_sum: 7E
    2024-10-30 14:43:09,804 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-30 14:43:09,805 INFO: Parser eventParser: event_id: [00 33]
    2024-10-30 14:43:09,805 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Input set_route_out a2dp.

    2024-10-30 14:43:14,178 INFO:  input command: set_route_out a2dp 
    2024-10-30 14:43:14,179 INFO: Parser cmdParser: cmd opcode: 3302 param: [01] name: CMD_SRC_PLAY_SET_PLAY_ROUTE
    2024-10-30 14:43:14,179 INFO: Packet sendPacket: <<<send packet: AA 55 03 00 02 33 01 72
    2024-10-30 14:43:14,250 WARNING: AciHostCLI retrans: retransmit command set_route_out a2dp due to ack timeout! retry: 1
    2024-10-30 14:43:14,251 INFO: Packet sendPacket: <<<send packet: AA 55 03 00 02 33 01 72
    2024-10-30 14:43:14,260 INFO: AciHostCLI continuously_read: >>>receive packet: AA 4B 05 00 00 00 02 33 00 7B
    2024-10-30 14:43:14,261 INFO: Parser eventParser: syncWord: AA,seqn: 4B,len: 5,opcode: 0000,params: [02 33 00], check_sum: 7B
    2024-10-30 14:43:14,261 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-30 14:43:14,261 INFO: Parser eventParser: event_id: [02 33]
    2024-10-30 14:43:14,261 INFO: Parser eventParser: status: [00]
    
  5. Play music on Phone, then ACI Host will receive APP_EVENT_AVRCP_PLAYER_STATUS and EVENT_TRACK_CHANGED.

    2024-10-30 14:43:33,319 INFO: AciHostCLI continuously_read: >>>receive packet: AA 4C 0A 00 0B 00 41 AF 7B 6C 32 20 01 00 75
    2024-10-30 14:43:33,320 INFO: Parser eventParser: syncWord: AA,seqn: 4C,len: 10,opcode: 000B,params: [41 AF 7B 6C 32 20 01 00], check_sum: 75
    2024-10-30 14:43:33,320 INFO: Parser eventParser: event name: APP_EVENT_AVRCP_PLAYER_STATUS
    2024-10-30 14:43:33,320 INFO: Parser eventParser: bd_addr: [41 AF 7B 6C 32 20]
    2024-10-30 14:43:33,322 INFO: Parser eventParser: play_status: [01]
    2024-10-30 14:43:33,322 INFO: Parser eventParser: play_mode: [00]
    2024-10-30 14:43:33,323 INFO: Packet sendPacket: <<<send packet: AA 56 05 00 00 00 0B 00 00 9A
    2024-10-30 14:43:33,335 INFO: AciHostCLI continuously_read: >>>receive packet: AA 4D 10 00 21 00 41 AF 7B 6C 32 20 00 00 00 00 00 00 00 00 59
    2024-10-30 14:43:33,336 INFO: Parser eventParser: syncWord: AA,seqn: 4D,len: 16,opcode: 0021,params: [41 AF 7B 6C 32 20 00 00 00 00 00 00 00 00], check_sum: 59
    2024-10-30 14:43:33,336 INFO: Parser eventParser: event name: EVENT_TRACK_CHANGED
    2024-10-30 14:43:33,337 INFO: Packet sendPacket: <<<send packet: AA 57 05 00 00 00 21 00 00 83
    
  6. ACI Host CLI test: Input route_out start.

    2024-10-30 14:43:38,276 INFO:  input command: route_out start 
    2024-10-30 14:43:38,276 INFO: Parser cmdParser: cmd opcode: 3306 param: [] name: CMD_SRC_PLAY_ROUTE_OUT_START
    2024-10-30 14:43:38,277 INFO: Packet sendPacket: <<<send packet: AA 58 02 00 06 33 6D
    2024-10-30 14:43:38,287 INFO: AciHostCLI continuously_read: >>>receive packet: AA 4E 05 00 00 00 06 33 00 74
    2024-10-30 14:43:38,288 INFO: Parser eventParser: syncWord: AA,seqn: 4E,len: 5,opcode: 0000,params: [06 33 00], check_sum: 74
    2024-10-30 14:43:38,288 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-30 14:43:38,288 INFO: Parser eventParser: event_id: [06 33]
    2024-10-30 14:43:38,288 INFO: Parser eventParser: status: [00]
    
  7. ACI Host CLI test: Input route_in start.

    2024-10-30 14:43:40,239 INFO:  input command: route_in start 
    2024-10-30 14:43:40,240 INFO: Parser cmdParser: cmd opcode: 3304 param: [] name: CMD_SRC_PLAY_ROUTE_IN_START
    2024-10-30 14:43:40,240 INFO: Packet sendPacket: <<<send packet: AA 59 02 00 04 33 6E
    2024-10-30 14:43:40,252 INFO: AciHostCLI continuously_read: >>>receive packet: AA 4F 05 00 00 00 04 33 00 75
    2024-10-30 14:43:40,253 INFO: Parser eventParser: syncWord: AA,seqn: 4F,len: 5,opcode: 0000,params: [04 33 00], check_sum: 75
    2024-10-30 14:43:40,253 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-30 14:43:40,253 INFO: Parser eventParser: event_id: [04 33]
    2024-10-30 14:43:40,254 INFO: Parser eventParser: status: [00]
    

HFP Intergrated Transceiver Transmission

Based on the HFP transmission, SCO data can be transferred from the Phone, through ACI Device to the Headset. HFP intergrated transceiver transmission process:

AciHostCLI Test

ACI Host sends CMD_HFP_AG_CONNECT_SCO to ACI Device to connect the SCO link between ACI Device and Headset to send data. ACI Host sends CMD_HFP_AG_DISCONNECT_SCO to ACI Device to disconnect the SCO link between ACI Device and the Headset. ACI Host CLI commands are hfpag conn and hfpag disconn. Before using the function, inquiry and page scan should be set as disable. Since there are two SCO links in this scenario, CMD_SRC_PLAY_SET_MULTI_ESCO is used to support the coexistence of two links.

Command

Parameters

ACI Host CLI CMD

CMD_HFP_AG_CONNECT_SCO(0x0480)

action = SCO_CONNECT(0x01)

hfpag conn_1

CMD_HFP_AG_DISCONNECT_SCO(0x0481)

action = SCO_DISCONNECT(0x01)

hfpag disconn_1

CMD_SRC_PLAY_SET_MULTI_ESCO(0x3310)

action = Active(0x01, 0x02)

set_multi_esco active

CMD_XM_SET_MODE = 0x0030

device_mode = BT_DEVICE_MODE_IDLE(0)

mode idle

  1. ACI Host CLI test: Connect ACI Device to Phone.

    Please refer to Connect to Phone.

  2. ACI Host CLI test: Connect ACI Device to BUD.

    Please refer to Connect to BUD.

  3. ACI Host CLI test: Disable inquiry scan and page scan.

    2024-10-31 11:18:32,485 INFO:  input command: mode idle 
    2024-10-31 11:18:32,486 INFO: Parser cmdParser: cmd opcode: 0030 param: [00] name: CMD_XM_SET_MODE
    2024-10-31 11:18:32,486 INFO: Packet sendPacket: <<<send packet: AA 1D 03 00 30 00 00 B0
    2024-10-31 11:18:32,495 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1C 05 00 00 00 30 00 00 AF
    2024-10-31 11:18:32,496 INFO: Parser eventParser: syncWord: AA,seqn: 1C,len: 5,opcode: 0000,params: [30 00 00], check_sum: AF
    2024-10-31 11:18:32,497 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-31 11:18:32,497 INFO: Parser eventParser: event_id: [30 00]
    2024-10-31 11:18:32,497 INFO: Parser eventParser: status: [00]
    
  4. ACI Host CLI test: Set multilink SCO active.

    2024-10-31 11:18:42,533 INFO:  input command: set_multi_esco active 
    2024-10-31 11:18:42,534 INFO: Parser cmdParser: cmd opcode: 3310 param: [01 02] name: CMD_SRC_PLAY_SET_MULTI_ESCO
    2024-10-31 11:18:42,534 INFO: Packet sendPacket: <<<send packet: AA 1E 04 00 10 33 01 02 98
    2024-10-31 11:18:42,623 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1D 05 00 00 00 10 33 00 9B
    2024-10-31 11:18:42,624 INFO: Parser eventParser: syncWord: AA,seqn: 1D,len: 5,opcode: 0000,params: [10 33 00], check_sum: 9B
    2024-10-31 11:18:42,624 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-31 11:18:42,624 INFO: Parser eventParser: event_id: [10 33]
    2024-10-31 11:18:42,625 INFO: Parser eventParser: status: [00]
    
  5. Call the Phone connected to ACI Device.

    2024-10-31 11:18:52,144 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1E 04 00 0A 00 00 02 D2
    2024-10-31 11:18:52,144 INFO: Parser eventParser: syncWord: AA,seqn: 1E,len: 4,opcode: 000A,params: [00 02], check_sum: D2
    2024-10-31 11:18:52,147 INFO: Parser eventParser: event name: APP_EVENT_HFP_CALL_STATUS
    2024-10-31 11:18:52,148 INFO: Parser eventParser: link_id: [00]
    2024-10-31 11:18:52,148 INFO: Parser eventParser: status: [02]
    2024-10-31 11:18:52,149 INFO: Packet sendPacket: <<<send packet: AA 1F 05 00 00 00 0A 00 00 D2
    2024-10-31 11:18:53,646 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 1D 00 07 04 00 01 01 04 00 00 81 31 35 39 36 32 31 37 33 35 38 30 00 00 00 00 00 00 00 00
    2024-10-31 11:18:53,646 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 29,opcode: 0407,params: [00 01 01 04 00 00 81 31 35 39 36 32 31 37 33 35 38 30 00 00 00 00 00 00 00 00 00], check_sum: F3
    2024-10-31 11:18:53,648 INFO: Parser eventParser: event name: EVENT_CURRENT_CALLS
    2024-10-31 11:18:53,649 INFO: Packet sendPacket: <<<send packet: AA 20 05 00 00 00 07 04 00 D0
    2024-10-31 11:18:53,805 INFO: AciHostCLI continuously_read: >>>receive packet: AA 20 04 00 00 04 00 02 D6
    2024-10-31 11:18:53,806 INFO: Parser eventParser: syncWord: AA,seqn: 20,len: 4,opcode: 0400,params: [00 02], check_sum: D6
    2024-10-31 11:18:53,806 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2024-10-31 11:18:53,807 INFO: Parser eventParser: link_id: [00]
    2024-10-31 11:18:53,808 INFO: Parser eventParser: state: [02]
    2024-10-31 11:18:53,809 INFO: Packet sendPacket: <<<send packet: AA 21 05 00 00 00 00 04 00 D6
    2024-10-31 11:18:53,821 INFO: AciHostCLI continuously_read: >>>receive packet: AA 21 04 00 00 04 00 01 D6
    2024-10-31 11:18:53,821 INFO: Parser eventParser: syncWord: AA,seqn: 21,len: 4,opcode: 0400,params: [00 01], check_sum: D6
    2024-10-31 11:18:53,822 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2024-10-31 11:18:53,822 INFO: Parser eventParser: link_id: [00]
    2024-10-31 11:18:53,822 INFO: Parser eventParser: state: [01]
    
  6. ACI Host CLI test: Connect the SCO link between ACI Device and Headset.

    2024-10-31 11:19:01,258 INFO:  input command: hfpag conn_1 
    2024-10-31 11:19:01,258 INFO: Parser cmdParser: cmd opcode: 0480 param: [01] name: CMD_HFP_AG_CONNECT_SCO
    2024-10-31 11:19:01,259 INFO: Packet sendPacket: <<<send packet: AA 2A 03 00 80 04 01 4E
    2024-10-31 11:19:01,266 INFO: AciHostCLI continuously_read: >>>receive packet: AA 27 05 00 00 00 80 04 00 50
    2024-10-31 11:19:01,272 INFO: Parser eventParser: syncWord: AA,seqn: 27,len: 5,opcode: 0000,params: [80 04 00], check_sum: 50
    2024-10-31 11:19:01,275 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-31 11:19:01,276 INFO: Parser eventParser: event_id: [80 04]
    2024-10-31 11:19:01,276 INFO: Parser eventParser: status: [00]
    2024-10-31 11:19:01,458 INFO: AciHostCLI continuously_read: >>>receive packet: AA 28 04 00 88 03 01 02 46
    2024-10-31 11:19:01,458 INFO: Parser eventParser: syncWord: AA,seqn: 28,len: 4,opcode: 0388,params: [01 02], check_sum: 46
    2024-10-31 11:19:01,459 INFO: Packet sendPacket: <<<send packet: AA 2B 05 00 00 00 88 03 00 45
    2024-10-31 11:19:01,474 INFO: AciHostCLI continuously_read: >>>receive packet: AA 29 04 00 00 04 01 01 CD
    2024-10-31 11:19:01,474 INFO: Parser eventParser: syncWord: AA,seqn: 29,len: 4,opcode: 0400,params: [01 01], check_sum: CD
    2024-10-31 11:19:01,476 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2024-10-31 11:19:01,476 INFO: Parser eventParser: link_id: [01]
    2024-10-31 11:19:01,477 INFO: Parser eventParser: state: [01]
    2024-10-31 11:19:01,477 INFO: Packet sendPacket: <<<send packet: AA 2C 05 00 00 00 00 04 00 CB
    
  7. Hang up Phone call.

    2024-10-31 11:19:09,365 INFO: AciHostCLI continuously_read: >>>receive packet: AA 2F 1D 00 07 04 00 01 01 00 00 00 81 31 35 39 36 32 31 37 33 35 38 30 00 00 00 00 00 00 00 00
    2024-10-31 11:19:09,366 INFO: Parser eventParser: syncWord: AA,seqn: 2F,len: 29,opcode: 0407,params: [00 01 01 00 00 00 81 31 35 39 36 32 31 37 33 35 38 30 00 00 00 00 00 00 00 00 00], check_sum: E7
    2024-10-31 11:19:09,368 INFO: Parser eventParser: event name: EVENT_CURRENT_CALLS
    2024-10-31 11:19:09,371 INFO: Packet sendPacket: <<<send packet: AA 32 05 00 00 00 07 04 00 BE
    2024-10-31 11:19:10,435 INFO: AciHostCLI continuously_read: >>>receive packet: AA 30 04 00 00 04 00 00 C8
    2024-10-31 11:19:10,436 INFO: Parser eventParser: syncWord: AA,seqn: 30,len: 4,opcode: 0400,params: [00 00], check_sum: C8
    2024-10-31 11:19:10,436 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2024-10-31 11:19:10,437 INFO: Parser eventParser: link_id: [00]
    2024-10-31 11:19:10,438 INFO: Parser eventParser: state: [00]
    2024-10-31 11:19:10,438 INFO: Packet sendPacket: <<<send packet: AA 33 05 00 00 00 00 04 00 C4
    2024-10-31 11:19:10,564 INFO: AciHostCLI continuously_read: >>>receive packet: AA 31 04 00 0A 00 00 00 C1
    2024-10-31 11:19:10,564 INFO: Parser eventParser: syncWord: AA,seqn: 31,len: 4,opcode: 000A,params: [00 00], check_sum: C1
    2024-10-31 11:19:10,572 INFO: Parser eventParser: event name: APP_EVENT_HFP_CALL_STATUS
    2024-10-31 11:19:10,572 INFO: Parser eventParser: link_id: [00]
    2024-10-31 11:19:10,573 INFO: Parser eventParser: status: [00]
    2024-10-31 11:19:10,574 INFO: Packet sendPacket: <<<send packet: AA 34 05 00 00 00 0A 00 00 BD
    
  8. ACI Host CLI test: Disconnect the SCO link between ACI Device and Headset.

    2024-10-31 11:19:16,368 INFO:  input command: hfpag disconn_1 
    2024-10-31 11:19:16,368 INFO: Parser cmdParser: cmd opcode: 0481 param: [01] name: CMD_HFP_AG_DISCONNECT_SCO
    2024-10-31 11:19:16,369 INFO: Packet sendPacket: <<<send packet: AA 35 03 00 81 04 01 42
    2024-10-31 11:19:16,403 INFO: AciHostCLI continuously_read: >>>receive packet: AA 32 05 00 00 00 81 04 00 44
    2024-10-31 11:19:16,406 INFO: Parser eventParser: syncWord: AA,seqn: 32,len: 5,opcode: 0000,params: [81 04 00], check_sum: 44
    2024-10-31 11:19:16,409 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2024-10-31 11:19:16,409 INFO: Parser eventParser: event_id: [81 04]
    2024-10-31 11:19:16,410 INFO: Parser eventParser: status: [00]
    2024-10-31 11:19:16,442 INFO: AciHostCLI continuously_read: >>>receive packet: AA 33 04 00 00 04 01 00 C4
    2024-10-31 11:19:16,443 INFO: Parser eventParser: syncWord: AA,seqn: 33,len: 4,opcode: 0400,params: [01 00], check_sum: C4
    2024-10-31 11:19:16,443 INFO: Parser eventParser: event name: APP_EVENT_SCO_STATE
    2024-10-31 11:19:16,444 INFO: Parser eventParser: link_id: [01]
    2024-10-31 11:19:16,444 INFO: Parser eventParser: state: [00]
    2024-10-31 11:19:16,445 INFO: Packet sendPacket: <<<send packet: AA 36 05 00 00 00 00 04 00 C1
    

UART DFU

Introduction

DFU (Device Firmware Upgrade) function allows for seamless firmware updates. Bluetooth Audio Transceiver has incorporated a comprehensive DFU system based on UART. This system enables users to upgrade devices effortlessly through the utilization of the ACI Host CLI Tool. By placing the designated upgrade package into a specified folder and configuring the file name and version number, users can execute the device update with a single command.

Prepare the Upgrade Package

In order to perform a DFU process, it is necessary to prepare an upgrade package. The creation of the upgrade package can be accomplished using the MPPG tool. This involves two main steps:

  1. Generating the OTA header image. During this process, please ensure the appropriate version number is filled in (this version number will later need to be entered in the config.yml file in ACI Host CLI Tool). For detailed instructions, refer to Prepare the Image to Update.

  2. Packing the generated OTA header image with other images to be upgraded. For detailed instructions, refer to Pack Whole Image.

Once the upgrade package is prepared, place it in the sdk\tool\AciHostCLI-v1.x.x.xx-Common_SDK\dfu folder. Then, open the config.yml file and fill in the upgrade package’s file name and version number.

Upon completing the aforementioned steps, simply enter the command dfu start in the ACI Host to initiate the upgrade process for your device.

ACI Host CLI Test

The ACI Host sends CMD_UART_DFU with various opcodes to execute specific functions. This includes using the UART_DFU_START_REQ opcode to initiate the DFU, the UART_DFU_DATA_IND opcode to transmit data packets, the UART_DFU_REBOOT opcode to reboot the device, and the UART_DFU_ABORT opcode to terminate the DFU. The device side sends the EVENT_DFU_START_RSP event to confirm the initiation of the DFU, the EVENT_DFU_DATA_REQ event to request data packets, and the EVENT_DFU_RESULT event to notify the ACI Host of the upgrade result.

Command

Parameters

ACI Host CLI CMD

CMD_UART_DFU(0x3270)

opcode = UART_DFU_START_REQ(0x0000)

dfu start

CMD_UART_DFU(0x3270)

opcode = UART_DFU_DATA_IND(0x0001)

None

CMD_UART_DFU(0x3270)

opcode = UART_DFU_ABORT(0x0002)

dfu abort

CMD_UART_DFU(0x3270)

opcode = UART_DFU_REBOOT(0x0003)

None

  1. ACI Host CLI test: Start DFU.

    2023-10-27 17:51:21,440 INFO: input command: dfu start
    2023-10-27 17:51:21,573 INFO: DFU open: file_size 2434320
    2023-10-27 17:51:21,574 INFO: Parser cmdParser: cmd opcode: 3270 param: [00 00 02 00 00 00] name: CMD_UART_DFU
    2023-10-27 17:51:21,575 INFO: Packet sendPacket: <<<send packet: AA 06 08 00 70 32 00 00 02 00 00 00 4E
    2023-10-27 17:51:21,647 WARNING: AciHostCLI retrans: retransmit command dfu start due to ack timeout! retry: 1
    2023-10-27 17:51:21,648 INFO: Packet sendPacket: <<<send packet: AA 06 08 00 70 32 00 00 02 00 00 00 4E
    2023-10-27 17:51:21,660 INFO: AciHostCLI continuously_read: >>>receive packet: AA 04 05 00 00 00 70 32 00 55
    2023-10-27 17:51:21,661 INFO: Parser eventParser: syncWord: AA,seqn: 04,len: 5,opcode: 0000,params: [70 32 00], check_sum: 55
    2023-10-27 17:51:21,661 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-10-27 17:51:21,662 INFO: Parser eventParser: event_id: [70 32]
    2023-10-27 17:51:21,663 INFO: Parser eventParser: status: [00]
    2023-10-27 17:51:21,663 INFO: AciHostCLI continuously_read: >>>receive packet: AA 05 03 00 60 31 01 66
    2023-10-27 17:51:21,664 INFO: Parser eventParser: syncWord: AA,seqn: 05,len: 3,opcode: 3160,params: [01], check_sum: 66
    2023-10-27 17:51:21,665 INFO: Parser eventParser: event name: EVENT_DFU_START_RSP
    2023-10-27 17:51:21,665 INFO: Parser eventParser: status: [01]
    2023-10-27 17:51:21,666 INFO: DFU handle_duf_rsp: self.state dfuState.STARTED
    2023-10-27 17:51:21,667 INFO: Packet sendPacket: <<<send packet: AA 07 05 00 00 00 60 31 00 63
    
  2. ACI Host CLI test: Transmit data.

    2023-10-27 17:51:21,676 INFO: AciHostCLI continuously_read: >>>receive packet: AA 06 08 00 61 31 00 00 00 00 48 00 18
    2023-10-27 17:51:21,677 INFO: Parser eventParser: syncWord: AA,seqn: 06,len: 8,opcode: 3161,params: [00 00 00 00 48 00], check_sum: 18
    2023-10-27 17:51:21,677 INFO: Parser eventParser: event name: EVENT_DFU_DATA_REQ
    2023-10-27 17:51:21,678 INFO: Parser eventParser: offset: [00 00 00 00]
    2023-10-27 17:51:21,679 INFO: Parser eventParser: length: [48 00]
    2023-10-27 17:51:21,679 INFO: DFU handle_duf_rsp: next offset 0, length 72
    2023-10-27 17:51:21,680 INFO: Packet sendPacket: <<<send packet: AA 08 05 00 00 00 61 31 00 61
    2023-10-27 17:51:21,680 INFO: Parser cmdParser: cmd opcode: 3270 param: [01 00 47 4D 54 F3 24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 0B EC 03 06 01 00 00 00 00 00 00 00 00 00 00 00 00 EC 03 06 00 00 00 00 00 00 00 00 00 00 00 00 00] name: CMD_UART_DFU
    2023-10-27 17:51:21,681 INFO: Packet sendPacket: <<<send packet: AA 09 4C 00 70 32 01 00 47 4D 54 F3 24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    2023-10-27 17:51:21,692 INFO: AciHostCLI continuously_read: >>>receive packet: AA 07 05 00 00 00 70 32 00 52
    2023-10-27 17:51:21,693 INFO: Parser eventParser: syncWord: AA,seqn: 07,len: 5,opcode: 0000,params: [70 32 00], check_sum: 52
    2023-10-27 17:51:21,693 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-10-27 17:51:21,694 INFO: Parser eventParser: event_id: [70 32]
    2023-10-27 17:51:21,694 INFO: Parser eventParser: status: [00]
    ....
    2023-10-27 17:53:08,591 INFO: AciHostCLI continuously_read: >>>receive packet: AA 84 08 00 61 31 F0 F2 24 00 64 00 78
    2023-10-27 17:53:08,592 INFO: Parser eventParser: syncWord: AA,seqn: 84,len: 8,opcode: 3161,params: [F0 F2 24 00 64 00], check_sum: 78
    2023-10-27 17:53:08,592 INFO: Parser eventParser: event name: EVENT_DFU_DATA_REQ
    2023-10-27 17:53:08,593 INFO: Parser eventParser: offset: [F0 F2 24 00]
    2023-10-27 17:53:08,593 INFO: Parser eventParser: length: [64 00]
    2023-10-27 17:53:08,593 INFO: DFU handle_duf_rsp: next offset 2421488, length 100
    2023-10-27 17:53:08,594 INFO: Packet sendPacket: <<<send packet: AA 5E 05 00 00 00 61 31 00 0B
    2023-10-27 17:53:08,594 INFO: Parser cmdParser: cmd opcode: 3270 param: [01 00 4F 52 28 00 B0 21 28 00 38 3F 28 00 6C 3E 28 00 A8 28 28 00 24 89 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 06 01 02 06 01 A0 00 FF FF FF FF 1F 00 92 02 94 02 96 02 09 11 19 21 29 31 39 41 49 51 59 61 69 71 79 7F F4 01] name: CMD_UART_DFU
    2023-10-27 17:53:08,595 INFO: Packet sendPacket: <<<send packet: AA 5F 68 00 70 32 01 00 4F 52 28 00 B0 21 28 00 38 3F 28 00 6C 3E 28 00 A8 28 28 00 24 89 28 00
    2023-10-27 17:53:08,603 INFO: AciHostCLI continuously_read: >>>receive packet: AA 85 05 00 00 00 70 32 00 D4
    2023-10-27 17:53:08,604 INFO: Parser eventParser: syncWord: AA,seqn: 85,len: 5,opcode: 0000,params: [70 32 00], check_sum: D4
    2023-10-27 17:53:08,605 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-10-27 17:53:08,606 INFO: Parser eventParser: event_id: [70 32]
    2023-10-27 17:53:08,606 INFO: Parser eventParser: status: [00]
    
  3. ACI Host CLI test: DFU successfully.

    2023-10-27 17:53:09,099 INFO: Parser eventParser: syncWord: AA,seqn: 86,len: 3,opcode: 3162,params: [01], check_sum: E3
    2023-10-27 17:53:09,100 INFO: Parser eventParser: event name: EVENT_DFU_RESULT
    2023-10-27 17:53:09,101 INFO: Parser eventParser: result: [01]
    2023-10-27 17:53:09,101 WARNING: DFU handle_dfu_result: result True, note True!!!
    2023-10-27 17:53:09,102 INFO: Packet sendPacket: <<<send packet: AA 60 05 00 00 00 62 31 00 08
    2023-10-27 17:53:09,103 INFO: DFU finish_dfu!!!
    2023-10-27 17:53:09,103 INFO: Parser cmdParser: cmd opcode: 3270 param: [03 00] name: CMD_UART_DFU
    2023-10-27 17:53:09,104 INFO: Packet sendPacket: <<<send packet: AA 61 04 00 70 32 03 00 F6
    2023-10-27 17:53:09,176 WARNING: AciHostCLI retrans: retransmit command dfu reboot due to ack timeout! retry: 1
    2023-10-27 17:53:09,177 INFO: Packet sendPacket: <<<send packet: AA 61 04 00 70 32 03 00 F6
    2023-10-27 17:53:09,179 INFO: AciHostCLI continuously_read: >>>receive packet: AA 87 05 00 00 00 70 32 00 D2
    2023-10-27 17:53:09,179 INFO: Parser eventParser: syncWord: AA,seqn: 87,len: 5,opcode: 0000,params: [70 32 00], check_sum: D2
    2023-10-27 17:53:09,180 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-10-27 17:53:09,180 INFO: Parser eventParser: event_id: [70 32]
    2023-10-27 17:53:09,181 INFO: Parser eventParser: status: [00]
    2023-10-27 17:53:09,834 INFO: AciHostCLI continuously_read: >>>receive packet: AA 01 08 00 23 00 15 03 77 56 22 03 CA
    2023-10-27 17:53:09,835 INFO: Parser eventParser: syncWord: AA,seqn: 01,len: 8,opcode: 0023,params: [15 03 77 56 22 03], check_sum: CA
    2023-10-27 17:53:09,835 INFO: Parser eventParser: event name: EVENT_BT_READY
    2023-10-27 17:53:09,836 INFO: Parser eventParser: factory_addr: [15 03 77 56 22 03]
    2023-10-27 17:53:09,837 INFO: Packet sendPacket: <<<send packet: AA 62 05 00 00 00 23 00 00 76
    2023-10-27 17:53:09,849 INFO: AciHostCLI continuously_read: >>>receive packet: AA 02 03 00 07 00 01 F3
    2023-10-27 17:53:09,850 INFO: Parser eventParser: syncWord: AA,seqn: 02,len: 3,opcode: 0007,params: [01], check_sum: F3
    2023-10-27 17:53:09,851 INFO: Parser eventParser: event name: EVENT_DEVICE_STATE
    2023-10-27 17:53:09,851 INFO: Parser eventParser: device_state: [01]
    2023-10-27 17:53:09,852 INFO: Packet sendPacket: <<<send packet: AA 63 05 00 00 00 07 00 00 91
    

The following charts focus on the design SPEC of Bluetooth Audio Transceiver. It is written to help users easily and completely understand the code flow of the application. The following topics are included:

  • Software Architecture.

  • Firmware Initialization and Configuration (includes Flash and FTL).

  • Memory (includes Global and Heap).

  • Flash.

  • IO.

  • OTA.

  • DLPS.

  • Code Flow (including main functions of typical scenarios, such as transmitter, receiver, transceiver, and transmitter_mp3).

Before studying the content of this article, it is highly recommended to first study the following documents:

Software Architecture

Please refer to SDK User Guide for more details.

Firmware Initialization and Configuration

Initialization and Main Application Loop

This procedure develops an application for Bluetooth/Bluetooth Low Energy audio on the RTL87x3E Series platforms. The main procedure is to be carried out in the following steps:

  1. Call the ram_config() API to configure DSP to share 80KB RAM with MCU.

  2. Call the log_module_trace_set() API to disable some trace logs during system initialization.

  3. Call the APP_PRINT_INFO2() API to print the wake-up reason, compile time, and restart reason.

  4. Call the os_msg_queue_create() API to create a message and event queue for task communication.

  5. Call the app_init_timer() API to initialize APP timer.

  6. Call the pm_cpu_freq_init() API to initialize CPU freq module.

  7. Call the app_cfg_init() API to initialize the configuration.

  8. Call the board_init() API to initialize PINMUX and pad settings.

  9. Call the app_bt_gap_init() API to initialize GAP parameters of Bluetooth and Bluetooth Low Energy.

  10. Call the framework_init() API to initialize the System Manager, Remote Manager, Bluetooth Manager and Audio Manager. This is done using the following steps:

    • Call the sys_mgr_init() API to initialize system.

    • Call the remote_mgr_init() API to initialize remote.

    • Call the bt_mgr_init() API to initialize Bluetooth.

    • Call the audio_mgr_init() API to initialize audio.

  11. Call the app_ota_init() API to initialize OTA.

  12. Call the driver_init() API to initialize the drivers. This is done using the following steps:

    • Call the app_adp_init() API to init adaptor.

    • Call the app_iap_cp_hw_init() API to init I2C for CP chip.

    • Call the app_console_init() API to initialize console.

    • Call the app_charger_init() API to initialize charger.

    • Call the app_line_in_driver_init() API to initialize line-in.

    • Call the app_amp_init() API to init AMP.

    • Call the app_qdec_driver_init() API to initialize QDEC.

    • Call the app_dlps_system_wakeup_clear_rtc_int() API to init RTC.

    • Call the ext_flash_init() API to init external flash.

  13. Call the app_auto_power_off_init() API to initialize the auto power off module.

  14. Call the app_audio_init() API to initialize audio, such as initializing EQ, setting VP language, setting volume, etc.

  15. Call the app_mmi_init() API to initialize MMI.

  16. Call the app_test_init() API to initialize test.

  17. Call the app_gap_init() API to initialize GAP.

  18. Call the app_ble_gap_init() API to initialize Bluetooth Low Energy GAP.

  19. Call the app_bt_policy_init() API to initialize Bluetooth policy.

  20. Call the app_ble_client_init() API to initialize LE client.

  21. Call the gatt_svc_init() API to initialize GATT service.

  22. Call the profile init APIs to initialize Bluetooth profiles. This is done using the following steps:

    • Call the app_hfp_init() API to initialize HFP.

    • Call the app_avrcp_init() API to initialize AVRCP.

    • Call the app_a2dp_init() API to initialize A2DP.

    • Call the app_sdp_init() API to initialize SDP.

    • Call the app_spp_init() API to initialize SPP.

    • Call the app_pbap_init() API to initialize PBAP.

    • Call the app_hid_init() API to initialize HID.

    • Call the app_iap_init() API to initialize iAP.

  23. Call the app_ble_service_init() APIs to initialize Bluetooth Low Energy Services. This is done using the following steps:

    • Call the transmit_srv_add() API to initialize transmit service.

    • Call the ota_add_service() API to initialize OTA service.

    • Call the bas_add_service() API to initialize battery service.

  24. Call the app_lea_acc_profile_init() API to initialize LE Audio service and profiles.

  25. Call the os_task_create() API to create a new task and add it to the list of tasks that are ready to run.

  26. Call the os_sched_start() API to start the RTOS kernel scheduler.

Configuration

Some parameters are configured through the MCUConfig Tool, and once configured, they are saved in the APP Config Image, the location and size of which is specified by the flash map file. Some parameters need to be saved to be used the next time the system boots up, and these configurations are saved in the FTL.

Configuration in Flash

The flash map file is located in sdk\bin\rtl87x3e\flash_map_config\4M\flash_4M\flash_map.h.

The corresponding configurations are as follows:

#define BANK0_APP_CFG_ADDR        0x021F0000
#define BANK0_APP_CFG_SIZE        0x00002000  *//8K Bytes*

The APP Config Image, which is 8 KBytes (defined as BANK0_APP_CFG_SIZE), contains the following sections that are pre-allocated fields and cannot be modified:

#define APP_CONFIG_OFFSET                   0
#define APP_CONFIG_SIZE                     1024

#define APP_LED_OFFSET                      (APP_CONFIG_OFFSET + APP_CONFIG_SIZE)
#define APP_LED_SIZE                        512

#define SYS_CONFIG_OFFSET                   (APP_LED_OFFSET + APP_LED_SIZE)
#define SYS_CONFIG_SIZE                     512

#define APP_CONFIG2_OFFSET                  (SYS_CONFIG_OFFSET + SYS_CONFIG_SIZE)
#define APP_CONFIG2_SIZE                    512

#define TONE_DATA_OFFSET        4096 //Rsv 4K for APP parameter for better flash control
#define TONE_DATA_SIZE          3072

The variables corresponding to APP_CONFIG_OFFSET and APP_CONFIG_SIZE are defined as follows: Only device_name_legacy_default and device_name_le_default are generated through MCUConfig Tool configuration, while all other fields are configured and initialized through app_cfg_init().

typedef struct
{
    uint32_t sync_word;
    uint8_t device_name_legacy_default[DEVICE_NAME_MAX_LEN]; //this field offset is fixed, SHALL NOT modify
    uint8_t device_name_le_default[DEVICE_NAME_MAX_LEN];     //this field offset is fixed, SHALL NOT modify
    ...
    ...
 } T_APP_CFG_CONST;

Configuration in FTL

The areas used by FTL are defined as follows, and users can extend new areas according to their product needs.

//FTL start
#define APP_RW_DATA_ADDR        3072
#define APP_RW_DATA_SIZE        360

#define FACTORY_RESET_OFFSET    124

#define GCSS_ATT_TBL_INFO_ADDR              (APP_RW_DATA_ADDR + APP_RW_DATA_SIZE)
#define GCSS_ATT_TBL_INFO_SIZE              (30 * 16)

#define APP_FINDMY_INFO_ADDR                (GCSS_ATT_TBL_INFO_ADDR + GCSS_ATT_TBL_INFO_SIZE)
#define APP_FINDMY_INFO_SIZE                320
//FTL end

The variables corresponding to APP_RW_DATA_ADDR and APP_RW_DATA_SIZE are defined as follows:

typedef struct
{
    T_APP_CFG_NV_HDR hdr;
    //offset: 8
    uint8_t device_name_legacy[40];
    uint8_t device_name_le[40];

    uint8_t le_single_random_addr[6];
    ...
    ...
} T_APP_CFG_NV;

Memory

The available size of Global and Heap memory used by the application is configured in:
sdk\board\evb\bt_audio_trx\inc\rtl87x3e\mem_config.h. Users can adjust the parameters according to the product memory usage requirements.

MCU Memory

#define APP_RAM_TEXT_SIZE      (5*1024)
#define APP_GLOBAL_SIZE       (14*1024)

DSP Share Memory

#define DSP_SHM_TOTAL_SIZE     80 * 1024
#define DSP_SHM_GLOBAL_SIZE    10 * 1024
#define DSP_SHM_HEAP_ADDR      DSP_SHM_GLOBAL_ADDR + DSP_SHM_GLOBAL_SIZE
#define DSP_SHM_HEAP_SIZE      (DSP_SHM_TOTAL_SIZE - DSP_SHM_GLOBAL_SIZE)

How to Check the Memory Usage

The use of Global and TEXT RAM can be confirmed by the following file:
sdk\board\evb\bt_audio_trx\bin\rtl87x3e\flash_4M_dualbank\bank0\bt_audio_trx_bank0.map.

Execution Region RAM_TEXT (Exec base: 0x00208800, Load base: 0x0214351c, Size: 0x000014a0, Max: 0x00002800, ABSOLUTE)
Execution Region RAM_GLOBAL (Exec base: 0x002c0000, Load base: 0x02139868, Size: 0x000021b8, Max: 0x00003800, ABSOLUTE)
Execution Region SHARE_RAM_DATA (Exec base: 0x00300000, Load base: 0x0213a0ec, Size: 0x00000000, Max: 0x00002800, ABSOLUTE)

The use of Heap RAM can be confirmed by the following log:

APP_PRINT_WARN1("app_task unused memory: %d", mem_peek());

Flash

APP Image in Flash Map

The flash map file is located in sdk\bin\rtl87x3e\flash_map_config\4M\flash_4M\flash_map.h. The maximum size of the APP image is defined by BANK0_APP_SIZE.

#define BANK0_APP_ADDR          0x02099000
#define BANK0_APP_SIZE          0x000CD000  *//820K Bytes*

How to Check APP Image Size Used

The actual size of the APP image used can be confirmed by the following file:
sdk\board\evb\bt_audio_trx\bin\rtl87x3e\flash_4M_dualbank\bank0\bt_audio_trx_bank0.map.

Load Region LOAD_FLASH **//Base: 0x0086e000, Size: 0x0008eeb8, Max: 0x000c8000, ABSOLUTE*

IO

IO Resource

GPIO

In some scenarios that do not need to play voice prompts and tones, some analog pins can be released to be used as GPIO. Taking the LOUT_P pin as an example, the following three steps are mainly required:

  1. Remove the SPK setting.

    Use the MCUConfig Tool to remove the SPK setting of the audio on the Audio Route page. This ensures the pad of LOUT_P will not be configured.

  1. Mute voice prompts and tones.

    Open the macro of F_APP_DISABLE_NOTIFICATION_SUPPORT in app_flags.h.

    #define F_APP_USER_EQ_SUPPORT               1
    //open
    #define F_APP_DISABLE_NOTIFICATION_SUPPORT  1
    #define F_APP_MONITOR_MEMORY_AND_TIMER      0
    
  2. Set AVCC driver.

    Set AVCC_DRV to Always active on the System Configuration page.

DMA

DMA Resources

Currently, there are a total of 9 DMA channels available for use. Some channels are already utilized or reserved for DSP and log UART purposes. There are 3 channels currently unoccupied. In addition to this, the DSP reserved channel 8 is not used by DSP and is also available for APP use.

Channel

State

GDMA_Channel 0

Idle

GDMA_Channel 1

Idle

GDMA_Channel 2

DSP reserved

GDMA_Channel 3

DSP reserved

GDMA_Channel 4

DSP reserved

GDMA_Channel 5

DSP reserved

GDMA_Channel 6

Idle

GDMA_Channel 7

Log UART

GDMA_Channel 8

DSP reserved, can be used for APP.

DMA Current Usage
  1. UART With ACI Host.

    For MP3 Transmitter Application (F_APP_BT_AUDIO_TRANSMITTER_MP3_DEMO_SUPPORT), due to substantial audio data stream, the UART will dynamically request 2 channels.

    static void app_console_uart_init(void)
    {
        ...
        console_uart_config.uart_rx_dma_enable = false;
        console_uart_config.uart_tx_dma_enable = false;
    
    #if F_APP_BT_AUDIO_TRANSMITTER_MP3_DEMO_SUPPORT
        console_uart_config.uart_tx_dma_enable = true;
        console_uart_config.uart_rx_dma_enable = true;
    #endif
        ...
    }
    
  2. SPI.

    In the case of the Transceiver Application (F_APP_BT_AUDIO_TRANSCEIVER_DEMO_SUPPORT), SPI TX dynamically requests 1 channel, while SPI RX utilizes channel 8, which is reserved for DMA purposes.

    // SPI TX
    void app_spi_master_init(void)
    {
        ...
        if (!GDMA_channel_request(&spi_tx_dma_ch_num, app_spi_master_tx_dma_handler, true))
        {
            APP_PRINT_ERROR0("app_spi_master_init: tx channel request fail");
            return;
        }
        ...
    }
    
    // SPI RX
    static uint8_t spi_rx_dma_ch_num = 8;
    #define SPI_RX_DMA_CHANNEL_NUM     spi_rx_dma_ch_num
    static void app_spi_master_dma_rx_init(void *readbuf)
    {
        ...
        GDMA_InitStruct.GDMA_ChannelNum      = SPI_RX_DMA_CHANNEL_NUM;
        ...
        GDMA_INTConfig(SPI_RX_DMA_CHANNEL_NUM, GDMA_INT_Transfer, ENABLE);
    }
    

Key

The Key module supports two types of keys: MFB and GPIO keys. On the EVB, it can accommodate up to 1 MFB and 8 GPIO keys. Typically, MFB is utilized for power on and power off functionalities, while GPIO keys are mapped to MMI (Man-Machine Interface) features.

The configuration for key module functionalities is defined in app_key_cfg.c. Users have the flexibility to configure various aspects, including enabling or disabling key functionality, mapping keys to GPIO, and associating keys with MMI functions.

Refer to T_MMI_ACTION in app_mmi.h for a comprehensive list of all supported MMI interfaces. This enumeration provides details on the various MMI actions that can be utilized for configuring and mapping functionalities to different key scenarios.

typedef enum
{
    MMI_NULL = 0x00,
    MMI_HF_END_OUTGOING_CALL = 0x02,
    ...
    MMI_TOTAL
} T_MMI_ACTION;

MFB

To enable the MFB functionality, set app_key_cfg.mfb_replace_key0 to 1.

void app_key_cfg_init(void)
{
    ...
    app_key_cfg.mfb_replace_key0 = 1;
    ...
}

In the power off state, different durations of long-pressing the MFB key can achieve power on, enter pairing mode, and factory reset. Modify the following configurations for specific duration definitions (The unit is 100 ms):

void app_key_cfg_init(void)
{
    ...
    app_key_cfg.key_power_on_interval = 25;
    app_key_cfg.key_enter_pairing_interval = 60;
    app_key_cfg.key_factory_reset_interval = 90;
    ...
}

In the power on state, a long-pressing of the MFB key allows for shutting down. The duration to trigger the shutdown key can be configured through key_power_off_interval.

void app_key_cfg_init(void)
{
    ...
    app_key_cfg.key_power_off_interval = 30;
    ...
}

GPIO Key

Hardware Configurations

To utilize GPIO Keys, first, map the keys to the required GPIOs. This can be achieved by modifying key_pinmux[8], where these GPIOs can be configured for key 0 to key 7. Enable the keys through key_enable_mask. For instance, configure the GPIO for key 1 as P0_1, key 2 as P1_0, and enable both key 1 and key 2.

void app_key_cfg_init(void)
{
    ...
    uint8_t key_pinmux[8] = {0xFF, P0_1, P1_0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    memcpy(app_key_cfg.key_pinmux, key_pinmux, sizeof(key_pinmux));
    app_key_cfg.key_enable_mask = KEY1_MASK | KEY2_MASK;
    ...
}

It’s essential to note that keys are default low-active. Depending on the circuitry, if the key is high-active, include the corresponding key mask in key_high_active_mask.

void app_key_cfg_init(void)
{
    ...
    app_key_cfg.key_high_active_mask = KEY2_MASK | KEY4_MASK | KEY6_MASK;
    ...
}
Operation Modes of Keys

GPIO keys support various operation modes, categorized based on key scenario into short click, long press, and multiple clicks. They are further distinguished by the number of keys as single key and combine key. Specifically, there are six operation modes:

  • Mode 1:single key + short click.

  • Mode 2:single key + long press.

  • Mode 3:single key + multiple clicks (2/3/4/5 clicks).

  • Mode 4:combine key + short click.

  • Mode 5:combine key + long press.

  • Mode 6:combine key + multiple clicks (2/3/4/5 clicks).

The trigger duration for long press is configured through key_long_press_interval, and the detection duration for multiple clicks is configured through key_multi_click_interval.

void app_key_cfg_init(void)
{
    ...
    app_key_cfg.key_long_press_interval = 20;
    app_key_cfg.key_multi_click_interval = 3;
    ...
}

For operation mode 2, long repeat functionality is supported. This means that when holding down the key for an extended period, the corresponding MMI function can be triggered multiple times. The interval for triggering is configured through key_long_press_repeat_interval. The corresponding keys are configured through key_long_press_repeat_mask.

void app_key_cfg_init(void)
{
    ...
    app_key_cfg.key_long_press_repeat_interval = 4;
    app_key_cfg.key_long_press_repeat_mask = KEY_NULL;
    ...
}

The mapping of different operation modes to MMI functions is maintained through tables. The modes 1 and 2 are part of the basic functionality maintained by the key table, while modes 2 to 6 are considered hybrid functionality and are maintained by the hybrid key table.

Key Table

As depicted in the figure, the key_table is a multidimensional array of size 2 x 9 x 8. key_table[0] corresponds to the short click table, and key_table[1] corresponds to the long press table. Different MMI functions can be assigned to keys under different call statuses.

There are a total of 9 call statuses, defined as follows:

enum key_table_call_status
{
    CALL_IDLE,
    VOICE_DIAL,
    INCOMING_CALL,
    OUT_GOING_CALL,
    CALL_ACTIVE,
    CALL_ACTIVE_WITH_CALL_WAITING,
    CALL_ACTIVE_WITH_CALL_HOLD,
    MULTI_CALL_ACTIVE_WITH_CALL_WAITING,
    MULTI_CALL_ACTIVE_WITH_CALL_HOLD,
};

For example, MMI_DEV_MIC_VOL_UP can be configured to be triggered by a short press of key 1 in the CALL_IDLE status and MMI_DEV_MIC_VOL_DOWN can be triggered by a long press of key 1 in the CALL_IDLE status.

void app_key_cfg_init(void)
{
    ...
    // sample of single key short click
    app_key_cfg.key_table[SHORT_CLICK][CALL_IDLE][KEY_1] = MMI_DEV_MIC_VOL_UP;

    // sample of single key long press
    app_key_cfg.key_table[LONG_PRESS][CALL_IDLE][KEY_1] = MMI_DEV_MIC_VOL_DOWN;
    ...
}
Hybrid Key Table

As illustrated in the figure below, the hybrid key table is a multidimensional array of size 9 x 8. Different MMI functions can be assigned to different hybrid types under various call statuses.

Hybrid types consist of a hybrid mask and hybrid scenario. The hybrid mask defines the key combination, and the hybrid scenario defines the operation mode. All hybrid types are defined through hybrid_key_mapping, supporting a maximum of 8 hybrid types.

For example, configure the following:

  • Trigger MMI_DEV_MIC_VOL_DOWN by operating HYBRID_TYPE_0 (double-clicking key 1) in the CALL_IDLE status.

  • Trigger MMI_START_ROLESWAP by operating HYBRID_TYPE_1 (triple-clicking key 1) in the CALL_IDLE status.

  • Trigger MMI_DEV_MIC_VOL_DOWN by simultaneously short pressing key 1 and key 2 (HYBRID_TYPE_2) while in the CALL_IDLE status.

    void app_key_cfg_init(void)
    {
        ...
        // sample of double click
        app_key_cfg.hybrid_key_table[CALL_IDLE][HYBRID_TYPE_0] = MMI_DEV_MIC_VOL_DOWN;
        app_key_cfg.hybrid_key_mapping[HYBRID_TYPE_0][HYBRID_MASK] = KEY1_MASK;
        app_key_cfg.hybrid_key_mapping[HYBRID_TYPE_0][HYBRID_SCENARIO] = HYBRID_KEY_2_CLICK;
    
        // sample of triple click
        app_key_cfg.hybrid_key_table[CALL_IDLE][HYBRID_TYPE_1] = MMI_START_ROLESWAP;
        app_key_cfg.hybrid_key_mapping[HYBRID_TYPE_1][HYBRID_MASK] = KEY1_MASK;
        app_key_cfg.hybrid_key_mapping[HYBRID_TYPE_1][HYBRID_SCENARIO] = HYBRID_KEY_3_CLICK;
    
        // sample of combine key single click
        app_key_cfg.hybrid_key_table[CALL_IDLE][HYBRID_TYPE_2] = MMI_DEV_MIC_VOL_DOWN;
        app_key_cfg.hybrid_key_mapping[HYBRID_TYPE_2][HYBRID_MASK] = KEY1_MASK | KEY2_MASK;
        app_key_cfg.hybrid_key_mapping[HYBRID_TYPE_2][HYBRID_SCENARIO] = HYBRID_KEY_SHORT_PRESS;
        ...
    }
    

OTA

Refer to OTA for details.

DLPS

Please refer to Low Power Mode for details.

Code Flow

This chapter describes the code flow of some of the main functions.

Basic Function

Power On/Off and Factory Reset

Functions such as power on, power off, and factory reset are realized by transmitting MMI commands through UART. These commands are centrally processed in app_cmd_general.c, and the used APIs are introduced as follows:

void app_cmd_general_cmd_handle(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path,
                                uint8_t app_idx, uint8_t *ack_pkt)
{
  uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));

  switch (cmd_id)
  {
  case CMD_MMI:
  ...
    app_mmi_handle_action(cmd_ptr[3]);
  ...
  }
  break;
}

APP handles key messages in function app_mmi_handle_action(). The user triggers the specific key process, then the device would perform the related action.

If the device performs power on, it will call sys_mgr_power_on() after judging the device state under case MMI_DEV_POWER_ON.

void app_mmi_handle_action(uint8_t action)
{
  ...
  switch (action)
  {
    case MMI_DEV_POWER_ON:
        {
            if (app_db.device_state == APP_DEVICE_STATE_OFF_ING)
            {
                if (app_bt_policy_get_b2s_connected_num())
                {
                    app_bt_policy_disconnect_all_link();
                }

                app_mmi_modify_reboot_check_times(REBOOT_CHECK_POWER_ON_MAX_TIMES);
            }
            else if (app_db.device_state == APP_DEVICE_STATE_OFF)
            {
                if (!app_db.is_long_press_power_on_play_vp && !mp_hci_test_mode_is_running())
                {
                    app_audio_tone_type_play(TONE_POWER_ON, false, false);
                }
                app_db.is_long_press_power_on_play_vp = false;

                sys_mgr_power_on();
            }
        }
        break;
  ...
  }
}

If the device performs power off, it will call app_mmi_power_off() which encapsulates sys_mgr_power_off() after judging device state under case MMI_DEV_POWER_OFF.

case MMI_DEV_POWER_OFF:
    {
      ...
      if (app_db.device_state == APP_DEVICE_STATE_ON)
      {
        ...
        app_device_state_change(APP_DEVICE_STATE_OFF_ING);

        app_dlps_disable(APP_DLPS_ENTER_CHECK_WAIT_RESET);
        ...
        app_stop_timer(&timer_idx_reboot_check);
        app_mmi_reboot_check_timer_start(500);
        app_timer_register_pm_excluded(&timer_idx_reboot_check);

        if (mp_hci_test_mode_is_running())
        {
            mp_hci_test_mmi_handle_action(action);
        }
        else
        {
            app_sniff_mode_disable_all();
//power off
            app_mmi_power_off();
        }
      }
    }
    break;

If the device performs a factory reset, it will call sys_mgr_power_off() after checking the factory reset behavior.

case MMI_DEV_FACTORY_RESET:
    {
      app_dlps_disable(APP_DLPS_ENTER_CHECK_WAIT_RESET);
      app_mmi_check_factory_reset_behavior(action);
      ...
      app_stop_timer(&timer_idx_reboot_check);
      app_mmi_reboot_check_timer_start(500);

      app_db.waiting_factory_reset = true;
      if (app_db.device_state == APP_DEVICE_STATE_ON)
      {
          app_device_state_change(APP_DEVICE_STATE_OFF_ING);
          app_sniff_mode_disable_all();
          sys_mgr_power_off();
      }
    }

Bluetooth Connection and Linkback

The device utilizes CMD_BT_CREATE_CONNECTION to establish a Bluetooth connection, and CMD_XM_USER_CFM_REQ to confirm the connection request from another device. APIs that can be referred to are as follows.

The APIs called in app_cmd_br.c are declared in br_cmd_handle(), developers can enter the profiles to be connected in ACI Host CLI Tool (please refer to Connection and Linkback Function). The specific profile mask can refer to app_link_util.h, which can be adjusted according to needs.

void br_cmd_handle(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t app_idx,
                   uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    switch (cmd_id)
    {
      ...
      case CMD_BT_CREATE_CONNECTION:
      {
        struct
        {
            uint16_t cmd_id;
            uint32_t profile_mask;
            uint8_t  addr[6];
        } __attribute__((packed)) *CMD = (typeof(CMD))cmd_ptr;
        ...
        app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);

        linkback_todo_queue_insert_normal_node(CMD->addr, CMD->profile_mask,
                                                app_cfg_const.timer_linkback_timeout * 1000, 0);
        linkback_run();
      }
      break;
      ...
    }
}

After inserting a normal linkback node, the linkback node information will be checked, then the profiles to be connected will be placed in p_item->linkback_node.plan_profs in linkback_todo_queue_all_node().

void linkback_todo_queue_insert_normal_node(uint8_t *bd_addr, uint32_t plan_profs,
                                            uint32_t retry_timeout, bool is_group_member)
{
    T_LINKBACK_NODE_ITEM *p_item;

    p_item = linkback_todo_queue_find_node_item(bd_addr);
    ...
    linkback_todo_queue_all_node();
}

The linkback process runs and checks the status of linkback_active_node. After confirming that the node exists and the doing profile is not 0, linkback_profile_connect_start() will continue to be executed.

Then, the linkback_active_node_step_suc_adjust_remain_profs()/linkback_active_node_step_fail_adjust_remain_profs() will be returned according to the result of linkback_profile_search_start().

void linkback_run(void)
{
    T_LINKBACK_NODE node;
    uint32_t profs;
    ...
    if (b2s_connected_find_node(linkback_active_node.linkback_node.bd_addr, &profs))
    {
        if (profs & linkback_active_node.doing_prof)
        {
            ENGAGE_PRINT_TRACE1("linkback_run: prof 0x%08x, already connected",
                                linkback_active_node.doing_prof);

            linkback_active_node_step_suc_adjust_remain_profs();

            goto RETRY;
        }
    ...
    }
    ...
    if (linkback_profile_is_need_search(linkback_active_node.doing_prof))
    {
        if (!linkback_profile_search_start(linkback_active_node.linkback_node.bd_addr,
                                           linkback_active_node.doing_prof, linkback_active_node.linkback_node.is_special))
        {
            linkback_active_node_step_fail_adjust_remain_profs();

            goto RETRY;
        }
        ...
    }
    else
    {
        if (linkback_profile_connect_start(linkback_active_node.linkback_node.bd_addr,
                                           linkback_active_node.doing_prof, &linkback_active_node.linkback_conn_param))
        {
            goto EXIT;
        }
        else
        {
            linkback_active_node_step_fail_adjust_remain_profs();

            goto RETRY;
        }
    }
}

After link is established, Bluetooth stack will report BT_EVENT_LINK_USER_CONFIRMATION_REQ, which requires the device to confirm. The device needs to enter CMD_XM_USER_CFM_REQ to confirm the connection request in app_customer_bt_handle_cmd().

Note

When cfm is 0x01, it means confirm request. When cfm is 0x00, it means reject request.

void app_customer_bt_handle_cmd(uint8_t app_idx, T_CMD_PATH cmd_path, uint8_t *cmd_ptr,
                                uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    switch (cmd_id)
    {
      ...
      case CMD_XM_USER_CFM_REQ:
        {
            ...
            cfm = cmd_ptr[3];
            if (cfm == 0x00)
            {
                gap_br_user_cfm_req_cfm(app_db.br_link[app_index].bd_addr, GAP_CFM_CAUSE_REJECT);
                ...
            }
            else if (cfm == 0x01)
            {
                gap_br_user_cfm_req_cfm(app_db.br_link[app_index].bd_addr, GAP_CFM_CAUSE_ACCEPT);
            }
        }
        break;
    }
}

Bluetooth Low Energy

All Bluetooth Low Energy commands are processed in app_cmd_ble_handle in app_cmd_ble.c, while events are processed by a number of functions in app_rpt_ble.c.

Advertising

Advertising is the first step to Bluetooth Low Energy connection (as a peripheral). Furthermore, it can convey a bit of information by itself with scan response.

  1. Create an advertisement.

    Go through the command CMD_XM_LE_ADV_CREATE in app_cmd_ble.c, it calls static function adv_create. The adv_create function calls ble_ext_adv_mgr_init_adv_params() which creates an advertisement in the lower layer.

    It also calls ble_ext_adv_mgr_register_callback() to get advertisement states from the lower layer. In the end, adv_create saves advertisement information in p_elem to ble.advs.q. Handle is the most important member of p_elem which was always referenced as a parameter for other commands.

    static uint8_t adv_create(ADV_PARAMS *p_params)
    {
        ADV_Q_ELEM *p_elem = calloc(1, sizeof(*p_elem));
    
        if (p_params->adv_data)
        {
            memcpy(p_elem->adv_data, p_params->adv_data, p_params->adv_data_len);
            p_elem->adv_data_len = p_params->adv_data_len;
        }
    
        if (p_params->scan_rsp)
        {
            memcpy(p_elem->scan_rsp, p_params->scan_rsp, p_params->scan_rsp_len);
            p_elem->scan_rsp_len = p_params->scan_rsp_len;
        }
    
        p_elem->state = BLE_EXT_ADV_MGR_ADV_DISABLED;
    
        ble_ext_adv_mgr_init_adv_params(&p_elem->handle, p_params->adv_prop, p_params->interval_min,
                                        p_params->interval_max, p_params->own_addr_type, p_params->peer_addr_type, p_params->peer_addr,
                                        GAP_ADV_FILTER_ANY, p_elem->adv_data_len, p_elem->adv_data,
                                        p_elem->scan_rsp_len, p_elem->scan_rsp, p_params->own_addr);
    
        APP_PRINT_TRACE2("app_customer_ble adv_create: adv_data %b, le_single_random_addr %s",
                        TRACE_BINARY(sizeof(p_elem->adv_data), p_elem->adv_data),
                        TRACE_BDADDR(app_cfg_nv.le_single_random_addr));
    
        /* set adv event handle callback for further process*/
        ble_ext_adv_mgr_register_callback(adv_callback, p_elem->handle);
    
        os_queue_in(&ble.advs.q, p_elem); //save adv information by p_elem in ble.advs.q
    
        return p_elem->handle;
    }
    
  2. Start an advertisement.

    Glance over the CMD_XM_LE_START_ADVERTISING command, and you will find a wrapper function called adv_start, which requires a handle and triggers ble_ext_adv_mgr_enable to enable advertising.

    static bool adv_start(uint8_t handle, uint16_t duration_10ms)
    {
        ADV_Q_ELEM *p_adv_elem = find_adv_elem_by_hdl(handle);
    
        if (p_adv_elem)
        {
            if (p_adv_elem->state == BLE_EXT_ADV_MGR_ADV_DISABLED)
            {
                if (ble_ext_adv_mgr_enable(handle, duration_10ms) == GAP_CAUSE_SUCCESS)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                APP_PRINT_TRACE0("customer_adv_start: Already started");
                return true;
            }
        }
        return false;
    }
    
  3. Check the state of an advertisement.

    As the description above, adv_callback registered by ble_ext_adv_mgr_register_callback() will check advertisement states from the lower layer. In the case of BLE_EXT_ADV_STATE_CHANGE, it gets the advertising state from cb_data.p_ble_state_change->state. The enumeration definition is as follows:

    typedef enum
    {
        BLE_EXT_ADV_MGR_ADV_DISABLED,/**< when call api ble_ext_adv_mgr_disable, the application adv state will be set to BLE_EXT_ADV_MGR_ADV_DISABLED*/
        BLE_EXT_ADV_MGR_ADV_ENABLED, /**< when call api ble_ext_adv_mgr_enable, the application adv state will be set to BLE_EXT_ADV_MGR_ADV_ENABLED*/
    } T_BLE_EXT_ADV_MGR_STATE;
    

    At last, the adv_callback function will update the state in p_elem in ble.advs.q.

    if (p_adv_elem)
    {
        p_adv_elem->state = cb_data.p_ble_state_change->state;
        ......
    }
    
  4. Scan response.

    Scan response is set as a parameter for CMD_XM_LE_ADV_CREATE.

Connection Establishment

The connection establishment process involves two flows, corresponding to the two roles: Peripheral and Central.

  1. Connection establishments for Peripheral.

    Peripheral means the device is advertising when creating a connection. The event EVENT_XM_LE_CON_STATE will report a connection state (LE_LINK_STATE). The enumeration is described below. Besides, it also gives the connection parameters such as conn_interval, conn_latency and sup_tout.

    typedef enum
    {
        LE_LINK_STATE_DISCONNECTED,
        LE_LINK_STATE_CONNECTING,
        LE_LINK_STATE_CONNECTED,
        LE_LINK_STATE_DISCONNECTING,
    } LE_LINK_STATE;
    
    void app_rpt_ble_conn_cmpl(T_APP_LE_LINK *p_link)
    {
        ......
        le_get_conn_param(GAP_PARAM_CONN_INTERVAL, &rpt.conn_interval, p_link->conn_id);
        le_get_conn_param(GAP_PARAM_CONN_LATENCY, &rpt.conn_latency, p_link->conn_id);
        le_get_conn_param(GAP_PARAM_CONN_TIMEOUT, &rpt.sup_tout, p_link->conn_id);
    
        app_report_event(CMD_PATH_UART, EVENT_XM_LE_CON_STATE, 0, (uint8_t *)&rpt, sizeof(rpt));
    }
    
  2. Scanning for Central.

    Central means that the device should scan advertisements from Peripheral and then initiate connection creation. Ble_scan_start starts scanning for Peripheral’s advertisements with scan parameters and a callback to get scan information. The example code is as follows:

    void app_lea_ini_scan_start(void)
    {
        APP_PRINT_INFO0("app_ble_scan_start");
        BLE_SCAN_PARAM param;
    
        param.own_addr_type = GAP_LOCAL_ADDR_LE_PUBLIC;
        param.phys = GAP_EXT_SCAN_PHYS_1M_BIT;
        param.ext_filter_policy = GAP_SCAN_FILTER_ANY;
        param.ext_filter_duplicate = GAP_SCAN_FILTER_DUPLICATE_ENABLE;
    
        param.scan_param_1m.scan_type = GAP_SCAN_MODE_PASSIVE;
        param.scan_param_1m.scan_interval = 0x140;
        param.scan_param_1m.scan_window = 0xD0;
    
        param.scan_param_coded.scan_type = GAP_SCAN_MODE_PASSIVE;
        param.scan_param_coded.scan_interval = 0x0050;
        param.scan_param_coded.scan_window = 0x0025;
    
        if (ble_scan_start(&app_lea_ini_scan_handle, app_lea_ini_scan_cb, &param, NULL))
        {
            app_lea_clear_scan_dev();
        }
    }
    

    The scan results are reported in the callback registered by ble_scan_start. The scan information is defined in BLE_SCAN_EVT_DATA.

    typedef union
    {
        T_LE_EXT_ADV_REPORT_INFO *report;
    } BLE_SCAN_EVT_DATA;
    
  3. Connection establishments for Central.

    Typically, a connection is initiated after obtaining the scan information of the desired device from the aforementioned scanning process.

    Le_connect in CMD_LE_CREATE_CONN initiates a connection and the key parameter is bd_addr received from T_LE_EXT_ADV_REPORT_INFO. The connection state reporting is the same as described in establishments for peripheral.

Audio Tone Play

When configuring audio tone/VP playback, it is necessary to check the index in the MCUConfig Tool first, and initialize the index pointed to by VP in app_audio_tone_cfg_init(). The tone index must correspond to the tone type parameters. The index position in the MCUConfig Tool is shown below.

void app_audio_tone_cfg_init(void)
{
    memset(&app_audio_tone_cfg, TONE_INVALID_INDEX, sizeof(T_APP_AUDIO_TONE_CFG));
    app_audio_tone_cfg.tone_link_connected   = 0x8c;
    app_audio_tone_cfg.tone_hf_call_in       = 0x8d;
    app_audio_tone_cfg.tone_pairing          = 0x90;
    app_audio_tone_cfg.tone_link_disconnect  = 0x97;
    app_audio_tone_cfg.tone_power_off        = 0x9b;
    app_audio_tone_cfg.tone_power_on         = 0x9c;
}

Users can play VP by calling app_audio_tone_type_play(), where tone_type corresponds to T_APP_AUDIO_TONE_TYPE, and TONE_POWER_ON can be selected as the power on tone. The tone_index corresponds to the index in app_audio_tone_cfg above. According to the size of VOICE_PROMPT_INDEX and tone_index, it will be judged to ringtone_play() or voice_prompt_play(). If TONE_POWER_ON is selected, it will go to voice_prompt_play().

Note

If a new WAV file is placed under the voice prompt folder path (tool\MCUConfigTool-vx.xxx.xxx.x-Common_SDK\Voice Prompt), it may be inserted between the existing indexes, which will cause the index in the tool to change and not correspond to the index in the code. Therefore, the code index needs to be modified based on the index in the tool.

typedef enum
{
    TONE_POWER_ON,                      //0x00
    TONE_POWER_OFF,                     //0x01
    ...

} T_APP_AUDIO_TONE_TYPE;

#define VOICE_PROMPT_INDEX              0x80
#define TONE_INVALID_INDEX              0xFF

bool app_audio_tone_type_play(T_APP_AUDIO_TONE_TYPE tone_type, bool flush, bool relay)
{
    bool ret = false;
    uint8_t tone_index = TONE_INVALID_INDEX;
    int8_t check_result = 0;

    ...

    tone_index = app_audio_get_tone_index(tone_type);
    check_result = app_audio_tone_play_check(tone_type, tone_index);

    APP_PRINT_INFO6("app_audio_tone_type_play: tone_type 0x%02x, tone_index 0x%02x, state=%d, index=0x%02x, flush=%d, check_result = %d",
                    tone_type,
                    tone_index,
                    app_db.tone_vp_status.state,
                    app_db.tone_vp_status.index,
                    flush,
                    check_result);
    ...

    if (tone_index < VOICE_PROMPT_INDEX)
    {
        if (flush)
        {
            ringtone_cancel(tone_index, true);
        }
        ret = ringtone_play(tone_index, relay);
    }
    else if (tone_index < TONE_INVALID_INDEX)
    {
        if (flush)
        {
            voice_prompt_cancel(tone_index - VOICE_PROMPT_INDEX, true);
        }
        ret = voice_prompt_play(tone_index - VOICE_PROMPT_INDEX,
                                (T_VOICE_PROMPT_LANGUAGE_ID)app_cfg_nv.voice_prompt_language,
                                relay);
    }

    return ret;
}

For example, users can use it in app_mmi.c. When using the mmi pwron CMD to boot, call app_audio_tone_type_play() in case MMI_DEV_POWER_ON, fill in the parameters with TONE_POWER_ON, and then the VP can be played during the boot operation.

    case MMI_DEV_POWER_ON:
        {
            if (app_db.device_state == APP_DEVICE_STATE_OFF_ING)
            {
                if (app_bt_policy_get_b2s_connected_num())
                {
                    app_bt_policy_disconnect_all_link();
                }

                app_mmi_modify_reboot_check_times(REBOOT_CHECK_POWER_ON_MAX_TIMES);
            }
            else if (app_db.device_state == APP_DEVICE_STATE_OFF)
            {
                if (!app_db.is_long_press_power_on_play_vp && !mp_hci_test_mode_is_running())
                {
                    app_audio_tone_type_play(TONE_POWER_ON, false, false);
                }
                app_db.is_long_press_power_on_play_vp = false;

                sys_mgr_power_on();
            }
        }
        break;

Bluetooth Audio Transmitter

Source Play

Source play function, which can transmit MIC or line-in signal to BUDs through HFP, A2DP, or BIS. These two input methods and three output methods can be combined in various ways by set_route_in and set_route_out. The file path of the source play function is: src\sample\bt_audio_trx\source_play.

The functions of each file are as follows:

  • app_src_play.c includes selection and switching of source play input source and output source, and play/stop of output source.

  • app_src_play_a2dp.c includes processing when the output source is A2DP.

  • app_src_play_hfp.c includes processing when the output source is HFP.

  • app_src_play_cmd.c encapsulates the APIs mentioned above as commands.

The input and output paths are defined in the following structures in app_src_play.h:

//input route
typedef enum
{
    SOURCE_ROUTE_MIC         = 1,
    SOURCE_ROUTE_LINE_IN     = 2,
    SOURCE_ROUTE_USB         = 3,
    SOURCE_ROUTE_SD_CARD     = 4,
    SOURCE_ROUTE_INVALID     = 0xFF
} T_SOURCE_ROUTE;
//output route
typedef enum
{
    PLAY_ROUTE_A2DP         = 1,
    PLAY_ROUTE_HFP_AG       = 2,
    PLAY_ROUTE_BIS          = 3,
    PLAY_ROUTE_CIS          = 4,
    PLAY_ROUTE_LOCAL        = 5,
    PLAY_ROUTE_INVALID      = 0xFF
} T_PLAY_ROUTE;
MIC/Line-in Source Play Input Route

The MIC/line-in input adopts the record path, the input path can be set by modifying the device parameter in audio_track_create().

The source_play structure:

static struct
{
    T_PLAY_ROUTE play_route;
    struct
    {
        T_SOURCE_ROUTE          src_route;
        T_AUDIO_TRACK_HANDLE    handle;
        uint8_t                 default_volume;
    } record;
} source_play

Set and get source input route:

void app_src_play_set_src_route(T_SOURCE_ROUTE src_route)
{
    APP_PRINT_INFO1("app_src_play_set_src_route: src_route %d", src_route);
    source_play.record.src_route = src_route;
}
//set and get input source route via CMD
void app_src_play_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                 uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
    case CMD_SRC_PLAY_SET_SRC_ROUTE:
        {
            uint8_t src_route = cmd_ptr[2];
            app_src_play_set_src_route((T_SOURCE_ROUTE)src_route);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    case CMD_SRC_PLAY_GET_SRC_ROUTE:
        {
            ack_pkt[2] = app_src_play_get_src_route();
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
    }
}

Modify device parameter of audio track due to src_route.

static void record_start(void)
{
    ...
    if (source_play.record.src_route == SOURCE_ROUTE_MIC)
    {
        device = AUDIO_DEVICE_IN_MIC;
    }
    else if (source_play.record.src_route == SOURCE_ROUTE_LINE_IN)
    {
        device = AUDIO_DEVICE_IN_AUX;
    }
}
USB Source Play Input Route

The USB input adopts the pipe path, the input path can be set by modifying the device parameter in audio_pipe_create().

The source_play structure:

typedef struct
{
    T_PLAY_ROUTE play_route;
    struct
    {
        T_SOURCE_ROUTE          src_route;
        T_AUDIO_PIPE_HANDLE     handle;
        T_RING_BUFFER           src_rbuf;
        uint8_t                *src_fill_buf;
        uint16_t                src_fill_len;
        uint8_t                *snk_drain_buf;
        uint8_t                 default_volume;
        uint16_t                seq_num;
        uint8_t                 state;
    } pipe;
} T_SOURCE_PIPE_PLAY;

Set and get source input route:

void app_src_play_set_src_route(T_SOURCE_ROUTE src_route)
{
    APP_PRINT_INFO1("app_src_play_set_src_route: src_route %d", src_route);
    source_play.record.src_route = src_route;
}
//set and get input source route via CMD
void app_src_play_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                 uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
    case CMD_SRC_PLAY_SET_SRC_ROUTE:
        {
            uint8_t src_route = cmd_ptr[2];
            app_src_play_set_src_route((T_SOURCE_ROUTE)src_route);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    case CMD_SRC_PLAY_GET_SRC_ROUTE:
        {
            ack_pkt[2] = app_src_play_get_src_route();
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
    }
}
SD Card Source Play Input Route

Input format information from SD card that requires the use of file system to read audio files in app_src_play_sd_start(uint8_t play_route).

bool app_src_play_sd_start(uint8_t play_route)
{
    uint8_t err_code = 0;
    T_FILE_FORMAT_INFO file_format_info;
    uint32_t playback_offset = 0;
    uint16_t name_len = 0;

    //select a file TEMP_FILE_NAME_STRING
    if (sd.fs_handle == NULL)
    {
        // init file system and get sd.fs_handle
        uint8_t res = app_src_playback_open_and_get_file_info(SINGLE_FILE, (uint8_t *)TEMP_FILE_NAME_STRING,
                                                              &name_len, &playback_offset);
        if (res != PLAYBACK_SUCCESS)
        {
            err_code = 1;
            goto ERR;
        }
    }
    else
    {
        uint8_t *p_file_name = audio_fs_get_filename(sd.fs_handle);
        name_len = audio_fs_get_filenameLen(sd.fs_handle);
        // memcpy((uint8_t *)TEMP_FILE_NAME_STRING, p_file_name, name_len);
        playback_offset = audio_fs_get_file_offset(sd.fs_handle);
    }

    app_src_sd_card_dlps_disable(APP_SD_DLPS_ENTER_CHECK_PLAYING);
    app_src_sd_card_power_down_disable(APP_SD_POWER_DOWN_ENTER_CHECK_PLAYBACK);

    // read file header to get format for
    if (app_src_play_sd_get_file_format(&file_format_info) == false)
    {
        err_code = 2;
        return false;
    }

    if (play_route == PLAY_ROUTE_INVALID)
    {
        err_code = 3;
        return false;
    }
    else if (play_route == PLAY_ROUTE_LOCAL)
    {
        app_src_play_sd_local_start(&file_format_info);
    }
    else if (play_route == PLAY_ROUTE_BIS ||
             play_route == PLAY_ROUTE_CIS)
    {
        app_src_play_sd_pipe_start(&file_format_info);
    }

    return true;
ERR:
    APP_PRINT_ERROR1("app_src_play_sd_start: err_code %d", -err_code);
    return false;
}
MIC/Line-in Source Play Output Route

Similar to input source, source play output route can be set as HFP, A2DP or BIS.

Set and get source output route:

void app_src_play_set_play_route(T_PLAY_ROUTE play_route)
{
    APP_PRINT_INFO1("app_src_play_set_play_route: play_route %d", play_route);
    source_play.play_route = play_route;
}

//set and get output source route via CMD
void app_src_play_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                 uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
    ...
    case CMD_SRC_PLAY_SET_PLAY_ROUTE:
        {
            uint8_t play_route = cmd_ptr[2];
            app_src_play_set_play_route((T_PLAY_ROUTE)play_route);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    case CMD_SRC_PLAY_GET_PLAY_ROUTE:
        {
            ack_pkt[2] = app_src_play_get_play_route();
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
    }
}

Create and start audio_track after configurations, record_read_cb will process the MIC/line-in input source data to convert to the format specified in the source output route.

static void record_start(void)
{
    APP_PRINT_TRACE0("record_start!!");
    uint32_t device = 0;
    T_AUDIO_FORMAT_INFO format_info;
    if (source_play.play_route == PLAY_ROUTE_A2DP)
    {
        if (!app_src_play_get_a2dp_format((uint8_t *)&format_info))
        {
            APP_PRINT_ERROR0("record_start: a2dp format info does not exist");
            return;
        }
        app_src_play_print_a2dp_format("record_start", format_info);
    }
    else if (source_play.play_route == PLAY_ROUTE_HFP_AG)
    {
        if (!app_src_play_get_hfp_format((uint8_t *)&format_info))
        {
            APP_PRINT_ERROR0("record_start: hfp format info does not exist");
            return;
        }
        app_src_play_print_hfp_format("record_start", format_info);
    }
    else if (source_play.play_route == PLAY_ROUTE_BIS)
    {
#if BAP_BROADCAST_SOURCE
        if (!app_lea_get_data_format((uint8_t *)&format_info))
        {
            APP_PRINT_ERROR0("record_start: lc3 format info does not exist");
            return;
        }
#endif
        // app_src_play_print_hfp_format("record_start", format_info);
    }
    else if (source_play.play_route == PLAY_ROUTE_CIS)
    {
        if (!app_lea_get_data_format((uint8_t *)&format_info))
        {
            APP_PRINT_ERROR0("record_start: lc3 format info does not exist");
            return;
        }
    }
    ...
    source_play.record.handle = audio_track_create(AUDIO_STREAM_TYPE_RECORD,
                                                   AUDIO_STREAM_MODE_NORMAL,
                                                   AUDIO_STREAM_USAGE_LOCAL,
                                                   format_info,
                                                   0,
                                                   source_play.record.default_volume,
                                                   device,
                                                   NULL,
                                                   record_read_cb);

    if (source_play.record.handle == NULL)
    {
        APP_PRINT_ERROR0("app_customer_mic_record record_start: handle is NULL");
        return;
    }

    audio_track_start(source_play.record.handle);
}
static bool record_read_cb(T_AUDIO_TRACK_HANDLE  handle,
                           uint32_t             *timestamp,
                           uint16_t             *seq_num,
                           T_AUDIO_STREAM_STATUS *status,
                           uint8_t              *frame_num,
                           void                 *buf,
                           uint16_t              required_len,
                           uint16_t             *actual_len)
{
    {
        mic_dump_record_data("app_mic_record_read_cb", buf, required_len);
        uint8_t actual_frame_num = *frame_num;
        if (source_play.record.handle)
        {
            if (source_play.play_route == PLAY_ROUTE_A2DP)
            {
                uint8_t res = app_src_play_a2dp_handle_data(buf, required_len, actual_frame_num);
            }
            else if (source_play.play_route == PLAY_ROUTE_HFP_AG)
            {
                app_src_play_hfp_send_sco(buf, required_len);
            }
            else if (source_play.play_route == PLAY_ROUTE_BIS ||
                     source_play.play_route == PLAY_ROUTE_CIS)
            {
#if (BAP_BROADCAST_SOURCE || BAP_UNICAST_CLIENT)
                app_lea_iso_data_send(buf, required_len, true, *timestamp, *seq_num);
#endif
            }
        }

    }

    *actual_len = required_len;

    return true;
}

pipe_encode_cb will process the USB input source data to convert to the format specified in the source output route.

static void usb_pipe_start(void)
{
    T_AUDIO_FORMAT_INFO src_info;
    T_AUDIO_FORMAT_INFO snk_info;
    uint16_t src_len = 0;

    if (source_play.play_route == PLAY_ROUTE_A2DP)
    {
        if (!app_src_play_get_a2dp_format((uint8_t *)&snk_info))
        {
            APP_PRINT_ERROR0("usb_pipe_start: a2dp format info does not exist");
            return;
        }
        app_src_play_print_a2dp_format("usb_pipe_start", snk_info);
    }
    else if (source_play.play_route == PLAY_ROUTE_HFP_AG)
    {
        if (!app_src_play_get_hfp_format((uint8_t *)&snk_info))
        {
            APP_PRINT_ERROR0("usb_pipe_start: hfp format info does not exist");
            return;
        }
        app_src_play_print_hfp_format("usb_pipe_start", snk_info);
    }
    else if (source_play.play_route == PLAY_ROUTE_BIS)
    {
#if BAP_BROADCAST_SOURCE
        if (!app_lea_get_data_format((uint8_t *)&snk_info))
        {
            APP_PRINT_ERROR0("usb_pipe_start: lc3 format info does not exist");
            return;
        }
#endif
        // app_src_play_print_hfp_format("record_start", format_info);
    }
    else if (source_play.play_route == PLAY_ROUTE_CIS)
    {
        if (!app_lea_get_data_format((uint8_t *)&snk_info))
        {
            APP_PRINT_ERROR0("usb_pipe_start: lc3 format info does not exist");
            return;
        }
    }
    else
    {
        APP_PRINT_ERROR1("usb_pipe_start: play_route", source_pipe_play.play_route);
        return;
    }

    if (source_pipe_play.pipe.handle != NULL)
    {
        APP_PRINT_ERROR0("usb_pipe_start: already started");
        return;
    }



    src_info.type = AUDIO_FORMAT_TYPE_PCM;
    src_info.frame_num = 1;
    src_info.attr.pcm.sample_rate = 48000;
    /*FIXME: frame_length due to snk_format*/

    src_info.attr.pcm.chann_num = 2;
    src_info.attr.pcm.bit_width = 16;

    APP_PRINT_INFO1("usb_pipe_start: snk type %x", snk_info.type);
    switch (snk_info.type)
    {
    case AUDIO_FORMAT_TYPE_LC3:
        {
            src_len = 512;
            snk_info.frame_num = 1;
            src_lea_db.lea_data_buf = calloc(1, snk_info.attr.lc3.frame_length * 2);
            if (src_lea_db.lea_data_buf == NULL)
            {
                APP_PRINT_ERROR0("usb_pipe_start: lea_data_buf NULL");
                return;
            }
            src_lea_db.frame_len = snk_info.attr.lc3.frame_length;
            if (snk_info.attr.lc3.frame_duration == AUDIO_LC3_FRAME_DURATION_7_5_MS)
            {
                src_lea_db.frame_duration = 7500;
            }
            else
            {
                src_lea_db.frame_duration = 10000;
            }
        }
        break;
    case AUDIO_FORMAT_TYPE_SBC:
        {
            src_len = 512;
            snk_info.frame_num = 1;
        }
        break;
    case AUDIO_FORMAT_TYPE_MSBC:
        {
            src_len = 720;
            snk_info.frame_num = 1;
        }
        break;
    default:
        return;
    }

    /*Frame length per channel in octets for encoding or decoding.*/
    src_info.attr.pcm.frame_length = src_len / src_info.attr.pcm.chann_num;
    source_pipe_play.pipe.src_fill_buf = calloc(1, src_len);
    if (source_pipe_play.pipe.src_fill_buf == NULL)
    {
        APP_PRINT_ERROR0("usb_pipe_start: src_fill_buf NULL");
        usb_pipe_buf_release();
        return;
    }
    source_pipe_play.pipe.src_fill_len = src_len;

    source_pipe_play.pipe.snk_drain_buf = calloc(1, PIPE_DRAIN_BUF_LEN);
    if (source_pipe_play.pipe.snk_drain_buf == NULL)
    {
        APP_PRINT_ERROR0("usb_pipe_start: snk_drain_buf NULL");
        usb_pipe_buf_release();
        return;
    }

    source_pipe_play.pipe.handle = audio_pipe_create(src_info,
                                                     snk_info,
                                                     source_pipe_play.pipe.default_volume,
                                                     pipe_encode_cb);
    if (!source_pipe_play.pipe.handle)
    {
        APP_PRINT_ERROR0("usb_pipe_start: pipe.handle NULL");
        usb_pipe_buf_release();
        return;
    }

}
static bool pipe_encode_cb(T_AUDIO_PIPE_HANDLE handle, T_AUDIO_PIPE_EVENT event, uint32_t  param)
{
    if (handle != source_pipe_play.pipe.handle)
    {
        return true;
    }

    if ((event != AUDIO_PIPE_EVENT_DATA_IND) && (event != AUDIO_PIPE_EVENT_DATA_FILLED))
    {
        APP_PRINT_INFO2("pipe_encode_cb: handle %x event %x", handle, event);
    }

    switch (event)
    {
    case AUDIO_PIPE_EVENT_RELEASED:
        {
            source_pipe_play.pipe.state = PIPE_STATE_IDLE;
            usb_pipe_buf_release();
            source_pipe_play.pipe.handle = NULL;
        }
        break;
    case AUDIO_PIPE_EVENT_CREATED:
        {
            source_pipe_play.pipe.state = PIPE_STATE_CREATED;
            audio_pipe_start(source_pipe_play.pipe.handle);
        }
        break;
    case AUDIO_PIPE_EVENT_STARTED:
        {
            source_pipe_play.pipe.state = PIPE_STATE_STARTED;
        }
        break;
    case AUDIO_PIPE_EVENT_STOPPED:
        {
            source_pipe_play.pipe.state = PIPE_STATE_CREATED;
        }
        break;
    case AUDIO_PIPE_EVENT_DATA_IND:
        {
            pipe_handle_data_ind();
        }
        break;
    case AUDIO_PIPE_EVENT_DATA_FILLED:
        {
            pipe_handle_data_filled();
        }
        break;
    case AUDIO_PIPE_EVENT_MIXED:
        break;
    case AUDIO_PIPE_EVENT_DEMIXED:
        break;
    default:
        break;
    }

    return true;

}

When the play_route is set to A2DP, record_read_cb will call app_src_play_a2dp_handle_data, the A2DP output format will be saved by app_src_play_save_a2dp_format when Bluetooth reports BT_EVENT_A2DP_CONFIG_CMPL in app_audio_bt_cback.

void app_src_play_save_a2dp_format(uint8_t *format_info)
{
    if (!a2dp_play.a2dp_format_ready)
    {
        memcpy(&a2dp_play.a2dp_format, format_info, sizeof(T_AUDIO_FORMAT_INFO));
        a2dp_play.a2dp_format.attr.sbc.bitpool = 0x22;
        a2dp_play.a2dp_format_ready = true;
    }
    app_src_play_print_a2dp_format("app_src_play_save_a2dp_format: ",
                                   a2dp_play.a2dp_format);
}

uint16_t app_src_play_a2dp_handle_data(uint8_t *p_data, uint16_t data_len, uint8_t frame_number)
{
    uint16_t res = SRC_PLAY_A2DP_SUCCESS;
    if (ring_buffer_write(&a2dp_play.ring_buf, p_data, data_len))
    {
        a2dp_play.num_frame_buf++;
    }
    else
    {
        res = SRC_PLAY_A2DP_ERR_RINGBUF;
        APP_PRINT_ERROR0("xiaoai_process_voice_data: xiaoai_record.voice_buf is full, drop pkt");
    }

    if (a2dp_play.num_frame_buf == A2DP_PACKET_FRAME_NUM)
    {
        a2dp_play.num_frame_buf = 0;
        uint16_t data_len_to_send = data_len * A2DP_PACKET_FRAME_NUM;
        uint8_t *p_data_to_send = malloc(data_len_to_send);
        if (p_data_to_send)
        {
            uint32_t actual_len = ring_buffer_read(&a2dp_play.ring_buf, data_len_to_send, p_data_to_send);
            APP_PRINT_INFO1("app_src_play_a2dp_handle_data: actual_len %d sent", actual_len);

            res = app_src_play_a2dp_send_data(p_data_to_send, data_len_to_send, A2DP_PACKET_FRAME_NUM);

            free(p_data_to_send);
        }
        else
        {
            res = SRC_PLAY_A2DP_ERR_RAM;
        }
    }
    return res;
}

When the play_route is set to HFP, record_read_cb will call app_src_play_hfp_send_sco. The HFP output format will be saved by app_src_play_save_hfp_format when Bluetooth reports BT_EVENT_SCO_CONN_CMPL in app_audio_bt_cback.

void app_src_play_save_hfp_format(uint8_t *format_info)
{
    if (!hfp_play.hfp_format_ready)
    {
        memcpy(&hfp_play.hfp_format, format_info, sizeof(T_AUDIO_FORMAT_INFO));
        hfp_play.hfp_format_ready = true;
    }
    app_src_play_print_hfp_format("app_src_play_save_hfp_format: ",
                                  hfp_play.hfp_format);
}

void app_src_play_hfp_send_sco(uint8_t *p_data, uint16_t len)
{
    uint8_t active_hf_idx = app_hfp_get_active_idx();
    T_APP_BR_LINK *p_link;
    p_link = app_link_find_br_link(app_db.br_link[active_hf_idx].bd_addr);
    if (p_link == NULL)
    {
        APP_PRINT_ERROR0("app_src_play_hfp_send_sco: no br link found");
        return;
    }
    hfp_seq_num++;
    if (p_link->sco.duplicate_fst_data)
    {
        p_link->sco.duplicate_fst_data = false;
        bt_sco_data_send(p_link->bd_addr, hfp_seq_num - 1, p_data, len);
    }
    bt_sco_data_send(p_link->bd_addr, hfp_seq_num, p_data, len);
}

When the play_route is set to BIS/CIS, record_read_cb will call app_lea_iso_data_send. The BIS output format will be saved by app_lea_save_data_format in app_lea_handle_bis_data_path_setup. The CIS output format will be saved by app_lea_save_data_format in app_lea_handle_cis_data_path_setup.

static void app_lea_save_data_format(T_APP_LEA_ISO_CHANN *p_iso_chann)
{
    save_format.type = AUDIO_FORMAT_TYPE_LC3;
    codec_max_sdu_len_get(&p_iso_chann->codec_data, &p_iso_chann->iso_sdu_len);
    //always get two-channel data but send data according to bis/cis num
    save_format.attr.lc3.chann_location = AUDIO_CHANNEL_LOCATION_SL | AUDIO_CHANNEL_LOCATION_SR;
    save_format.attr.lc3.sample_rate = app_lea_get_sample_rate(p_iso_chann);
    save_format.attr.lc3.frame_length = p_iso_chann->codec_data.octets_per_codec_frame;
    if (p_iso_chann->codec_data.frame_duration == FRAME_DURATION_CFG_7_5_MS)
    {
        save_format.attr.lc3.frame_duration = AUDIO_LC3_FRAME_DURATION_7_5_MS;
    }
    else
    {
        save_format.attr.lc3.frame_duration = AUDIO_LC3_FRAME_DURATION_10_MS;
    }
    save_format.attr.lc3.presentation_delay = p_iso_chann->presentation_delay;
}

void app_lea_iso_data_send(uint8_t *p_data, uint16_t len, bool ext_flag, uint32_t ts, uint16_t seq)
{
    T_GAP_CAUSE cause = GAP_CAUSE_SUCCESS;
    T_APP_LEA_ISO_CHANN *p_iso_chann = NULL;
    uint8_t chnl_cnt = 0;
    uint32_t time_stamp = 0;
    uint16_t seq_num = 0;
    for (uint8_t i = 0; i < app_db.iso_input_queue.count; i++)
    {
        p_iso_chann = (T_APP_LEA_ISO_CHANN *)os_queue_peek(&app_db.iso_input_queue, i);

        if (p_iso_chann->codec_data.audio_channel_allocation == AUDIO_LOCATION_MONO)
        {
            chnl_cnt = 1;
        }
        else
        {
            chnl_cnt = __builtin_popcount(p_iso_chann->codec_data.audio_channel_allocation);
        }
        if (ext_flag)
        {
            time_stamp = ts;
            seq_num = seq;
        }
        else
        {
            time_stamp = (p_iso_chann->time_stamp + p_iso_chann->pkt_seq_num) *
                         (p_iso_chann->sdu_interval * 1000);
            seq_num = p_iso_chann->pkt_seq_num;
        }


        if (chnl_cnt == 2)
        {
            cause = gap_iso_send_data(p_data,
                                      p_iso_chann->iso_conn_handle,
                                      len,
                                      false,
                                      time_stamp,
                                      seq_num);

        }
        else if (chnl_cnt == 1)
        {
            if (p_iso_chann->codec_data.audio_channel_allocation & (AUDIO_LOCATION_FL |
                                                                    AUDIO_LOCATION_SIL))
            {
                cause = gap_iso_send_data(p_data,
                                          p_iso_chann->iso_conn_handle,
                                          len / 2,
                                          0,
                                          time_stamp,
                                          seq_num);
            }
            else
            {
                cause = gap_iso_send_data(p_data + (len / 2),
                                          p_iso_chann->iso_conn_handle,
                                          len / 2,
                                          0,
                                          time_stamp,
                                          seq_num);
            }
        }
        p_iso_chann->pkt_seq_num++;
        if (cause != GAP_CAUSE_SUCCESS)
        {
            APP_PRINT_ERROR1("app_lea_iso_data_send: failed, cause 0x%x", cause);
        }
    }
    return;
}
SD Card Source Play Output Route

Similar to the input source, the SD card source play output route can be set as local play, BIS, or CIS.

bool app_src_play_sd_start(uint8_t play_route)
{
    ...
    if (play_route == PLAY_ROUTE_INVALID)
    {
        err_code = 3;
        return false;
    }
    else if (play_route == PLAY_ROUTE_LOCAL)
    {
        app_src_play_sd_local_start(&file_format_info);
    }
    else if (play_route == PLAY_ROUTE_BIS ||
             play_route == PLAY_ROUTE_CIS)
    {
        app_src_play_sd_pipe_start(&file_format_info);
    }
}

If choosing the play route as PLAY_ROUTE_LOCAL, the local start is set in app_src_play_sd_local_start().

static void app_src_play_sd_local_start(T_FILE_FORMAT_INFO *file_format)
{
    if (sd.local_play.handle != NULL)
    {
        audio_track_release(sd.local_play.handle);
        sd.local_play.handle = NULL;
    }

    T_LOCALPLAY_SET_INFO set_play_info;

    app_src_play_sd_set_local_play_info(file_format, &set_play_info);
    sd.local_play.play_monitor.put_data_time_ms = set_play_info.play_duration;
    sd.local_play.play_monitor.preq_pkts = set_play_info.preq_pkts;

    sd.local_play.handle = audio_track_create(AUDIO_STREAM_TYPE_PLAYBACK, //stream_type
                                              AUDIO_STREAM_MODE_NORMAL, // mode
                                              AUDIO_STREAM_USAGE_SNOOP, // usage
                                              file_format->format_info, //format_info
                                              sd.local_play.volume, //volume
                                              0,
                                              AUDIO_DEVICE_OUT_SPK, // device
                                              NULL,
                                              NULL);

    if (sd.local_play.handle != NULL)
    {
        audio_track_latency_set(sd.local_play.handle, set_play_info.latency, true);
        audio_track_threshold_set(sd.local_play.handle, set_play_info.upper_level,
                                  set_play_info.lower_level);
        sd.local_play.play_monitor.delay_stop_ms = set_play_info.latency;
    }
    sd.op_next_action = SD_STOPPED_IDLE_ACTION;
    // app_src_playback_volume_set(sd.local_play.volume);
    sd.local_play.play_state = SD_PLAY_STATE_PLAY;
    sd.local_play.play_monitor.local_track_state = PLAYBACK_TRACK_STATE_CLEAR;
    sd.local_play.play_monitor.sec_track_state = PLAYBACK_TRACK_STATE_CLEAR;
    sd.local_play.play_monitor.buffer_state = PLAYBACK_BUF_NORMAL;
    audio_track_start(sd.local_play.handle);
}

If choose to play the route as PLAY_ROUTE_BIS or PLAY_ROUTE_CIS, the route start is set in app_src_play_sd_pipe_start().

void app_src_play_sd_pipe_start(T_FILE_FORMAT_INFO *file_format)
{
    T_AUDIO_FORMAT_INFO src_info = file_format->format_info;
    T_AUDIO_FORMAT_INFO snk_info;
    T_PLAY_ROUTE play_route = app_src_play_get_play_route();

    if (play_route == PLAY_ROUTE_A2DP)
    {
        // TODO: Support A2DP TX
        return;
    }
    else if (play_route == PLAY_ROUTE_HFP_AG)
    {
        // TODO: Support HFP TX
        return;
    }
#if (BAP_BROADCAST_SOURCE || BAP_UNICAST_CLIENT)
    else if (play_route == PLAY_ROUTE_BIS || play_route == PLAY_ROUTE_CIS)
    {
        if (!app_lea_get_data_format(LEA_CODEC_DIR_ENCODE, &snk_info))
        {
            APP_PRINT_ERROR0("app_src_play_sd_pipe_start: lc3 format info does not exist");
            return;
        }

        uint8_t chnl_cnt;
        if (snk_info.attr.lc3.chann_location == AUDIO_LOCATION_MONO)
        {
            chnl_cnt = 1;
        }
        else
        {
            chnl_cnt = __builtin_popcount(snk_info.attr.lc3.chann_location);
        }

        lea_tx_mgr.pkt_len = snk_info.attr.lc3.frame_length * chnl_cnt;
        lea_tx_mgr.p_lea_send_buf = calloc(1, lea_tx_mgr.pkt_len);
        if (lea_tx_mgr.p_lea_send_buf == NULL)
        {
            APP_PRINT_ERROR0("app_src_play_sd_pipe_start: p_lea_send_buf malloc fail");
            return;
        }
        lea_tx_mgr.target_threshold = 5; // frame_cnt
        lea_tx_mgr.pre_fill_num = 4;
        APP_PRINT_INFO2("app_src_play_sd_pipe_start: pkt_len %d, target_threshold %d",
                        lea_tx_mgr.pkt_len, lea_tx_mgr.target_threshold);
        if (snk_info.attr.lc3.frame_duration == AUDIO_LC3_FRAME_DURATION_10_MS)
        {
            lea_tx_mgr.timer_duration = 10000;
        }
        else
        {
            lea_tx_mgr.timer_duration = 7500;
        }
    }
#endif
    src_info.frame_num = 1;
    snk_info.frame_num = 1;
    if (sd.pipe_play.handle == NULL)
    {
        sd.pipe_play.handle = audio_pipe_create(AUDIO_STREAM_MODE_NORMAL,
                                                src_info, snk_info,
                                                sd.pipe_play.volume,
                                                app_src_play_sd_pipe_cback);
    }

    sd.op_next_action = SD_STOPPED_IDLE_ACTION;
}

Audio track/pipe will be created after calling app_src_play_sd_local_start()/app_src_play_sd_pipe_start(), they will be released in the calling of app_src_play_sd_local_stop() and app_src_play_sd_pipe_stop().

void app_src_play_sd_stop(uint8_t play_route)
{
    if (play_route == PLAY_ROUTE_LOCAL)
    {
        app_src_play_sd_local_stop();
    }
    else if (play_route == PLAY_ROUTE_BIS ||
             play_route == PLAY_ROUTE_CIS)
    {
        app_src_play_sd_pipe_stop();
    }
}

static void app_src_play_sd_local_stop(void)
{
    uint8_t res = PLAYBACK_SUCCESS;
    audio_fs_decode_deinit();
    app_stop_timer(&timer_idx_sd_local_put_data);
    sd.local_play.play_state = SD_PLAY_STATE_IDLE;
    if (sd.local_play.handle != NULL)
    {
        sd.local_play.play_monitor.local_track_state = PLAYBACK_TRACK_STATE_CLEAR;
        audio_track_release(sd.local_play.handle);
    }

    if (sd.fs_handle != NULL)
    {
        if (0 != audio_fs_close(sd.fs_handle))
        {
            // return;
        }
        sd.fs_handle = NULL;
    }
    app_src_sd_card_dlps_enable(APP_SD_DLPS_ENTER_CHECK_PLAYING);
    // TODO: FIX ME
    // app_sd_card_power_down_enable(APP_SD_POWER_DOWN_ENTER_CHECK_PLAYBACK);

}

static void app_src_play_sd_pipe_stop(void)
{
    audio_fs_decode_deinit();
    if (sd.pipe_play.handle != NULL)
    {
        audio_pipe_release(sd.pipe_play.handle);
    }
    if (sd.fs_handle != NULL)
    {
        if (0 != audio_fs_close(sd.fs_handle))
        {
            // return;
        }
        sd.fs_handle = NULL;
    }
    app_src_sd_card_dlps_enable(APP_SD_DLPS_ENTER_CHECK_PLAYING);
}

When the end of the file is reached, the file system also releases the handle created to read audio file information.

Source Play Start/Stop

Source play start/stop can be divided into two parts, input route start/stop and output route start/stop.

When source play input route needs to be activated:

bool app_src_play_route_in_start(void)
{
    bool result = false;

    if (source_play.src_route == SOURCE_ROUTE_USB)
    {
        if (usb_ds_attr.active)
        {
            result = usb_encode_pipe_start();
        }
        if (usb_us_attr.active)
        {
            result = usb_decode_pipe_start();
        }
    }
#if F_APP_SD_CARD_PLAY
    else if (source_play.src_route == SOURCE_ROUTE_SD_CARD)
    {
        result = app_src_play_sd_start(source_play.play_route);
    }
#endif
#if F_APP_INTEGRATED_TRANSCEIVER
    else if (source_play.src_route == SOURCE_ROUTE_A2DP)
    {
        result = app_src_play_pipe_start(source_play.play_route);
    }
#endif
    else
    {
        result = record_start();
    }

    return result;
}

When the source play input route needs to be stopped, it means releasing the started audio_track and freeing the record handle:

void app_src_play_route_in_stop(void)
{
    if (source_play.src_route == SOURCE_ROUTE_USB)
    {
        if (usb_ds_attr.active)
        {
            usb_encode_pipe_stop();
        }
        if (usb_us_attr.active)
        {
            usb_decode_pipe_stop();
        }
    }
#if F_APP_SD_CARD_PLAY
    else if (source_play.src_route == SOURCE_ROUTE_SD_CARD)
    {
        app_src_play_sd_stop(source_play.play_route);
    }
#endif
#if F_APP_INTEGRATED_TRANSCEIVER
    else if (source_play.src_route == SOURCE_ROUTE_A2DP)
    {
        app_src_play_pipe_stop();
    }
#endif
    else
    {
        record_stop();
    }
}

When source play output route needs to be activated, depending on the output format, specific processing is required:

bool app_src_play_a2dp_start_req(void)
{
    APP_PRINT_INFO0("app_src_play_a2dp_start_req");
    return bt_a2dp_stream_start_req(a2dp_play.sink_addr);
}

bool app_src_play_hfp_start_req(void)
{
    APP_PRINT_INFO0("app_src_play_hfp_start_req");
    return bt_hfp_ag_audio_connect_req(hfp_play.hf_addr);
}

bool app_lea_bsrc_start(void)
{
    if (app_db.bsrc_db.source_handle == NULL)
    {
        APP_PRINT_ERROR0("app_lea_bsrc_start: init bis firstly!");
        return false;
    }
    app_db.bsrc_db.prefer_state = BROADCAST_SOURCE_STATE_STREAMING;
    app_lea_bsrc_target_state();
    return true;
}

bool app_lea_ini_cis_media_start(uint8_t group_idx)
{
    bool ret = false;

    if (group_idx < app_db.group_handle_queue.count)
    {
        T_APP_LEA_GROUP_INFO *p_group = (T_APP_LEA_GROUP_INFO *)os_queue_peek(&app_db.group_handle_queue,
                                                                              group_idx);
        if (p_group)
        {
            ret = app_lea_ini_start_media(p_group->group_handle);
        }
    }

    return ret;
}
//start in cases
bool app_src_play_route_out_start(void)
{
    bool result = false;
    switch (source_play.play_route)
    {
    case PLAY_ROUTE_A2DP:
        {
            result = app_src_play_a2dp_start_req();
        }
        break;

    case PLAY_ROUTE_HFP_AG:
        {
            result = app_src_play_hfp_start_req();
        }
        break;

#if BAP_BROADCAST_SOURCE
    case PLAY_ROUTE_BIS:
        {
            result = app_lea_bsrc_start();
        }
        break;
#endif

#if BAP_UNICAST_CLIENT
    case PLAY_ROUTE_CIS:
        {
            result = app_lea_ini_cis_media_start(0);
        }
#endif

    case PLAY_ROUTE_LOCAL:
        {
            // DO Nothing
            result = true;
        }

    case PLAY_ROUTE_MULTI_A2DP:
        {
            result = app_src_play_a2dp_start_req();
        }
        break;

    default:
        break;
    }
    return result;
}

When the source play output route needs to be stopped, depending on the output format, specific processing is required:

void app_src_play_a2dp_stop(void)
{
    APP_PRINT_TRACE0("app_src_play_a2dp_stop");
    a2dp_play.num_frame_buf = 0;
    ring_buffer_clear(&a2dp_play.ring_buf);
    if (a2dp_play.a2dp_state != A2DP_STATE_STREAM_STOP)
    {
        bt_a2dp_stream_suspend_req(a2dp_play.sink_addr);
    }
    app_dlps_enable(APP_DLPS_ENTER_CHECK_PLAYBACK);
}

void app_src_play_hfp_stop(void)
{
    APP_PRINT_TRACE0("app_src_play_hfp_stop");
    bt_hfp_ag_audio_disconnect_req(hfp_play.hf_addr);
}

bool app_lea_bsrc_stop(bool release)
{
    if (app_db.bsrc_db.source_handle == NULL)
    {
        return false;
    }
    if (release)
    {
        app_db.bsrc_db.prefer_state = BROADCAST_SOURCE_STATE_IDLE;
    }
    else
    {
        if (app_db.bsrc_db.prefer_state != BROADCAST_SOURCE_STATE_IDLE)
        {
            app_db.bsrc_db.prefer_state = BROADCAST_SOURCE_STATE_CONFIGURED;
        }
    }
    app_lea_bsrc_target_state();
    return true;
}

bool app_lea_ini_cis_stream_stop(uint8_t group_idx, bool release)
{
    bool ret = false;

    if (group_idx < app_db.group_handle_queue.count)
    {
        T_APP_LEA_GROUP_INFO *p_group = (T_APP_LEA_GROUP_INFO *)os_queue_peek(&app_db.group_handle_queue,
                                                                              group_idx);
        if (p_group)
        {
            if (release)
            {
                ret = app_lea_ini_unicast_audio_release(p_group->group_handle);
            }
            else
            {
                ret = app_lea_ini_unicast_audio_stop(p_group->group_handle, 0);
            }

        }
    }
    return ret;
}
//stop in cases
void app_src_play_route_out_stop(void)
{
    switch (source_play.play_route)
    {
    case PLAY_ROUTE_A2DP:
        {
            app_src_play_a2dp_stop();
        }
        break;

    case PLAY_ROUTE_HFP_AG:
        {
            app_src_play_hfp_stop();
        }
        break;

#if BAP_BROADCAST_SOURCE
    case PLAY_ROUTE_BIS:
        {
            app_lea_bsrc_stop(true);
        }
        break;
#endif

#if BAP_UNICAST_CLIENT
    case PLAY_ROUTE_CIS:
        {
            app_lea_ini_cis_stream_stop(0, true);
        }
#endif

    case PLAY_ROUTE_MULTI_A2DP:
        {
            result = app_src_play_a2dp_stop();
        }
        break;

    default:
        break;
    }
}

The APIs mentioned above are called in app_src_play_handle_cmd_set, User can fill in the corresponding cmd_id in the ACI Host CLI Tool according to the following case to perform operations:

void app_src_play_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                 uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
    ...
    case CMD_SRC_PLAY_ROUTE_IN_START:
        {
            app_src_play_route_in_start();
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    case CMD_SRC_PLAY_ROUTE_IN_STOP:
        {
            app_src_play_route_in_stop();
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    case CMD_SRC_PLAY_ROUTE_OUT_START:
        {
            if (app_src_play_route_out_start())
            {
                ack_pkt[2] = CMD_SET_STATUS_COMPLETE;
            }
            else
            {
                ack_pkt[2] = CMD_SET_STATUS_SCENARIO_ERROR;
            }
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    case CMD_SRC_PLAY_ROUTE_OUT_STOP:
        {
            app_src_play_route_out_stop();
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    default:
        break;
    }
}

LE Audio Initiator - BIS

Bluetooth Low Energy Audio CAP roles can be divided into Acceptor, Initiator, and Commander. In transmitter application, Initiator role is supported, which can transmit BIS or transmit and receive CIS.

In this chapter, the design SPEC for BIS will be presented.

Initialization

Initialization is performed through the function of app_lea_profile_init(), including configuration of LE Audio parameters, initialization of BAP and CAP, as well as the necessary data processing setup.

//app_lea_ini_profile.c

void app_lea_profile_init(void)
{
    T_BLE_AUDIO_PARAMS ble_audio_param = {0};
    ble_audio_param.evt_queue_handle = audio_evt_queue_handle;
    ble_audio_param.io_queue_handle = audio_io_queue_handle;
    ble_audio_param.bt_gatt_client_init = (GATT_CLIENT_DISCOV_MODE_REG_SVC_BIT |
                                           GATT_CLIENT_DISCOV_MODE_CCCD_STORAGE_BIT |
                                           GATT_CLIENT_DISCOV_MODE_USE_EXT_CLIENT);
    ble_audio_param.acl_link_num = MAX_BLE_LINK_NUM;
    ble_audio_param.io_event_type = IO_MSG_TYPE_LE_AUDIO;
    ble_audio_init(&ble_audio_param);
    app_lea_ini_bap_init();
    app_lea_ini_cap_init();
    app_lea_audio_data_init();
}
Configure BIS

Before broadcasting data through BIS, it is necessary to initialize the broadcast source parameters. This can be achieved through the CMD_LEA_BSRC_INIT command, specifying codec configuration, BIS number, and ULL mode, among others. For detailed explanations for the command, please refer to ACI_CMD_LEA_BSRC_INIT.

void app_lea_ini_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                uint16_t cmd_len, uint8_t *ack_pkt)
{
    ...
    switch (cmd_id)
    {
    ...
    case CMD_LEA_BSRC_INIT:
        {
            struct
            {
                uint16_t    cmd_id;
                uint8_t     codec_cfg;
                uint8_t     bis_num;
                bool        encryption;
                bool        ull_mode;
                uint16_t    pd;
            } __attribute__((packed)) *bis_param = (typeof(bis_param))cmd_ptr;

            T_CODEC_CFG_ITEM codec_cfg_type = (T_CODEC_CFG_ITEM)bis_param->codec_cfg;
            uint8_t bis_num = bis_param->bis_num;
            bool encryption = bis_param->encryption;
            app_db.bis_ull_mode = bis_param->ull_mode;
            uint16_t presentation_delay = bis_param->pd;
            APP_PRINT_TRACE1("app_lea_ini_handle_cmd_set: bis ull mode %d", app_db.cis_ull_mode);
            T_QOS_CFG_TYPE qos_type = QOS_CFG_BIS_HIG_RELIABILITY;
            if (app_db.bis_ull_mode)
            {
                qos_type = QOS_CFG_BIS_LOW_LATENCY;
            }
            app_lea_bsrc_init(codec_cfg_type,
                              qos_type,
                              bis_num,
                              GAP_LOCAL_ADDR_LE_PUBLIC,
                              encryption,
                              presentation_delay);

            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
    }
}
Establish BIS

The broadcast source defines several states as below, among which STATE_CONFIGURED_STARTING, STATE_CONFIGURED_STOPPING, STATE_STREAMING_STARTING and STATE_STREAMING_STOPPING are intermediate states, while STATE_IDLE, STATE_CONFIGURED and STATE_STREAMING can serve as target states.

typedef enum
{
    BROADCAST_SOURCE_STATE_IDLE                = 0x00,
    BROADCAST_SOURCE_STATE_CONFIGURED_STARTING = 0x01,
    BROADCAST_SOURCE_STATE_CONFIGURED          = 0x02,
    BROADCAST_SOURCE_STATE_CONFIGURED_STOPPING = 0x03,
    BROADCAST_SOURCE_STATE_STREAMING_STARTING  = 0x04,
    BROADCAST_SOURCE_STATE_STREAMING           = 0x05,
    BROADCAST_SOURCE_STATE_STREAMING_STOPPING  = 0x06,
} T_BROADCAST_SOURCE_STATE;

By calling the app_lea_bsrc_start() API, the broadcast will attempt to transition its state to BROADCAST_SOURCE_STATE_STREAMING.

bool app_lea_bsrc_start(void)
{
    if (app_db.bsrc_db.source_handle == NULL)
    {
        APP_PRINT_ERROR0("app_lea_bsrc_start: init bis firstly!");
        return false;
    }
    app_db.bsrc_db.prefer_state = BROADCAST_SOURCE_STATE_STREAMING;
    app_lea_bsrc_target_state();
    return true;
}

Specifically, the module will configure and enable the Extended Advertisement and the Periodic Advertisement through app_lea_bsrc_config(), and create BIG through app_lea_bsrc_establish(). When the broadcast source successfully transitions to the BROADCAST_SOURCE_STATE_STREAMING state (the state changed event could be notified in app_lea_bsrc_sm_cb() through with MSG_BROADCAST_SOURCE_STATE_CHANGE message), the data path will be established by calling broadcast_source_setup_data_path().

void app_lea_bsrc_sm_cb(T_BROADCAST_SOURCE_HANDLE handle, uint8_t cb_type, void *p_cb_data)
{
    ...
    switch (cb_type)
    {
    case MSG_BROADCAST_SOURCE_STATE_CHANGE:
        {
            APP_PRINT_INFO2("MSG_BROADCAST_SOURCE_STATE_CHANGE: state %d, cause 0x%x",
                            p_sm_data->p_state_change->state,
                            p_sm_data->p_state_change->cause);
            app_db.bsrc_db.state = p_sm_data->p_state_change->state;
            app_lea_bsrc_target_state();
            if (p_sm_data->p_state_change->state == BROADCAST_SOURCE_STATE_STREAMING &&
                p_sm_data->p_state_change->cause == GAP_SUCCESS)
            {
                uint8_t codec_id[5] = {LC3_CODEC_ID, 0, 0, 0, 0};
                for (uint8_t i = 0; i < app_db.bsrc_db.group1_bis_num; i++)
                {
                    broadcast_source_setup_data_path(app_db.bsrc_db.source_handle, i + 1,
                                                     codec_id, 0, 0, NULL);
                }
            }
        }
        break;
    ...
    }
}

Once the data path is successfully established, notifications will also be received in app_lea_bsrc_sm_cb() with the message of MSG_BROADCAST_SOURCE_SETUP_DATA_PATH. In the app_lea_handle_bis_data_path_setup() function, data path information is processed and stored in the form of T_APP_LEA_ISO_CHANN. Other modules, such as the source play module, can utilize this information to specify the format for creating audio tracks. This enables data from sources like MIC, line-in, or USB to be transmitted via BIS.

void app_lea_bsrc_sm_cb(T_BROADCAST_SOURCE_HANDLE handle, uint8_t cb_type, void *p_cb_data)
{
    ...
    switch (cb_type)
    {
    case MSG_BROADCAST_SOURCE_SETUP_DATA_PATH:
        {
            APP_PRINT_INFO2("MSG_BROADCAST_SOURCE_SETUP_DATA_PATH: bis_idx %d, cause 0x%x",
                            p_sm_data->p_setup_data_path->bis_idx,
                            p_sm_data->p_setup_data_path->cause);
            if (p_sm_data->p_setup_data_path->cause == GAP_SUCCESS)
            {
                T_LEA_SETUP_DATA_PATH data = {0};

                data.iso_mode = BIG_ISO_MODE;
                data.iso_conn_handle = p_sm_data->p_setup_data_path->bis_conn_handle;
                data.path_direction = DATA_PATH_INPUT_FLAG;
                data.presentation_delay = app_db.bsrc_db.prefer_qos.presentation_delay;
                memcpy(&data.codec_parsed_data, &app_db.bsrc_db.codec_cfg, sizeof(T_CODEC_CFG));
                if (app_db.bsrc_db.cfg_bis_num == 1)
                {
                    data.codec_parsed_data.audio_channel_allocation = AUDIO_LOCATION_SIL | AUDIO_LOCATION_SIR;
                }
                else if (app_db.bsrc_db.cfg_bis_num == 2)
                {
                    if (p_sm_data->p_setup_data_path->bis_idx == 1)
                    {
                        data.codec_parsed_data.audio_channel_allocation = AUDIO_LOCATION_SIL;
                    }
                    else if (p_sm_data->p_setup_data_path->bis_idx == 2)
                    {
                        data.codec_parsed_data.audio_channel_allocation = AUDIO_LOCATION_SIR;
                    }
                }
                app_lea_handle_bis_data_path_setup(&data);
            }
        }
        break;
    ...
    }
}
void app_lea_handle_bis_data_path_setup(T_LEA_SETUP_DATA_PATH *p_data)
{
    T_APP_LEA_ISO_CHANN *p_iso_chann = app_lea_find_iso_chann(p_data->iso_conn_handle,
                                                              p_data->path_direction);
    uint8_t chnl_cnt;
    uint8_t blocks_num = 1;

    if (p_iso_chann != NULL)
    {
        APP_PRINT_WARN0("app_lea_handle_bis_data_path_setup: iso channel already exist");
        return;
    }
    else
    {
        p_iso_chann = app_lea_add_iso_chann(p_data->iso_conn_handle,
                                            p_data->path_direction);
        if (p_iso_chann == NULL)
        {
            return;
        }
        p_iso_chann->iso_mode = p_data->iso_mode;
    }
    p_iso_chann->codec_data = p_data->codec_parsed_data;
    p_iso_chann->presentation_delay = p_data->presentation_delay;
    p_iso_chann->time_stamp = 0;
    p_iso_chann->pkt_seq_num = 0;
    if (p_iso_chann->codec_data.audio_channel_allocation == AUDIO_LOCATION_MONO)
    {
        chnl_cnt = 1;
    }
    else
    {
        chnl_cnt = __builtin_popcount(p_iso_chann->codec_data.audio_channel_allocation);
    }
    if (p_iso_chann->codec_data.type_exist & CODEC_CFG_TYPE_BLOCKS_PER_SDU_EXIST)
    {
        blocks_num = p_iso_chann->codec_data.codec_frame_blocks_per_sdu;
    }
    p_iso_chann->frame_num = blocks_num * chnl_cnt;

    APP_PRINT_INFO7("app_lea_handle_bis_data_path_setup: iso handle 0x%04x, frame_num %d, "
                    "dir %u, sample_frequency 0x%x, audio_channel_allocation 0x%08x, presentation_delay 0x%x, chnl_cnt %d",
                    p_iso_chann->iso_conn_handle, p_iso_chann->frame_num,
                    p_iso_chann->path_direction,
                    p_iso_chann->codec_data.sample_frequency,
                    p_iso_chann->codec_data.audio_channel_allocation,
                    p_iso_chann->presentation_delay,
                    chnl_cnt);

    if (p_data->path_direction == DATA_PATH_INPUT_FLAG)
    {
        if (app_db.bsrc_db.cfg_bis_num == app_db.iso_input_queue.count)
        {
            app_lea_save_data_format(p_iso_chann);
#if F_APP_A2DP_XMIT_SRC_LEA_SUPPORT
            app_a2dp_xmit_lea_pipe_rcfg();
#endif
        }
    }
}
Broadcast Data

Using the app_lea_iso_data_send() API, data can be transmitted via BIS or CIS. The ext_flag is used to specify whether to include ts (timestamp) and seq (sequence) parameters. Typically, when the data source is a MIC, line-in, or USB, the ts and seq values from the registered callback in the audio track will be used.

void app_lea_iso_data_send(uint8_t *p_data, uint16_t len, bool ext_flag, uint32_t ts, uint16_t seq)
{
    T_GAP_CAUSE cause = GAP_CAUSE_SUCCESS;
    T_APP_LEA_ISO_CHANN *p_iso_chann = NULL;
    uint8_t chnl_cnt = 0;
    uint32_t time_stamp = 0;
    uint16_t seq_num = 0;

    uint32_t s = os_lock();
    for (uint8_t i = 0; i < app_db.iso_input_queue.count; i++)
    {
        p_iso_chann = (T_APP_LEA_ISO_CHANN *)os_queue_peek(&app_db.iso_input_queue, i);

        if (p_iso_chann->codec_data.audio_channel_allocation == AUDIO_LOCATION_MONO)
        {
            chnl_cnt = 1;
        }
        else
        {
            chnl_cnt = __builtin_popcount(p_iso_chann->codec_data.audio_channel_allocation);
        }
        if (ext_flag)
        {
            time_stamp = ts;
            seq_num = seq;
        }
        else
        {
            time_stamp = (p_iso_chann->time_stamp + p_iso_chann->pkt_seq_num) *
                         (p_iso_chann->sdu_interval);
            seq_num = p_iso_chann->pkt_seq_num;
        }


        if (chnl_cnt == 2)
        {
            cause = gap_iso_send_data(p_data,
                                      p_iso_chann->iso_conn_handle,
                                      len,
                                      false,
                                      time_stamp,
                                      seq_num);

        }
        else if (chnl_cnt == 1)
        {
            if (p_iso_chann->codec_data.audio_channel_allocation & (AUDIO_LOCATION_FL |
                                                                    AUDIO_LOCATION_SIL))
            {
                cause = gap_iso_send_data(p_data,
                                          p_iso_chann->iso_conn_handle,
                                          len / 2,
                                          0,
                                          time_stamp,
                                          seq_num);
            }
            else
            {
                cause = gap_iso_send_data(p_data + (len / 2),
                                          p_iso_chann->iso_conn_handle,
                                          len / 2,
                                          0,
                                          time_stamp,
                                          seq_num);
            }
        }
        p_iso_chann->pkt_seq_num++;
        if (cause != GAP_CAUSE_SUCCESS)
        {
            APP_PRINT_ERROR1("app_lea_iso_data_send: failed, cause 0x%x", cause);
        }
    }
    os_unlock(s);
    return;
}

LE Audio Initiator - CIS

Bluetooth Low Energy Audio CAP roles can be divided into Acceptor, Initiator, and Commander. In transmitter applications, Initiator role is supported, which can transmit BIS or transmit and receive CIS.

In this chapter, the design SPEC for CIS will be presented.

Initialization

Initialization is performed through the function of app_lea_profile_init(), including configuration of LE Audio parameters, initialization of BAP and CAP, as well as the necessary data processing setup.

//app_lea_ini_profile.c

void app_lea_profile_init(void)
{
    T_BLE_AUDIO_PARAMS ble_audio_param = {0};
    ble_audio_param.evt_queue_handle = audio_evt_queue_handle;
    ble_audio_param.io_queue_handle = audio_io_queue_handle;
    ble_audio_param.bt_gatt_client_init = (GATT_CLIENT_DISCOV_MODE_REG_SVC_BIT |
                                           GATT_CLIENT_DISCOV_MODE_CCCD_STORAGE_BIT |
                                           GATT_CLIENT_DISCOV_MODE_USE_EXT_CLIENT);
    ble_audio_param.acl_link_num = MAX_BLE_LINK_NUM;
    ble_audio_param.io_event_type = IO_MSG_TYPE_LE_AUDIO;
    ble_audio_init(&ble_audio_param);
    app_lea_ini_bap_init();
    app_lea_ini_cap_init();
    app_lea_audio_data_init();
}
Connect to LE Audio Device

The Initiator initiates scan by using app_lea_ini_scan_start() to scan for nearby LE Audio devices and reports them to the ACI Host.

// start scanning
void app_lea_ini_scan_start(void)
{
    APP_PRINT_INFO0("app_ble_scan_start");
    BLE_SCAN_PARAM param;

    param.own_addr_type = GAP_LOCAL_ADDR_LE_PUBLIC;
    param.phys = GAP_EXT_SCAN_PHYS_1M_BIT;
    param.ext_filter_policy = GAP_SCAN_FILTER_ANY;
    param.ext_filter_duplicate = GAP_SCAN_FILTER_DUPLICATE_ENABLE;

    param.scan_param_1m.scan_type = GAP_SCAN_MODE_PASSIVE;
    param.scan_param_1m.scan_interval = 0x140;
    param.scan_param_1m.scan_window = 0xD0;

    param.scan_param_coded.scan_type = GAP_SCAN_MODE_PASSIVE;
    param.scan_param_coded.scan_interval = 0x0050;
    param.scan_param_coded.scan_window = 0x0025;

    if (ble_scan_start(&app_lea_ini_scan_handle, app_lea_ini_scan_cb, &param, NULL))
    {
        app_lea_clear_scan_dev();
    }
}
// report scanned devices to ACI Host
void app_lea_ini_scan_report(T_LE_EXT_ADV_REPORT_INFO *p_report)
{
    T_APP_LEA_ADV_DATA lea_data = {0};
    T_APP_LEA_SCAN_DEV *p_dev;
    APP_PRINT_INFO3("app_lea_ini_scan_report: event_type 0x%x, bd_addr %s, addr_type %d",
                    p_report->event_type,
                    TRACE_BDADDR(p_report->bd_addr),
                    p_report->addr_type);
    p_dev = app_lea_find_scan_dev(p_report->bd_addr, p_report->addr_type);

    if (p_dev)
    {
        return;
    }
    app_lea_ini_scan_data_parse(p_report->data_len, p_report->p_data, &lea_data);
    if (lea_data.adv_data_flags)
    {

        APP_PRINT_INFO5("app_lea_ini_scan_report: adv_data_flags 0x%x, ascs(type %d, sink 0x%x, source 0x%x), cap(type %d)",
                        lea_data.adv_data_flags,
                        lea_data.ascs_announcement_type,
                        lea_data.ascs_sink_available_contexts,
                        lea_data.ascs_source_available_contexts,
                        lea_data.cap_announcement_type);
        app_lea_add_scan_dev(p_report->bd_addr, p_report->addr_type, &lea_data);
        app_lea_ini_scan_report_result(p_report->event_type,
                                       p_report->bd_addr,
                                       p_report->addr_type,
                                       &lea_data);
#if CSIP_SET_COORDINATOR
        if (lea_data.adv_data_flags & APP_LEA_ADV_DATA_RSI_BIT)
        {
            set_coordinator_check_adv_rsi(p_report->data_len, p_report->p_data,
                                          p_report->bd_addr, p_report->addr_type);
        }
#endif
    }
}

On the ACI Host side, initiate the establishment of an LE connection by invoking the app_lea_create_conn() API using the CMD_LE_CREATE_CONN command.

void app_cmd_ble_handle(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t app_idx,
                        uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
        case CMD_LE_CREATE_CONN:
        {
            ...
#if F_APP_LE_AUDIO_INITIATOR_SUPPORT
            T_GAP_CAUSE gap_cause = app_lea_create_conn(CMD->remote_bd,
                                                        (T_GAP_REMOTE_ADDR_TYPE)CMD->remote_bd_type);
#else
            T_GAP_CAUSE gap_cause = le_connect(CMD->init_phys, CMD->remote_bd,
                                               (T_GAP_REMOTE_ADDR_TYPE)CMD->remote_bd_type,
                                               (T_GAP_LOCAL_ADDR_TYPE)CMD->local_bd_type, CMD->scan_timeout);

            APP_PRINT_TRACE5("app_cmd_ble_handle: init_phys %d, remote_bd_type %d, remote_bd %s, local_bd_type %d, scan_timeout %d",
                             CMD->init_phys, CMD->remote_bd_type, TRACE_BDADDR(CMD->remote_bd), CMD->local_bd_type,
                             CMD->scan_timeout);
#endif
            ((ACK_PKT)ack_pkt)->status = (uint16_t)gap_cause;
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
        ...
    }
    ...
}

If the remote device supports coordinate set and belongs to a group of devices, the Initiator will continue to scan for other devices in that group and automatically establish connections. The coordinated set information is reported in LE_AUDIO_MSG_CSIS_CLIENT_READ_RESULT message.

uint16_t app_lea_ini_csis_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
    uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;

    switch (msg)
    {
    case LE_AUDIO_MSG_CSIS_CLIENT_READ_RESULT:
        {
            ...
            // check if there are more members in the group and start scanning again
            if (p_read_result->mem_info.set_mem_size > 1 &&
                app_link_get_le_link_num() < p_read_result->mem_info.set_mem_size)
            {
                app_lea_group_scan_start(group_handle);
            }
        }
        break;
    ...
    }
    ...
}
CIS Media

For a unicast stream, there are eight different streaming states defined as below.

typedef enum
{
    AUDIO_STREAM_STATE_IDLE               = 0x00,   /**< Available API: bap_unicast_audio_cfg */
    AUDIO_STREAM_STATE_IDLE_CONFIGURED    = 0x01,   /**< Available API: bap_unicast_audio_start, bap_unicast_audio_remove_cfg */
    AUDIO_STREAM_STATE_CONFIGURED         = 0x02,   /**< Available API: bap_unicast_audio_start, bap_unicast_audio_release */
    AUDIO_STREAM_STATE_STARTING           = 0x03,   /**< Available API: bap_unicast_audio_stop, bap_unicast_audio_release */
    AUDIO_STREAM_STATE_STREAMING          = 0x04,   /**< Available API: bap_unicast_audio_stop, bap_unicast_audio_release,
                                                         bap_unicast_audio_update */
    AUDIO_STREAM_STATE_PARTIAL_STREAMING  = 0x05,   /**< Available API: bap_unicast_audio_stop, bap_unicast_audio_release,
                                                         bap_unicast_audio_update */
    AUDIO_STREAM_STATE_STOPPING           = 0x06,   /**< Available API: bap_unicast_audio_release */
    AUDIO_STREAM_STATE_RELEASING          = 0x07,
} T_AUDIO_STREAM_STATE;

The changes in the stream state will be notified through AUDIO_GROUP_MSG_BAP_STATE message in app_lea_ini_group_cb() and relayed to ACI Host.

void app_lea_ini_group_cb(T_AUDIO_GROUP_MSG msg, T_BLE_AUDIO_GROUP_HANDLE handle,
                          void *buf)
{
    T_APP_RESULT result = APP_RESULT_SUCCESS;
    T_APP_LEA_GROUP_INFO *p_group = app_lea_find_group(handle);
    switch (msg)
    {
        ...
        case AUDIO_GROUP_MSG_BAP_STATE:
        {
            T_AUDIO_GROUP_BAP_STATE *p_data = (T_AUDIO_GROUP_BAP_STATE *)buf;
            APP_PRINT_INFO6("AUDIO_GROUP_MSG_BAP_STATE: group handle 0x%x, session handle 0x%x, curr_action %d, state %d, result %d, cause 0x%x",
                            handle, p_data->handle, p_data->curr_action,
                            p_data->state, p_data->result, p_data->cause);

            struct
            {
                void *group_handle;
                uint8_t state;
            } __attribute__((packed)) rpt = {};
            rpt.group_handle = handle;
            rpt.state = p_data->state;
            app_report_event(CMD_PATH_UART, EVENT_LE_AUDIO_BAP_STATE, 0, (uint8_t *)&rpt,
                             sizeof(rpt));

            if (p_group != NULL && p_group->lea_unicast.session_handle == p_data->handle)
            {
                p_group->lea_unicast.bap_state = p_data->state;
                if ((p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_IDLE ||
                     p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_IDLE_CONFIGURED) &&
                    p_group->lea_unicast.release_req == true)
                {
                    bap_unicast_audio_remove_session(p_group->lea_unicast.session_handle);
                }
            }
        }
        break;
        ...
    }
}

To transmit media via CIS, users can invoke app_lea_ini_cis_media_start() to transition the stream state to AUDIO_STREAM_STATE_STREAMING.

bool app_lea_ini_cis_media_start(uint8_t group_idx)
{
    bool ret = false;

    if (group_idx < app_db.group_handle_queue.count)
    {
        T_APP_LEA_GROUP_INFO *p_group = (T_APP_LEA_GROUP_INFO *)os_queue_peek(&app_db.group_handle_queue,
                                                                              group_idx);
        if (p_group)
        {
            ret = app_lea_ini_start_media(p_group->group_handle);
        }
    }

    return ret;
}

Specifically, the function will invoke:

  1. app_lea_ini_select_media_prefer_codec() API to choose the codec type.

  2. bap_unicast_audio_cfg() API to set unicast audio configuration.

  3. app_lea_ini_config_codec() API to configure ASE codec.

  4. bap_unicast_audio_start() API to create CIS and set up data path.

    static bool app_lea_ini_start_media(T_BLE_AUDIO_GROUP_HANDLE group_handle)
    {
        T_APP_LEA_GROUP_INFO *p_group;
        uint8_t err_idx = 0;
    
        p_group = app_lea_find_group(group_handle);
        if (p_group)
        {
            if (app_lea_ini_ready_to_start(p_group, AUDIO_CONTEXT_MEDIA, 0))
            {
                if (p_group->lea_unicast.session_handle == NULL)
                {
                    p_group->lea_unicast.session_handle = audio_stream_session_allocate(p_group->group_handle);
                    if (p_group->lea_unicast.session_handle == NULL)
                    {
                        err_idx = 1;
                        goto failed;
                    }
                    p_group->lea_unicast.bap_state = AUDIO_STREAM_STATE_IDLE;
                    p_group->lea_unicast.contexts_type = AUDIO_CONTEXT_MEDIA;
                    p_group->lea_unicast.target_latency = ASE_TARGET_HIGHER_RELIABILITY;
                }
    
                if (p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_IDLE)
                {
                    if (app_lea_ini_select_media_prefer_codec(p_group) == false)
                    {
                        err_idx = 2;
                        goto failed;
                    }
                    if (bap_unicast_audio_cfg(p_group->lea_unicast.session_handle, p_group->lea_unicast.cfg_type,
                                            p_group->lea_unicast.dev_num, p_group->lea_unicast.dev_tbl) == false)
                    {
                        err_idx = 3;
                        goto failed;
                    }
                    if (app_lea_ini_config_codec(p_group) == false)
                    {
                        err_idx = 4;
                        goto failed;
                    }
                    if (bap_unicast_audio_start(p_group->lea_unicast.session_handle) == false)
                    {
                        err_idx = 5;
                        goto failed;
                    }
                }
                else if (p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_IDLE_CONFIGURED ||
                        p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_CONFIGURED)
                {
                    if (p_group->lea_unicast.contexts_type != AUDIO_CONTEXT_MEDIA)
                    {
                        err_idx = 6;
                        goto failed;
                    }
                    if (bap_unicast_audio_start(p_group->lea_unicast.session_handle) == false)
                    {
                        err_idx = 7;
                        goto failed;
                    }
                }
                else
                {
                    err_idx = 8;
                    goto failed;
                }
            }
            else
            {
                err_idx = 9;
                goto failed;
            }
        }
        else
        {
            err_idx = 10;
            goto failed;
        }
        return true;
    failed:
        APP_PRINT_ERROR2("app_lea_ini_start_media: failed, group_handle 0x%x, err_idx %d",
                        group_handle, err_idx);
        return false;
    }
    

Once the data path is successfully established, notifications will also be received in app_lea_ini_group_cb() with the message of AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH. In the app_lea_handle_cis_data_path_setup() function, data path information is processed and stored in the form of T_APP_LEA_ISO_CHANN. Other modules, such as the source play module, can utilize this information to specify the format for creating an audio track. This enables data from sources like MIC, line-in, or USB to be transmitted via CIS.

void app_lea_ini_group_cb(T_AUDIO_GROUP_MSG msg, T_BLE_AUDIO_GROUP_HANDLE handle,
                          void *buf)
{
    T_APP_RESULT result = APP_RESULT_SUCCESS;
    T_APP_LEA_GROUP_INFO *p_group = app_lea_find_group(handle);
    switch (msg)
    {
        ...
        case AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH:
        {
            T_AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH *p_data = (T_AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH *)buf;
            APP_PRINT_INFO6("AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH: group handle 0x%x, session handle 0x%x, dev_handle 0x%x, ase_id 0x%x, direction %d, cis_conn_handle 0x%x",
                            handle, p_data->handle,
                            p_data->dev_handle,
                            p_data->ase_id,
                            p_data->path_direction,
                            p_data->cis_conn_handle);
            T_LEA_SETUP_DATA_PATH data = {0};
            data.iso_mode = CIG_ISO_MODE;
            data.iso_conn_handle = p_data->cis_conn_handle;
            data.codec_parsed_data = p_data->codec_parsed_data;
            data.path_direction = p_data->path_direction;
            if (p_group != NULL && p_group->lea_unicast.session_handle == p_data->handle)
            {
                T_AUDIO_SESSION_QOS_CFG qos_cfg;
                if (bap_unicast_audio_get_session_qos(p_group->lea_unicast.session_handle, &qos_cfg))
                {
                    if (p_data->path_direction == DATA_PATH_INPUT_FLAG)
                    {
                        data.presentation_delay = qos_cfg.sink_presentation_delay;
                    }
                    else
                    {
                        data.presentation_delay = qos_cfg.source_presentation_delay;
                    }
                }
            }
            app_lea_handle_cis_data_path_setup(&data);
        }
        break;
        ...
    }
}
void app_lea_handle_cis_data_path_setup(T_LEA_SETUP_DATA_PATH *p_data)
{
    T_APP_LEA_ISO_CHANN *p_iso_chann = app_lea_find_iso_chann(p_data->iso_conn_handle,
                                                              p_data->path_direction);

    if (p_iso_chann != NULL)
    {
        APP_PRINT_WARN0("app_lea_handle_cis_data_path_setup: iso channel already exist");
        return;
    }
    else
    {
        if (p_data->path_direction == DATA_PATH_INPUT_FLAG)
        {
            p_iso_chann = app_lea_add_iso_pending_chann(p_data->iso_conn_handle,
                                                        p_data->path_direction);
        }
        else
        {
            p_iso_chann = app_lea_add_iso_chann(p_data->iso_conn_handle,
                                                p_data->path_direction);

        }

        if (p_iso_chann == NULL)
        {
            return;
        }
        p_iso_chann->iso_mode = p_data->iso_mode;
    }
    p_iso_chann->codec_data = p_data->codec_parsed_data;
    p_iso_chann->presentation_delay = p_data->presentation_delay;
    p_iso_chann->time_stamp = 0;
    p_iso_chann->pkt_seq_num = 0;
    p_iso_chann->frame_num = app_lea_get_frame_num(p_iso_chann);
    //lea src
    if (p_data->path_direction == DATA_PATH_INPUT_FLAG)
    {
        uint8_t current_iso_cnt = app_db.input_path_pending_q.count + app_db.iso_input_queue.count;
        uint8_t link_num = app_link_get_le_link_num();
        APP_PRINT_INFO3("app_lea_handle_cis_data_path_setup: current_iso_cnt %d conn_dev %d, link_num %d",
                        current_iso_cnt,
                        app_db.conn_dev_queue.count,
                        link_num);
        if (current_iso_cnt >= link_num)
        {
            uint8_t i;
            uint8_t n = app_db.input_path_pending_q.count;

            APP_PRINT_INFO1("handle_cis_data_path_setup_cmplt_msg: pending num %u",
                            app_db.input_path_pending_q.count);
            for (i = 0; i < n; i++)
            {
                p_iso_chann = (T_APP_LEA_ISO_CHANN *)os_queue_out(&app_db.input_path_pending_q);
                APP_PRINT_INFO2("app_lea_handle_cis_data_path_setup: adding path handle %u curr_num %x",
                                p_iso_chann->iso_conn_handle,
                                app_db.iso_input_queue.count);
                os_queue_in(&app_db.iso_input_queue, (void *)p_iso_chann);
            }
            app_lea_save_data_format(p_iso_chann);
        }
    }
    APP_PRINT_INFO6("app_lea_handle_cis_data_path_setup: iso handle 0x%04x, frame_num %d, "
                    "dir %u, sample_frequency 0x%x, audio_channel_allocation 0x%08x, presentation_delay 0x%x",
                    p_iso_chann->iso_conn_handle, p_iso_chann->frame_num,
                    p_iso_chann->path_direction,
                    p_iso_chann->codec_data.sample_frequency,
                    p_iso_chann->codec_data.audio_channel_allocation,
                    p_iso_chann->presentation_delay);
}
CIS Conversation

Differing from CIS media, CIS Conversation both transmits and receives data streams. However, what is similar is that they share the stream state defined by unicast stream, which can be referenced in chapter CIS Media for an introduction to stream states.

To transmit and receive audio stream via CIS, users can invoke app_lea_ini_start_conversation() to transition the stream state to AUDIO_STREAM_STATE_STREAMING. Specifically, the function will invoke:

  1. app_lea_ini_select_conversation_prefer_codec() API to choose the codec type.

  2. bap_unicast_audio_cfg() API to set unicast audio configuration.

  3. app_lea_ini_config_codec() API to configure ASE codec.

  4. bap_unicast_audio_start() API to create CIS and set up data path(s).

    bool app_lea_ini_start_conversation(T_BLE_AUDIO_GROUP_HANDLE group_handle)
    {
        T_APP_LEA_GROUP_INFO *p_group;
        uint8_t err_idx = 0;
    
        p_group = app_lea_find_group(group_handle);
        if (p_group)
        {
            if (app_lea_ini_ready_to_start(p_group, AUDIO_CONTEXT_CONVERSATIONAL, AUDIO_CONTEXT_CONVERSATIONAL))
            {
                if (p_group->lea_unicast.session_handle == NULL)
                {
                    p_group->lea_unicast.session_handle = audio_stream_session_allocate(p_group->group_handle);
                    if (p_group->lea_unicast.session_handle == NULL)
                    {
                        err_idx = 1;
                        goto failed;
                    }
                    p_group->lea_unicast.bap_state = AUDIO_STREAM_STATE_IDLE;
                    p_group->lea_unicast.contexts_type = AUDIO_CONTEXT_CONVERSATIONAL;
                    p_group->lea_unicast.target_latency = ASE_TARGET_LOWER_LATENCY;
                }
    
                if (p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_IDLE)
                {
                    if (app_lea_ini_select_conversation_prefer_codec(p_group) == false)
                    {
                        err_idx = 2;
                        goto failed;
                    }
                    if (bap_unicast_audio_cfg(p_group->lea_unicast.session_handle, p_group->lea_unicast.cfg_type,
                                            p_group->lea_unicast.dev_num, p_group->lea_unicast.dev_tbl) == false)
                    {
                        err_idx = 3;
                        goto failed;
                    }
                    if (app_lea_ini_config_codec(p_group) == false)
                    {
                        err_idx = 4;
                        goto failed;
                    }
                    if (bap_unicast_audio_start(p_group->lea_unicast.session_handle) == false)
                    {
                        err_idx = 5;
                        goto failed;
                    }
                }
                else if (p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_IDLE_CONFIGURED ||
                        p_group->lea_unicast.bap_state == AUDIO_STREAM_STATE_CONFIGURED)
                {
                    if (p_group->lea_unicast.contexts_type != AUDIO_CONTEXT_CONVERSATIONAL)
                    {
                        err_idx = 6;
                        goto failed;
                    }
                    if (bap_unicast_audio_start(p_group->lea_unicast.session_handle) == false)
                    {
                        err_idx = 7;
                        goto failed;
                    }
                }
                else
                {
                    err_idx = 8;
                    goto failed;
                }
            }
            else
            {
                err_idx = 9;
                goto failed;
            }
        }
        else
        {
            err_idx = 10;
            goto failed;
        }
        return true;
    failed:
        APP_PRINT_ERROR2("app_lea_ini_start_conversation: failed, group_handle 0x%x, err_idx %d",
                        group_handle, err_idx);
        return false;
    }
    

Similar to CIS Media, once the data path is successfully established, notifications will also be received in app_lea_ini_group_cb() with the message of AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH. In the app_lea_handle_cis_data_path_setup() function, data path information is processed and stored in the form of T_APP_LEA_ISO_CHANN.

Unlike CIS Media, CIS Conversation establishes both an input-direction data path for sending data and an output-direction data path for receiving data (The direction is defined from the perspective of the lower stack).

Unicast Data

CIS, similar to BIS, utilize the API app_lea_iso_data_send() to send data. Please refer to Broadcast Data for more details.

For CIS Conversation, data reception is also a part of its functionality. Data is reported through the registered app_lea_data_direct_cb(), allowing further data processing within this function.

void app_lea_data_direct_cb(uint8_t cb_type, void *p_cb_data)
{
    T_BT_DIRECT_CB_DATA *p_data = (T_BT_DIRECT_CB_DATA *)p_cb_data;

    switch (cb_type)
    {
    case BT_DIRECT_MSG_ISO_DATA_IND:
        {
#if 0
            APP_PRINT_TRACE5("app_lea_data_direct_cb: conn_handle 0x%x, iso_sdu_len %d, pkt_seq_num 0x%x, time_stamp 0x%x, pkt_status_flag 0x%x",
                            p_data->p_bt_direct_iso->conn_handle, p_data->p_bt_direct_iso->iso_sdu_len,
                            p_data->p_bt_direct_iso->pkt_seq_num, p_data->p_bt_direct_iso->time_stamp,
                            p_data->p_bt_direct_iso->pkt_status_flag);
#endif
#if 0
            uint8_t *p_iso_data = p_data->p_bt_direct_iso->p_buf + p_data->p_bt_direct_iso->offset;
            APP_PRINT_INFO5("app_lea_data_direct_cb: BT_DIRECT_MSG_ISO_DATA_IND, iso_sdu_len 0x%x, p_buf %p, offset %d, p_data %p, data %b",
                            p_data->p_bt_direct_iso->iso_sdu_len, p_data->p_bt_direct_iso->p_buf,
                            p_data->p_bt_direct_iso->offset, p_iso_data, TRACE_BINARY(p_data->p_bt_direct_iso->iso_sdu_len,
                                                                                    p_iso_data));
#endif
            APP_PRINT_TRACE5("app_lea_data_direct_cb: conn_handle 0x%x, iso_sdu_len %d, pkt_seq_num 0x%x, time_stamp 0x%x, pkt_status_flag 0x%x",
                            p_data->p_bt_direct_iso->conn_handle, p_data->p_bt_direct_iso->iso_sdu_len,
                            p_data->p_bt_direct_iso->pkt_seq_num, p_data->p_bt_direct_iso->time_stamp,
                            p_data->p_bt_direct_iso->pkt_status_flag);

            if (p_data->p_bt_direct_iso->pkt_status_flag != ISOCH_DATA_PKT_STATUS_VALID_DATA)
            {
                gap_iso_data_cfm(p_data->p_bt_direct_iso->p_buf);
                break;
            }

            T_APP_LEA_ISO_CHANN *p_iso_chann = app_lea_find_iso_chann(p_data->p_bt_direct_iso->conn_handle,
                                                                    DATA_PATH_OUTPUT_FLAG);
            if (p_iso_chann != NULL)
            {
#if 0
                //Just for sample. Application can send the data to DSP.
                uint16_t written_len;
                T_AUDIO_STREAM_STATUS status;

                if (p_data->p_bt_direct_iso->iso_sdu_len != 0)
                {
                    status = AUDIO_STREAM_STATUS_CORRECT;
                }
                else
                {
                    status = AUDIO_STREAM_STATUS_LOST;
                }
                audio_track_write(handle, p_data->p_bt_direct_iso->time_stamp,
                                p_data->p_bt_direct_iso->pkt_seq_num,
                                status,
                                p_iso_chann->frame_num,
                                p_data->p_bt_direct_iso->p_buf + p_data->p_bt_direct_iso->offset,
                                p_data->p_bt_direct_iso->iso_sdu_len,
                                &written_len);
#endif
            }

            gap_iso_data_cfm(p_data->p_bt_direct_iso->p_buf);
        }
        break;

    default:
        APP_PRINT_ERROR1("app_lea_data_direct_cb: unhandled cb_type 0x%x", cb_type);
        break;
    }
}

Bluetooth Audio Receiver

A2DP Sink

A2DP Profile Initialization

bt_a2dp_init() is utilized in app_a2dp_init() to initialize the A2DP profile and configure the maximum number of remote devices and A2DP latency. A2DP latency is used to enable synchronization of audio and video playback by reporting SNK delay values caused by buffering, decoding, and rendering.

bt_a2dp_role_set() is utilized to set the Sink or Source of the A2DP role.

bt_a2dp_stream_endpoint_add() is utilized to add an A2DP stream endpoint.

void app_a2dp_init(void)
{
    if (app_cfg_const.supported_profile_mask & A2DP_PROFILE_MASK)
    {
        bt_a2dp_init(app_cfg_const.a2dp_link_number, A2DP_LATENCY_MS);

#if (F_APP_A2DP_SOURCE_SUPPORT || F_APP_A2DP_XMIT_SRC_SUPPORT || F_SOURCE_PLAY_SUPPORT)
        bt_a2dp_role_set(BT_A2DP_ROLE_SRC);
#else
        bt_a2dp_role_set(BT_A2DP_ROLE_SNK);
#endif
        if (app_cfg_const.a2dp_codec_type_sbc)
        {
            T_BT_A2DP_STREAM_ENDPOINT sep;

            sep.codec_type = BT_A2DP_CODEC_TYPE_SBC;
            sep.u.codec_sbc.sampling_frequency_mask = app_cfg_const.sbc_sampling_frequency;
            sep.u.codec_sbc.channel_mode_mask = app_cfg_const.sbc_channel_mode;
            sep.u.codec_sbc.block_length_mask = app_cfg_const.sbc_block_length;
            sep.u.codec_sbc.subbands_mask = app_cfg_const.sbc_subbands;
            sep.u.codec_sbc.allocation_method_mask = app_cfg_const.sbc_allocation_method;
            sep.u.codec_sbc.min_bitpool = app_cfg_const.sbc_min_bitpool;
            sep.u.codec_sbc.max_bitpool = app_cfg_const.sbc_max_bitpool;

            bt_a2dp_stream_endpoint_add(sep);
        }

        if (app_cfg_const.a2dp_codec_type_aac)
        {
            T_BT_A2DP_STREAM_ENDPOINT sep;

            sep.codec_type = BT_A2DP_CODEC_TYPE_AAC;
            sep.u.codec_aac.object_type_mask = app_cfg_const.aac_object_type;
            sep.u.codec_aac.sampling_frequency_mask = app_cfg_const.aac_sampling_frequency;
            sep.u.codec_aac.channel_number_mask = app_cfg_const.aac_channel_number;
            sep.u.codec_aac.vbr_supported = app_cfg_const.aac_vbr_supported;
            sep.u.codec_aac.bit_rate = app_cfg_const.aac_bit_rate;
            bt_a2dp_stream_endpoint_add(sep);
        }

#if F_APP_A2DP_CODEC_LDAC_SUPPORT
        if (app_cfg_const.a2dp_codec_type_ldac)
        {
            T_BT_A2DP_STREAM_ENDPOINT sep;

            sep.codec_type = BT_A2DP_CODEC_TYPE_LDAC;
            sep.u.codec_ldac.sampling_frequency_mask = app_cfg_const.ldac_sampling_frequency;
            sep.u.codec_ldac.channel_mode_mask = app_cfg_const.ldac_channel_mode;
            bt_a2dp_stream_endpoint_add(sep);
        }
#endif

        bt_mgr_cback_register(app_a2dp_bt_cback);
    }
A2DP Connect

In linkback_profile_search_start(), the function gap_br_start_sdp_discov() will first be called to discover A2DP SDP according to A2DP Sink’s UUID.

bool linkback_profile_search_start(uint8_t *bd_addr, uint32_t prof, bool is_special)
{
    bool ret = true;
    T_GAP_UUID_DATA uuid;
    T_GAP_UUID_TYPE uuid_type = GAP_UUID16;
    ...
    switch (prof)
    {
    ...
    case A2DP_SINK_PROFILE_MASK:
        {
            uuid.uuid_16 = UUID_AUDIO_SINK;
        }
        break;
    ...
    if (ret)
    {
        if (gap_br_start_sdp_discov(bd_addr, uuid_type, uuid) != GAP_CAUSE_SUCCESS)
        {
            ret = false;
        }
    }

    return ret;
}

Then, A2DP Sink will initiate profile connection by bt_a2dp_connect_req().

bool linkback_profile_connect_start(uint8_t *bd_addr, uint32_t prof, T_LINKBACK_CONN_PARAM *param)
{
    bool ret = true;
    ...
    switch (prof)
    {
    case A2DP_PROFILE_MASK:
        ret = bt_a2dp_connect_req(bd_addr, param->protocol_version);
        break;
    ...
    return ret;
}

For A2DP Sink, app_a2dp_bt_cback() function is used to handle Bluetooth Manager A2DP Sink-related events.

bt_a2dp_connect_cfm() accepts or rejects the incoming connection from the remote device.

static void app_a2dp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    T_APP_BR_LINK *p_active_a2dp_link = &app_db.br_link[active_a2dp_idx];
    bool handle = true;
    T_APP_BR_LINK *p_link = NULL;

    switch (event_type)
    {
    case BT_EVENT_A2DP_CONN_IND:
        {
            T_APP_BR_LINK *p_link = app_link_find_br_link(param->a2dp_conn_ind.bd_addr);
            if (p_link != NULL)
            {
                bt_a2dp_connect_cfm(p_link->bd_addr, true);
            }
        }
        break;
    ...
}
A2DP Streaming Control

For A2DP Sink, the app_a2dp_bt_cback() function is used to handle Bluetooth Manager A2DP Streaming events. app_judge_active_a2dp_idx_and_qos() will be called to determine an A2DP link on one device as the active link, allowing AVRCP to control it.

static void app_a2dp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    T_APP_BR_LINK *p_active_a2dp_link = &app_db.br_link[active_a2dp_idx];
    bool handle = true;
    T_APP_BR_LINK *p_link = NULL;

    switch (event_type)
    {
    ...
    case BT_EVENT_A2DP_STREAM_START_IND:
        {
            if ((p_active_a2dp_link->a2dp.is_streaming == false ||
                 p_active_a2dp_link->avrcp.play_status == BT_AVRCP_PLAY_STATUS_PAUSED) ||
                (memcmp(p_active_a2dp_link->bd_addr,
                        param->a2dp_stream_start_ind.bd_addr, 6) == 0))
            {
                APP_PRINT_INFO3("app_a2dp_bt_cback: BT_EVENT_A2DP_STREAM_START_IND active_a2dp_idx %d, streaming_fg %d, avrcp_play_status %d",
                                active_a2dp_idx, p_active_a2dp_link->a2dp.is_streaming, p_active_a2dp_link->avrcp.play_status);
                app_sniff_mode_b2s_disable_all(SNIFF_DISABLE_MASK_A2DP);

                app_audio_set_bud_stream_state(BUD_STREAM_STATE_AUDIO);

                bt_a2dp_stream_start_cfm(p_active_a2dp_link->bd_addr, true);
                p_active_a2dp_link->a2dp.is_streaming = true;
                app_judge_active_a2dp_idx_and_qos(p_active_a2dp_link->id, JUDGE_EVENT_A2DP_START);
            }
        }
        break;

    case BT_EVENT_A2DP_STREAM_START_RSP:
        {
            if (p_active_a2dp_link->a2dp.is_streaming == false ||
                (memcmp(p_active_a2dp_link->bd_addr,
                        param->a2dp_stream_start_rsp.bd_addr, 6) == 0))
            {
                APP_PRINT_INFO2("app_a2dp_bt_cback: BT_EVENT_A2DP_STREAM_START_RSP active_a2dp_idx %d, streaming_fg %d",
                                active_a2dp_idx, p_active_a2dp_link->a2dp.is_streaming);

                app_sniff_mode_b2s_disable_all(SNIFF_DISABLE_MASK_A2DP);

                app_audio_set_bud_stream_state(BUD_STREAM_STATE_AUDIO);
                p_link = app_link_find_br_link(param->a2dp_stream_start_rsp.bd_addr);
                if (p_link != NULL)
                {
                    p_link->a2dp.is_streaming = true;
                    app_judge_active_a2dp_idx_and_qos(p_link->id, JUDGE_EVENT_A2DP_START);
                }
            }
        }
        break;

    case BT_EVENT_A2DP_STREAM_STOP:
        {
            if (memcmp(p_active_a2dp_link->bd_addr,
                       param->a2dp_stream_stop.bd_addr, 6) == 0)
            {
                if (app_link_get_a2dp_start_num() <= 1)
                {
                    app_sniff_mode_b2s_enable_all(SNIFF_DISABLE_MASK_A2DP);
                }

                if (app_hfp_get_call_status() == APP_HFP_CALL_IDLE)
                {
                    app_audio_set_bud_stream_state(BUD_STREAM_STATE_IDLE);
                }

            }
            p_link = app_link_find_br_link(param->a2dp_stream_stop.bd_addr);
            if (p_link != NULL)
            {
                p_link->a2dp.is_streaming = false;
                app_judge_active_a2dp_idx_and_qos(p_link->id, JUDGE_EVENT_A2DP_STOP);
            }


        }
        break;

    case BT_EVENT_A2DP_STREAM_CLOSE:
        {
            if (memcmp(p_active_a2dp_link->bd_addr,
                       param->a2dp_stream_close.bd_addr, 6) == 0)
            {
                if (app_hfp_get_call_status() == APP_HFP_CALL_IDLE)
                {
                    app_audio_set_bud_stream_state(BUD_STREAM_STATE_IDLE);
                }
            }
            p_link = app_link_find_br_link(param->a2dp_stream_close.bd_addr);
            if (p_link != NULL)
            {
                p_link->a2dp.is_streaming = false;
                app_judge_active_a2dp_idx_and_qos(p_link->id, JUDGE_EVENT_A2DP_STOP);
            }


        }
        break;
    ...
}

void app_judge_active_a2dp_idx_and_qos(uint8_t app_idx, T_APP_JUDGE_A2DP_EVENT event)
{
    uint8_t active_a2dp_idx = app_a2dp_get_active_idx();
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    APP_PRINT_TRACE6("app_judge_active_a2dp_idx_and_qos: 1 event %d, active_a2dp_idx %d, app_idx %d, "
                     "a2dp.wait_resume_link_id %d, streaming_fg %d, active_media_paused %d",
                     event, active_a2dp_idx, app_idx, a2dp.wait_resume_link_id,
                     app_db.br_link[active_a2dp_idx].a2dp.is_streaming, app_db.active_media_paused);
    switch (event)
    {
    case JUDGE_EVENT_A2DP_CONNECTED:
        {
            uint8_t link_number = app_connected_profile_link_num(A2DP_PROFILE_MASK);
            if (link_number <= 1)
            {
                set_active_a2dp_avrcp(app_db.br_link[app_idx].bd_addr);
                app_bond_set_priority(app_db.br_link[app_idx].bd_addr);
                if (link_number <= 0)
                {
                    //exception
                }
            }
            else
            {
                if ((app_db.br_link[active_a2dp_idx].a2dp.is_streaming == false) &&
                    (app_hfp_get_call_status() == APP_HFP_CALL_IDLE))
                {
                    if (app_cfg_const.enable_multi_link)
                    {
                        app_bond_set_priority(app_db.br_link[app_idx].bd_addr);
                        app_bond_set_priority(app_db.br_link[find_other_link_by_bond_prio(app_idx)].bd_addr);
                    }
                    else
                    {
                        set_active_a2dp_avrcp(app_db.br_link[app_idx].bd_addr);
                        app_bond_set_priority(app_db.br_link[app_idx].bd_addr);
                    }
                }
            }
        }
        break;

    case JUDGE_EVENT_A2DP_START:
        {
            APP_PRINT_TRACE3("JUDGE_EVENT_A2DP_START: active_a2dp_idx %d, avrcp %d, stream %d",
                             active_a2dp_idx,
                             app_db.br_link[active_a2dp_idx].avrcp.play_status,
                             app_db.br_link[active_a2dp_idx].a2dp.is_streaming);

            if (app_cfg_const.enable_multi_sco_disc_resume)
            {
                app_pause_other_a2dp_avrcp(active_hf_idx, true);
            }
            else
            {
                app_pause_other_a2dp_avrcp(active_hf_idx, false);
            }

            app_bt_policy_qos_param_update(app_db.br_link[app_idx].bd_addr, BP_TPOLL_A2DP_PLAY_EVENT);
        }
        break;

    case JUDGE_EVENT_A2DP_DISC:
        {
            if (active_a2dp_idx == app_idx)
            {
                //app_bt_sniffing_stop(app_db.br_link[app_idx].bd_addr, BT_SNIFFING_TYPE_A2DP);
                if (app_connected_profile_link_num(A2DP_PROFILE_MASK))
                {
                    set_active_a2dp_avrcp(app_db.br_link[find_other_link_by_bond_prio(
                                                             app_idx)].bd_addr);
                    app_bond_set_priority(app_db.br_link[find_other_link_by_bond_prio(app_idx)].bd_addr);
                }
            }
            app_bt_policy_qos_param_update(app_db.br_link[app_idx].bd_addr, BP_TPOLL_A2DP_STOP_EVENT);
        }
        break;

    case JUDGE_EVENT_A2DP_STOP:
        {
            app_db.br_link[app_idx].avrcp.play_status = BT_AVRCP_PLAY_STATUS_PAUSED;
#if F_APP_MUTILINK_VA_PREEMPTIVE
            app_db.br_link[app_idx].a2dp.stream_only = false;
#endif

            if ((active_a2dp_idx == app_idx) && (a2dp.wait_resume_link_id == MAX_BR_LINK_NUM))
            {
                uint8_t i;
                for (i = 0; i < MAX_BR_LINK_NUM; i++)
                {
                    uint8_t idx = find_other_link_by_bond_prio(active_a2dp_idx);
                    if (app_db.br_link[idx].connected_profile &
                        (A2DP_PROFILE_MASK | AVRCP_PROFILE_MASK))
                    {
                        if ((idx != active_a2dp_idx) &&
                            (app_db.br_link[idx].a2dp.is_streaming == true))
                        {
                            APP_PRINT_TRACE2("JUDGE_EVENT_A2DP_STOP: active_a2dp_idx %d, idx %d", active_a2dp_idx, idx);
                            set_active_a2dp_avrcp_with_prio(idx);
                            break;
                        }
                    }
                }
            }
            app_bt_policy_qos_param_update(app_db.br_link[app_idx].bd_addr, BP_TPOLL_A2DP_STOP_EVENT);
        }
        break;

    case JUDGE_EVENT_MEDIAPLAYER_PLAYING:
        {
            if (app_cfg_const.disable_multilink_preemptive)
            {

            }
            else
            {
                APP_PRINT_TRACE3("JUDGE_EVENT_MEDIAPLAYER_PLAYING: preemptive active_a2dp_idx %d, app_idx %d, streaming_fg %d",
                                 active_a2dp_idx, app_idx, app_db.br_link[app_idx].a2dp.is_streaming);
                if (app_db.br_link[app_idx].a2dp.is_streaming == true)
                {
                    if (app_hfp_get_call_status() != APP_HFP_CALL_IDLE)
                    {
                        if (app_cfg_const.enable_multi_sco_disc_resume)
                        {
                            app_pause_other_a2dp_avrcp(active_hf_idx, true);
                        }
                        else
                        {
                            app_pause_other_a2dp_avrcp(active_hf_idx, false);
                        }
                    }
                    else
                    {
                        set_active_a2dp_avrcp(app_db.br_link[app_idx].bd_addr);
                        app_pause_other_a2dp_avrcp(app_idx, false);
                        app_bond_set_priority(app_db.br_link[app_idx].bd_addr);
                    }
                }
            }
            app_bt_policy_qos_param_update(app_db.br_link[app_idx].bd_addr, BP_TPOLL_A2DP_PLAY_EVENT);
        }
        break;

    case JUDGE_EVENT_MEDIAPLAYER_PAUSED:
        {
        }
        break;

    case JUDGE_EVENT_SNIFFING_STOP:
        {
        }
        break;

    default:
        break;
    }

    if (active_a2dp_idx == app_idx)
    {
        if (event == JUDGE_EVENT_A2DP_START)
        {
            app_audio_a2dp_play_status_update(APP_A2DP_STREAM_A2DP_START);
            if (app_cfg_const.timer_auto_power_off_while_phone_connected_and_anc_apt_off)
            {
                app_auto_power_off_disable(AUTO_POWER_OFF_MASK_AUDIO);
            }
        }
        else if (event == JUDGE_EVENT_A2DP_STOP)
        {
            app_audio_a2dp_play_status_update(APP_A2DP_STREAM_A2DP_STOP);
            if (app_cfg_const.timer_auto_power_off_while_phone_connected_and_anc_apt_off)
            {
                app_auto_power_off_enable(AUTO_POWER_OFF_MASK_AUDIO,
                                          app_cfg_const.timer_auto_power_off_while_phone_connected_and_anc_apt_off);
            }
        }
    }

    APP_PRINT_TRACE4("app_judge_active_a2dp_idx_and_qos: 2 event %d, active_a2dp_idx %d, app_idx %d, "
                     "a2dp.wait_resume_link_id %d",
                     event, active_a2dp_idx, app_idx, a2dp.wait_resume_link_id);
}

HFP HF

HFP roles can be divided into AG and HF:

  • Audio Gateway (AG) is the device that is the gateway of the audio, both for input and output. Typical devices acting as Audio Gateways are cellular phones.

  • Hands-Free unit (HF) is the device acting as the Audio Gateway’s remote audio input and output mechanism. It also provides some remote control means.

The code flow of HFP HF in the receiver role is introduced here.

HFP HF UUID

HFP HF’s UUID registration is referred to in hfp_sdp_record().

static const uint8_t hfp_sdp_record[] =
{
    //total length
    SDP_DATA_ELEM_SEQ_HDR,
    0x4B,//0x37,//0x59,

    //attribute SDP_ATTR_SRV_CLASS_ID_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_SRV_CLASS_ID_LIST >> 8),
    (uint8_t)SDP_ATTR_SRV_CLASS_ID_LIST,
    SDP_DATA_ELEM_SEQ_HDR,          //0x35
    0x06,                                   //6bytes
    SDP_UUID16_HDR,                     //0x19
    (uint8_t)(UUID_HANDSFREE >> 8), //0x111E
    (uint8_t)(UUID_HANDSFREE),
    SDP_UUID16_HDR,                     //0x19
    (uint8_t)(UUID_GENERIC_AUDIO >> 8),  //0x1203
    (uint8_t)(UUID_GENERIC_AUDIO),

    //attribute SDP_ATTR_PROTO_DESC_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_PROTO_DESC_LIST >> 8),
    (uint8_t)SDP_ATTR_PROTO_DESC_LIST,
    SDP_DATA_ELEM_SEQ_HDR,          //0x35
    0x0C,                                   //12bytes
    SDP_DATA_ELEM_SEQ_HDR,      //0x35
    0x03,                               //3bytes
    SDP_UUID16_HDR,                 //0x19
    (uint8_t)(UUID_L2CAP >> 8),     //0x0100
    (uint8_t)(UUID_L2CAP),
    SDP_DATA_ELEM_SEQ_HDR,      //0x35
    0x05,                               //5bytes
    SDP_UUID16_HDR,                 //0x19
    (uint8_t)(UUID_RFCOMM >> 8),   //0x0003
    (uint8_t)(UUID_RFCOMM),
    SDP_UNSIGNED_ONE_BYTE,           //0x08
    RFC_HFP_CHANN_NUM,  //0x02

    //attribute SDP_ATTR_BROWSE_GROUP_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_BROWSE_GROUP_LIST >> 8),
    (uint8_t)SDP_ATTR_BROWSE_GROUP_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x03,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_PUBLIC_BROWSE_GROUP >> 8),
    (uint8_t)UUID_PUBLIC_BROWSE_GROUP,
    /*
        //attribute SDP_ATTR_LANG_BASE_ATTR_ID_LIST...it is used for SDP_ATTR_SRV_NAME
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_ATTR_LANG_BASE_ATTR_ID_LIST >> 8),
        (uint8_t)SDP_ATTR_LANG_BASE_ATTR_ID_LIST,
        SDP_DATA_ELEM_SEQ_HDR,
        0x09,
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_LANG_ENGLISH >> 8),
        (uint8_t)SDP_LANG_ENGLISH,
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_CHARACTER_UTF8 >> 8),
        (uint8_t)SDP_CHARACTER_UTF8,
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_BASE_LANG_OFFSET >> 8),
        (uint8_t)SDP_BASE_LANG_OFFSET,

        //attribute SDP_ATTR_SRV_NAME
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)((SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET) >> 8),
        (uint8_t)(SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET),
        SDP_STRING_HDR,                             //0x25 text string
        0x0F,                                   //15 bytes
        0x48, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x66, 0x72, 0x65, 0x65,
        0x20, 0x75, 0x6e, 0x69, 0x74, //"Hands-free unit"
    */

    //attribute SDP_ATTR_PROFILE_DESC_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_PROFILE_DESC_LIST >> 8),
    (uint8_t)SDP_ATTR_PROFILE_DESC_LIST,
    SDP_DATA_ELEM_SEQ_HDR,          //0x35
    0x08,                                   //8 bytes
    SDP_DATA_ELEM_SEQ_HDR,      //0x35
    0x06,                               //6 bytes
    SDP_UUID16_HDR,                 //0x19
    (uint8_t)(UUID_HANDSFREE >> 8), //0x111E
    (uint8_t)(UUID_HANDSFREE),
    SDP_UNSIGNED_TWO_BYTE,           //0x09
    (uint8_t)(0x0107 >> 8),     //version number default hf1.7
    (uint8_t)(0x0107),

    //Attribute SDP_ATTR_SRV_NAME
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)((SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET) >> 8),
    (uint8_t)(SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET),
    SDP_STRING_HDR,
    0x0F,
    'H', 'a', 'n', 'd', 's', '-', 'F', 'r', 'e', 'e', ' ', 'u', 'n', 'i', 't',

    //attribute SDP_ATTR_SUPPORTED_FEATURES
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)((SDP_ATTR_SUPPORTED_FEATURES) >> 8),
    (uint8_t)(SDP_ATTR_SUPPORTED_FEATURES),
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(0x003F >> 8),
    (uint8_t)(0x003F)
};
HFP Profile Initialization

bt_hfp_init() is utilized in app_hfp_init() to initialize HFP profile, and to configure the maximum link number of HFP links. It sets the HFP RFCOMM channel number and configures the supported HFP features. HFP HF features are initialized in app_cfg_const.hfp_brsf_capability.

void app_hfp_hf_init(void)
{
    if (app_cfg_const.supported_profile_mask & (HFP_PROFILE_MASK | HSP_PROFILE_MASK))
    {
        bt_hfp_init(app_cfg_const.hfp_link_number, RFC_HFP_CHANN_NUM,
                    RFC_HSP_CHANN_NUM, app_cfg_const.hfp_hf_brsf_capability);
        audio_mgr_cback_register(app_hfp_audio_cback);
        bt_mgr_cback_register(app_hfp_bt_cback);

        app_timer_reg_cb(app_hfp_timeout_cb, &hfp.tmr.id);
    }
}

void app_hfp_init(void)
{

#if (F_APP_SCO_XMIT_AG_SUPPORT || F_SOURCE_PLAY_SUPPORT)
    app_hfp_ag_init();
#else
    app_hfp_hf_init();
#endif

}
HFP Profile Linkback

HFP HF will call gap_br_start_sdp_discov() in linkback_profile_search_start() to discover the HFP SDP record in AG.

bool linkback_profile_search_start(uint8_t *bd_addr, uint32_t prof, bool is_special)
{
    bool ret = true;
    T_GAP_UUID_DATA uuid;
    T_GAP_UUID_TYPE uuid_type = GAP_UUID16;
    ...
    switch (prof)
    {
    ...
    case HFP_HF_PROFILE_MASK:
        {
            uuid.uuid_16 = UUID_HANDSFREE;
        }
        break;
    ...
    if (ret)
    {
        if (gap_br_start_sdp_discov(bd_addr, uuid_type, uuid) != GAP_CAUSE_SUCCESS)
        {
            ret = false;
        }
    }

    return ret;
}

Then, HFP HF will initiate a profile connection to AG by bt_hfp_connect_req().

Note

If both devices initiate a connection at the same time, both channels shall be closed and each device shall wait a random time (not more than 1s and not less than 100ms) and then try to initiate the connection again. If it is known which device is the master, that device can retry at once.

bool linkback_profile_connect_start(uint8_t *bd_addr, uint32_t prof, T_LINKBACK_CONN_PARAM *param)
{
    bool ret = true;
    ...
    switch (prof)
    {
    case HFP_PROFILE_MASK:

#if (F_APP_SCO_XMIT_AG_SUPPORT || F_SOURCE_PLAY_SUPPORT)
        ret = bt_hfp_ag_connect_req(bd_addr, param->server_channel, true);
#else
        ret = bt_hfp_connect_req(bd_addr, param->server_channel, true);
#endif

        break;

    return ret;
}
HFP Profile Callback Handler

For HFP HF, app_hfp_bt_cback() function is used to handle Bluetooth Manager HFP HF-related events:

  • HFP profile connection request should be confirmed when receiving BT_EVENT_HFP_CONN_IND.

  • HFP profile connection is completed when receiving BT_EVENT_HFP_CONN_CMPL.

  • HFP profile disconnection is indicated when receiving BT_EVENT_HFP_DISCONN_CMPL.

static void app_hfp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    bool handle = true;

    switch (event_type)
    {
    case BT_EVENT_HFP_CONN_IND:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_conn_ind.bd_addr);
            if (p_link == NULL)
            {
                APP_PRINT_ERROR0("app_hfp_bt_cback: no acl link found");
                return;
            }
            bt_hfp_connect_cfm(p_link->bd_addr, true);
        }
        break;

    case BT_EVENT_HFP_CONN_CMPL:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_conn_cmpl.bd_addr);
            if (p_link != NULL)
            {
                uint8_t link_number;
                uint8_t pair_idx_mapping;

                p_link->hfp.call_id_type_chk = true;
                p_link->hfp.call_id_type_num = false;

                app_bond_get_pair_idx_mapping(p_link->bd_addr, &pair_idx_mapping);
                bt_hfp_speaker_gain_level_report(p_link->bd_addr, app_cfg_nv.voice_gain_level[pair_idx_mapping]);

                bt_hfp_microphone_gain_level_report(p_link->bd_addr, 0x0a);

                app_hfp_batt_level_report(p_link->bd_addr);

                link_number = app_connected_profile_link_num(HFP_PROFILE_MASK | HSP_PROFILE_MASK);
                if (link_number == 1)
                {
                    app_hfp_set_active_idx(p_link->bd_addr);
                    app_bond_set_priority(p_link->bd_addr);
                }
                if (app_db.br_link[app_db.first_hf_index].hfp.state == APP_HF_STATE_STANDBY)
                {
                    app_db.first_hf_index = p_link->id;
                }
                else
                {
                    app_db.last_hf_index = p_link->id;
                }
                p_link->hfp.state = APP_HF_STATE_CONNECTED;
            }
        }
        break;

    case BT_EVENT_HFP_VOICE_RECOGNITION_ACTIVATION:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_voice_recognition_activation.bd_addr);
            if (p_link != NULL)
            {
                if (p_link->hfp.call_status == APP_HFP_CALL_IDLE)
                {
                    p_link->hfp.call_status = APP_HFP_VOICE_ACTIVATION_ONGOING;
                }

                app_hfp_update_call_status();

                if (p_link->remote_device_vendor_id == APP_REMOTE_DEVICE_IOS)
                {
                    app_start_timer(&hfp.tmr.indices[TIMER_CANCEL_VOICE_DAIL], "cancel_iphone_voice_dail",
                                    hfp.tmr.id, TIMER_CANCEL_VOICE_DAIL, false,
                                    p_link->id, 1000);
                }
            }
        }
        break;

    case BT_EVENT_HFP_VOICE_RECOGNITION_DEACTIVATION:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_voice_recognition_deactivation.bd_addr);
            if (p_link != NULL)
            {
                if (p_link->hfp.call_status == APP_HFP_VOICE_ACTIVATION_ONGOING)
                {
                    p_link->hfp.call_status = APP_HFP_CALL_IDLE;
                }

                app_hfp_update_call_status();
            }
        }
        break;

    case BT_EVENT_HFP_CALL_STATUS:
        {
            T_APP_BR_LINK *p_link;
#if C_APP_END_OUTGOING_CALL_PLAY_CALL_END_TONE == 0
            uint8_t temp_idx = hfp.active_link_id;
#endif
            p_link = app_link_find_br_link(param->hfp_call_status.bd_addr);
            if (p_link != NULL)
            {
                switch (param->hfp_call_status.curr_status)
                {
                case BT_HFP_CALL_IDLE:
                    {
                        p_link->hfp.call_status = APP_HFP_CALL_IDLE;
                    }
                    break;

                case BT_HFP_CALL_INCOMING:
                    {
                        p_link->hfp.call_status = APP_HFP_CALL_INCOMING;
                    }
                    break;

                case BT_HFP_CALL_OUTGOING:
                    {
                        p_link->hfp.call_status = APP_HFP_CALL_OUTGOING;
                    }
                    break;

                case BT_HFP_CALL_ACTIVE:
                    {
                        p_link->hfp.call_status = APP_HFP_CALL_ACTIVE;
                    }
                    break;

                case BT_HFP_CALL_HELD:
                    {
                        //p_link->call_status = APP_HFP_CALL_HELD;
                    }
                    break;

                case BT_HFP_CALL_ACTIVE_WITH_CALL_WAITING:
                    {
                        p_link->hfp.call_status = APP_HFP_CALL_ACTIVE_WITH_CALL_WAITING;
                    }
                    break;

                case BT_HFP_CALL_ACTIVE_WITH_CALL_HELD:
                    {
                        p_link->hfp.call_status = APP_HFP_CALL_ACTIVE_WITH_CALL_HELD;
                    }
                    break;

                default:
                    break;
                }

                if ((app_cfg_const.enable_auto_answer_incoming_call == 1) &&
                    (p_link->hfp.call_status == APP_HFP_CALL_INCOMING))
                {
                    hfp.auto_answer_call_interval = app_cfg_const.timer_hfp_auto_answer_call * 1000;
                    app_start_timer(&hfp.tmr.indices[TIMER_AUTO_ANSWER_CALL], "auto_answer_call",
                                    hfp.tmr.id, TIMER_AUTO_ANSWER_CALL, p_link->id, false,
                                    hfp.auto_answer_call_interval);
                }

                if (p_link->hfp.call_status == APP_HFP_CALL_IDLE)
                {
                    p_link->hfp.call_id_type_chk = true;
                    p_link->hfp.call_id_type_num = false;
                }

                app_hfp_update_call_status();

                if ((p_link->hfp.call_status == APP_HFP_VOICE_ACTIVATION_ONGOING) &&
                    (p_link->remote_device_vendor_id == APP_REMOTE_DEVICE_IOS))
                {
                    app_start_timer(&hfp.tmr.indices[TIMER_CANCEL_VOICE_DAIL], "cancel_iphone_voice_dail",
                                    hfp.tmr.id, TIMER_CANCEL_VOICE_DAIL, p_link->id, false,
                                    1000);
                }

                if (app_cfg_nv.bud_role != REMOTE_SESSION_ROLE_SECONDARY)
                {
                    if (param->hfp_call_status.prev_status == BT_HFP_CALL_INCOMING &&
                        param->hfp_call_status.curr_status == BT_HFP_CALL_IDLE)
                    {
                        if (app_db.reject_call_by_key)
                        {
                            app_db.reject_call_by_key = false;
                            app_audio_tone_type_play(TONE_HF_CALL_REJECT, false, false);
                        }
                    }

                    if (p_link->id == temp_idx &&
                        param->hfp_call_status.prev_status == BT_HFP_CALL_ACTIVE &&
                        param->hfp_call_status.curr_status == BT_HFP_CALL_IDLE)
                    {
                        app_audio_tone_type_play(TONE_HF_CALL_END, false, false);
                    }

                    if (p_link->id == hfp.active_link_id &&
                        param->hfp_call_status.prev_status != BT_HFP_CALL_ACTIVE &&
                        param->hfp_call_status.curr_status == BT_HFP_CALL_ACTIVE)
                    {
                        app_audio_tone_type_play(TONE_HF_CALL_ACTIVE, false, false);
                    }

                    if (param->hfp_call_status.prev_status != BT_HFP_CALL_OUTGOING &&
                        param->hfp_call_status.curr_status == BT_HFP_CALL_OUTGOING)
                    {
                        app_audio_tone_type_play(TONE_HF_OUTGOING_CALL, false, false);
                    }
                }
            }

            if (param->hfp_call_status.curr_status == BT_HFP_CALL_ACTIVE ||
                param->hfp_call_status.curr_status == BT_HFP_CALL_INCOMING ||
                param->hfp_call_status.curr_status == BT_HFP_CALL_OUTGOING)
            {
                if (app_cfg_const.timer_auto_power_off_while_phone_connected_and_anc_apt_off)
                {
                    app_auto_power_off_disable(AUTO_POWER_OFF_MASK_VOICE);
                }

                app_audio_set_bud_stream_state(BUD_STREAM_STATE_VOICE);
            }
            else if (param->hfp_call_status.curr_status == BT_HFP_CALL_IDLE)
            {
                if (app_cfg_const.timer_auto_power_off_while_phone_connected_and_anc_apt_off)
                {
                    app_auto_power_off_enable(AUTO_POWER_OFF_MASK_VOICE,
                                              app_cfg_const.timer_auto_power_off_while_phone_connected_and_anc_apt_off);
                }

                app_audio_set_bud_stream_state(BUD_STREAM_STATE_IDLE);
            }


        }
        break;

    case BT_EVENT_HFP_SERVICE_STATUS:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_service_status.bd_addr);

            if (p_link != NULL)
            {
                p_link->hfp.service_status = param->hfp_service_status.status;
                app_hfp_check_service_status();
            }
        }
        break;

    case BT_EVENT_HFP_CALL_WAITING_IND:
    case BT_EVENT_HFP_CALLER_ID_IND:
        {
            if (app_cfg_nv.bud_role != REMOTE_SESSION_ROLE_SECONDARY)
            {
                T_APP_BR_LINK *br_link;
                T_APP_LE_LINK *le_link;
                char *number;
                uint16_t num_len;

                if (event_type == BT_EVENT_HFP_CALLER_ID_IND)
                {
                    br_link = app_link_find_br_link(param->hfp_caller_id_ind.bd_addr);
                    le_link = app_link_find_le_link_by_addr(param->hfp_caller_id_ind.bd_addr);
                    number = (char *)param->hfp_caller_id_ind.number;
                    num_len = strlen(param->hfp_caller_id_ind.number);
                }
                else
                {
                    br_link = app_link_find_br_link(param->hfp_call_waiting_ind.bd_addr);
                    le_link = app_link_find_le_link_by_addr(param->hfp_call_waiting_ind.bd_addr);
                    number = (char *)param->hfp_call_waiting_ind.number;
                    num_len = strlen(param->hfp_call_waiting_ind.number);
                }

                if (br_link != NULL)
                {

                    if (br_link->hfp.call_id_type_chk == true)
                    {
                        if (br_link->connected_profile & PBAP_PROFILE_MASK)
                        {
                            if (bt_pbap_vcard_listing_by_number_pull(br_link->bd_addr, number) == false)
                            {
                                br_link->hfp.call_id_type_chk = false;
                                br_link->hfp.call_id_type_num = true;
                            }
                        }
                        else
                        {
                            br_link->hfp.call_id_type_chk = false;
                            br_link->hfp.call_id_type_num = true;
                        }
                    }

                    if (br_link->hfp.call_id_type_chk == false)
                    {
                        if (br_link->hfp.call_id_type_num == true)
                        {
                            T_CMD_PATH cmd_path = CMD_PATH_UART;
                            uint8_t app_link_id = 0xff;
                            T_CALLER_ID_TYPE call_id_type = CALLER_ID_NUMBER;

                            if (br_link->connected_profile & SPP_PROFILE_MASK)
                            {
                                app_link_id = br_link->id;
                                cmd_path = CMD_PATH_SPP;
                            }
                            else if (br_link->connected_profile & IAP_PROFILE_MASK)
                            {
                                app_link_id = br_link->id;
                                cmd_path = CMD_PATH_IAP;
                            }
                            else if (le_link != NULL)
                            {
                                app_link_id = le_link->id;
                                cmd_path = CMD_PATH_LE;
                            }
                            app_hfp_call_id_rpt(cmd_path,  app_link_id, call_id_type, num_len, (uint8_t *)number);
                        }
                    }
                }
            }
        }
        break;

    case BT_EVENT_HFP_RING_ALERT:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_ring_alert.bd_addr);
            if (p_link != NULL)
            {
                p_link->hfp.is_inband_ring = param->hfp_ring_alert.is_inband;

                if ((app_cfg_const.always_play_hf_incoming_tone_when_incoming_call == false) &&
                    ((p_link->hfp.is_inband_ring == false) ||
                     (p_link->id != hfp.active_link_id))) /* TODO check active sco link */
                {
                    if (hfp.ring_active == false && p_link->hfp.call_status == APP_HFP_CALL_INCOMING)
                    {
                        hfp.ring_active = true;

                        app_hfp_ring_alert(p_link);
                    }
                }
            }
        }
        break;

    case BT_EVENT_HFP_SPK_VOLUME_CHANGED:
        {
            T_APP_BR_LINK *p_link;
            p_link = app_link_find_br_link(param->hfp_spk_volume_changed.bd_addr);
            uint8_t temp_buff[7];

            if (p_link != NULL)
            {
                if (app_db.remote_session_state == REMOTE_SESSION_STATE_DISCONNECTED)
                {
                    uint8_t pair_idx_mapping;

                    app_bond_get_pair_idx_mapping(p_link->bd_addr, &pair_idx_mapping);

                    app_cfg_nv.voice_gain_level[pair_idx_mapping] = (param->hfp_spk_volume_changed.volume *
                                                                     app_dsp_cfg_vol.voice_out_volume_max +
                                                                     0x0f / 2) / 0x0f;

                    memcpy(&temp_buff[0], &param->hfp_spk_volume_changed.bd_addr, 6);
                    temp_buff[6] = app_cfg_nv.voice_gain_level[pair_idx_mapping];
                    app_report_event(CMD_PATH_UART, APP_EVENT_VOLUME_SYNC, 0, temp_buff, sizeof(temp_buff));

                    app_audio_vol_set(p_link->sco.track_handle, app_cfg_nv.voice_gain_level[pair_idx_mapping]);
                    app_audio_track_spk_unmute(AUDIO_STREAM_TYPE_VOICE);
                }
                else
                {

                }
            }
        }
        break;

    case BT_EVENT_HFP_MIC_VOLUME_CHANGED:
        {
        }
        break;

    case BT_EVENT_REMOTE_CONN_CMPL:
        {
            if (app_cfg_nv.bud_role == REMOTE_SESSION_ROLE_PRIMARY)
            {
                app_hfp_voice_nr_enable();
            }
        }
        break;

    case BT_EVENT_HFP_DISCONN_CMPL:
        {
            T_APP_BR_LINK *p_link;

            p_link = app_link_find_br_link(param->hfp_disconn_cmpl.bd_addr);
            if (p_link != NULL)
            {
                if (param->hfp_disconn_cmpl.cause == (HCI_ERR | HCI_ERR_CONN_ROLESWAP))
                {
                    //do nothing
                }
                else
                {
                    p_link->hfp.call_status = APP_HFP_CALL_IDLE;
                    p_link->hfp.state = APP_HF_STATE_STANDBY;
                    if (app_db.first_hf_index == p_link->id)
                    {
                        app_db.first_hf_index = app_db.last_hf_index;
                    }

                    for (uint8_t i = 0; i < MAX_BR_LINK_NUM; i++)
                    {
                        if (app_db.br_link[i].connected_profile & (HFP_PROFILE_MASK | HSP_PROFILE_MASK))
                        {
                            app_hfp_set_active_idx(app_db.br_link[i].bd_addr);
                            app_bond_set_priority(app_db.br_link[i].bd_addr);
                            break;
                        }
                    }

                    if (app_hfp_get_call_status() != APP_HFP_CALL_IDLE)
                    {
                        app_hfp_update_call_status();
                    }
                }

                if ((param->hfp_disconn_cmpl.cause & ~HCI_ERR) != HCI_ERR_CONN_ROLESWAP)
                {
                    app_hfp_check_service_status();
                }
            }
        }
        break;


    default:
        handle = false;
        break;
    }

    if (handle == true)
    {
        APP_PRINT_INFO1("app_hfp_bt_cback: event_type 0x%04x", event_type);
    }
}
Send HFP Vendor AT Command

bt_hfp_send_vnd_at_cmd_req() is utilized in br_cmd_handle() to send HFP vendor AT command.

void br_cmd_handle(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t app_idx,
                   uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));

    APP_PRINT_TRACE1("app_cmd br_cmd_handle: cmd_id 0x%04x", cmd_id);

    typedef struct
    {
        uint16_t cmd_id;
        uint8_t  status;
    } __attribute__((packed)) *ACK_PKT;

    switch (cmd_id)
    {
    case CMD_BT_SEND_AT_CMD:
        {
            uint8_t app_index = cmd_ptr[2];

            if (bt_hfp_send_vnd_at_cmd_req(app_db.br_link[app_index].bd_addr, (char *)&cmd_ptr[3]) == false)
            {
                ack_pkt[2] = CMD_SET_STATUS_DISALLOW;
            }

            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    }
}
HFP Call Status

HFP HF’s call status T_BT_HFP_CALL_STATUS is updated with event BT_EVENT_HFP_CALL_STATUS when HF receives related AG indicators or HF takes action to change them.

typedef enum t_bt_hfp_call_status
{
    BT_HFP_CALL_IDLE                              = 0x00,
    BT_HFP_CALL_INCOMING                          = 0x01,
    BT_HFP_CALL_OUTGOING                          = 0x02,
    BT_HFP_CALL_ACTIVE                            = 0x03,
    BT_HFP_CALL_HELD                              = 0x04,
    BT_HFP_CALL_ACTIVE_WITH_CALL_WAITING          = 0x05,
    BT_HFP_CALL_ACTIVE_WITH_CALL_HELD             = 0x06,
} T_BT_HFP_CALL_STATUS;

HFP HF application could control the audio module and handle answer/reject action according to the call status, which are processed in app_mmi_handle_action().

void app_mmi_hf_reject_call(void)
{
    T_APP_BR_LINK *p_link;
    T_APP_AUDIO_TONE_TYPE tone_type = TONE_TYPE_INVALID;
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    p_link = &(app_db.br_link[active_hf_idx]);

    if (app_cfg_nv.bud_role == REMOTE_SESSION_ROLE_SECONDARY)
    {
        return;
    }

    if (p_link != NULL)
    {
        app_hfp_stop_ring_alert_timer();

        tone_type = (T_APP_AUDIO_TONE_TYPE)app_hfp_get_call_in_tone_type(p_link);
        app_audio_tone_type_cancel(tone_type, false);
        if (bt_hfp_call_terminate_req(p_link->bd_addr))
        {
            app_db.reject_call_by_key = true;
        }
    }
}

void app_mmi_hf_end_active_call(void)
{
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    if (app_cfg_nv.bud_role == REMOTE_SESSION_ROLE_SECONDARY)
    {
        return;
    }

    if (app_db.br_link[app_hfp_get_active_idx()].hfp.call_status > APP_HFP_CALL_ACTIVE)
    {
        bt_hfp_release_active_call_accept_held_or_waiting_call_req(app_db.br_link[active_hf_idx].bd_addr);
    }
    else
    {
        bt_hfp_call_terminate_req(app_db.br_link[active_hf_idx].bd_addr);
    }
}

void app_mmi_hf_end_outgoing_call(void)
{
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    if (app_cfg_nv.bud_role == REMOTE_SESSION_ROLE_SECONDARY)
    {
        return;
    }

    bt_hfp_call_terminate_req(app_db.br_link[active_hf_idx].bd_addr);
}

void app_mmi_handle_action(uint8_t action)
{
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    switch (action)
    {
    ...
    case MMI_HF_ANSWER_CALL:
        {
            T_APP_BR_LINK *p_link;
            T_APP_AUDIO_TONE_TYPE tone_type = TONE_TYPE_INVALID;
            p_link = &(app_db.br_link[active_hf_idx]);

            if (app_cfg_nv.bud_role == REMOTE_SESSION_ROLE_SECONDARY)
            {
                return;
            }

            if (p_link != NULL)
            {
                app_hfp_stop_ring_alert_timer();

                tone_type = (T_APP_AUDIO_TONE_TYPE)app_hfp_get_call_in_tone_type(p_link);
                app_audio_tone_type_cancel(tone_type, false);
                bt_hfp_call_answer_req(p_link->bd_addr);
            }
        }
        break;

    case MMI_HF_REJECT_CALL:
        {
            app_mmi_hf_reject_call();
        }
        break;

    case MMI_HF_END_ACTIVE_CALL:
        {
            app_mmi_hf_end_active_call();
        }
        break;

    case MMI_HF_END_OUTGOING_CALL:
        {
            app_mmi_hf_end_outgoing_call();
        }
        break;
    ...
    }
}

MAP MCE

MAP roles can be divided into MSE and MCE:

  • Message Server Equipment (MSE) is the device that provides the message repository engine (i.e., has the ability to provide a client unit with messages that are stored in this device and notifications of changes in its message repository).

  • Message Client Equipment (MCE) is the device that uses the message repository engine of the MSE for browsing and displaying existing messages and to upload messages created on the MCE to the MSE.

The code flow of MAP MCE is introduced here.

MAP Initialization

Main function is invoked when the application is powered on or the chip is reset, MAP initialization function is included in app_test_init().

void app_test_init(void)
{
    bt_map_init(1, RFC_MAP_MNS_CHANN_NUM, L2CAP_MAP_MNS_PSM, 0x0000024F);
    ...
    os_task_create(&app_task_handle, "app_task", app_task, NULL, stack_size, 2);
    ...

    os_sched_start();
    return 0;
}

int main(void)
{
  ...
#if F_APP_TEST_SUPPORT
        app_test_init();
#endif
  ...
}
SDP Record for MNS on MCE Device

There shall be one service record for the MCE device (Message Notification Service, server role).

#define RFC_MAP_MNS_CHANN_NUM           20        //user defined
#define L2CAP_MAP_MNS_PSM               0x1001    //user defined

#if F_APP_BT_PROFILE_MAP_MCE_SUPPORT
const uint8_t map_mce_sdp_record[] =
{
    SDP_DATA_ELEM_SEQ_HDR,
    0x49,
    //attribute SDP_ATTR_SRV_CLASS_ID_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_SRV_CLASS_ID_LIST >> 8),
    (uint8_t)SDP_ATTR_SRV_CLASS_ID_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x03,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_MSG_NOTIFICATION_SERVER >> 8),
    (uint8_t)(UUID_MSG_NOTIFICATION_SERVER),

    //attribute SDP_ATTR_PROTO_DESC_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_PROTO_DESC_LIST >> 8),
    (uint8_t)SDP_ATTR_PROTO_DESC_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x11,
    SDP_DATA_ELEM_SEQ_HDR,
    0x03,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_L2CAP >> 8),
    (uint8_t)(UUID_L2CAP),
    SDP_DATA_ELEM_SEQ_HDR,
    0x05,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_RFCOMM >> 8),
    (uint8_t)(UUID_RFCOMM),
    SDP_UNSIGNED_ONE_BYTE,
    RFC_MAP_MNS_CHANN_NUM,  //channel number
    SDP_DATA_ELEM_SEQ_HDR,
    0x03,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_OBEX >> 8),
    (uint8_t)(UUID_OBEX),

    //Attribute SDP_ATTR_SRV_NAME
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)((SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET) >> 8),
    (uint8_t)(SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET),
    SDP_STRING_HDR,
    0x0B,
    'R', 'e', 'a', 'l', 't', 'e', 'k', '-', 'M', 'N', 'S',

    //attribute SDP_ATTR_PROFILE_DESC_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_PROFILE_DESC_LIST >> 8),
    (uint8_t)SDP_ATTR_PROFILE_DESC_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x08,
    SDP_DATA_ELEM_SEQ_HDR,
    0x06,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_MSG_ACCESS_PROFILE >> 8),
    (uint8_t)UUID_MSG_ACCESS_PROFILE,
    SDP_UNSIGNED_TWO_BYTE,
    0x01,
    0x04,   //version 1.4

    //attribute SDP_ATTR_L2C_PSM
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)((SDP_ATTR_L2C_PSM) >> 8),
    (uint8_t)(SDP_ATTR_L2C_PSM),
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(L2CAP_MAP_MNS_PSM >> 8),
    (uint8_t)(L2CAP_MAP_MNS_PSM),

    //attribute SDP_ATTR_MAP_SUPPERTED_FEATS
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)((SDP_ATTR_MAP_SUPPERTED_FEATS) >> 8),
    (uint8_t)(SDP_ATTR_MAP_SUPPERTED_FEATS),
    SDP_UNSIGNED_FOUR_BYTE,
    (uint8_t)(0x0000024F >> 24),
    (uint8_t)(0x0000024F >> 16),
    (uint8_t)(0x0000024F >> 8),
    (uint8_t)(0x0000024F)
};
#endif
MAP Connect

OBEX connections in MAP shall always be initiated by the MCE device. The establishment of a Message Notification Service connection is done with the MCE as OBEX Server and the MSE as OBEX Client. The establishment of a Message Notification connection requires the previous establishment of a Message Access Service connection.

The MAP connection is realized by CMD, gap_br_start_sdp_discov() is invoked to establish MAS through SDP using UUID in app_map_handle_cmd(), UUID needs to be set as UUID_MSG_ACCESS_SERVER.

void app_map_handle_cmd(uint8_t app_idx, T_CMD_PATH cmd_path, uint8_t *cmd_ptr,
                        uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
    case CMD_MAP_CONNECT:
        {
            T_GAP_UUID_DATA uuid_data;

            uuid_data.uuid_16 = UUID_MSG_ACCESS_SERVER;
            gap_br_start_sdp_discov(app_db.br_link[app_idx].bd_addr, GAP_UUID16, uuid_data);

            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    }
}

void app_handle_cmd_set(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t rx_seqn,
                        uint8_t app_idx)
{
    uint16_t cmd_id;
    uint8_t  ack_pkt[3];

    cmd_id     = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ack_pkt[0] = cmd_ptr[0];
    ack_pkt[1] = cmd_ptr[1];
    ack_pkt[2] = CMD_SET_STATUS_COMPLETE;
    ...
    switch (cmd_id)
    {
    case CMD_MAP_SDP_REQUEST...CMD_MAP_PUSH_MESSAGE:
        app_map_handle_cmd(app_idx, (T_CMD_PATH)cmd_path, cmd_ptr, cmd_len, ack_pkt);

        break;
    }
}

bt_map_mas_msg_notification_set() is used to register for being notified of the arrival of new messages in app_handle_cmd_set(). After this API is called, the MSE device will establish an OBEX connection for the message notification service.

void app_handle_cmd_set(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t rx_seqn,
                        uint8_t app_idx)
{
    ...
    case CMD_MAP_REG_MSG_NOTIFICATION:
        {
            struct
            {
                uint16_t cmd_id;
                uint8_t enable;
            } __attribute__((packed)) *params = (typeof(params)) cmd_ptr;

            bt_map_mas_msg_notification_set(app_db.br_link[app_idx].bd_addr, params->enable);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
}

bt_map_mns_connect_cfm() accepts or rejects the incoming MNS Connection when receiving BT_EVENT_MAP_MNS_CONN_IND.

static void app_test_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    bool handle = true;
    ...
    switch (event_type)
    {
    ...
    case BT_EVENT_MAP_MNS_CONN_IND:
        {
            bt_map_mns_connect_cfm(param->map_mns_conn_ind.bd_addr, true);
        }
        break;
    }
}
MAP Get Message

When getting a message, bt_map_mas_folder_set() is used to navigate the folders of the MSE.

bt_map_mas_folder_listing_get() is used to retrieve the Folder-Listing object from the current folder of the MSE. The Folder-Listing object is an XML object and shall be encoded in UTF-8. In the context of the MAP profile, the Folder-Listing object shall not contain message entries. It shall only contain folder entries located in the current folder level.

bt_map_mas_msg_listing_get() is used to retrieve Messages-Listing objects from the MSE. The Messages-Listing object is an XML object and shall be encoded in UTF-8.

bt_map_mas_msg_get() is used to retrieve a specific message from the MSE, and the corresponding event is BT_EVENT_MAP_GET_MSG_CMPL.

void app_handle_cmd_set(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t rx_seqn,
                        uint8_t app_idx)
{
    ...
    case CMD_MAP_SET_FOLDER:
        {
            struct
            {
                uint16_t cmd_id;
                uint8_t folder;
            } __attribute__((packed)) *params;

            params = (typeof(params)) cmd_ptr;

            bt_map_mas_folder_set(app_db.br_link[app_idx].bd_addr, (T_BT_MAP_FOLDER)params->folder);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    case CMD_MAP_GET_FOLDER_LISTING:
        {
            struct
            {
                uint16_t cmd_id;
                uint8_t max_list_count;
                uint8_t start_offset;
            } __attribute__((packed)) *params = (typeof(params)) cmd_ptr;

            bt_map_mas_folder_listing_get(app_db.br_link[app_idx].bd_addr, params->max_list_count,
                                          params->start_offset);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

//inbox name is fixed here
    case CMD_MAP_GET_MESSAGE_LISTING:
        {
            struct
            {
                uint16_t cmd_id;
                uint8_t max_list_count;
                uint8_t start_offset;
            } __attribute__((packed)) *params = (typeof(params)) cmd_ptr;

            uint8_t map_path_inbox[12] =
            {
                0x00, 0x69, 0x00, 0x6e, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x78, 0x00, 0x00
            };
            bt_map_mas_msg_listing_get(app_db.br_link[app_idx].bd_addr, map_path_inbox, sizeof(map_path_inbox),
                                       params->max_list_count, params->start_offset);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

    case CMD_MAP_GET_MESSAGE:
        {
            struct
            {
                uint16_t cmd_id;
                uint8_t handle_len;
                uint8_t msg_handle[];
            } __attribute__((packed)) *params = (typeof(params)) cmd_ptr;

            bt_map_mas_msg_get(app_db.br_link[app_idx].bd_addr, params->msg_handle, params->handle_len, false);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
}
MAP Push Message

bt_map_mas_msg_push() is used to push a message to a folder of the MSE. In the case of sending messages through the MSE, the messages shall be uploaded into the ‘Outbox’ folder of the MSE. In the case of uploading messages to the MSE, the messages shall not be uploaded into the ‘Outbox’ folder of the MSE, but any other folder is permitted. In the case of sending messages through the MSE, the MCE shall get a notification when the messages have been sent to the network and thus have been shifted by the MSE from the ‘Outbox’ to the ‘Sent’ folder.

    case CMD_MAP_PUSH_MESSAGE:
        {
            struct
            {
                uint16_t cmd_id;
                uint16_t msg_len;
                uint8_t msg[];
            } __attribute__((packed)) *params = (typeof(params)) cmd_ptr;

            uint8_t map_path_outbox[14] =
            {
                0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x62,
                0x00, 0x6f, 0x00, 0x78, 0x00, 0x00
            };
            bt_map_mas_msg_push(app_db.br_link[app_idx].bd_addr, map_path_outbox, sizeof(map_path_outbox),
                                false, false, params->msg, params->msg_len);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
MAP Disconnect

bt_map_mas_disconnect_req() is used to disconnect Message Access Service.

    case CMD_MAP_DISCONNECT:
        {
            bt_map_mas_disconnect_req(app_db.br_link[app_idx].bd_addr);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

PBAP PCE

PBAP roles can be divided into PSE and PCE:

  • Phone Book Server Equipment (PSE) is the device that contains the source phone book objects.

  • Phone Book Client Equipment (PCE) is the device that retrieves phone book objects from the Server Equipment.

The code flow of PBAP PCE is introduced here.

PBAP Initialization

bt_pbap_init() is invoked in app_pbap_init() when the application is powered on or the chip is reset.

void app_pbap_init(void)
{
    if (app_cfg_const.supported_profile_mask & PBAP_PROFILE_MASK)
    {
        bt_pbap_init(app_cfg_const.pbap_link_number);
        bt_mgr_cback_register(app_pbap_bt_cback);
        app_timer_reg_cb(app_pbap_timeout_cb, &app_pbap_timer_id);
    }
}

int main(void)
{
  ...
#if F_APP_BT_PROFILE_PBAP_PCE_SUPPORT
        app_pbap_init();
#endif
  ...
}
PBAP Connect

We always use UUID_PBAP_PSE to do service discovery. OBEX connections in PBAP shall always be initiated by the PCE device using bt_pbap_connect_req().

CMD_PBAP_CONNECT is utilized to initiate SDP in app_pbap_cmd_handle(), and bt_pbap_connect_req will be called after receiving BT_EVENT_SDP_ATTR_INFO.

void app_pbap_cmd_handle(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t app_idx,
                         uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    switch (cmd_id)
    {
    case CMD_PBAP_CONNECT:
        {
            T_GAP_UUID_DATA uuid_data;

            uuid_data.uuid_16 = UUID_PBAP_PSE;
            gap_br_start_sdp_discov(app_db.br_link[app_idx].bd_addr, GAP_UUID16, uuid_data);

            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;
    ...
    }
}

void app_handle_cmd_set(uint8_t *cmd_ptr, uint16_t cmd_len, uint8_t cmd_path, uint8_t rx_seqn,
                        uint8_t app_idx)
{
    uint16_t cmd_id;
    uint8_t  ack_pkt[3];

    cmd_id     = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
#if F_APP_PBAP_CMD_SUPPORT
    case CMD_PBAP_DOWNLOAD...CMD_PBAP_DISCONNECT:
        {
            app_pbap_cmd_handle(cmd_ptr, cmd_len, cmd_path, app_idx, ack_pkt);
        }
        break;
#endif
    ...
    }
}

static void app_test_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    bool handle = true;
    ...
    switch (event_type)
    {
    ...
    case BT_EVENT_SDP_ATTR_INFO:
        {
            T_BT_SDP_ATTR_INFO *sdp_info = &param->sdp_attr_info.info;

            if (sdp_info->srv_class_uuid_data.uuid_16 == UUID_MSG_ACCESS_SERVER)
            {
                bt_map_mas_connect_over_rfc_req(param->sdp_attr_info.bd_addr, sdp_info->server_channel);
            }
            else if (sdp_info->srv_class_uuid_data.uuid_16 == UUID_PBAP_PSE)
            {
                bt_pbap_connect_req(param->sdp_attr_info.bd_addr, sdp_info->server_channel,
                                    sdp_info->supported_feat);
            }
        }
        break;
      ...
    }
}

Note

It takes time to complete the authorization which involves user participation. So DO NOT initiate a PBAP connection immediately after pairing with phone. It is recommended to establish a PBAP connection when actually needed.

PBAP Pull

CMD_PBAP_DOWNLOAD is utilized to download the phonebook of interest in app_pbap_cmd_handle(), users can choose the content to be pulled according to different cases such as current call history (cch), phonebook, all records, etc.

    case CMD_PBAP_DOWNLOAD:
        {
            app_pbap_download_info_set_default();

            switch (cmd_ptr[2])
            {
            ...
            case PBAP_DOWNLOAD_METHOD_ALL:
                {
                    pbap_download_info.download_flag |= (PBAP_DOWNLOAD_ME_PB_MASK | PBAP_DOWNLOAD_SM_PB_MASK |
                                                         PBAP_DOWNLOAD_CCH_MASK);
                }
                break;

            case PBAP_DOWNLOAD_METHOD_ALL_PB:
                {
                    pbap_download_info.download_flag |= (PBAP_DOWNLOAD_ME_PB_MASK | PBAP_DOWNLOAD_SM_PB_MASK);
                }
                break;

            case PBAP_DOWNLOAD_METHOD_CCH:
                {
                    pbap_download_info.storage = BT_PBAP_PHONE_BOOK_CCH;
                    pbap_download_info.phone_book = BT_PBAP_PHONE_BOOK_CCH;
                }
                break;

            default:
                ack_pkt[2] = CMD_SET_STATUS_PARAMETER_ERROR;
                break;
            }

            if (ack_pkt[2] == CMD_SET_STATUS_COMPLETE)
            {
                pbap_download_info.method = cmd_ptr[2];
                pbap_download_info.filter = (uint64_t)(cmd_ptr[3] | (cmd_ptr[4] << 8) | (cmd_ptr[5] << 16) |
                                                       (cmd_ptr[6] << 24));

                if (bt_pbap_phone_book_size_get(app_db.br_link[active_hf_idx].bd_addr,
                                                (T_BT_PBAP_REPOSITORY)pbap_download_info.repos,
                                                (T_BT_PBAP_PHONE_BOOK)pbap_download_info.phone_book) == false)
                {
                    ack_pkt[2] = CMD_SET_STATUS_PROCESS_FAIL;
                }
            }
            app_report_event(cmd_path, APP_EVENT_ACK, app_idx, ack_pkt, 3);
        }
        break;
    ...

Users can also control PBAP pause/continue/abort to pull information through CMD_PBAP_DOWNLOAD_CONTROL, where bt_pbap_pull_abort(), bt_pbap_pull_continue() are called:

    case CMD_PBAP_DOWNLOAD_CONTROL:
        {
            switch (cmd_ptr[2])
            {
            case PBAP_DOWNLOAD_CONTROL_ABORT:
                {
                    if (bt_pbap_pull_abort(app_db.br_link[active_hf_idx].bd_addr) == false)
                    {
                        ack_pkt[2] = CMD_SET_STATUS_PROCESS_FAIL;
                    }
                    else
                    {
                        app_stop_timer(&timer_idx_pbap_pull_continue);
                    }
                }
                break;

            case PBAP_DOWNLOAD_CONTROL_SUSPEND:
                {
                    enable_auto_pbap_download_continue_flag = false;
                }
                break;

            case PBAP_DOWNLOAD_CONTROL_CONTINUE:
                {
                    if (bt_pbap_pull_continue(app_db.br_link[active_hf_idx].bd_addr))
                    {
                        enable_auto_pbap_download_continue_flag = true;
                    }
                    else
                    {
                        ack_pkt[2] = CMD_SET_STATUS_PROCESS_FAIL;
                    }
                }
                break;

            default:
                ack_pkt[2] = CMD_SET_STATUS_PARAMETER_ERROR;
                break;
            }

            app_report_event(cmd_path, APP_EVENT_ACK, app_idx, ack_pkt, 3);
            if (ack_pkt[2] == CMD_SET_STATUS_COMPLETE)
            {
                uint8_t temp_buff[1];

                temp_buff[0] = cmd_ptr[2];
                app_report_event(cmd_path, APP_EVENT_PBAP_REPORT_SESSION_STATUS, app_idx, temp_buff,
                                 sizeof(temp_buff));
            }
        }
        break;
PBAP Disconnect

When the PBAP connection is no longer needed, call bt_pbap_disconnect_req() in CMD_PBAP_DISCONNECT to terminate the PBAP connection.

    case CMD_PBAP_DISCONNECT:
        {
            bt_pbap_disconnect_req(app_db.br_link[app_idx].bd_addr);
            app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
        }
        break;

CIS Acceptor

Bluetooth Low Energy Audio CAP roles can be divided into Acceptor, Initiator, and Commander. The Acceptor role can enable Bluetooth Low Energy Audio advertising and be connected by a remote device, control the music player and telephone call by MCP and CCP profile.

CIS Initialization

app_lea_acc_profile_init() includes the initialization flow for ASCS, VCS, CSIS, MCP, CCP, and other modules.

void app_lea_acc_profile_init(void)
{
    T_CAP_INIT_PARAMS cap_init_param = {0};

#if (F_APP_TMAP_CT_SUPPORT || F_APP_TMAP_UMR_SUPPORT)
    app_lea_ascs_init();
#endif
#if F_APP_MCP_SUPPORT
    app_lea_mcp_init();
#endif
#if F_APP_CCP_SUPPORT
    app_lea_ccp_init();
#endif
    app_lea_pacs_init();
#if F_APP_VCS_SUPPORT
    app_lea_vcs_init();
#endif
#if F_APP_TAMP_BMR_SUPPORT
    app_lea_bca_init();
#endif
    app_lea_profile_bap_init();
#if F_APP_CSIS_SUPPORT
    app_lea_csis_init(&cap_init_param);
#endif
    app_lea_profile_cap_init(&cap_init_param);
#if F_APP_TMAS_SUPPORT
    app_lea_profile_tmas_init();
#endif
#if (F_APP_TMAP_CT_SUPPORT || F_APP_TMAP_UMR_SUPPORT)
    app_lea_uca_init();
#endif
}
CIS Connect

Firstly, the Acceptor needs to enable Bluetooth Low Energy Audio advertising, and then the remote device can scan and create a Bluetooth Low Energy Audio link to it. The adv_interval_min and adv_interval_max parameters can be modified by the user to change the Bluetooth Low Energy Audio advertising interval. Actually, the user can enable or disable the F_APP_LE_AUDIO_CIS_RND_ADDR macro to use public or static random address for advertisement.

static void app_lea_adv_set(uint16_t audio_adv_flag, uint8_t service_num)
{
    uint16_t audio_adv_len = 0;
    T_LE_EXT_ADV_EXTENDED_ADV_PROPERTY adv_event_prop = LE_EXT_ADV_EXTENDED_ADV_CONN_UNDIRECTED;
    uint16_t adv_interval_min = 0x40;
    uint16_t adv_interval_max = 0x50;

#if F_APP_LE_AUDIO_CIS_RND_ADDR
    T_GAP_LOCAL_ADDR_TYPE own_address_type = GAP_LOCAL_ADDR_LE_RANDOM;
#else
    T_GAP_LOCAL_ADDR_TYPE own_address_type = GAP_LOCAL_ADDR_LE_PUBLIC;
#endif
    T_GAP_REMOTE_ADDR_TYPE peer_address_type = GAP_REMOTE_ADDR_LE_PUBLIC;
    uint8_t  peer_address[6] = {0, 0, 0, 0, 0, 0};
    T_GAP_ADV_FILTER_POLICY filter_policy = GAP_ADV_FILTER_ANY;

#if F_APP_LE_AUDIO_CIS_RND_ADDR
    //the type of static random address is 0xC0
    if ((app_cfg_nv.lea_static_random_addr[5] & 0xC0) != 0xC0)
    {
        le_gen_rand_addr(GAP_RAND_ADDR_STATIC, app_cfg_nv.lea_static_random_addr);
        app_cfg_store(app_cfg_nv.lea_static_random_addr, 6);
        APP_PRINT_TRACE1("app_lea_adv_set: cis_static_random_addr %s",
                         TRACE_BDADDR(app_cfg_nv.lea_static_random_addr));

    }
#endif

    audio_adv_len = app_lea_adv_ext_data(audio_adv_flag, service_num);
    ble_ext_adv_mgr_init_adv_params(&app_lea_adv_handle, adv_event_prop, adv_interval_min,
                                    adv_interval_max, own_address_type, peer_address_type, peer_address,
                                    filter_policy, audio_adv_len, app_lea_adv_data,
                                    sizeof(app_lea_adv_scan_rsp_data), app_lea_adv_scan_rsp_data, NULL);
    ble_ext_adv_mgr_change_adv_phy(app_lea_adv_handle, GAP_PHYS_PRIM_ADV_1M, GAP_PHYS_2M);
    ble_ext_adv_mgr_register_callback(app_lea_adv_cback, app_lea_adv_handle);
}

app_lea_adv_start() enables Bluetooth Low Energy Audio advertising, and app_lea_adv_stop() disables Bluetooth Low Energy Audio advertising.

void app_lea_adv_start(uint8_t mode)
{
    uint8_t public_addr_lsb[6];
    uint8_t len = 0;

    gap_get_param(GAP_PARAM_BD_ADDR, public_addr_lsb);

    APP_PRINT_INFO2("app_lea_adv_start: public addr %s mode %d",
                    TRACE_BDADDR(public_addr_lsb), mode);

    if ((mode == LEA_ADV_MODE_PAIRING) && (app_link_get_le_link_num() > 2))
    {
        return;
    }

    if (app_lea_adv_state == BLE_EXT_ADV_MGR_ADV_DISABLED)
    {
#if F_APP_LE_AUDIO_CIS_RND_ADDR
        ble_ext_adv_mgr_set_random(app_lea_adv_handle, app_cfg_nv.lea_static_random_addr);
#endif
        if (ble_ext_adv_mgr_enable(app_lea_adv_handle, 0) == GAP_CAUSE_SUCCESS)
        {
            if ((T_LEA_ADV_MODE)mode == LEA_ADV_MODE_LINK_LOSS_LINK_BACK)
            {
                app_start_timer(&timer_idx_lea_adv, "lea_adv_linkloss", app_lea_adv_timer_id,
                                APP_LEA_TMR_LINKLOSS, 0, false, LEA_ADV_TMR_LINK_LOST * 1000);
            }
            else  if ((T_LEA_ADV_MODE)mode == LEA_ADV_MODE_PAIRING)
            {
                app_start_timer(&timer_idx_lea_adv, "lea_adv_pairing", app_lea_adv_timer_id,
                                APP_LEA_TMR_PAIRING, 0, false, LEA_ADV_TMR_PAIRING * 1000);
            }
        }
    }

    return;
}

void app_lea_adv_stop()
{
    app_stop_timer(&timer_idx_lea_adv);

    ble_ext_adv_mgr_disable(app_lea_adv_handle, 0);
}

For the Acceptor, the app_lea_uca_link_sm() function is used to handle Bluetooth Low Energy Audio and Legacy events. It has three states: LEA_LINK_IDLE, LEA_LINK_CONNECTED, and LEA_LINK_STREAMING to handle different events. Based on some specific events, the state machine can switch its state with the app_lea_uca_link_state_change() API.

void app_lea_uca_link_sm(uint16_t conn_handle, uint8_t event, void *p_data)
{
    T_APP_LE_LINK *p_link;
    p_link = app_link_find_le_link_by_conn_handle(conn_handle);

    if (p_link == NULL)
    {
        return;
    }

    APP_PRINT_INFO3("app_lea_uca_link_sm: conn_handle 0x%x, event %x, %d", conn_handle, event,
                    p_link->lea_link_state);
    switch (p_link->lea_link_state)
    {
    case LEA_LINK_IDLE:
        app_lea_uca_link_idle(p_link, event, p_data);
        break;

    case LEA_LINK_CONNECTED:
        app_lea_uca_link_connected(p_link, event, p_data);
        break;

    case LEA_LINK_STREAMING:
        app_lea_uca_link_streaming(p_link, event, p_data);
        break;

    default:
        break;
    }
    app_lea_uca_dump_ase_info(p_link);
    app_lea_uca_dump_call_info(p_link);
}

static void app_lea_uca_link_state_change(T_APP_LE_LINK *p_link, T_LEA_LINK_STATE state)
{
    APP_PRINT_INFO2("app_lea_uca_link_state_change: change from %d to %d", p_link->lea_link_state,
                    state);
    p_link->lea_link_state = state;
}

For example, unicast audio state machine idle state app_lea_uca_link_idle() handles LEA_CONNECT event, and the state will change to LEA_LINK_CONNECTED from LEA_LINK_IDLE.

static void app_lea_uca_link_idle(T_APP_LE_LINK *p_link, uint8_t event, void *p_data)
{
    APP_PRINT_INFO2("app_lea_uca_link_idle: event %x, state %x", event, p_link->lea_link_state);
    switch (event)
    {
    case LEA_CONNECT:
        {
            // TODO: to avoid service discovery taking long time, change to 7.5ms
            //ble_set_prefer_conn_param(p_link->conn_id, 0x06, 0x06, 0, 500);
            app_lea_uca_link_state_change(p_link, LEA_LINK_CONNECTED);
            app_bond_le_set_bond_flag((void *)p_link, BOND_FLAG_LEA);

            app_sniff_mode_b2s_enable_all(SNIFF_DISABLE_MASK_LEA);
        }
        break;

    default:
        break;
    }
}
CIS Media

For CIS Acceptor down-link audio path, app_lea_uca_handle_iso_data() sends ISO data to DSP, which can decode LC3 audio data to PCM, and output audio by codec.

void app_lea_uca_handle_iso_data(T_BT_DIRECT_CB_DATA *p_data)
{
    T_LEA_ASE_ENTRY *p_ase_entry;

    p_ase_entry = app_lea_ascs_find_ase_entry_non_conn(LEA_ASE_DOWN_DIRECT,
                                                       (void *)&p_data->p_bt_direct_iso->conn_handle,
                                                       NULL);

    if (p_ase_entry != NULL)
    {
        uint16_t written_len;
        T_AUDIO_STREAM_STATUS status;

        if (p_data->p_bt_direct_iso->iso_sdu_len != 0)
        {
            status = AUDIO_STREAM_STATUS_CORRECT;
        }
        else
        {
            status = AUDIO_STREAM_STATUS_LOST;
        }

        audio_track_write(p_ase_entry->track_handle, p_data->p_bt_direct_iso->time_stamp,
                          p_data->p_bt_direct_iso->pkt_seq_num,
                          status,
                          p_ase_entry->frame_num,
                          p_data->p_bt_direct_iso->p_buf + p_data->p_bt_direct_iso->offset,
                          p_data->p_bt_direct_iso->iso_sdu_len,
                          &written_len);
    }
}

The Acceptor can control the remote connected device’s music player by mcp_client_write_media_cp() to fill the specific parameter. For example, the Acceptor can pause the music player.

T_MCP_CLIENT_WRITE_MEDIA_CP_PARAM param;

param.opcode = MCS_MEDIA_CONTROL_POINT_CHAR_OPCODE_PAUSE;
mcp_client_write_media_cp(p_link->conn_handle, 0, p_link->gmcs, &param, true);
CIS Conversation

For the conversation scenario, the acceptor also needs to handle the up-link audio path. app_lea_uca_audio_cback() receives ISO data from the DSP which can encode PCM to LC3 audio data and send it to the remote device.

static void app_lea_uca_audio_cback(T_AUDIO_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_AUDIO_EVENT_PARAM *param = event_buf;

    switch (event_type)
    {
	...
    case AUDIO_EVENT_TRACK_DATA_IND:
        {
            uint32_t timestamp;
            uint16_t seq_num;
            uint8_t frame_num;
            uint16_t read_len;
            uint8_t *buf;
            T_AUDIO_STREAM_STATUS status;

            if (param->track_data_ind.len == 0)
            {
                return;
            }

            buf = malloc(param->track_data_ind.len);

            if (buf == NULL)
            {
                return;
            }

            if (audio_track_read(param->track_data_ind.handle,
                                 &timestamp,
                                 &seq_num,
                                 &status,
                                 &frame_num,
                                 buf,
                                 param->track_data_ind.len,
                                 &read_len) == true)
            {
                uint16_t conn_handle = 0;

#if F_APP_CCP_SUPPORT
                conn_handle = app_lea_ccp_get_active_conn_handle();
#endif
                T_LEA_ASE_ENTRY *p_ase_entry = app_lea_ascs_find_ase_entry(LEA_ASE_TRACK, conn_handle,
                                                                           param->track_data_ind.handle);
                if (p_ase_entry != NULL)
                {
                    if (app_lea_uca_mic_ignore_cnt == 0)
                    {
                        gap_iso_send_data((uint8_t *)buf, p_ase_entry->cis_conn_handle, param->track_data_ind.len, true,
                                          timestamp,
                                          seq_num);
                    }

                    if (app_lea_uca_mic_ignore_cnt > 0)
                    {
                        app_lea_uca_mic_ignore_cnt--;
                    }
                }

            }
            free(buf);
        }
        break;
    }
}

Actually, the acceptor can control the remote connected device’s telephone call by ccp_client_write_call_cp() filling the specific parameter. For example, the acceptor can accept the incoming call.

T_CCP_CLIENT_WRITE_CALL_CP_PARAM write_call_cp_param = {0};

write_call_cp_param.opcode = TBS_CALL_CONTROL_POINT_CHAR_OPCODE_ACCEPT;
write_call_cp_param.param.accept_opcode_call_index = p_call_entry->call_index;
ccp_client_write_call_cp(p_link->conn_handle, 0, p_link->gtbs, false, &write_call_cp_param);
CIS VCS

For LE Audio volume control, the Acceptor also needs to save the volume value and SPK mute state to FTL from the volume controller. The function app_lea_vol_update_track_volume() will configure the current audio track volume using the VCS value to accurately reflect the audio output.

static uint16_t app_lea_vcs_handle_vcs_msg(T_LE_AUDIO_MSG msg, void *buf)
{
    ...
    switch (msg)
    {
    case LE_AUDIO_MSG_VCS_VOLUME_CP_IND:
        {
            T_APP_LE_LINK *p_link;
            T_VCS_VOLUME_CP_IND *p_vcs_vol_state = (T_VCS_VOLUME_CP_IND *)buf;

            p_link = app_link_find_le_link_by_conn_handle(p_vcs_vol_state->conn_handle);
            if (p_link != NULL)
            {
                app_cfg_nv.lea_vol_setting = p_vcs_vol_state->volume_setting;
                app_cfg_nv.lea_vol_out_mute = p_vcs_vol_state->mute;

                APP_PRINT_TRACE3("app_lea_vcs_handle_vcs_msg: LE_AUDIO_MSG_VCS_VOLUME_CP_IND \
conn_handle 0x%02X, volume_setting 0x%02X, mute %d",
                                 p_vcs_vol_state->conn_handle,
                                 p_vcs_vol_state->volume_setting,
                                 p_vcs_vol_state->mute);
            }
        }
        break;

    default:
        break;
    }

    return cb_result;
}

static uint16_t app_lea_vol_ble_audio_cback(T_LE_AUDIO_MSG msg, void *buf)
{
    ...
    switch (msg)
    {
    case LE_AUDIO_MSG_VCS_VOLUME_CP_IND:
        {
            T_APP_LE_LINK *p_link;
            T_VCS_VOLUME_CP_IND *p_vcs_vol_state = (T_VCS_VOLUME_CP_IND *)buf;

            p_link = app_link_find_le_link_by_conn_handle(p_vcs_vol_state->conn_handle);
            if ((p_link != NULL))
            {
                app_lea_vol_update_track_volume();
            }
        }
        break;

    default:
        break;
    }

    return cb_result;
}

The acceptor can change the local device’s audio volume, such as volume up/down, and SPK mute/unmute. It will always notify the new volume state by calling vcs_set_param(&vcs_param) to the remotely connected device.

T_VCS_PARAM vcs_param;

vcs_get_param(&vcs_param);
...
vcs_param.volume_setting = volume;
vcs_param.mute = mute;
vcs_param.volume_flags = VCS_USER_SET_VOLUME_SETTING;
vcs_param.change_counter++;
vcs_set_param(&vcs_param);

BIS Acceptor

BIS Acceptor Initialization

app_lea_acc_profile_init() is utilized to initialize BIS Acceptor-related services and profiles.

app_lea_pacs_init() is utilized to initialize PACS. app_lea_vcs_init() is utilized to initialize VCS. app_lea_bca_init() is utilized to initialize broadcast audio-related functions. app_lea_profile_bap_init() is utilized to initialize BAP role and ISO capabilities. app_lea_csis_init() is utilized to initialize CSIS. app_lea_profile_cap_init() is utilized to initialize CAS. app_lea_profile_tmas_init() is utilized to initialize TMAS.

void app_lea_acc_profile_init(void)
{
    T_CAP_INIT_PARAMS cap_init_param = {0};

    app_lea_pacs_init();
#if F_APP_VCS_SUPPORT
    app_lea_vcs_init();
#endif
#if F_APP_TAMP_BMR_SUPPORT
    app_lea_bca_init();
#endif
    app_lea_profile_bap_init();
#if F_APP_CSIS_SUPPORT
    app_lea_csis_init(&cap_init_param);
#endif
    app_lea_profile_cap_init(&cap_init_param);
#if F_APP_TMAS_SUPPORT
    app_lea_profile_tmas_init();
#endif
}
BIS Acceptor Connect

The Acceptor must establish a connection with the Commander if it wants to be controlled by a remote Commander. To accomplish this, the Acceptor shall enable LE advertising before the Initiator scanning and creating a connection. The Acceptor could stop the advertising by calling app_lea_adv_stop() if it wants to stop advertising or timeout.

void app_lea_adv_start(uint8_t mode)
{
    uint8_t public_addr_lsb[6];
    uint8_t len = 0;

    gap_get_param(GAP_PARAM_BD_ADDR, public_addr_lsb);

    APP_PRINT_INFO2("app_lea_adv_start: public addr %s mode %d",
                    TRACE_BDADDR(public_addr_lsb), mode);

    if ((mode == LEA_ADV_MODE_PAIRING) && (app_link_get_le_link_num() > 2))
    {
        return;
    }

    if (app_lea_adv_state == BLE_EXT_ADV_MGR_ADV_DISABLED)
    {
#if F_APP_LE_AUDIO_CIS_RND_ADDR
        ble_ext_adv_mgr_set_random(app_lea_adv_handle, app_cfg_nv.lea_static_random_addr);
#endif
        if (ble_ext_adv_mgr_enable(app_lea_adv_handle, 0) == GAP_CAUSE_SUCCESS)
        {
            if ((T_LEA_ADV_MODE)mode == LEA_ADV_MODE_LINK_LOSS_LINK_BACK)
            {
                app_start_timer(&timer_idx_lea_adv, "lea_adv_linkloss", app_lea_adv_timer_id,
                                APP_LEA_TMR_LINKLOSS, 0, false, LEA_ADV_TMR_LINK_LOST * 1000);
            }
            else  if ((T_LEA_ADV_MODE)mode == LEA_ADV_MODE_PAIRING)
            {
                app_start_timer(&timer_idx_lea_adv, "lea_adv_pairing", app_lea_adv_timer_id,
                                APP_LEA_TMR_PAIRING, 0, false, LEA_ADV_TMR_PAIRING * 1000);
            }
        }
    }

    return;
}

void app_lea_adv_stop()
{
    app_stop_timer(&timer_idx_lea_adv);

    ble_ext_adv_mgr_disable(app_lea_adv_handle, 0);
}

app_lea_bca_sm() function is used to handle Bluetooth Low Energy Audio events based on the corresponding state.

bool app_lea_bca_sm(uint8_t event, void *p_data)
{
    APP_PRINT_INFO2("app_lea_bca_sm: event 0x%x, state 0x%x", event,
                    app_lea_bca_state_machine);
    bool accept = true;

    switch (app_lea_bca_state_machine)
    {
    case LEA_BCA_STATE_IDLE:
        {
            accept = app_lea_bca_state_idle(event, p_data);
        }
        break;
    case LEA_BCA_STATE_PRE_SCAN:
    case LEA_BCA_STATE_PRE_ADV:
        accept = app_lea_bca_state_starting(event, p_data);
        break;

    case LEA_BCA_STATE_CONN_SCAN:
    case LEA_BCA_STATE_CONN:
        accept = app_lea_bca_state_conn(event, p_data);
        break;

    case LEA_BCA_STATE_SCAN:
        accept = app_lea_bca_state_scan(event, p_data);
        break;

    case LEA_BCA_STATE_STREAMING:
        accept = app_lea_bca_state_streaming(event, p_data);
        break;

    default:
        accept = false;
        break;
    }
    return accept;
}
BIS Acceptor Synchronize

If the Acceptor wants to synchronize a source autonomously without an assistant, it must scan the extended advertising and periodic advertising nearby, and create the Periodic Advertising (PA) and Broadcast Isochronous Stream (BIS) synchronization.

In order to receive the broadcast sync state and event, and to initiate state changes and further operations at a higher layer, the following broadcast audio sync callback function needs to be registered.

void app_lea_bca_sync_cb(T_BLE_AUDIO_SYNC_HANDLE handle, uint8_t cb_type, void *p_cb_data)
{
    T_BLE_AUDIO_SYNC_CB_DATA *p_sync_cb = (T_BLE_AUDIO_SYNC_CB_DATA *)p_cb_data;
    T_APP_LEA_BCA_DB *p_bc_source = app_lea_bca_find_device_by_bs_handle(handle);
    if (p_bc_source == NULL)
    {
        return;
    }
    APP_PRINT_INFO1("app_lea_bca_sync_cb: cb_type %d", cb_type);

    switch (cb_type)
    {
	...
    case MSG_BLE_AUDIO_PA_SYNC_STATE:
        {
            APP_PRINT_INFO3("MSG_BLE_AUDIO_PA_SYNC_STATE: sync_state %d, action %d, cause 0x%x\r\n",
                            p_sync_cb->p_pa_sync_state->sync_state,
                            p_sync_cb->p_pa_sync_state->action,
                            p_sync_cb->p_pa_sync_state->cause);
            T_APP_LEA_BCA_SYNC_CHECK para;

            para.type = BS_TYPE_PA;
            para.p_sync_cb = p_sync_cb;
            para.p_bc_source = p_bc_source;
            para.handle = handle;

            //PA sync lost
            if (((p_sync_cb->p_pa_sync_state->action == BLE_AUDIO_PA_LOST) ||
                 (p_sync_cb->p_pa_sync_state->action == BLE_AUDIO_PA_SYNC)) &&
                (p_sync_cb->p_pa_sync_state->sync_state == GAP_PA_SYNC_STATE_TERMINATED) &&
                (p_sync_cb->p_pa_sync_state->cause == 0x13e))
            {
                if (app_lea_bca_release_all(para))
                {
                    app_lea_bca_tgt_active(false, (APP_BIS_BIS_CTRL_RESET_ACTIVE & APP_BIS_BIS_CTRL_RESET_SD_ACTIVE));
                    app_lea_mgr_tri_mmi_handle_action(MMI_BIG_START, true);
                }
            }
            else if ((p_sync_cb->p_pa_sync_state->sync_state == GAP_PA_SYNC_STATE_SYNCHRONIZING_WAIT_SCANNING)
                     &&
                     !p_bc_source->is_past)
            {
                p_bc_source->is_past = 1;
                app_lea_acc_scan_start();
            }
            else if (((p_sync_cb->p_pa_sync_state->action == BLE_AUDIO_PA_TERMINATE) &&
                      (p_sync_cb->p_pa_sync_state->cause == 0x144) &&
                      (p_sync_cb->p_pa_sync_state->sync_state == GAP_PA_SYNC_STATE_TERMINATED)))
            {
                if (app_lea_bca_release_all(para))
                {
                    app_lea_bca_tgt_active(false, (APP_BIS_BIS_CTRL_RESET_ACTIVE & APP_BIS_BIS_CTRL_RESET_SD_ACTIVE));
                }
            }
            else if (((p_sync_cb->p_pa_sync_state->action == BLE_AUDIO_PA_TERMINATE) &&
                      (p_sync_cb->p_pa_sync_state->cause == 0x116) &&
                      (p_sync_cb->p_pa_sync_state->sync_state == GAP_PA_SYNC_STATE_TERMINATED)))
            {
                if (app_lea_bca_state() == LEA_BCA_STATE_WAIT_TERM ||
                    app_lea_bca_state() == LEA_BCA_STATE_WAIT_RETRY)
                {
                    if (app_lea_bca_release_all(para))
                    {
                        app_lea_bca_tgt_active(false, (APP_BIS_BIS_CTRL_RESET_ACTIVE & APP_BIS_BIS_CTRL_RESET_SD_ACTIVE));
                    }
                }
            }

            p_bc_source->sync_state = p_sync_cb->p_pa_sync_state->sync_state;
        }
        break;

    case MSG_BLE_AUDIO_BASE_DATA_MODIFY_INFO:
        {
            APP_PRINT_TRACE3("MSG_BLE_AUDIO_BASE_DATA_MODIFY_INFO: p_base_mapping %p, used %d, sd_source %d\r\n",
                             p_sync_cb->p_base_data_modify_info->p_base_mapping, p_bc_source->used, app_lea_bca_get_sd_source());

            if (p_sync_cb->p_base_data_modify_info->p_base_mapping)
            {
                T_BASE_DATA_MAPPING *p_mapping = p_sync_cb->p_base_data_modify_info->p_base_mapping;

                app_lea_bca_remap_bis(p_mapping, handle);
                p_bc_source->used |= APP_LEA_BCA_BASE_DATA;

                if (p_bc_source->used & APP_LEA_BCA_BIG_INFO &&
                    ((app_lea_bca_bs_tgt.ctrl & APP_BIS_BIS_CTRL_SD_ACTIVE) == 0))
                {
                    if (app_lea_bca_get_sd_source() != 0xff && p_bc_source->is_encryp)
                    {
                        bass_send_broadcast_code_required(p_bc_source->source_id);
                    }
                    else
                    {
                        app_lea_bca_big_establish(handle, p_bc_source->is_encryp);
                    }
                }
            }
        }
        break;


    case MSG_BLE_AUDIO_PA_REPORT_INFO:
        {
            if (p_bc_source->big_state == BIG_SYNC_RECEIVER_SYNC_STATE_SYNCHRONIZED)
            {
                ble_audio_pa_terminate(p_bc_source->sync_handle);
            }
        }
        break;

    case MSG_BLE_AUDIO_PA_BIGINFO:
        {
            T_LE_BIGINFO_ADV_REPORT_INFO *p_adv_report_info =  p_sync_cb->p_le_biginfo_adv_report_info;

            APP_PRINT_INFO7("MSG_BLE_AUDIO_PA_BIGINFO: num_bis %d, %d, %d, %d, 0x%x ,%d, %d",
                            p_adv_report_info->num_bis,
                            p_adv_report_info->encryption,
                            app_lea_bca_state_machine,
                            p_bc_source->used,
                            app_lea_bca_get_sd_source(),
                            p_bc_source->is_encryp,
                            p_adv_report_info->encryption);

            if (app_lea_bca_state_machine == LEA_BCA_STATE_WAIT_TERM)
            {
                break;
            }

            p_bc_source->used |= APP_LEA_BCA_BIG_INFO;
            p_bc_source->is_encryp = p_adv_report_info->encryption;

            if ((p_bc_source->used & APP_LEA_BCA_BASE_DATA) == 0)
            {
                break;
            }

            if (app_lea_bca_bs_tgt.ctrl & APP_BIS_BIS_CTRL_SD_ACTIVE)
            {
                T_BIG_MGR_SYNC_RECEIVER_BIG_CREATE_SYNC_PARAM sync_param;

                app_lea_bca_apply_sync_pera(&sync_param, handle, p_adv_report_info->encryption);
            }
            else
            {
                if (app_lea_bca_get_sd_source() != 0xff &&
                    !p_bc_source->is_encryp && p_adv_report_info->encryption)
                {
                    bass_send_broadcast_code_required(p_bc_source->source_id);
                }
                else
                {
                    app_lea_bca_big_establish(handle, p_adv_report_info->encryption);
                }
            }
        }
        break;

    case MSG_BLE_AUDIO_BIG_SYNC_STATE:
        {
            T_APP_LEA_BCA_SYNC_CHECK para;
            para.type = BS_TYPE_BIG;
            para.p_sync_cb = p_sync_cb;
            para.p_bc_source = p_bc_source;
            para.handle = handle;

            APP_PRINT_INFO4("MSG_BLE_AUDIO_BIG_SYNC_STATE: sync_state %d, action %d,action role %d, cause 0x%x\r\n",
                            p_sync_cb->p_big_sync_state->sync_state,
                            p_sync_cb->p_big_sync_state->action,
                            p_sync_cb->p_big_sync_state->action_role,
                            p_sync_cb->p_big_sync_state->cause);


            if ((p_sync_cb->p_big_sync_state->sync_state == BIG_SYNC_RECEIVER_SYNC_STATE_TERMINATED) &&
                (p_sync_cb->p_big_sync_state->action == BLE_AUDIO_BIG_TERMINATE ||
                 p_sync_cb->p_big_sync_state->action == BLE_AUDIO_BIG_IDLE) &&
                (p_sync_cb->p_big_sync_state->cause == 0))
            {
                uint8_t dev_info = 0;

                APP_PRINT_INFO1("app_lea_bca_sync_cb: BIG_SYNC_RECEIVER_SYNC_STATE_TERMINATED, sync_handle: 0x%x",
                                p_bc_source->sync_handle);

                if (app_lea_bca_release_all(para))
                {
                    app_lea_bca_tgt_active(false, (APP_BIS_BIS_CTRL_RESET_ACTIVE & APP_BIS_BIS_CTRL_RESET_SD_ACTIVE));
                }
            }
            else if ((p_sync_cb->p_big_sync_state->sync_state == BIG_SYNC_RECEIVER_SYNC_STATE_TERMINATED) &&
                     ((p_sync_cb->p_big_sync_state->action == BLE_AUDIO_BIG_SYNC) ||
                      (p_sync_cb->p_big_sync_state->action == BLE_AUDIO_BIG_IDLE)) &&
                     ((p_sync_cb->p_big_sync_state->cause == 0x113) || (p_sync_cb->p_big_sync_state->cause == 0x108) ||
                      (p_sync_cb->p_big_sync_state->cause == 0x13e)))
            {
                uint8_t dev_info = 0;

                if (!app_lea_bca_release_all(para))
                {
                    app_lea_bca_state_change(LEA_BCA_STATE_WAIT_RETRY);
                }
                else
                {
                    app_lea_bca_tgt_active(false, (APP_BIS_BIS_CTRL_RESET_ACTIVE & APP_BIS_BIS_CTRL_RESET_SD_ACTIVE));
                }

                if (p_bc_source->big_state == BIG_SYNC_RECEIVER_SYNC_STATE_SYNCHRONIZED)
                {
                    app_audio_tone_type_play(TONE_BIS_LOSST, false, false);
                }

                app_lea_mgr_tri_mmi_handle_action(MMI_BIG_START, true);


            }
            else if (p_sync_cb->p_big_sync_state->sync_state == BIG_SYNC_RECEIVER_SYNC_STATE_SYNCHRONIZED)
            {
                if (p_sync_cb->p_big_sync_state->action == BLE_AUDIO_BIG_SYNC)
                {
                    T_BLE_AUDIO_BIS_INFO bis_sync_info;

                    bool result = ble_audio_get_bis_sync_info(p_bc_source->sync_handle,
                                                              &bis_sync_info);
                    if (result == false)
                    {
                        // goto failed;
                    }
                    APP_PRINT_ERROR4("BIG_SYNC_RECEIVER_SYNC_STATE_SYNCHRONIZED%d,%d,%d, source_id=%d: ", result,
                                     bis_sync_info.bis_num, bis_sync_info.bis_info[0].bis_idx, p_bc_source->source_id);

                    uint8_t codec_id[5] = {1, 0, 0, 0, 0};
                    uint32_t controller_delay = 0x1122;
                    codec_id[0] = LC3_CODEC_ID;
                    APP_PRINT_INFO1("app_lea_bca_sync_cb: MSG_BLE_AUDIO_BIG_SYNC_STATE: bis_idx: %d",
                                    p_bc_source->bis_idx);

                    ble_audio_bis_setup_data_path(handle, p_bc_source->bis_idx, codec_id, controller_delay, 0, NULL);
                    app_lea_acc_scan_stop();
                }
            }

            if (p_sync_cb->p_big_sync_state->sync_state == BIG_SYNC_RECEIVER_SYNC_STATE_TERMINATED ||
                p_sync_cb->p_big_sync_state->sync_state == BIG_SYNC_RECEIVER_SYNC_STATE_TERMINATING)
            {
                p_bc_source->used &= (APP_LEA_BCA_BASE_DATA_RESET & APP_LEA_BCA_BIG_INFO_RESET);
            }

            p_bc_source->big_state = p_sync_cb->p_big_sync_state->sync_state;
        }
        break;
	...

    default:
        break;
    }
    return;
}

Bluetooth Audio Transceiver

A2DP Transparent Transmission

SPI and A2DP Transmit Manager

In the A2DP Transparent Transmission scenario, Device 1 is connected to the phone to receive A2DP data, which is then transmitted to Device 2 through SPI. Device 2 converts the received data into SBC or LC3 format and forwards it to the headphones through A2DP or BIS.

  1. Initiate SPI.

    For Device 1, its SPI role is set as a master, and the relevant functionality is enabled by activating the F_APP_SPI_ROLE_MASTER flag. The initialization function to achieve this is app_spi_master_init().

    For Device 2, its SPI role is set as a slave, and the relevant functionality is enabled by activating the F_APP_SPI_ROLE_SLAVE flag. The initialization function is app_spi_slave_init().

  2. A2DP Format Transmission.

    Device 2 utilizes the Audio Pipe to convert data format, thus requiring knowledge of the specific input data format. When Device 1 receives the BT_EVENT_A2DP_STREAM_START_IND, it will obtain the negotiated data format and utilize the CMD_A2DP_XMIT_CONFIG command to forward this information to Device 2 through SPI.

    //Device 1 sends data format information
    app_audio_bt_cback()
        |---app_audio_a2dp_stream_start_handle()
                |---app_a2dp_xmit_mgr_report_a2dp_param()
    
    void app_a2dp_xmit_mgr_report_a2dp_param(uint8_t *a2dp_param, uint16_t len)
    {
        app_report_event(CMD_PATH_SPI, CMD_A2DP_XMIT_CONFIG, 0, a2dp_param, len);
    }
    

    Device 2 processes the received commands within the app_a2dp_xmit_mgr_handle_cmd_set() function. When it receives the A2DP FORMAT command, the corresponding content is stored in the a2dp_xmit_mgr.a2dp_in_format variable, which will be utilized by the Audio Pipe operations. Additionally, the a2dp_xmit_mgr.a2dp_in_format_ready is set to true, effectively remembering the current state.

    //Device 2 receives data format information
    void app_a2dp_xmit_mgr_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                        uint16_t cmd_len, uint8_t *ack_pkt)
    {
        ...
        switch (cmd_id)
        {
        ...
        case CMD_A2DP_XMIT_CONFIG:
            {
                uint8_t *p_param = &cmd_ptr[2];
                uint16_t param_len = cmd_len - 2;
                app_a2dp_xmit_mgr_save_a2dp_in_format(p_param, param_len);
            }
            break;
        ...
        }
    }
    
    void app_a2dp_xmit_mgr_save_a2dp_in_format(uint8_t *format_info, uint16_t param_len)
    {
        if (!a2dp_xmit_mgr.a2dp_in_format_ready)
        {
            memcpy(&a2dp_xmit_mgr.a2dp_in_format, format_info, param_len);
            a2dp_xmit_mgr.a2dp_in_format_ready = true;
        }
        app_a2dp_xmit_mgr_print_format("app_a2dp_xmit_mgr_save_a2dp_in_format: ",
                                    a2dp_xmit_mgr.a2dp_in_format);
    }
    
  3. A2DP Data Transmission.

    In the A2DP Transparent Transmission scenario, once Device 1 receives audio data from the mobile, it immediately forwards it to Device 2 without local playback. The audio data is transmitted via SPI together with the CMD_A2DP_XMIT_AUDIO command:

    static void app_audio_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
    {
    
    switch (event_type)
    {
    case BT_EVENT_A2DP_STREAM_DATA_IND:
        {
            ...
    #if (F_APP_A2DP_XMIT_SNK_SUPPORT || F_APP_A2DP_XMIT_SNK_LEA_SUPPORT)
            app_a2dp_xmit_mgr_report_a2dp_data(param->a2dp_stream_data_ind.payload,
                                                param->a2dp_stream_data_ind.len);
    #endif
            ...
        }
    }
    
    void app_a2dp_xmit_mgr_report_a2dp_data(uint8_t *p_data, uint16_t len)
    {
        app_report_event(CMD_PATH_SPI, CMD_A2DP_XMIT_AUDIO, 0, p_data, len);
    }
    

    For Device 2, it cannot directly send the received audio data to the headphones because the format negotiated between Device 2 and the headphones is typically different from the format used for transmission between Device 1 and the mobile phone. Therefore, format conversion is required on the Device 2 side using the Audio Pipe. However, before proceeding with the conversion, it is important to note that upon receiving audio data, Device 2 will first store it in a pre-allocated ring buffer. This buffer serves as a temporary storage, making the data available for the subsequent Audio Pipe processing.

    Currently, Device 2 supports two different output methods for audio transmission to the headphones: A2DP and BIS. To modularly build these two different output options, we have implemented the relevant functionalities for A2DP output in the app_a2dp_xmit_src.c file and for BIS output in the app_a2dp_xmit_lea.c file. The data processing functions for these outputs are app_a2dp_xmit_src_handle_a2dp_data_ind() and app_a2dp_xmit_lea_handle_a2dp_data_ind() respectively.

    void app_a2dp_xmit_mgr_handle_a2dp_data_in(uint8_t *p_audio, uint16_t audio_len)
    {
        switch (a2dp_xmit_mgr.xmit_play_route)
        {
    #if F_APP_A2DP_XMIT_SRC_SUPPORT
        case XMIT_PLAY_ROUTE_A2DP_SRC:
            {
                app_a2dp_xmit_src_handle_a2dp_data_ind(p_audio, audio_len);
            }
            break;
    #endif
    #if F_APP_A2DP_XMIT_SRC_LEA_SUPPORT
        case XMIT_PLAY_ROUTE_BIS:
            {
                app_a2dp_xmit_lea_handle_a2dp_data_ind(p_audio, audio_len);
            }
            break;
    #endif
        default:
            APP_PRINT_ERROR1("app_a2dp_xmit_mgr_handle_a2dp_data_in: invalid route path %d",
                            a2dp_xmit_mgr.xmit_play_route);
            break;
        }
    }
    

    It may have been noticed that when receiving data, the processing is determined based on the variable a2dp_xmit_mgr.xmit_play_route which distinguishes whether it should be handled by the app_a2dp_xmit_src_handle_a2dp_data_ind() function or the app_a2dp_xmit_lea_handle_a2dp_data_ind() function. The value of this variable determines the appropriate function to select for processing the received audio data. From the user’s perspective, a prior selection between A2DP or BIS output must be made by issuing the command CMD_A2DP_XMIT_ROUTE_OUT_CTRL through ACI Host. The Bluetooth Audio Transceiver APP will then store this choice in the variable a2dp_xmit_mgr.xmit_play_route to perform audio data demultiplexing based on the selected output.

    void app_a2dp_xmit_mgr_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                        uint16_t cmd_len, uint8_t *ack_pkt)
    {
        ...
        switch (cmd_id)
        {
        ...
        case CMD_A2DP_XMIT_SET_ROUTE_OUT:
            {
                a2dp_xmit_mgr.xmit_play_route = (T_A2DP_XMIT_PLAY_ROUTE)cmd_ptr[2];
                app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
            }
            break;
        ...
        }
    }
    
A2DP Output
  1. Request Starting Streaming.

    For Device 2’s output, the initiation or termination is controlled by the CMD_A2DP_XMIT_ROUTE_OUT_CTRL command. For A2DP output, upon receiving the XMIT_PLAY_STATE_START parameter, the app_a2dp_xmit_src_stream_start_req() function initiates an AVDTP_START request to the mobile phone.

    void app_a2dp_xmit_mgr_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                        uint16_t cmd_len, uint8_t *ack_pkt)
    {
        ...
        switch (cmd_id)
        {
        ...
        case CMD_A2DP_XMIT_ROUTE_OUT_CTRL:
            {
                T_A2DP_XMIT_PLAY_STATE type = (T_A2DP_XMIT_PLAY_STATE)cmd_ptr[2];
                app_a2dp_xmit_mgr_route_out_start_stop(type);
                app_cmd_set_event_ack(cmd_path, app_idx, ack_pkt);
            }
            break;
        ...
        }
    }
    
    app_a2dp_xmit_mgr_route_out_start_stop()
        |---app_a2dp_xmit_src_start_stop()
                |---app_a2dp_xmit_src_stream_start_req()
                        |---bt_a2dp_stream_start_req()
    
    
    static void app_a2dp_xmit_src_stream_start_req(void)
    {
        bt_a2dp_stream_start_req(a2d_src_ctrl.sink_addr);
    }
    

    Subsequently, the phone establishes an A2DP connection and negotiates the audio format. The APP retrieves the negotiation result through BT_EVENT_A2DP_CONFIG_CMPL and stores the format in the a2d_src_ctrl.format_info_out variable.

    app_audio_bt_cback() //BT_EVENT_A2DP_CONFIG_CMPL
        |---app_a2dp_xmit_src_save_a2dp_out_param()
    
    void app_a2dp_xmit_src_save_a2dp_out_param(uint8_t *format_info)
    {
        if (!a2d_src_ctrl.data_route_out_ready)
        {
            memcpy(&a2d_src_ctrl.format_info_out, format_info, sizeof(T_AUDIO_FORMAT_INFO));
            a2d_src_ctrl.data_route_out_ready = true;
        }
        app_a2dp_xmit_mgr_print_format("app_a2dp_xmit_src_save_a2dp_out_param: ",
                                        a2d_src_ctrl.format_info_out);
    }
    
  2. Create Audio Pipe.

    Once the mobile phone accepts Device 2’s stream start request, the APP receives the BT_EVENT_A2DP_STREAM_START_RSP event. At this point, both the audio input format transmitted from Device 1 and the output format negotiated with the phone are available. Consequently, the APP can create the Audio Pipe for further processing.

    app_a2dp_xmit_src_bt_cback() //BT_EVENT_A2DP_STREAM_START_RSP
        |---app_a2dp_xmit_src_start_rsp_handler()
                |---app_a2dp_xmit_src_param_rcfg()
    
    static uint8_t app_a2dp_xmit_src_param_rcfg(void)
    {
        uint8_t res = A2DP_XMIT_MGR_SUCCESS;
    
        if (audio_pipe_handle != NULL)
        {
            res = A2DP_XMIT_MGR_PIPE_CREATE_ERROR;
            return res;
        }
    
        if (!app_a2dp_xmit_mgr_get_a2dp_in_format((uint8_t *)&a2d_src_ctrl.format_info_in))
        {
            APP_PRINT_ERROR0("app_a2dp_xmit_lea_pipe_rcfg: a2dp format info does not exist");
            res = A2DP_XMIT_MGR_SYS_ERROR;
            return res;
        }
    
        if (a2d_src_ctrl.data_route_out_ready)
        {
            T_AUDIO_FORMAT_INFO format_info_in = a2d_src_ctrl.format_info_in;
            T_AUDIO_FORMAT_INFO format_info_out = a2d_src_ctrl.format_info_out;
    
            if (audio_pipe_handle == NULL)
            {
                audio_pipe_handle = audio_pipe_create(format_info_in, format_info_out,
                                                    a2dp_gain_table[app_cfg_nv.audio_gain_level[cur_pair_idx]],
                                                    audio_pipe_callback);
            }
        }
        else
        {
            res = A2DP_XMIT_MGR_SYS_ERROR;
        }
        return res;
    }
    
  3. Fill Data to Audio Pipe.

    When creating the Audio Pipe, the audio_pipe_callback() function is registered. Upon receiving the AUDIO_PIPE_EVENT_STARTED, it indicates that the Audio Pipe is ready to operate. In this event, the app_a2dp_xmit_src_fill_pipe() function is used to fill the first packet of data to the Audio Pipe. After completing the filling, an AUDIO_PIPE_EVENT_DATA_FILLED event is received, allowing for the continued filling of data.

    When there is no data available in the ring buffer for filling, the flag_pipe_get_data_empty is set.

    audio_pipe_callback() //AUDIO_PIPE_EVENT_STARTED
        |---app_a2dp_xmit_src_fill_pipe()
    
    static uint16_t app_a2dp_xmit_src_fill_pipe(void)
    {
        uint16_t res = A2DP_XMIT_MGR_SUCCESS;
        uint8_t frame_info[2];
        res = app_a2dp_xmit_mgr_a2dp_raw_data_read(frame_info, 2);
        if (res == A2DP_XMIT_MGR_SUCCESS)
        {
            uint16_t audio_len = (uint16_t)(frame_info[0] | (frame_info[1] << 8));
    
            uint8_t *p_read_data_buf = malloc(audio_len);
            if (p_read_data_buf)
            {
                res = app_a2dp_xmit_mgr_a2dp_raw_data_read(p_read_data_buf, audio_len);
                if (res == A2DP_XMIT_MGR_SUCCESS)
                {
                    flag_pipe_get_data_empty = false;
                    APP_PRINT_INFO2("app_a2dp_xmit_src_fill_pipe: seq_num %d, audio_len %d", seq_num, audio_len);
    
                    if (!audio_pipe_fill(audio_pipe_handle, 0, seq_num, AUDIO_STREAM_STATUS_CORRECT, 0,
                                        (void *)p_read_data_buf, audio_len))
                    {
                        res = A2DP_XMIT_MGR_PIPE_FILL_ERROR;
                    }
                    else
                    {
                        seq_num++;
                    }
                }
                else
                {
                    flag_pipe_get_data_empty = true;
                }
                free(p_read_data_buf);
            }
            else
            {
                res = A2DP_XMIT_MGR_MEM_ERROR;
            }
        }
        else
        {
            flag_pipe_get_data_empty = true;
        }
    
        return res;
    }
    

    If data is received from Device 1 and flag_pipe_get_data_empty is set, the data is directly taken and filled into the pipe for processing.

    app_a2dp_xmit_mgr_handle_a2dp_data_in()
        |---app_a2dp_xmit_src_handle_a2dp_data_ind()
    
    void app_a2dp_xmit_src_handle_a2dp_data_ind(uint8_t *data, uint16_t len)
    {
        if (a2d_src_ctrl.play_state != XMIT_PLAY_STATE_START)
        {
            APP_PRINT_ERROR1("app_a2dp_xmit_src_handle_a2dp_data_ind: play_state %d err",
                            a2d_src_ctrl.play_state);
            return;
        }
    
        if (app_a2dp_xmit_mgr_a2dp_raw_data_write(data, len) == A2DP_XMIT_MGR_SUCCESS)
        {
            if (flag_pipe_get_data_empty)
            {
                app_a2dp_xmit_src_fill_pipe();
            }
        }
    }
    
  4. Send Generated Data to Earphones.

    After converting the data format using the Audio Pipe, the APP will receive an AUDIO_PIPE_EVENT_DATA_IND event in audio_pipe_cllback(). Upon receiving this event, the transformed audio data can be obtained using the audio pipe drain() function and subsequently sent to the headphones with the bt_a2dp_stream_data_send() function.

    audio_pipe_callback() //AUDIO_PIPE_EVENT_DATA_IND
        |---app_a2dp_xmit_src_pipe_data_ind()
    
    static uint16_t app_a2dp_xmit_src_pipe_data_ind(void)
    {
        uint16_t res = A2DP_XMIT_MGR_SUCCESS;
        uint16_t data_len = 0;
        uint16_t frame_number = 0;
    
        audio_pipe_drain(audio_pipe_handle, p_drain_data_buf, &data_len, &frame_number);
        if (data_len == 0)
        {
            res = A2DP_XMIT_MGR_PIPE_DRAIN_ERROR;
        }
        else
        {
            if (src_a2dp_credits)
            {
                if (bt_a2dp_stream_data_send(a2d_src_ctrl.sink_addr, a2dp_seq_num, (uint8_t)frame_number,
                                            p_drain_data_buf,
                                            data_len))
                {
                    a2dp_seq_num++;
                    src_a2dp_credits--;
                }
                else
                {
                    res = A2DP_XMIT_MGR_DATA_SEND_ERROR;
                }
            }
            else
            {
                APP_PRINT_WARN0("app_a2dp_xmit_src_pipe_data_ind: no reason need to send");
            }
        }
        APP_PRINT_INFO1("app_a2dp_xmit_src_pipe_data_ind: res 0x%x", res);
        return res;
    }
    
  5. Request Stopping Streaming.

    To stop the audio conversion and data transmission on Device 2, similar to the initialization process, use the CMD_A2DP_XMIT_ROUTE_OUT_CTRL command with the XMIT_PLAY_STATE_IDLE parameter. This action will initiate an AVDTP_SUSPEND request, release the Audio Pipe, and clear any residual audio data from Device 1.

    app_a2dp_xmit_mgr_route_out_start_stop()
        |---app_a2dp_xmit_src_start_stop()
                |---app_a2dp_xmit_src_stream_stop()
    
    static void app_a2dp_xmit_src_stream_stop(void)
    {
        if (a2d_src_ctrl.bt_strm_state != A2DP_XMIT_SRC_STREAM_STOP)
        {
            bt_a2dp_stream_suspend_req(a2d_src_ctrl.sink_addr);
        }
    
        if (a2d_src_ctrl.play_state == XMIT_PLAY_STATE_START)
        {
            a2d_src_ctrl.play_state = XMIT_PLAY_STATE_IDLE;
        }
        if (audio_pipe_handle != NULL)
        {
            audio_pipe_release(audio_pipe_handle);
            audio_pipe_handle = NULL;
        }
    
        app_a2dp_xmit_mgr_a2dp_raw_data_clear();
        app_dlps_enable(APP_DLPS_ENTER_CHECK_PLAYBACK);
    }
    
BIS Output
  1. Initiate BIS and Start Streaming.

    To utilize the BIS for audio output, first initialize it. By using the CMD_LEA_BSRC_START command, options for a single BIS output (stereo) or dual BIS outputs (Left and Right). Subsequently, use the CMD_A2DP_XMIT_ROUTE_OUT_CTRL command with the XMIT_PLAY_STATE_START parameter to establish one or two datapaths for BIS, making it into a streaming state.

    app_a2dp_xmit_mgr_handle_cmd_set() //CMD_A2DP_XMIT_ROUTE_OUT_CTRL
        |---app_a2dp_xmit_mgr_route_out_start_stop()
            |---app_a2dp_xmit_lea_src_start_stop()
                |---app_lea_bsrc_start()
    void app_a2dp_xmit_lea_src_start_stop(T_A2DP_XMIT_PLAY_STATE type)
    {
        APP_PRINT_INFO1("app_a2dp_xmit_lea_src_start_stop: %d", type);
        if (type == XMIT_PLAY_STATE_START)
        {
            app_lea_bsrc_start();
        }
        else if (type == XMIT_PLAY_STATE_IDLE)
        {
            app_lea_bsrc_stop(true);
        }
    }
    
  2. Create Audio Pipe.

    Upon successful creation of the datapath, the output format will be saved, and an Audio Pipe will be generated in the app_a2dp_xmit_lea_pipe_rcfg() function.

    void app_lea_handle_bis_data_path_setup(T_LEA_SETUP_DATA_PATH *p_data)
    {
        ...
        if (p_data->path_direction == DATA_PATH_INPUT_FLAG)
        {
            if (app_db.bsrc_db.cfg_bis_num == app_db.iso_input_queue.count)
            {
                app_lea_save_data_format(p_iso_chann);
    #if F_APP_A2DP_XMIT_SRC_LEA_SUPPORT
                app_a2dp_xmit_lea_pipe_rcfg(); // TODO: put to BROADCAST_SOURCE_STATE_CONFIGURED?
    #endif
            }
        }
    }
    
    void app_a2dp_xmit_lea_pipe_rcfg(void)
    {
        if (!app_a2dp_xmit_mgr_get_a2dp_in_format((uint8_t *)&a2dp_xmit_lea_ctrl.format_in))
        {
            APP_PRINT_ERROR0("app_a2dp_xmit_lea_pipe_rcfg: a2dp format info does not exist");
            return;
        }
    
        if (!app_lea_get_data_format((uint8_t *)&a2dp_xmit_lea_ctrl.format_out))
        {
            APP_PRINT_ERROR0("app_a2dp_xmit_lea_pipe_rcfg: lc3 format info does not exist");
            return;
        }
    
        app_a2dp_xmit_mgr_print_format("app_a2dp_xmit_lea_pipe_rcfg: ",
                                    a2dp_xmit_lea_ctrl.format_in);
        app_a2dp_xmit_mgr_print_format("app_a2dp_xmit_lea_pipe_rcfg: ",
                                    a2dp_xmit_lea_ctrl.format_out);
    
        if (a2dp_xmit_lea_ctrl.format_out.attr.lc3.chann_location == AUDIO_LOCATION_MONO)
        {
            a2dp_xmit_lea_ctrl.chnl_cnt = 1;
        }
        else
        {
            a2dp_xmit_lea_ctrl.chnl_cnt = __builtin_popcount(
                                            a2dp_xmit_lea_ctrl.format_out.attr.lc3.chann_location);
        }
    
        uint16_t len = a2dp_xmit_lea_ctrl.format_out.attr.lc3.frame_length * a2dp_xmit_lea_ctrl.chnl_cnt;
        a2dp_xmit_lea_ctrl.p_lea_send_buf = calloc(1, len);
        APP_PRINT_INFO1("app_a2dp_xmit_lea_pipe_rcfg: p_lea_send_buf len %d", len);
        if (a2dp_xmit_lea_ctrl.p_lea_send_buf == NULL)
        {
            APP_PRINT_ERROR0("app_a2dp_xmit_lea_pipe_rcfg: p_lea_send_buf malloc fail");
            return;
        }
    
        if (audio_pipe_handle == NULL)
        {
            audio_pipe_handle = audio_pipe_create(a2dp_xmit_lea_ctrl.format_in, a2dp_xmit_lea_ctrl.format_out,
                                                app_dsp_cfg_vol.playback_volume_default,
                                                app_a2dp_xmit_lea_pipe_callback);
        }
        uint32_t sync_timer_period = 0;
        if (a2dp_xmit_lea_ctrl.format_out.attr.lc3.frame_duration == AUDIO_LC3_FRAME_DURATION_10_MS)
        {
            app_a2dp_xmit_lea_sync_timer_init(10000);
        }
        else
        {
            app_a2dp_xmit_lea_sync_timer_init(7500);
        }
    }
    
  3. Fill Data to Audio Pipe.

    When creating the Audio Pipe, the app_a2dp_xmit_lea_pipe_callback() function is registered. Upon receiving the AUDIO_PIPE_EVENT_STARTED, it indicates that the Audio Pipe is ready to operate. In this event, the app_a2dp_xmit_lea_fill_pipe() function is used to fill the first packet of data to Audio Pipe. After completing the filling, an AUDIO_PIPE_EVENT_DATA_FILLED event is received, allowing the continued filling of data.

    When there is no data available in the ring buffer for filling, the flag_pipe_get_data_empty is set.

    app_a2dp_xmit_lea_pipe_callback() //AUDIO_PIPE_EVENT_STARTED
        |---app_a2dp_xmit_lea_fill_pipe()
    
    static uint16_t app_a2dp_xmit_lea_fill_pipe(void)
    {
        uint16_t res = A2DP_XMIT_MGR_SUCCESS;
        uint8_t frame_info[2];
    
        res = app_a2dp_xmit_mgr_a2dp_raw_data_read(frame_info, 2);
        if (res == A2DP_XMIT_MGR_SUCCESS)
        {
            uint16_t audio_len = (uint16_t)(frame_info[0] | (frame_info[1] << 8));
    
            uint8_t *p_read_data_buf = malloc(audio_len);
            if (p_read_data_buf)
            {
                res = app_a2dp_xmit_mgr_a2dp_raw_data_read(p_read_data_buf, audio_len);
                if (res == A2DP_XMIT_MGR_SUCCESS)
                {
                    flag_pipe_get_data_empty = false;
                    APP_PRINT_INFO2("app_a2dp_xmit_lea_fill_pipe: pipe_fill_seq %d, audio_len %d",
                                    a2dp_xmit_lea_ctrl.pipe_fill_seq, audio_len);
    
                    if (!audio_pipe_fill(audio_pipe_handle, 0, a2dp_xmit_lea_ctrl.pipe_fill_seq,
                                        AUDIO_STREAM_STATUS_CORRECT, 0,
                                        (void *)p_read_data_buf, audio_len))
                    {
                        res = A2DP_XMIT_MGR_PIPE_FILL_ERROR;
                    }
                    else
                    {
                        a2dp_xmit_lea_ctrl.pipe_fill_seq++;
                    }
                }
                else
                {
                    flag_pipe_get_data_empty = true;
                }
                free(p_read_data_buf);
            }
            else
            {
                res = A2DP_XMIT_MGR_MEM_ERROR;
            }
        }
        else
        {
            flag_pipe_get_data_empty = true;
        }
    
        return res;
    }
    

    If data is received from Device 1 and flag_pipe_get_data_empty is set, the data is directly taken and filled into the pipe for processing.

    app_a2dp_xmit_mgr_handle_a2dp_data_in()
        |---app_a2dp_xmit_lea_handle_a2dp_data_ind()
    
    void app_a2dp_xmit_lea_handle_a2dp_data_ind(uint8_t *p_audio, uint16_t audio_len)
    {
        if (a2dp_xmit_lea_ctrl.play_state == XMIT_PLAY_STATE_IDLE)
        {
            APP_PRINT_ERROR0("app_a2dp_xmit_lea_handle_a2dp_data_ind: brsc not started");
            return;
        }
    
        if (app_a2dp_xmit_mgr_a2dp_raw_data_write(p_audio, audio_len) == A2DP_XMIT_MGR_SUCCESS)
        {
            if (flag_pipe_get_data_empty)
            {
                app_a2dp_xmit_lea_fill_pipe();
            }
        }
    }
    
  4. Send Generated Data to Earphones.

    After converting the data format using the Audio Pipe, the APP will receive a AUDIO_PIPE_EVENT_DATA_IND event in app_a2dp_xmit_lea_pipe_callback(). Due to the fixed interval required for BIS packet transmission, the converted data cannot be directly sent out, instead, it needs to be stored in the ring buffer of a2dp_xmit_lea_ctrl.ring_buf using the function of app_a2dp_xmit_lea_iso_data_storage().

    app_a2dp_xmit_lea_pipe_callback //AUDIO_PIPE_EVENT_DATA_IND
        |---app_a2dp_xmit_lea_pipe_data_ind_handler
    
    static uint16_t app_a2dp_xmit_lea_pipe_data_ind_handler(void)
    {
        uint16_t res = A2DP_XMIT_MGR_SUCCESS;
        uint16_t data_len = 0;
        uint16_t frame_number = 0;
    
        audio_pipe_drain(audio_pipe_handle, p_drain_data_buf, &data_len, &frame_number);
        if (data_len == 0)
        {
            res = A2DP_XMIT_MGR_PIPE_DRAIN_ERROR;
        }
        else
        {
            res = app_a2dp_xmit_lea_iso_data_storage(p_drain_data_buf, data_len);
        }
        APP_PRINT_INFO3("app_a2dp_xmit_lea_pipe_data_ind_handler: data_len %d, frame_number %d, res %d",
                        data_len, frame_number, res);
        return res;
    }
    

    The packet transmission is controlled by a hardware timer. To ensure a continuous data flow for transmission, the hardware timer initiates its operation only after receiving three sets of converted data.

    static bool app_a2dp_xmit_lea_pipe_callback(T_AUDIO_PIPE_HANDLE handle, T_AUDIO_PIPE_EVENT event,
    uint32_t param)
    {
        ...
        switch (event)
        {
        ...
        case AUDIO_PIPE_EVENT_DATA_IND:
        {
            if (app_a2dp_xmit_lea_pipe_data_ind_handler() == A2DP_XMIT_MGR_SUCCESS)
            {
                a2dp_xmit_lea_ctrl.pipe_ind_seq++;
            }
            if (!a2dp_xmit_lea_ctrl.timer_started &&
                a2dp_xmit_lea_ctrl.pipe_ind_seq > 2)
            {
                app_a2dp_xmit_lea_sync_timer_start();
            }
        }
        break;
        ...
        }
        ...
    }
    

    When the set interval time elapses, the app_a2dp_xmit_lea_iso_data_read() function is utilized to retrieve the stored converted data from the ring buffer. Subsequently, the data in the transformed format is sent out using the app_lea_iso_data_send() function.

    app_a2dp_xmit_lea_sync_timer_handler()
        |---app_a2dp_xmit_lea_msg_send()
                |---app_a2dp_xmit_lea_msg_handle()
                        |---app_a2dp_xmit_lea_send_iso_data()
    
    static void app_a2dp_xmit_lea_send_iso_data(void)
    {
        uint16_t res = A2DP_XMIT_MGR_SUCCESS;
        uint16_t len = a2dp_xmit_lea_ctrl.format_out.attr.lc3.frame_length * a2dp_xmit_lea_ctrl.chnl_cnt;
    
        uint8_t read_ret = app_a2dp_xmit_lea_iso_data_read(a2dp_xmit_lea_ctrl.p_lea_send_buf, len);
        if (read_ret != A2DP_XMIT_MGR_SUCCESS)
        {
            memset(a2dp_xmit_lea_ctrl.p_lea_send_buf, 0, len);
        }
        app_lea_iso_data_send(a2dp_xmit_lea_ctrl.p_lea_send_buf, len, false, 0, 0);
    }
    
  5. Request Stopping Streaming.

    To stop the audio conversion and data transmission on Device 2, similar to the initialization process, you need to use the CMD_A2DP_XMIT_ROUTE_OUT_CTRL command with the XMIT_PLAY_STATE_IDLE parameter. This action will remove the established datapaths.

    app_a2dp_xmit_mgr_route_out_start_stop()
        |---app_a2dp_xmit_lea_src_start_stop()
                |---app_lea_bsrc_stop()
    
    void app_a2dp_xmit_lea_src_start_stop(T_A2DP_XMIT_PLAY_STATE type)
    {
        APP_PRINT_INFO1("app_a2dp_xmit_lea_src_start_stop: %d", type);
        if (type == XMIT_PLAY_STATE_START)
        {
            app_lea_bsrc_start();
        }
        else if (type == XMIT_PLAY_STATE_IDLE)
        {
            app_lea_bsrc_stop(true);
        }
    }
    

    Once the datapaths are removed, the Audio Pipe will be released, any residual audio data from Device 1 and generated by the Audio Pipe will be cleared in app_a2dp_xmit_lea_handle_chann_remove().

    app_lea_handle_bis_data_path_remove()
        |---app_lea_remove_iso_chann()
            |---app_a2dp_xmit_lea_handle_chann_remove
    
    void app_a2dp_xmit_lea_handle_chann_remove(void)
    {
        APP_PRINT_INFO1("app_a2dp_xmit_lea_handle_chann_remove: iso_input_queue %d",
                        app_db.iso_input_queue.count);
        if (app_db.iso_input_queue.count == 0)
        {
            if (a2dp_xmit_lea_ctrl.timer_started)
            {
                app_a2dp_xmit_lea_sync_timer_stop();
            }
            a2dp_xmit_lea_ctrl.play_state = XMIT_PLAY_STATE_IDLE;
            if (audio_pipe_handle != NULL)
            {
                audio_pipe_release(audio_pipe_handle);
                audio_pipe_handle = NULL;
            }
        }
    
        if (a2dp_xmit_lea_ctrl.p_lea_send_buf != NULL)
        {
            free(a2dp_xmit_lea_ctrl.p_lea_send_buf);
            a2dp_xmit_lea_ctrl.p_lea_send_buf = NULL;
        }
    
        ring_buffer_clear(&a2dp_xmit_lea_ctrl.ring_buf);
        app_a2dp_xmit_mgr_a2dp_raw_data_clear();
    }
    

HFP Transparent Transmission

SPI and HFP Transmit Manager

In the HFP Transparent Transmission scenario, Device 1 is connected to the phone to receive HFP data, which is then transmitted to Device 2 through SPI. Device 2 forwards it to the headphones after SCO is connected.

For Device 1, its SPI role is set as master, and the relevant functionality is enabled by activating the F_APP_SPI_ROLE_MASTER flag. For Device 2, its SPI role is configured as slave, and the relevant functionality is enabled by activating the F_APP_SPI_ROLE_SLAVE flag.

When Device 1 receives the BT_EVENT_SCO_CONN_CMPL, it will obtain the negotiated data format and utilize the CMD_SCO_XMIT_CONFIG command in app_audio_sco_conn_cmpl_handle() to forward this information to Device 2 through SPI.

static void app_audio_sco_conn_cmpl_handle(uint8_t *bd_addr, uint8_t air_mode, uint8_t rx_pkt_len)
{
    uint8_t pair_idx_mapping;
    T_AUDIO_FORMAT_INFO format_info = {};
    p_link = app_link_find_br_link(bd_addr);
    ...
#if (F_APP_SCO_XMIT_AG_SUPPORT || F_APP_SCO_XMIT_HF_SUPPORT)
    app_report_event(CMD_PATH_SPI, CMD_SCO_XMIT_CONFIG, 0, (uint8_t *)&format_info,
                     sizeof(T_AUDIO_FORMAT_INFO));
    ...
#endif
    ...
}

static void app_audio_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    bool handle = true;
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    switch (event_type)
    {
    case BT_EVENT_SCO_CONN_CMPL:
        {
            ...
            if (param->sco_conn_cmpl.cause != 0)
            {
                break;
            }
            app_audio_sco_conn_cmpl_handle(param->sco_conn_cmpl.bd_addr, param->sco_conn_cmpl.air_mode,
                                           param->sco_conn_cmpl.rx_pkt_len);
            ...
        }
        break;
    ...
    }

Device 1 and Device 2 will respectively utilize app_sco_xmit_handle_sco_param() and app_sco_xmit_save_output_param() to save the negotiated data format. After this, both input and output channels can be marked as Ready by setting sco_ctrl.in_route_ready.

static void app_sco_xmit_handle_sco_param(uint8_t *param, uint16_t param_len)
{
    if (!sco_ctrl.in_route_ready)
    {
        memcpy(&sco_ctrl.format_info_in, param, param_len);
        if (sco_ctrl.format_info_in.type == AUDIO_FORMAT_TYPE_MSBC)
        {
            APP_PRINT_INFO7("app_sco_xmit_handle_sco_param: type %d, "
                            "sample_rate %d, allocation_method %d, bitpool %d, block_length %d, chann_mode %d, subband_num %d",
                            sco_ctrl.format_info_in.type,
                            sco_ctrl.format_info_in.attr.msbc.sample_rate,
                            sco_ctrl.format_info_in.attr.msbc.allocation_method,
                            sco_ctrl.format_info_in.attr.msbc.bitpool,
                            sco_ctrl.format_info_in.attr.msbc.block_length,
                            sco_ctrl.format_info_in.attr.msbc.chann_mode,
                            sco_ctrl.format_info_in.attr.msbc.subband_num);
        }
        else if (sco_ctrl.format_info_in.type == AUDIO_FORMAT_TYPE_CVSD)
        {
            APP_PRINT_INFO4("app_sco_xmit_handle_sco_param: type %d, "
                            "sample_rate %d, chann_num %d, frame_duration %d",
                            sco_ctrl.format_info_in.type,
                            sco_ctrl.format_info_in.attr.cvsd.sample_rate,
                            sco_ctrl.format_info_in.attr.cvsd.chann_num,
                            sco_ctrl.format_info_in.attr.cvsd.frame_duration);
        }
        sco_ctrl.in_route_ready = true;
    }
#if F_APP_SCO_XMIT_HF_SUPPORT
    app_sco_xmit_param_recfg();
#endif
}

void app_sco_xmit_save_output_param(T_AUDIO_FORMAT_INFO *format_info)
{
    if (!sco_ctrl.out_route_ready)
    {
        memcpy(&sco_ctrl.format_info_out, format_info, sizeof(T_AUDIO_FORMAT_INFO));
        if (sco_ctrl.format_info_out.type == AUDIO_FORMAT_TYPE_MSBC)
        {
            APP_PRINT_INFO7("app_sco_xmit_save_output_param: type %d, "
                            "sample_rate %d, allocation_method %d, bitpool %d, block_length %d, chann_mode %d, subband_num %d",
                            sco_ctrl.format_info_out.type,
                            sco_ctrl.format_info_out.attr.msbc.sample_rate,
                            sco_ctrl.format_info_out.attr.msbc.allocation_method,
                            sco_ctrl.format_info_out.attr.msbc.bitpool,
                            sco_ctrl.format_info_out.attr.msbc.block_length,
                            sco_ctrl.format_info_out.attr.msbc.chann_mode,
                            sco_ctrl.format_info_out.attr.msbc.subband_num);
        }
        else if (sco_ctrl.format_info_out.type == AUDIO_FORMAT_TYPE_CVSD)
        {
            APP_PRINT_INFO4("app_sco_xmit_save_output_param: type %d, "
                            "sample_rate %d, chann_num %d, frame_duration %d",
                            sco_ctrl.format_info_out.type,
                            sco_ctrl.format_info_out.attr.cvsd.sample_rate,
                            sco_ctrl.format_info_out.attr.cvsd.chann_num,
                            sco_ctrl.format_info_out.attr.cvsd.frame_duration);
        }
    }
    sco_ctrl.out_route_ready = true;
}
HFP Transmit Data

In the HFP Transparent Transmission scenario, once Device 1 receives SCO data from the mobile while the reference event is BT_EVENT_SCO_DATA_IND in app_audio_bt_cback(), it immediately forwards it to Device 2 without creating local track handle. The SCO data is transmitted via SPI together with the CMD_SCO_XMIT_AUDIO command. CMD_SCO_XMIT_AUDIO will be called in app_sco_xmit_handle_cmd_set(), SCO data will be sent to headphones via app_sco_xmit_send_sco().

static void app_audio_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    bool handle = true;
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    switch (event_type)
    {
    case BT_EVENT_SCO_DATA_IND:
        {
            ...
            p_link = app_link_find_br_link(param->sco_data_ind.bd_addr);
            if (p_link == NULL)
            {
                break;
            }
            p_link->sco.seq_num++;

#if (F_APP_SCO_XMIT_HF_SUPPORT || F_APP_SCO_XMIT_AG_SUPPORT)
            app_report_event(CMD_PATH_SPI, CMD_SCO_XMIT_AUDIO, 0, param->sco_data_ind.p_data,
                             param->sco_data_ind.length);
            ...
    }

static void app_sco_xmit_send_sco(uint8_t *data, uint16_t len)
{
    uint8_t active_hf_idx = app_hfp_get_active_idx();
    T_APP_BR_LINK *p_link;
    p_link = app_link_find_br_link(app_db.br_link[active_hf_idx].bd_addr);
    if (p_link == NULL)
    {
        APP_PRINT_ERROR0("app_sco_xmit_send_sco: no br link found");
    }
    sco_seq_num++;
    if (p_link->sco.duplicate_fst_data)
    {
        p_link->sco.duplicate_fst_data = false;
        bt_sco_data_send(p_link->bd_addr, sco_seq_num - 1, data, len);
    }
    bt_sco_data_send(p_link->bd_addr, sco_seq_num, data, len);
}

void app_sco_xmit_handle_cmd_set(uint8_t app_idx, uint8_t cmd_path, uint8_t *cmd_ptr,
                                 uint16_t cmd_len, uint8_t *ack_pkt)
{
    uint16_t cmd_id = (uint16_t)(cmd_ptr[0] | (cmd_ptr[1] << 8));
    ...
    switch (cmd_id)
    {
    ...
    case CMD_SCO_XMIT_AUDIO:
        {
            uint8_t *p_audio = &cmd_ptr[2];
            uint16_t audio_len = cmd_len - 2;
            if (flag_direct_send)
            {
                app_sco_xmit_send_sco(p_audio, audio_len);
            }
            ...
        }
        break;
    ...
    }
}

The specific operation process can refer to ACI Host CLI Test (HFP Transfer).

Bluetooth Audio Transmitter MP3

The path of the playback code is src\sample\bt_audio_trx\music_playback. The specific operation process can refer to ACI Host CLI Test.

Local Playback

The code of the local playback part is in playback_stream_ctrl.c. The music start process is as follows.

Receive Data

Device will enter MUSIC_FLOW_JUMP_HEAD state after receiving the music data transmitted by host in the idle state.

//music flow state
typedef enum
{
    MUSIC_FLOW_IDLE           = 0x00,
    MUSIC_FLOW_JUMP_HEAD      = 0x01,
    MUSIC_FLOW_CREAT_TRACK    = 0x02,
    MUSIC_FLOW_START          = 0x03,
    MUSIC_FLOW_STARTED        = 0x04
} T_MUSIC_FLOW_STATE;

static struct
{
    T_MUSIC_MODE          play_mode;
    T_MUSIC_STATE         play_state;
    uint8_t               play_flow;
    uint8_t               preq_pkts;
    uint16_t              frame_size;
    uint32_t              header_len;
    bool                  seamless_start;
    bool                  en_report_play_time;
    bool                  is_short_audio;
} music_info;

uint8_t app_music_start(void)
{
    uint8_t res = MUSIC_STATE_ERROR;
    APP_PRINT_INFO1("app_music_start: play_flow:%d", music_info.play_flow);

    if (music_info.play_flow == MUSIC_FLOW_IDLE)
    {
        music_info.play_flow = MUSIC_FLOW_JUMP_HEAD;
    }

    if ((music_info.play_flow == MUSIC_FLOW_JUMP_HEAD) &&
        (stream_get_data_size() > STREAM_BUF_CHECK_LEVEL ||
         PLAYBACK_AUDIO_FILE_STOPPING == playback_audio_file_get_state()))
    {
        if (app_music_enter_state(MUSIC_FLOW_JUMP_HEAD))
        {
            music_info.play_flow = MUSIC_FLOW_CREAT_TRACK;
            res = MUSIC_NEXT_STATE_ERROR;
        }
    }
    ...
}
Estimate Ring Buffer Water Level

When the file header transmission is completed in app_music_jump_file_header(), APP will estimate the water level of play ring buffer according to the current data in app_music_play_get_threshold().

After estimating the water level, play_flow will enter MUSIC_FLOW_CREAT_TRACK state.

static bool app_music_jump_file_header(void)
{
    bool head_jump_ok = false;
    uint8_t head_type = 0xFF;
    uint32_t read_len = 0;
    uint32_t ring_buf_size = stream_get_data_size();

    APP_PRINT_WARN2("app_watch_music_judge_file_header, header len: 0x%x, ring_buf_size: 0x%x",
                    music_info.header_len, ring_buf_size);

    if (ring_buf_size <= 0)
    {
        return false;
    }

    if (music_info.header_len == 0)
    {
        head_type = playback_audio_file_get_header(&music_info.header_len);
        switch (head_type)
        {
        case PLAYBACK_AF_ERR_HEADER:
        case PLAYBACK_AF_NOT_HEADER:
            ring_buf_size = stream_get_data_size();
            stream_remove_data(ring_buf_size, &read_len);
            music_info.header_len -= read_len;
            head_jump_ok = false;
            break;

        case PLAYBACK_AF_IS_HEADER:
            if (stream_get_data_size() > music_info.header_len)
            {
                stream_remove_data(music_info.header_len, &read_len);
                music_info.header_len -= read_len;
                head_jump_ok = true;
            }
            else if (music_info.header_len > STREAM_BUF_HIGH_LEVEL)
            {
                ring_buf_size = stream_get_data_size();
                stream_remove_data(ring_buf_size, &read_len);
                music_info.header_len -= read_len;
                head_jump_ok = false;
            }
            break;

        case PLAYBACK_AF_DATA_FRAME:
            head_jump_ok = true;
            break;

        default:
            break;
        }
    }
    else
    {
        ring_buf_size = stream_get_data_size();
        if (ring_buf_size >= music_info.header_len)
        {
            stream_remove_data(music_info.header_len, &read_len);
            music_info.header_len -= read_len;
        }
        else
        {
            stream_remove_data(ring_buf_size, &read_len);
            music_info.header_len -= read_len;
        }

        if (music_info.header_len == 0)
        {
            head_jump_ok = true;
        }
    }

    return head_jump_ok;
}

static bool app_music_enter_state(uint8_t state)
{
    bool ret_state = false;

    switch (state)
    {
    case MUSIC_FLOW_IDLE:
        {
            ret_state = true;
        }
        break;

    case MUSIC_FLOW_JUMP_HEAD:
        {
            ret_state = app_music_jump_file_header();
        }
        break;
    ...
}

static uint32_t app_music_play_get_threshold(void)
{
    uint32_t start_level = 0;

    if (music_info.is_short_audio)
    {
        start_level = (music_info.preq_pkts) * music_info.frame_size;
    }
    else
    {
        uint8_t frame_num_max = STREAM_BUF_HIGH_LEVEL / music_info.frame_size;

        if (music_info.frame_size > 2048)
        {
            start_level = STREAM_BUF_HIGH_LEVEL;
        }
        else if (music_info.frame_size > 1024)
        {
            if (frame_num_max > 10)
            {
                start_level = 10 * music_info.frame_size;
            }
            else
            {
                start_level = STREAM_BUF_HIGH_LEVEL;
            }
        }
        else
        {
            start_level = (music_info.preq_pkts + 8) * music_info.frame_size;
        }
    }

    APP_PRINT_INFO2("app_music_play_get_threshold: 0x%x, is_short_audio: %d", start_level,
                    music_info.is_short_audio);

    return start_level;
}
Start Play Audio Track

After the data is filled in (referring to playback_audio_file_is_end()) and reaches the preset water level, create and start the audio track playback.

uint8_t app_music_start(void)
{
    ...
    if ((music_info.play_flow == MUSIC_FLOW_CREAT_TRACK) &&
        (stream_get_data_size() > STREAM_BUF_CHECK_LEVEL ||
         PLAYBACK_AUDIO_FILE_STOPPING == playback_audio_file_get_state()))
    {
        if (app_music_enter_state(MUSIC_FLOW_CREAT_TRACK))
        {
            music_info.play_flow = MUSIC_FLOW_START;
            res = MUSIC_NEXT_STATE_ERROR;
        }
    }

    if (music_info.play_flow == MUSIC_FLOW_START)
    {
        if (stream_get_data_size() > app_music_play_get_threshold())
        {
            if (app_music_enter_state(MUSIC_FLOW_START))
            {
                res = MUSIC_SUCCESS;
                music_info.play_flow = MUSIC_FLOW_STARTED;
                app_music_send_player_status(MUSIC_PLAYER_PLAYING);
            }
        }
    }
    ...
}

static bool app_music_enter_state(uint8_t state)
{
    bool ret_state = false;

    switch (state)
    {
    case MUSIC_FLOW_CREAT_TRACK:
        {
            uint16_t u16_res = 0;
            T_PLAYBACK_AF_FORMAT_INFO get_fmt_info;
            T_PLAY_SET_INFO set_play_info;
            music_info.header_len = 0;

            u16_res = audio_fs_decode_before_get_frame(NULL);
            if (u16_res != 0)
            {
                ret_state = false;
                break;
            }
            u16_res = playback_audio_file_get_audio_info(&get_fmt_info);
            if (u16_res != 0)
            {
                ret_state = false;
                break;
            }
            else
            {
                music_info.frame_size = get_fmt_info.frame_size;
                playback_stream_get_music_info(get_fmt_info, &set_play_info);
                music_info.preq_pkts = set_play_info.preq_pkts;
                ret_state = true;
            }
        }
        break;

    case MUSIC_FLOW_START:
        {
            if (music_info.play_mode == MUSIC_LOCAL_PLAY)
            {
                playback_stream_ctrl_start();
            }
            ret_state = true;
        }
        break;
    ...
}

music_info.play_flow will enter MUSIC_FLOW_START, the API playback_stream_ctrl_start() in playback_stream_ctrl.c will be called, which controls the play flow of playback. As a protection, the track that may exist already will be released before the audio track creation. When the data is lower than the preset water level, continue to request data playback from the host in playback_stream_put_data().

uint8_t playback_stream_ctrl_start(void)
{
    uint8_t res = PLAYBACK_SUCCESS;
    uint32_t sampling_frequency = 0;

    APP_PRINT_TRACE0("playback_stream_ctrl_start ++");

    app_dlps_disable(APP_DLPS_ENTER_CHECK_PLAYBACK);

    if (playback_track_handle)
    {
        audio_track_release(playback_track_handle);
        playback_track_handle = NULL;
    }

    if (playback.eq_instance != NULL)
    {
        eq_release(playback.eq_instance);
        playback.eq_instance = NULL;
    }

    if ((res = playback_stream_parameter_recfg()) != 0)
    {
        return res;
    }

    playback.buffer_state = PLAYBACK_BUF_NORMAL;
    playback.play_state = PLAYBACK_STATE_PLAY;
    playback_stream_volume_set(playback.volume);
    if (playback_track_handle != NULL)
    {
        playback_stream_get_sample_rate(&sampling_frequency);
        if ((sampling_frequency == SAMPLE_RATE_44K) || (sampling_frequency == SAMPLE_RATE_48K))
        {
            app_eq_idx_check_accord_mode();
            playback.eq_instance = app_eq_create(EQ_CONTENT_TYPE_AUDIO, EQ_STREAM_TYPE_AUDIO, SPK_SW_EQ,
                                                 app_db.spk_eq_mode, app_cfg_nv.eq_idx);
            if (playback.eq_instance != NULL)
            {
                eq_enable(playback.eq_instance);
                audio_track_effect_attach(playback_track_handle, playback.eq_instance);
            }
        }
        else
        {
            APP_PRINT_WARN1("EQ don't support this sample rate: %d", sampling_frequency);
        }

        audio_track_start(playback_track_handle);
    }

    return res;
}

//need put data
void playback_stream_put_data(uint8_t pkt_num)
{
    uint16_t res = 0;
    uint8_t frame_cnt = 0;
    uint16_t time_ms = playback.put_data_time_ms;
    T_PLAYBACK_FRAME_PKT playback_frame;
    static uint16_t s_seq_num = 0;

    APP_PRINT_INFO1("playback_stream_put_data pkt_num: %d", pkt_num);

    while (frame_cnt < pkt_num)
    {
        // This maybe AUDIO_EVENT_TRACK_BUFFER_HIGH event
        if (playback.buffer_state == PLAYBACK_BUF_HIGH)
        {
            time_ms = playback.put_data_time_ms * 2;
            break;
        }
        res = playback_audio_file_get_frame(&playback_frame);
        if (res != 0)
        {
            APP_PRINT_ERROR1("playback_stream_put_data ERROR,RES:0x%x", res);
            break;
        }

        uint16_t written_len;
        s_seq_num++;
        if (audio_track_write(playback_track_handle,
                              0,//              timestamp,
                              s_seq_num,
                              AUDIO_STREAM_STATUS_CORRECT,
                              playback_frame.frame_num,//            frame_num,
                              playback_frame.buf,
                              playback_frame.length,
                              &written_len) == false)
        {
            res = PLAYBACK_AF_WRITE_ERROR;
            break;
        }
        frame_cnt++;
    }
    stream_check_and_request_data(); // request data from host
    playback.buffer_state = PLAYBACK_BUF_NORMAL;

    if (res == PLAYBACK_AF_END_ERROR)
    {
        app_stop_timer(&timer_idx_playback_put_data);
        if (frame_cnt == 0)
        {
            APP_PRINT_WARN0("playback_stream_put_data,file end, and paly next song!!!");
            playback_stream_ctrl_stop();
            app_music_send_player_status(MUSIC_PLAYER_STOPPED);
        }

    }
    else //if (playback_db.sd_play_state == APP_AUDIO_FS_STATE_PLAY)
    {
        playback_stream_put_data_start_timer(time_ms);
    }
}

A2DP Source Playback

The process of A2DP Source playback is similar to that of local playback. APP will call the a2dp_src_stream_ctrl_start() when music_info.play_flow enters the MUSIC_FLOW_START state.

static struct
{
    T_A2DP_SRC_PLAY_STATE       play_state;
    T_APP_A2DP_SRC_STATE        bt_strm_state;
    T_A2DP_SRC_BUF_STATE        buffer_state;
    uint8_t                     sink_addr[6];
    uint8_t                     frm_num; // check level
} a2d_src_ctrl;

void a2dp_src_stream_ctrl_start(void)
{
    APP_PRINT_INFO1("a2dp_src_stream_ctrl_start: bt stream state: %d", a2d_src_ctrl.bt_strm_state);
    a2d_src_ctrl.buffer_state = A2DP_SRC_BUF_LOW;
#if A2DP_SRC_STREAM_DBG == 0
    if (a2d_src_ctrl.bt_strm_state != APP_A2DP_SRC_STREAM_START)
    {
        bt_a2dp_stream_start_req(a2d_src_ctrl.sink_addr);
    }
    else
#endif
    {
        a2dp_src_stream_param_recfg();
        a2d_src_ctrl.play_state = A2DP_SRC_PLAY_STATE_PLAY;
        app_dlps_disable(APP_DLPS_ENTER_CHECK_PLAYBACK);
    }
}

When sending data to the headset, format conversion is required on the device side. The Audio Pipe will be created in the a2dp_src_stream_param_recfg() function.

uint8_t a2dp_src_stream_param_recfg(void)
{
    uint8_t res = A2DP_SRC_SUCCESS;
    uint16_t u16_res = 0;
    uint32_t sample_rate = 0;
//    uint16_t sample_counts = 1024; /* default */
//    uint16_t frame_duration = 20; /* default */
    uint16_t frame_size = 512;
    uint8_t channel_mode = 0;
//    uint32_t bit_rate = 0;

    T_PLAYBACK_AF_FORMAT_INFO get_fmt_info;

    if (audio_pipe_handle != NULL)
    {
        res = A2DP_SRC_PIPE_CREATE_ERROR;
        return res;
    }
    u16_res = playback_audio_file_get_audio_info(&get_fmt_info);
    if (u16_res == 0)
    {
        T_AUDIO_FORMAT_INFO format_info;
        uint32_t device = AUDIO_DEVICE_OUT_SPK;

        format_info = get_fmt_info.format_info;
        frame_size = get_fmt_info.frame_size;
        a2d_src_ctrl.frm_num = 4;
        if (frame_size > 2048)
        {
            frame_size = 1024;
        }
        uint8_t frm_num = STREAM_BUF_SIZE / 2 / frame_size;
        a2d_src_ctrl.frm_num = (frm_num > 8) ? 7 : 4;

        if (format_info.type == AUDIO_FORMAT_TYPE_AAC)
        {
            APP_PRINT_INFO4("a2dp_src_stream_param_recfg: AAC, "
                            " transport_format:0x%x, sample_rate:%d, channel_mode:%d, bitrate:%d",
                            format_info.attr.aac.transport_format,
                            format_info.attr.aac.sample_rate,
                            format_info.attr.aac.chann_num,
                            format_info.attr.aac.bitrate);
        }
        else if (format_info.type == AUDIO_FORMAT_TYPE_MP3)
        {
            APP_PRINT_INFO3("a2dp_src_stream_param_recfg: MP3, sample_rate:%d, channel_mode:%d, frm_num:%d",
                            format_info.attr.mp3.sample_rate,
                            format_info.attr.mp3.chann_mode,
                            a2d_src_ctrl.frm_num);
        }

        T_AUDIO_FORMAT_INFO snk_info;
        snk_info.type = AUDIO_FORMAT_TYPE_SBC;
        snk_info.attr.sbc.subband_num = 8;
        snk_info.attr.sbc.bitpool = a2dp_src_bitpool;          //change to be same with min bitpool
        snk_info.attr.sbc.sample_rate = 48000;
        snk_info.attr.sbc.block_length = 16;
        snk_info.attr.sbc.chann_mode = AUDIO_SBC_CHANNEL_MODE_JOINT_STEREO;
        snk_info.attr.sbc.allocation_method = 0;

        float sbc_block = snk_info.attr.sbc.block_length;
        float sbc_subband = snk_info.attr.sbc.subband_num;

        a2dp_sbc_time = (sbc_block * sbc_subband) / 48;
        if (audio_pipe_handle == NULL)
        {
            audio_pipe_handle = audio_pipe_create(format_info, snk_info,
                                                  a2dp_gain_table[app_cfg_nv.audio_gain_level[cur_pair_idx]],
                                                  audio_codec_callback);
        }

    }
    else
    {
        res = A2DP_SRC_SYS_ERROR;
    }
    return res;
}

The action of Audio Pipe will be processed mainly in a2dp_src_stream_handle_msg():

  • If the function receives AUDIO_PIPE_EVENT_CREATED, audio_pipe_start() will be called.

  • If the function receives AUDIO_PIPE_EVENT_STARTED, a2dp_src_stream_get_data_from_fs() will be called, and data will be sent to DSP.

  • If the function receives AUDIO_PIPE_EVENT_DATA_IND, a2dp_src_stream_data_ind() will be called.

  • If the function receives AUDIO_PIPE_EVENT_DATA_FILLED, a2dp_src_stream_fill_data() and stream_check_and_request_data() will be called, which means DSP buffer level low, need more data.

  • If the function receives AUDIO_PIPE_EVENT_RELEASED, Audio Pipe will be stopped and ring buffer will be released.

  • If the function receives AUDIO_A2DP_SRC_EVENT_DATA_SEND, a2dp_src_stream_send_data() will be called.

void a2dp_src_stream_handle_msg(T_IO_MSG msg)
{
    uint16_t subtype = msg.subtype;

    APP_PRINT_INFO1("a2dp_src_stream_handle_msg: subtype: (0x%x)", subtype);
    switch (subtype)
    {
    case AUDIO_PIPE_EVENT_CREATED:
        {
            uint32_t snk_buf_size = msg.u.param;

            APP_PRINT_TRACE1("AUDIO_PIPE_EVENT_CREATED snk_buf_size:0x%x", snk_buf_size);
            audio_pipe_start(audio_pipe_handle);
            p_snk_data_buf = os_mem_alloc(RAM_TYPE_DSPSHARE, snk_buf_size);
            a2d_src_ctrl.play_state = A2DP_SRC_PLAY_STATE_PLAY;
        }
        break;

    case AUDIO_PIPE_EVENT_STARTED: // send first pkt data to dsp
        {
            uint16_t res_tmp = 0;
            res_tmp = a2dp_src_stream_get_data_from_fs();
            APP_PRINT_TRACE1("AUDIO_PIPE_EVENT_STARTED res_tmp 0x%x", res_tmp) ;
        }
        break;

    case AUDIO_PIPE_EVENT_DATA_IND: // get encode data to buf_pool
        {
            if (a2d_src_ctrl.play_state == A2DP_SRC_PLAY_STATE_PLAY)
            {
                a2dp_src_stream_data_ind();
            }
        }
        break;

    case AUDIO_PIPE_EVENT_DATA_FILLED:  // dsp buf low, need put data to share memory
        {
            if (a2d_src_ctrl.play_state == A2DP_SRC_PLAY_STATE_PLAY)
            {
                a2dp_src_stream_fill_data();
                static uint8_t s_check_cnt = 0;
                s_check_cnt++;
                if (s_check_cnt > 4)
                {
                    s_check_cnt = 0;
                    stream_check_and_request_data();
                }
            }
        }
        break;

    case AUDIO_PIPE_EVENT_RELEASED:
        {
            if (p_snk_data_buf != NULL)
            {
                free(p_snk_data_buf);
                p_snk_data_buf = NULL;
            }

            if (a2dp_src_stream_ctrl_stop_complete_hook)
            {
                a2dp_src_stream_ctrl_stop_complete_hook();
            }
        }
        break;

    case AUDIO_A2DP_SRC_EVENT_DATA_SEND: // timer msg peek data from buf_pool and send data
        {
            a2dp_src_stream_send_data();
        }
        break;

    default:
        break;
    }
}

Bluetooth Audio Intergrated Transceiver

A2DP Intergrated Transceiver Transmission

In the A2DP Intergrated Transceiver Transmission scenario, ACI Device is connected to the Phone to receive A2DP data, which is transmitted to Headset simultaneously. The path of the main code is sdk\src\sample\bt_audio_trx\source_play\app_src_play_a2dp.c.

Acquisition of A2DP Format

In this scenario, you need to get the specific A2DP formats supported by the Phone and Headset respectively. Define the following structure to store the obtained formats:

typedef struct
{
    T_AUDIO_FORMAT_INFO             src_a2dp_format;
    bool                            src_a2dp_format_ready;
    T_AUDIO_FORMAT_INFO             sink_a2dp_format[MAX_BR_LINK_NUM];
    bool                            sink_a2dp_format_ready[MAX_BR_LINK_NUM];
    T_SRC_PLAY_A2DP_STATE           sink_a2dp_state[MAX_BR_LINK_NUM];
    T_MULTI_A2DP_PARAM              sink_a2dp_param[MAX_BR_LINK_NUM];
    uint8_t                         num_frame_buf;
    uint8_t                         *p_buf;
    T_RING_BUFFER                   ring_buf;
    uint8_t                         sink_addr[MAX_BR_LINK_NUM][6];
    uint8_t                         src_addr[6];
} T_SRC_PLAY_A2DP;

The A2DP data format of the connected device can be retrieved using the following function. This function is invoked within the app_audio_bt_cback() after each A2DP connection is established and successfully configured. If the obtained A2DP role (representing the Device’s role) is BT_A2DP_ROLE_SRC, then store the format in a2dp_play.sink_a2dp_format. If the role is BT_A2DP_ROLE_SNK, store the format in a2dp_play.src_a2dp_format.

void app_src_play_save_a2dp_format(T_AUDIO_FORMAT_INFO *format_info, uint8_t *bd_addr, uint8_t role)
{
    uint8_t link_idx;
    link_idx = app_src_play_a2dp_get_connected_idx(bd_addr);
    if (role == BT_A2DP_ROLE_SRC)
    {
        if (!a2dp_play.sink_a2dp_format_ready[link_idx])
        {
            memcpy(&a2dp_play.sink_a2dp_format[link_idx], format_info, sizeof(T_AUDIO_FORMAT_INFO));

            if (a2dp_play.sink_a2dp_format[link_idx].attr.sbc.bitpool == 0)
            {
                a2dp_play.sink_a2dp_format[link_idx].attr.sbc.bitpool = 0x22;
            }
            a2dp_play.sink_a2dp_format_ready[link_idx] = true;
        }
        app_src_play_print_a2dp_format("app_src_play_save_a2dp_snk_format: ",
                                       &a2dp_play.sink_a2dp_format[link_idx]);
    }
    else if (role == BT_A2DP_ROLE_SNK)
    {
        if (!a2dp_play.src_a2dp_format_ready)
        {
            memcpy(&a2dp_play.src_a2dp_format, format_info, sizeof(T_AUDIO_FORMAT_INFO));

            if (a2dp_play.src_a2dp_format.attr.sbc.bitpool == 0)
            {
                a2dp_play.src_a2dp_format.attr.sbc.bitpool = 0x22;
            }
            a2dp_play.src_a2dp_format_ready = true;
        }
        app_src_play_print_a2dp_format("app_src_play_save_a2dp_src_format: ",
                                       &a2dp_play.src_a2dp_format);
    }
}

static void app_audio_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    bool handle = true;
    uint8_t active_a2dp_idx = app_a2dp_get_active_idx();
    uint8_t active_hf_idx = app_hfp_get_active_idx();

    switch (event_type)
    {
    case BT_EVENT_A2DP_CONFIG_CMPL:
        {
            T_AUDIO_FORMAT_INFO format_info = {};
            app_audio_save_a2dp_config((uint8_t *)&param->a2dp_config_cmpl, &format_info);

#if F_SOURCE_PLAY_SUPPORT
            app_src_play_save_a2dp_format(&format_info, param->a2dp_config_cmpl.bd_addr,
                                          param->a2dp_config_cmpl.role);
#endif
        }
        break;
    }
}
Transmission of A2DP Data

The start/stop of data transmission is also controlled by the source play commands, which can be referred to Source Play Start/Stop. After output route is started and Phone start to play music, A2DP data can be obtained in BT_EVENT_A2DP_STREAM_DATA_IND, so the A2DP stream data can also be processed in function app_src_play_pipe_handle_stream_data_in() invoked in app_audio_bt_cback().

bool app_src_play_pipe_handle_stream_data_in(uint8_t *p_data, uint16_t data_len,
                                             uint8_t frame_number)
{
    if (flag_direct_send)
    {
        app_src_play_a2dp_handle_data(p_data, data_len, frame_number);
    }

    if (a2dp_snk_pipe_play.handle)
    {
        if (frame_number > 1)
        {
            a2dp_snk_pipe_play.p_fill_buf = malloc(data_len);
            a2dp_snk_pipe_play.fill_len = data_len;

            memcpy(a2dp_snk_pipe_play.p_fill_buf, p_data, a2dp_snk_pipe_play.fill_len);
            APP_PRINT_TRACE3("app_src_play_pipe_handle_stream_data_in: data_len %d, fill len %d, fill_buf %b",
                             data_len, a2dp_snk_pipe_play.fill_len,
                             TRACE_BINARY(data_len, a2dp_snk_pipe_play.p_fill_buf));
            if (a2dp_snk_pipe_play.p_fill_buf == NULL)
            {
                APP_PRINT_ERROR0("app_src_play_pipe_handle_stream_data_in: mem error!!");
                return false;
            }
            if (flag_pipe_get_data_empty)
            {
                app_src_play_pipe_fill_data();
            }
        }
        else
        {
            //TODO: ring buffer
        }
    }
    return true;
}

static void app_audio_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    switch (event_type)
    {
    case BT_EVENT_A2DP_STREAM_DATA_IND:
        {
            T_APP_BR_LINK *p_link;
            p_link = app_link_find_br_link(param->a2dp_stream_data_ind.bd_addr);
            if (p_link == NULL)
            {
                break;
            }
#if F_APP_INTEGRATED_TRANSCEIVER
            app_src_play_pipe_handle_stream_data_in(param->a2dp_stream_data_ind.payload,
                                                    param->a2dp_stream_data_ind.len, param->a2dp_stream_data_ind.frame_num);
#endif
        }
        break;
    }
}

To improve A2DP transmit quality, function gap_br_vendor_data_rate_set() in app_bt_policy.c can be invoked before sending A2DP data to Headset.

static void set_bd_addr(void)
{
...
#if F_APP_INTEGRATED_TRANSCEIVER
    gap_br_vendor_data_rate_set(0);
#else
    gap_br_vendor_data_rate_set(1);
#endif
...
}

If a2dp_play.src_a2dp_format and a2dp_play.sink_a2dp_format is the same, then the flag_direct_send will be set to 1 and the application will go directly to function app_src_play_a2dp_handle_data().

uint16_t app_src_play_a2dp_handle_data(uint8_t *p_data, uint16_t data_len, uint8_t frame_number)
{
    uint16_t res = SRC_PLAY_A2DP_SUCCESS;
    if (frame_number > 1)
    {
        res = app_src_play_a2dp_send_data(p_data, data_len, frame_number);
        return res;
    }

    if (ring_buffer_write(&a2dp_play.ring_buf, p_data, data_len))
    {
        a2dp_play.num_frame_buf += frame_number;
    }
    else
    {
        res = SRC_PLAY_A2DP_ERR_RINGBUF;
        APP_PRINT_ERROR0("app_src_play_a2dp_handle_data: a2dp_play.ring_buf is full, drop pkt");
    }

    if (a2dp_play.num_frame_buf == A2DP_PACKET_FRAME_NUM)
    {
        a2dp_play.num_frame_buf -= A2DP_PACKET_FRAME_NUM;
        uint16_t data_len_to_send = data_len * A2DP_PACKET_FRAME_NUM;
        uint8_t *p_data_to_send = malloc(data_len_to_send);
        if (p_data_to_send)
        {
            uint32_t actual_len = ring_buffer_read(&a2dp_play.ring_buf, data_len_to_send, p_data_to_send);
            APP_PRINT_INFO1("app_src_play_a2dp_handle_data: actual_len %d sent", actual_len);

            res = app_src_play_a2dp_send_data(p_data_to_send, data_len_to_send, A2DP_PACKET_FRAME_NUM);
#if F_APP_ATTACH_LOCAL_PLAY_SUPPORT
            if (app_src_play_is_local_play_attached())
            {
                app_src_play_attach_local_play_handle_data(p_data_to_send,
                                                           data_len_to_send,
                                                           a2dp_seq_num,
                                                           A2DP_PACKET_FRAME_NUM,
                                                           0);
            }
#endif
            free(p_data_to_send);
        }
        else
        {
            res = SRC_PLAY_A2DP_ERR_RAM;
        }
    }
    return res;
}

HFP Intergrated Transceiver Transmission

In the HFP Intergrated Transceiver Transmission scenario, ACI Device is connected to the Phone to receive SCO data, which is transmitted to Headset simultaneously. The path of the main code is sdk\src\sample\bt_audio_trx\source_play\app_src_play_hfp.c.

Acquisition of HFP Format

Similar to Acquisition of A2DP Format, the HFP HF and AG formats supported by Phone and Headset can also be obtained after the SCO connection is successfully established, which is also handled in the app_audio_sco_conn_cmpl_handle(). The format structure is defined as follow.

static struct
{
    T_AUDIO_FORMAT_INFO             hfp_hf_format;
    bool                            hfp_hf_format_ready;
    uint8_t                         hf_addr[6];
    T_AUDIO_FORMAT_INFO             hfp_ag_format;
    bool                            hfp_ag_format_ready;
    uint8_t                         ag_addr[6];
} hfp_play;

After the HFP connection is established, the Device will first save the address of the linked device as hfp_play.hf_addr and hfp_play.ag_addr according to the role event BT_EVENT_HFP_AG_CONN_CMPL and BT_EVENT_HFP_CONN_CMPL of the connection in app_src_play_hfp_bt_cback(). The processing function is as follows:

static void app_src_play_hfp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    T_APP_BR_LINK *p_link;
    bool handle = true;

    switch (event_type)
    {
    case BT_EVENT_HFP_AG_CONN_CMPL:
        {
            hfp_play.hfp_hf_format_ready = false;
            memcpy(hfp_play.hf_addr, param->hfp_ag_conn_cmpl.bd_addr, 6);
        }
        break;

#if F_APP_INTEGRATED_TRANSCEIVER
    case BT_EVENT_HFP_CONN_CMPL:
        {
            hfp_play.hfp_ag_format_ready = false;
            memcpy(hfp_play.ag_addr, param->hfp_conn_cmpl.bd_addr, 6);
        }
        break;
    }
}

The function to get the HFP data format is app_src_play_save_hfp_format, which will be invoked in app_audio_sco_conn_cmpl_handle() in the callback function case of BT_EVENT_SCO_CONN_CMPL, once the SCO connection is established.

void app_src_play_save_hfp_format(T_AUDIO_FORMAT_INFO *format_info, uint8_t *bd_addr)
{
    if ((!hfp_play.hfp_hf_format_ready) && (!memcmp(hfp_play.hf_addr, bd_addr, 6)))
    {
        memcpy(&hfp_play.hfp_hf_format, format_info, sizeof(T_AUDIO_FORMAT_INFO));
        hfp_play.hfp_hf_format_ready = true;
        app_src_play_print_hfp_format("app_src_play_save_hfp_hf_format: ",
                                      &hfp_play.hfp_hf_format);
    }

#if F_APP_INTEGRATED_TRANSCEIVER
    else if ((!hfp_play.hfp_ag_format_ready) && (!memcmp(hfp_play.ag_addr, bd_addr, 6)))
    {
        memcpy(&hfp_play.hfp_ag_format, format_info, sizeof(T_AUDIO_FORMAT_INFO));
        hfp_play.hfp_ag_format_ready = true;
        app_src_play_print_hfp_format("app_src_play_save_hfp_ag_format: ",
                                      &hfp_play.hfp_ag_format);
    }
#endif

}

static void app_audio_sco_conn_cmpl_handle(uint8_t *bd_addr, uint8_t air_mode, uint8_t rx_pkt_len)
{
    uint8_t pair_idx_mapping;
    T_AUDIO_FORMAT_INFO format_info = {};
    T_APP_BR_LINK *p_link;

    p_link = app_link_find_br_link(bd_addr);

    if (p_link == NULL)
    {
        return;
    }
#if F_SOURCE_PLAY_SUPPORT
    app_src_play_save_hfp_format(&format_info, bd_addr);
#endif
}


static void app_audio_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
...
    switch (event_type)
    {
    case BT_EVENT_SCO_CONN_CMPL:
        {
...
            app_audio_sco_conn_cmpl_handle(param->sco_conn_cmpl.bd_addr, param->sco_conn_cmpl.air_mode,
                                           param->sco_conn_cmpl.rx_pkt_len);
        }
        break;
    }
}
Transmission of SCO Data

To improve call quality, function bt_sco_link_retrans_window_set can be invoked in BT_EVENT_SCO_CONN_CMPL in the app_src_play_hfp_bt_cback() to set the transmit window of lowerstack after the SCO connection is established.

static void app_src_play_hfp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
...
    case BT_EVENT_SCO_CONN_CMPL:
        {
            if (!memcmp(hfp_play.ag_addr, param->sco_conn_cmpl.bd_addr, 6))
            {
                bt_sco_link_retrans_window_set(hfp_play.ag_addr, 1);
            }
            else if (!memcmp(hfp_play.hf_addr, param->sco_conn_cmpl.bd_addr, 6))
            {
                bt_sco_link_retrans_window_set(hfp_play.hf_addr, 1);
            }
        }
        break;
...
}

When Phone is called, SCO data will be generated simultaneously, and Device can process the data. By invoking app_src_play_hfp_send_sco(), SCO data will be sent to Phone and Headset respectively, which is a two-way communication.

void app_src_play_hfp_send_sco(uint8_t *p_data, uint16_t len, uint8_t bd_addr[6])
{
    uint8_t active_hf_idx = app_hfp_get_active_idx();
    uint16_t hfp_seq_num;
    T_APP_BR_LINK *p_link;
    bool sco_tx_result = false;

#if F_APP_INTEGRATED_TRANSCEIVER
    p_link = app_link_find_br_link(bd_addr);
#else
    p_link = app_link_find_br_link(app_db.br_link[active_hf_idx].bd_addr);
#endif

    if (p_link == NULL)
    {
        APP_PRINT_ERROR0("app_src_play_hfp_send_sco: no br link found");
        return;
    }

#if F_APP_INTEGRATED_TRANSCEIVER
    if (!memcmp(hfp_play.ag_addr, bd_addr, 6))
    {
        hfp_ag_seq_num++;
        hfp_seq_num = hfp_ag_seq_num;
        memcpy(bd_addr, hfp_play.hf_addr, 6);
    }
    else
    {
        hfp_hf_seq_num++;
        hfp_seq_num = hfp_hf_seq_num;
        memcpy(bd_addr, hfp_play.ag_addr, 6);
    }
#else
    hfp_hf_seq_num++;
    hfp_seq_num = hfp_hf_seq_num;
    memcpy(bd_addr, p_link->bd_addr, 6);
#endif

    if (p_link->sco.duplicate_fst_data)
    {
        p_link->sco.duplicate_fst_data = false;
        bt_sco_data_send(bd_addr, hfp_seq_num - 1, p_data, len);
#if CONFIG_REALTEK_APP_BT_AUDIO_TRI_DONGLE
        APP_PRINT_ERROR0("app_src_play_hfp_send_sco: duplicate_fst_data");
#endif
    }

    sco_tx_result = bt_sco_data_send(bd_addr, hfp_seq_num, p_data, len);
    if (sco_tx_result == false)
    {
        APP_PRINT_ERROR0("app_src_play_hfp_send_sco: bt_sco_data_send fail");
    }
}

static void app_src_play_hfp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
...
    case BT_EVENT_SCO_DATA_IND:
        {
#if F_APP_INTEGRATED_TRANSCEIVER
            if (param->sco_data_ind.status == 0)
            {
                app_src_play_hfp_send_sco(param->sco_data_ind.p_data, param->sco_data_ind.length,
                                          param->sco_data_ind.bd_addr);
            }
        }
#endif
...
}

UART DFU

In addition to the OTA Module OTA, the Bluetooth Audio Transceiver application also provides UART DFU functionality for device upgrades. This feature allows external MCU to transfer upgrade packages to the device via UART, without needing to be aware of the format of the upgrade package. It only needs to adhere to the specified interaction commands.

Currently, ACI Host can be used to simulate an external MCU device for implementing UART DFU upgrades.

Code Flow on Device Side

The UART DFU feature is disabled by default. To enable the feature, set F_APP_UART_DFU to 1 in the app_flags.h file:

// app_flags.h
#define F_APP_UART_DFU                      0

The ACI Host commands are implemented through CMD_UART_DFU. Different functionalities are achieved by carrying different opcodes in the CMD_UART_DFU command, including requesting to start DFU (UART_DFU_START_REQ), transferring data (UART_DFU_DATA_IND), rebooting the device (UART_DFU_REBOOT), and interrupting DFU (UART_DFU_ABORT).

void app_uart_dfu_process(uint8_t cmd_path, uint16_t opcode, uint8_t *p_data, uint16_t len)
{
    switch (opcode)
    {
    case UART_DFU_TEST_EN:
        uart_dfu_handle_test_en();
        break;
    case UART_DFU_START_REQ:
        uart_dfu_handle_start_req(cmd_path, p_data, len);
        break;

    case UART_DFU_DATA_IND:
        uart_dfu_handle_data_ind(cmd_path, p_data, len);
        break;

    case UART_DFU_REBOOT:
        uart_dfu_handle_reboot_req();
        break;

    case UART_DFU_ABORT:
        uart_dfu_handle_abort_req();
        break;

    case UART_DFU_GET_VER:
        uart_dfu_handle_get_ver(cmd_path);
        break;

    default:
        break;
    }
}

The device communicates its status to ACI Host by sending different events, including whether DFU is permitted (EVENT_DFU_START_RSP), requesting data (EVENT_DFU_DATA_REQ), reporting local version (EVENT_DFU_LOCAL_VERSION), and notifying DFU results (EVENT_DFU_RESULT).

typedef enum
{
    ...
    EVENT_DFU_START_RSP                      = 0x3160,
    EVENT_DFU_DATA_REQ                       = 0x3161,
    EVENT_DFU_RESULT                         = 0x3162,
    EVENT_DFU_LOCAL_VERSION                  = 0x3163,
    ...
} T_EVENT_ID;

When ACI Host sends UART_DFU_START_REQ opcode, it carries the version number of the upgrade package. The device checks whether its local version is lower than the provided one to determine whether to accept the upgrade. It then informs ACI Host through the EVENT_DFU_START_RSP event and requests the first set of data through the EVENT_DFU_DATA_REQ event.

static void uart_dfu_handle_start_req(uint8_t cmd_path, uint8_t *data, uint16_t len)
{
    uint32_t dfu_version, local_version;
    uint32_t next_block_offset;
    uint16_t next_block_length;
    uint8_t ret = 0;
    T_UART_DFU_START_RSP rsp_state = UART_DFU_REJECT;

    LE_STREAM_TO_UINT32(dfu_version, data);
    local_version = uart_dfu_get_ota_header_ver();

    APP_PRINT_INFO3("uart_dfu_handle_start_req: force_update %d, version local 0x%08x, dfu 0x%08x",
                    force_update, local_version, dfu_version);

    if (!force_update && local_version > dfu_version)
    {
        ret = 1;
        goto ERR;
    }

    if (dfu_mgr.state != UART_DFU_STATE_IDLE)
    {
        ret = 2;
        goto ERR;
    }

    ota_write_buf = malloc(OTA_WRITE_BUFFER_SIZE);
    if (ota_write_buf == NULL)
    {
        ret = 3;
        goto ERR;
    }

    app_dlps_disable(APP_DLPS_ENTER_CHECK_OTA_TOOLING_PARK);

    dfu_mgr.state = UART_DFU_STATE_MERGED_HEADER;
    rsp_state = UART_DFU_ACCEPT;
    app_report_event(cmd_path, EVENT_DFU_START_RSP, 0, (uint8_t *)&rsp_state, sizeof(rsp_state));

    next_block_offset = 0;
    next_block_length = OTA_MERGED_FILE_HEAD_SIZE;
    uart_dfu_req_data(cmd_path, next_block_offset, next_block_length);
    return;

ERR:
    APP_PRINT_INFO1("uart_dfu_handle_start_req: failed %d", -ret);
    app_report_event(cmd_path, EVENT_DFU_START_RSP, 0, (uint8_t *)&rsp_state, sizeof(rsp_state));

}

ACI Host retrieves the corresponding data from the file based on the offset and length received in the EVENT_DFU_DATA_REQ event, and sends it to the device through the UART_DFU_DATA_IND opcode. Subsequent data transfers are facilitated through EVENT_DFU_DATA_REQ event and UART_DFU_DATA_IND opcode until the device receives all the data. This process is handled in the uart_dfu_handle_data_ind() function. The device then informs ACI Host of the DFU result through the EVENT_DFU_RESULT event. ACI Host sends the UART_DFU_REBOOT opcode to the device to complete the entire UART DFU process.

static void uart_dfu_handle_data_ind(uint8_t cmd_path, uint8_t *data, uint16_t len)
{
    uint32_t next_block_offset = 0;
    uint16_t next_block_length = 0;

    if (dfu_mgr.cur_expect_block_len != len)
    {
        ...
    }

    if (dfu_mgr.state  == UART_DFU_STATE_MERGED_HEADER) //handle merged header
    {
        ...
        uart_dfu_req_data(cmd_path, next_block_offset, next_block_length);

        dfu_mgr.state  = UART_DFU_STATE_SUB_FILE_HEADER;
    }
    else if (dfu_mgr.state == UART_DFU_STATE_SUB_FILE_HEADER) //handle sub_file headers
    {
        ...
        uart_dfu_req_data(cmd_path, next_block_offset, next_block_length);

        dfu_mgr.state = UART_DFU_STATE_CONTROL_HEADER;
    }
    else if (dfu_mgr.state == UART_DFU_STATE_CONTROL_HEADER) // READ handle control header
    {
        ...
        uart_dfu_req_data(cmd_path, next_block_offset, next_block_length);

        dfu_mgr.state = UART_DFU_STATE_IMAGE_PAYLOAD;
    }
    else if (dfu_mgr.state == UART_DFU_STATE_IMAGE_PAYLOAD)
    {
        ...
        if ((dfu_mgr.buf_index == OTA_WRITE_BUFFER_SIZE) || // Every 4k write once
            (dfu_mgr.cur_sub_image_relative_offset ==
             dfu_mgr.sub_bin.sub_image_header[dfu_mgr.cur_sub_image_index].size)) // Or last packet
        {
            ...

            //last pkt of one sub image, check image
            if (dfu_mgr.cur_sub_image_relative_offset
                ==
                dfu_mgr.sub_bin.sub_image_header[dfu_mgr.cur_sub_image_index].size)
            {
                ...
                if (check_image)
                {
                    //update cur_sub_image_relative_offset
                    dfu_mgr.cur_sub_image_relative_offset = 0;
                    dfu_mgr.cur_sub_image_index++;
                    //if it is last sub image, complete check
                    if (dfu_mgr.cur_sub_image_index == dfu_mgr.end_sub_image_index)
                    {
                        //OTA complete
                        ...
                        uart_dfu_update_complete_check();
                        T_UART_DFU_RESULT duf_result = UART_DFU_SUCCESS;
                        app_report_event(CMD_PATH_UART, EVENT_DFU_RESULT, 0, (uint8_t *)&duf_result, sizeof(duf_result));
                        return;
                    }
                    else
                    {
                        //request Nth sub image
                        ...
                        uart_dfu_req_data(cmd_path, next_block_offset, next_block_length);
                        return;
                    }
                }
                else
                {
                    ...
                }
            }
        }
        //prepare next block
        ...
        dfu_mgr.state = UART_DFU_STATE_IMAGE_PAYLOAD;
        uart_dfu_req_data(cmd_path, next_block_offset, next_block_length);
        APP_PRINT_INFO1("uart_dfu_handle: cur relative offset 0x%x", dfu_mgr.cur_sub_image_relative_offset);
    }
}

During the UART DFU process, ACI Host can send the UART_DFU_ABORT opcode to abort the DFU process. If certain anomalies occur at the device, it will inform ACI Host through the EVENT_DFU_RESULT event, carrying the UART_DFU_FAIL status, and subsequently exit the DFU process.

static void uart_dfu_restore(void)
{
    memset(&dfu_mgr, 0, sizeof(T_UART_DFU_MGR));
    if (ota_write_buf != NULL)
    {
        free(ota_write_buf);
        ota_write_buf = NULL;
    }
    app_dlps_enable(APP_DLPS_ENTER_CHECK_OTA_TOOLING_PARK);
}

Integration for External MCU

Command Format

UART DFU is based on Command/Event interface ACI Data Formats. The External MCU sends commands to the device, and the device sends events to the MCU, reporting its status or requesting data.

The UART packet format is illustrated in the figure below. This chapter focuses on the specific format of UART DFU Command and UART DFU Event. Please refer to ACI Data Formats for an explanation of the packet header and packet tail.

External MCU should send the command Opcode CMD_UART_DFU (0x3270) with Sub-Opcode to achieve specific functions, including requesting to start DFU, sending DFU data, aborting DFU, and rebooting the device:

Opcode: CMD_UART_DFU (0x3270)

Sub-Opcode:
    UART_DFU_START_REQ  = 0x0000,
    UART_DFU_DATA_IND   = 0x0001,
    UART_DFU_ABORT      = 0x0002,
    UART_DFU_REBOOT     = 0x0003,
    UART_DFU_TEST_EN    = 0x0004,
    UART_DFU_GET_VER    = 0x0005,

The device supports the following events to report its own status or request data.

    EVENT_DFU_START_RSP                      = 0x3160,
    EVENT_DFU_DATA_REQ                       = 0x3161,
    EVENT_DFU_RESULT                         = 0x3162,
    EVENT_DFU_LOCAL_VERSION                  = 0x3163,
  1. Sub-Opcode: UART_DFU_START_REQ.

    Direction: External MCU -> Device

    Function: Request to start UART DFU.

    Format:

    Byte 0~1

    Byte 2~3

    Byte 4~7

    0x3270

    0x0000

    dfu_version

    Byte 4~7: Version the upgrade package, for example, 1.2.3.4 would be represented as 0x01020304.

  2. Sub-Opcode: UART_DFU_DATA_IND.

    Direction: External MCU -> Device

    Function: Send DFU data to device.

    Format:

    Byte 0~1

    Byte 2~3

    Byte 4~N

    0x3270

    0x0001

    data

    Byte 4~N: When a EVENT_DFU_DATA_REQ event is received from the device, carrying offset and length parameters, the External MCU extracts data of the specified length from the upgrade file, starting at the specified offset, and fills the data to this field.

  3. Sub-Opcode: UART_DFU_ABORT.

    Direction: External MCU -> Device

    Function: The External MCU terminates the DFU process.

    Format:

    Byte 0~1

    Byte 2~3

    0x3270

    0x0002

  4. Sub-Opcode: UART_DFU_REBOOT.

    Direction: External MCU -> Device

    Function: The External MCU needs to instruct the device to reboot after a successful upgrade.

    Format:

    Byte 0~1

    Byte 2~3

    0x3270

    0x0003

  5. Sub-Opcode: UART_DFU_TEST_EN.

    Direction: External MCU -> Device

    Function: If the External MCU wants to downgrade the device, it should send this command before UART_DFU_START_REQ to enable test mode.

    Format:

    Byte 0~1

    Byte 2~3

    0x3270

    0x0004

  6. Sub-Opcode: UART_DFU_GET_VER.

    Direction: External MCU -> Device

    Function: Obtain the version number of the OTA header image of the device. This is commonly utilized to allow the external MCU to request the device’s version, enabling the MCU to decide whether to initiate an upgrade request.

    Format:

    Byte 0~1

    Byte 2~3

    0x3270

    0x0005

  7. Event: EVENT_DFU_START_RSP.

    Direction: Device -> External MCU

    Function: When the device receives the UART_DFU_START_REQ command, it compares the current device version with the upgrade package version. Only if the upgrade package version is higher than the device version will it allow the upgrade, responding with UART_DFU_ACCEPT (0x01); otherwise, it replies with UART_DFU_REJECT (0x00).

    Format:

    Byte 0~1

    Byte 2

    0x3160

    Response state

    Byte 2: UART_DFU_ACCEPT (0x01) or UART_DFU_REJECT (0x00)

  8. Event: EVENT_DFU_DATA_REQ.

    Direction: Device -> External MCU

    Function: Used when the device accepts the upgrade and actively requests subsequent data packets.

    Format:

    Byte 0~1

    Byte 2~5

    Byte 6~7

    0x3161

    Offset

    Length

    Byte 2~5: Data offset in the upgrade file. Byte 6~7: Data length.

  9. Event: EVENT_DFU_RESULT.

    Direction: Device -> External MCU

    Function: The device reports the upgrade result. In case of errors during the upgrade process, the device reports the UART_DFU_FAIL status. If the upgrade is completed successfully, the device reports the UART_DFU_SUCCESS status.

    Format:

    Byte 0~1

    Byte 2

    0x3162

    status

    Byte 2: UART_DFU_SUCCESS (0x01) or UART_DFU_FAIL (0x00)

  10. Event: EVENT_DFU_LOCAL_VERSION.

    Direction: Device -> External MCU

    Function: Report device’s local version if UART_DFU_GET_VER received.

    Format:

    Byte 0~1

    Byte 2~5

    0x3163

    Version

    Byte 2~5: Device’s local version, represented as 0x01020304.

Interaction Flow

Interaction Flow

This figure depicts the interaction flow between the External MCU and the Device during a successful UART DFU process. Normal Mode DFU is employed for device upgrades, while Test Mode DFU is utilized for device downgrades, typically during the development and debugging phases. In Test Mode, the External MCU is required to send the UART_DFU_TEST_EN command before sending the UART_DFU_START_REQ. This ensures that upon receiving the UART_DFU_START_REQ command, the device skips version comparison and starts up from a lower version bank after the DFU process is complete.

Exception Handling

DFU Fail

On the device side, if any exception occurs, it will report EVENT_DFU_RESULT event with parameter UART_DFU_FAIL (0x00), and autonomously recover its state. In this case, the External MCU needs to restore its own state to ensure it can restart the DFU process successfully next time.

Unexpected Offset and Length

Upon receiving the EVENT_DFU_DATA_REQ event, the External MCU needs to check whether it can retrieve the corresponding data from the file based on the offset and length. If the offset and length exceed the file size, the External MCU should send the UART_DFU_ABORT command to terminate the DFU process.

Acoustics MP

Acoustics MP of Bluetooth Audio Transceiver application mainly includes HW EQ Fitting. This feature is used for Audio Component calibration, including SPK and MIC device. It also supports calibration via various scenarios, such as playback for SPK response, voice and record for MIC gain.

Flow on Device Side

The Acoustics MP feature is enabled by default. Two flags are used in the app_flags.h file: F_APP_SAIYAN_EQ_FITTING and F_APP_SUPPORT_CAPTURE_ACOUSTICS_MP:

  • F_APP_SAIYAN_EQ_FITTING enables HW EQ Fitting via playback and voice.

  • F_APP_SUPPORT_CAPTURE_ACOUSTICS_MP enables HW EQ Fitting via record (SPP Capture).

#define F_APP_SAIYAN_EQ_FITTING             1
#define F_APP_SUPPORT_CAPTURE_ACOUSTICS_MP  1

Before calibration, SPP connection should be established for interaction between the device and MP Tool.

The specific commands sent by MP Tool will be processed in app_eq_fitting_cmd_handle() or app_data_capture_cmd_handle() on the device’s side.

// HW EQ command
    case CMD_HW_EQ_TEST_MODE:                      // 0x1200
    case CMD_HW_EQ_START_SET:                      // 0x1201
    case CMD_HW_EQ_CONTINUE_SET:                   // 0x1202
    case CMD_HW_EQ_CLEAR_CALIBRATE_FLAG:           // 0x1204
    case CMD_HW_EQ_SET_TEST_MODE_TMP_EQ:           // 0x1205
    case CMD_HW_EQ_SET_TEST_MODE_TMP_EQ_ADVANCED:  // 0x1206
        {
            app_eq_fitting_cmd_handle(cmd_ptr, cmd_len, cmd_path, app_idx, ack_pkt);
        }
        break;

// SPP Capture command
    case CMD_DSP_CAPTURE_V2_START_STOP:            // 0x0220
        {
            app_data_capture_cmd_handle(cmd_ptr, cmd_len, cmd_path, app_idx, ack_pkt);
        }
        break;

And after processing the command, the device will reply with the EVENT_ACK and the other corresponding event to the tool by app_report_event():

// EVENT_ACK
    EVENT_ACK                               = 0x0000,

// HW EQ event
    EVENT_HW_EQ_TEST_MODE                     = 0x1200,
    EVENT_HW_EQ_START_SET                     = 0x1201,
    EVENT_HW_EQ_CONTINUE_SET                  = 0x1202,
    EVENT_HW_EQ_CLEAR_CALIBRATE_FLAG          = 0x1204,
    EVENT_HW_EQ_SET_TEST_MODE_TMP_EQ          = 0x1205,
    EVENT_HW_EQ_SET_TEST_MODE_TMP_EQ_ADVANCED = 0x1206,

// SPP Capture event
    EVENT_DSP_CAPTURE_V2_START_STOP_RESULT      = 0x0220,
    EVENT_DSP_CAPTURE_V2_DATA                   = 0x0221,

Note

It should be noted that EVENT_DSP_CAPTURE_V2_DATA does not actually have a corresponding command. It is actually capture data.

A complete Acoustics MP flow should include the following steps:

  • Enter HW EQ Test Mode.

  • Measure and calculate.

  • Apply temp EQ.

  • Download to flash.

  • Exit HW EQ Test Mode.

  • Check after download.

It can also be referred to the figure below, and among these steps, the more important are: Apply temp EQ, Download to flash, and Check after download.

Enter or Exit HW EQ Test Mode

The device uses CMD_HW_EQ_TEST_MODE (0x1200) to enter or exit HW EQ Test Mode, which can be distinguished by different parameters in the command. When entering HW EQ Test Mode, the is_test_mode flag will be set to true. Otherwise, this flag will be set to false.

    case CMD_HW_EQ_TEST_MODE:
        {
            uint8_t test_mode_status = cmd_ptr[2];

            if (test_mode_status == HW_EQ_ENTER_TEST_MODE)     // Enter HW EQ Test Mode
            {
                is_test_mode = true;
                ...
            }
            else if (test_mode_status == HW_EQ_EXIT_TEST_MODE) // Exit HW EQ Test Mode
            {
                is_test_mode = false;
                ...
            }
            else
            {
                ack_pkt[2] = CMD_SET_STATUS_PARAMETER_ERROR;
            }

            app_report_event(cmd_path, EVENT_ACK, app_idx, ack_pkt, 3);

            if (ack_pkt[2] == CMD_SET_STATUS_COMPLETE)
            {
                app_report_event(cmd_path, EVENT_HW_EQ_TEST_MODE, app_idx, &ack_pkt[2], sizeof(uint8_t));
            }
        }
        break;
Measure and Calculate

Through measurement, the compensation value can be calculated by fitting algorithm for the subsequent apply process. Different sample rates have different parameters. For example, when using 48k sampling rate to measure the SPK response, three sets of EQ filter parameters with different sample rates will be generated.

Apply Temp EQ

Then the device can use CMD_HW_EQ_SET_TEST_MODE_TMP_EQ_ADVANCED (0x1206) to apply temp EQ parameters. This command is used to assist Acoustics MP and verify calibration effect.

When the device is in HW EQ Test Mode, the tool can send temporary HW EQ parameters to the device. The device opens memory to temporarily store this parameter. Once an audio_track that meets the conditions (device, sample rate) is established, the device applies the HW EQ parameters, otherwise it will take a long time to test if each sample rate per scenario follows. When the device exits HW EQ Test Mode, the device will release the temp EQ parameters.

The device uses app_eq_fitting_set_test_mode_tmp_eq_advanced to handle the details. There will be 2 situations. One is to take effect in real time. That is, when receiving the temp EQ parameters, audio_track is already in the STARTED state by app_eq_fitting_is_streaming.

app_eq_fitting_cmd_handle()
    |---app_eq_fitting_set_test_mode_tmp_eq_advanced()

static void app_eq_fitting_set_test_mode_tmp_eq_advanced(void)
{
    if (test_mode_tmp_eq_advanced)
    {
        ...
        if (eq_para->device_type == HW_EQ_DEVICE_PRIMARY_SPEAKER) //pri spk
        {
            eq_type = CODEC_EQ_CONFIG_PATH_DAC;
            eq_channel = 0; // DAC0
        }
        else if (eq_para->device_type == HW_EQ_DEVICE_PRIMARY_MIC) // pri mic
        {
            eq_type = CODEC_EQ_CONFIG_PATH_ADC;
            eq_channel = 0; // ADC0
        }
        else if (eq_para->device_type == HW_EQ_DEVICE_SECONDARY_MIC) // sec mic
        {
            eq_type = CODEC_EQ_CONFIG_PATH_ADC;
            eq_channel = 1; // ADC1
        }

        if (app_eq_fitting_is_streaming(AUDIO_STREAM_TYPE_PLAYBACK)) //  playback scenario
        {
            sample_rate = app_eq_fitting_get_sample_rate(AUDIO_CATEGORY_AUDIO); // 44.1k or 48k
            if (sample_rate == eq_para->sample_rate) // sample rate match
            {
                audio_probe_codec_hw_eq_set(eq_type, eq_channel, eq_para->para, para_len); // HW EQ set
            }
        }
        else if (app_eq_fitting_is_streaming(AUDIO_STREAM_TYPE_VOICE)) // voice scenario
        {
            sample_rate = app_eq_fitting_get_sample_rate(AUDIO_CATEGORY_VOICE); // 16k
            if (sample_rate == eq_para->sample_rate) // sample rate match
            {
                audio_probe_codec_hw_eq_set(eq_type, eq_channel, eq_para->para, para_len); // HW EQ set
            }
        }
        else if (app_eq_fitting_is_streaming(AUDIO_STREAM_TYPE_RECORD)) // record scenario
        {
            sample_rate = app_eq_fitting_get_sample_rate(AUDIO_CATEGORY_RECORD); // 48k
            if (sample_rate == eq_para->sample_rate) // sample rate match
            {
                audio_probe_codec_hw_eq_set(eq_type, eq_channel, eq_para->para, para_len); // HW EQ set
            }
        }
    }
}

The other situation is that the EQ parameters will be temporarily stored and then applied when audio_track is established.

static void app_eq_fitting_cback(T_AUDIO_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    ...
    switch (event_type)
    {
    case AUDIO_EVENT_TRACK_STATE_CHANGED:
        {
            ...
            if (is_test_mode) // in HW EQ Test Mode
            {
                ...
                app_eq_fitting_set_test_mode_tmp_eq_advanced();
             }
            ...
        }
    }
    ...
}

Playback or voice scenario

If we want to apply EQ parameters during playback or voice scenario, we can trigger A2DP or HFP play to create the related audio_track.

Record scenario

If we want to apply EQ parameters in a record scenario, we can trigger Capture start to create the record track. The device uses CMD_DSP_CAPTURE_V2_START_STOP (0x0220) to start and stop capture.

// start capture
app_data_capture_cmd_handle()
    |---app_data_capture_recorder_create()
            |---audio_track_create()

// stop capture
app_data_capture_cmd_handle()
    |---app_data_capture_stop_process
            |---audio_track_release()
// capture data
app_data_capture_cmd_handle()
    |---app_data_capture_register()
            |---audio_probe_dsp_evt_cback_register(app_data_capture_dsp_event_cback);

void app_data_capture_dsp_event_cback(uint32_t event, void *msg)
{
    switch (event)
    {
    case AUDIO_PROBE_DSP_EVT_MAILBOX_DSP_DATA:
        {
            ...
            app_report_event(dsp_capture_data_path, EVENT_DSP_CAPTURE_V2_DATA, dsp_capture_data_app_idx,
                             p_info->p_data, p_info->data_len); // EVENT_DSP_CAPTURE_V2_DATA
        }
        break;
    ...
    }
}
Download to Flash

After the apply process is verified, the device can download “MP EQ Information” to flash by using CMD_HW_EQ_START_SET (0x1201) and CMD_HW_EQ_CONTINUE_SET (0x1202). The first 1KB of Flash is used to store HW EQ Fitting data currently.

app_eq_fitting_cmd_handle()
    |---app_eq_fitting_write_hw_eq()

static uint8_t app_eq_fitting_write_hw_eq(uint8_t *data, uint32_t len)
{
    uint8_t failed_cause = HW_EQ_WRITE_SUCCESS;
    bool resume_bp_lv = false;
    uint8_t old_bp_lv;
    uint8_t *flash_tem_buf = NULL;

    is_disallow_playback = true;

    if (!app_eq_fitting_is_media_buffer_idle())
    {
        failed_cause = HW_EQ_WRITE_WRONG_TRACK_STATE;
        goto exit;
    }

    /* need 4K for temporary storage, take it from heap */
    flash_tem_buf = (uint8_t *)malloc(FLASH_NOR_SECTOR_SIZE); // 0x1000
    if (!flash_tem_buf)
    {
        failed_cause = HW_EQ_WRITE_MALLOC_FAIL;
        goto exit;
    }

    if (!fmc_flash_nor_get_bp_lv(EQ_FITTING_ADDR, &old_bp_lv))
    {
        failed_cause = HW_EQ_WRITE_GET_BP_LV_FAIL;
        goto exit;
    }

    if (fmc_flash_nor_set_bp_lv(EQ_FITTING_ADDR, 0))
    {
        resume_bp_lv = true;
    }
    else
    {
        failed_cause = HW_EQ_WRITE_SET_BP_LV_FAIL;
        goto exit;
    }

    if (fmc_flash_nor_read(EQ_FITTING_ADDR, flash_tem_buf, FLASH_NOR_SECTOR_SIZE))
    {
        if (len <= EQ_FITTING_SIZE)
        {
            memcpy(flash_tem_buf, data, len);
        }
        else
        {
            failed_cause = HW_EQ_WRITE_WRONG_LEN;
            goto exit;
        }
    }
    else
    {
        failed_cause = HW_EQ_WRITE_READ_FAIL;
        goto exit;
    }

    if (!fmc_flash_nor_erase(EQ_FITTING_ADDR, FMC_FLASH_NOR_ERASE_SECTOR))
    {
        failed_cause = HW_EQ_WRITE_ERASE_FAIL;
        goto exit;
    }

    if (!fmc_flash_nor_write(EQ_FITTING_ADDR, flash_tem_buf, FLASH_NOR_SECTOR_SIZE))
    {
        failed_cause = HW_EQ_WRITE_FAIL;
        goto exit;
    }

exit:

    if (resume_bp_lv)
    {
        fmc_flash_nor_set_bp_lv(EQ_FITTING_ADDR, old_bp_lv);
    }

    if (flash_tem_buf)
    {
        free(flash_tem_buf);
    }

    if (failed_cause != HW_EQ_WRITE_WRONG_TRACK_STATE)
    {
        is_disallow_playback = false;
    }

    APP_PRINT_ERROR1("app_eq_fitting_write_hw_eq: cause %d", failed_cause);

    return failed_cause;
}
// flash_map.h
#define EQ_FITTING_ADDR                 0x02000000
#define EQ_FITTING_SIZE                 0x00000400  //1K Bytes
Check after Downloading

Finally, the device exits the MP test mode and returns to user mode. It is possible to trigger A2DP Play, HFP Play, or Capture Start again to check the parameters downloaded to flash before. It is expected to use the one downloaded to flash before.

static void app_eq_fitting_cback(T_AUDIO_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    ...
    switch (event_type)
    {
    case AUDIO_EVENT_TRACK_STATE_CHANGED:
        {
            ...
            if (stream_type == AUDIO_STREAM_TYPE_PLAYBACK)
            {
                app_eq_fitting_send_hw_eq(AUDIO_CATEGORY_AUDIO);
            }
            else if (stream_type == AUDIO_STREAM_TYPE_VOICE)
            {
                app_eq_fitting_send_hw_eq(AUDIO_CATEGORY_VOICE);
            }
            else if (stream_type == AUDIO_STREAM_TYPE_RECORD)
            {
                app_eq_fitting_send_hw_eq(AUDIO_CATEGORY_RECORD);
            }
            ...
        }
    }
    ...
}
static bool app_eq_fitting_send_hw_eq(T_AUDIO_CATEGORY category)
{
    ...
    for (i = 0; i < pysical_path_group.physical_path_num; i++)
    {
        ...
        if (eq_config_path != CODEC_EQ_CONFIG_PATH_MAX &&
            (io_idx < sizeof(hw_eq_info) / sizeof(T_HW_EQ_INFO *)))
        {
            T_HW_EQ_INFO *tmp = hw_eq_info[io_idx];

            while (tmp)
            {
                if (tmp->sample_rate == sample_rate) // sample rate match
                {
                    T_HW_EQ_PARA *buf = malloc(tmp->len);

                    if (buf)
                    {
                        if (app_eq_fitting_read_hw_eq(sizeof(T_HW_EQ_DATA) + tmp->offset, (uint8_t *)buf, tmp->len)) // read HW EQ from flash
                        {
                            audio_probe_codec_hw_eq_set(eq_config_path, channel, (uint8_t *)buf->para,
                                                        buf->stage_number * EQ_STAGE_LEN); // HW EQ set
                        }
                        free(buf);
                    }

                    break;
                }
                tmp = tmp->next;
            }
        }
    }
		...
    return true;
}

Command and Event

Enter or Exit MP EQ Test Mode
  1. CMD_HW_EQ_TEST_MODE

    Direction: Tool -> Device

    Function: Request to enter or exit HW EQ Test Mode.

    Format:

    Byte 0~1

    Byte 2

    0x1200

    test mode status

    Byte 2: HW_EQ_EXIT_TEST_MODE (0x00) or HW_EQ_ENTER_TEST_MODE (0x01).

  2. EVENT_HW_EQ_TEST_MODE

    Direction: Device -> Tool

    Function: The device reports the CMD process result to the tool.

    Format:

    Byte 0~1

    Byte 2

    0x1200

    status

    Byte 2: Status. 0x00 means success, and 0x03 means parameter error.

Start Set MP EQ Info
  1. CMD_HW_EQ_START_SET

    Direction: Tool -> Device

    Function: Request to start set MP EQ info.

    Format:

    Byte 0~1

    Byte 2~3

    Byte 4~5

    0x1201

    EQ_totallen

    CRC

    Byte 2~3: Total length of all EQ parameters.
    Byte 4~5: CRC16 of all EQ parameters. The device does check after receiving the complete EQ parameters.

  2. EVENT_HW_EQ_START_SET

    Direction: Device -> Tool

    Function: The device reports the CMD process result and Max_packet_size to the tool.

    Format:

    Byte 0~1

    Byte 2

    Byte 3~4

    0x1201

    status

    Max_packet_size

    Byte 2: Status. 0x00 means success, and 0x05 means process fail.
    Byte 3~4: Max_packet_size. The current setting is 500 bytes, which is MAX_EQ_TOOL_CMD_LENGTH in macro definition.

Continue Set MP EQ Info
  1. CMD_HW_EQ_CONTINUE_SET

    Direction: Tool -> Device

    Function: Request to continue set MP EQ info.

    Format:

    Byte 0~1

    Byte 2

    Byte 3

    Byte 4~N

    0x1202

    num_of_total_packet

    index_packet

    data[]

    Byte 2: Total packet number.
    Byte 3: Current package index. Valid index should be 0, 1, …, number_of_total_packet- 1.
    Byte 4~N: HW_EQ_DATA. That is, the following T_HW_EQ_DATA.

    typedef struct __attribute__((__packed__)) t_hw_eq_para
    {
        uint8_t device_type;
        uint8_t rsv;
        uint32_t sample_rate;
        uint8_t stage_number;
        uint8_t para[0];     /* para len is stage_number * 20 bytes */
    } T_HW_EQ_PARA;
    
    typedef struct __attribute__((__packed__)) t_hw_eq_data
    {
        uint32_t magic_word;
        uint8_t calibrated;
        uint16_t total_len;  /* total len of all groups of  */
        uint16_t crc16;      /* CRC calc range: all groups of eq para */
    
        T_HW_EQ_PARA eq_para[0]; // sereral Groups of T_HW_EQ_PARA
    } T_HW_EQ_DATA;
    
  2. EVENT_HW_EQ_CONTINUE_SET

    Direction: Device -> Tool

    Function: The device reports the CMD process result to the tool.

    Format:

    Byte 0~1

    Byte 2

    0x1202

    status

    Byte 2: status. 0x00 means success, 0x03 means parameter error and 0x05 means process fail.

Set Test Mode Temp EQ Advanced
  1. CMD_HW_EQ_SET_TEST_MODE_TMP_EQ_ADVANCED

    Direction: Tool -> Device

    Function: Request to set temp MP EQ info.

    Format:

    Byte 0~1

    Byte 2

    Byte 3~N

    0x1206

    eq_num

    data[]

    Byte 2: Number of EQ. 0x00 indicates clear temp EQ parameter, 0x01~0x03 are all valid number of EQ parameters and Others are RFU.
    Byte 3~N: T_HW_EQ_DATA.

  2. EVENT_HW_EQ_SET_TEST_MODE_TMP_EQ_ADVANCED

    Direction: Device -> Tool

    Function: The device reports the CMD process result to the tool.

    Format:

    Byte 0~1

    Byte 2

    0x1206

    status

    Byte 2: Status. 0x00 means success and 0x05 means process fail.

Find My

Find My is an application technology released by Apple. The magic of this technology is that the peripheral products that support this technology (such as AirTag) can use the Apple devices around it (iPhone, iPad, AirPods, AirTag, etc.) to help it locate even if it do not have a GPS module. For more detailed information, please refer to the official Apple website at https://www.apple.com/icloud/find-my/. The document outlines how to enable the Find My feature, provides a software overview of all Find My features, and guides users on getting started with running the Find My application.

Realtek Find My

Realtek Find My SDK is based on Find My Network ADK v1.0 and is compatible with the latest version of the Find My Network Accessory Specification.

Find My APP

To use Find My features, please use Find My APP on iOS devices. The Find My APP is where Apple devices are located, location is shared with friends and family, and Find My Network-enabled accessories are located. The APP displays the location of findable items and includes additional features to protect devices, such as playing sound and using Lost Mode.

Transport

The Find My Network accessory protocol uses Bluetooth LE as the primary transport to interact with Apple devices.

Roles

It includes the following four roles: Owner device, Accessory, Find My Network and Apple server. The relationship between the four roles is shown in the following figure:

Owner device

When an accessory is paired with an Apple device through the Find My APP, the accessory is associated with the Apple ID on that device. This device and all other Apple devices signed in with the same Apple ID are treated as owner devices.

Accessory

An accessory is a device that implements the Find My Network accessory protocol and can be located using the Apple Find My Network and servers. In the following, the accessory refers to the Realtek Bluetooth LE SoC that supports the Find My feature.

Find My Network

The Find My Network provides a mechanism to locate accessories by using the vast network of Apple devices that have Find My enabled.

Apple server

The Apple server receives encrypted location data from Finder devices and temporarily stores it.

Feature Enable

Our SDK supports Find My. To enable Find My, simply follow the steps below.

Add Find My File

Copy Find My source folder to the path of src\sample\bt_audio_trx.

Copy the crypto source folder to the path of src\sample\common\findmy.

Find My Macro Configuration

Enable the F_APP_FINDMY_FEATURE_SUPPORT macro for Find My in the app_flags.h file.

#define F_APP_FINDMY_FEATURE_SUPPORT        1

Global Size Configuration

Because Find My occupies more Global RAM size, please modify the value of APP_GLOBAL_SIZE in the mem_config.h file to match the actual RAM_GLOBAL size.

#define APP_GLOBAL_SIZE             (24*1024)

Configuration of MCUConfig Tool

Since Elliptic Curve Cryptography takes more than 4 seconds, the idle task cannot be executed, thus triggering a watchdog reset. Therefore, the watchdog timeout is recommended to be configured to 8 seconds.

Software Authentication Token

Licensees must download a provisioned software authentication token and UUID into Realtek nonvolatile memory (Flash) so that the Find My Network server can validate the pairing. Per the FMNA specification, the software authentication token is only valid per pairing session. It is necessary to write the initial software authentication token into the accessory Flash. Subsequent tokens will be updated in Flash whenever new tokens are received from iOS during pairing sessions. These updated tokens will remain in the Flash memory even after the system reboots. For more detailed information, please refer to Software Token Authentication Server Specification.

Apple token address is defined in flash_map.h.

#define BKP_DATA2_ADDR               0x023FE000
#define BKP_DATA2_SIZE               0x00002000  //8K Bytes

Note

When reprogramming the Find My images after pairing, ensure that the Erase All for Download and User Data option is not selected. Choosing this option will result in the latest token being erased or overwritten, preventing successful pairing in the future.

Download the token:

  1. To generate the token.bin for downloading, open TOKEN_DECODE.exe in the sdk\tool\token_decode path. Then input the base64 encoded token string and the corresponding UUID released by Apple.

  2. Copy token.bin and mp_bkupdata2.ini files to the path of sdk\tool\Gadgets.

  3. Open a command window, input:

    prepend_header.exe /backup_data2 token.bin /mp_ini mp_bkupdata2.ini /ic_type 87x3e
    
    md5.exe token_MP.bin
    
  4. Using the MPPG Tool, download the token_MP-XX.bin file, and the written address is defined in the flash map. Please refer to the following figure.

Bluetooth Requirements

Bluetooth Low Energy is used as the wireless transport for all communication between Apple products and accessories.

Bluetooth Connection

The accessory must support at least two simultaneous connections in a peripheral role.

#define APP_FINDMY_MAX_LINKS            2 /** FIND MY LE link number */

Accessory Information Service

The Accessory information service UUID is:

#define AIS_SERVICE_BASE_UUID                         {0x8B, 0x47, 0x38, 0xDC, 0xB9, 0x11, 0xA9, 0xA1, 0xB1, 0x43, 0x51, 0x3C, 0x02, 0x01, 0x29, 0x87}

The UUID for Accessory information service characteristics is 6AA5XXXX-6352-4D57-A7B4-003A416FBB0B, where XXXX is unique for each characteristic.

#define  GATT_UUID128_PROD_DATA             0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x01, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_MANU_NAME             0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x02, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_MODEL_NAME            0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x03, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_RESERVED              0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x04, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_ACC_CATEGORY          0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x05, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_ACC_CAP               0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x06, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_FW_VERS               0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x07, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_FINDMY_VERS           0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x08, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_BATT_TYPE             0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x09, 0x00, 0xA5, 0x6A
#define  GATT_UUID128_BATT_LVL              0x0B, 0xBB, 0x6F, 0x41, 0x3A, 0x00, 0xB4, 0xA7, 0x57, 0x4D, 0x52, 0x63, 0x0A, 0x00, 0xA5, 0x6A

The characteristic data can be received in ais_attr_read_cb().

T_APP_RESULT ais_attr_read_cb(uint8_t conn_id, T_SERVER_ID service_id,
                              uint16_t attrib_index, uint16_t offset, uint16_t *p_length, uint8_t **pp_value)

Find My Network Service

The Find My Network service UUID is:

#define FINDMY_UUID_SERVICE                           0xFD44

The UUID for Find My Network service characteristics is 4F86XXXX-943B-49EF-BED4-2F730304427A, where XXXX is unique for each characteristic.

#define GATT_UUID128_PAIR_CTRL_POINT                   0x7A, 0x42, 0x04, 0x03, 0x73, 0x2F, 0xD4, 0xBE, 0xEF, 0x49, 0x3B, 0x94, 0x01, 0x00, 0x86, 0x4F
#define GATT_UUID128_CONF_CTRL_POINT                   0x7A, 0x42, 0x04, 0x03, 0x73, 0x2F, 0xD4, 0xBE, 0xEF, 0x49, 0x3B, 0x94, 0x02, 0x00, 0x86, 0x4F
#define GATT_UUID128_NON_OWNER_CTRL_POINT              0x7A, 0x42, 0x04, 0x03, 0x73, 0x2F, 0xD4, 0xBE, 0xEF, 0x49, 0x3B, 0x94, 0x03, 0x00, 0x86, 0x4F
#define GATT_UUID128_PAIRED_OWNER_INFO_CTRL_POINT      0x7A, 0x42, 0x04, 0x03, 0x73, 0x2F, 0xD4, 0xBE, 0xEF, 0x49, 0x3B, 0x94, 0x04, 0x00, 0x86, 0x4F
#define GATT_UUID128_DEBUG_CTRL_POINT                  0x7A, 0x42, 0x04, 0x03, 0x73, 0x2F, 0xD4, 0xBE, 0xEF, 0x49, 0x3B, 0x94, 0x05, 0x00, 0x86, 0x4F

Set and update characteristic data through the following interface:

T_APP_RESULT fns_attr_write_cb(uint8_t conn_id, T_SERVER_ID service_id,
                               uint16_t attrib_index, T_WRITE_TYPE write_type, uint16_t length, uint8_t *p_value,
                               P_FUN_WRITE_IND_POST_PROC *p_write_ind_post_proc)

void fns_cccd_update_cb(uint8_t conn_id, T_SERVER_ID service_id, uint16_t index,
                        uint16_t cccbits)

Bluetooth LE Advertising

The chapter will cover the various states and operations related to Bluetooth Low Energy advertising for accessories within the Find My Network.

Find My State

The accessory operations can be described using a state machine with the states listed in this chapter and transition between them based on interactions with an owner device.

Unpaired

The accessory must be in an unpaired state on first startup or before the accessory setup is completed.

Connected

The accessory must enter the connected state after the Find My Network pairing successfully completes with the owner device.

Nearby

The accessory must enter the nearby state immediately after it disconnects from an owner device. The accessory shall remain in the nearby state for nearby time.

Separated

The accessory must enter the separated state under these conditions:

  1. The accessory is paired and starts up from a reset, power cycle, or other reinitialization procedure.

  2. The accessory is in the nearby state and the nearby time has expired.

Payload for Pairing

The accessory that is not Find My Network paired shall advertise the Find My Network service as a primary service when the user puts the accessory in pairing mode. The Bluetooth LE payload for pairing is:

static uint8_t pairing_adv_data[29] =
{
    /* Flags */
    0x18,             /* length */
    GAP_ADTYPE_SERVICE_DATA, /* type="Flags" */
    LO_WORD(FINDMY_UUID_SERVICE),
    HI_WORD(FINDMY_UUID_SERVICE),
};

The fmna_adv_init_pairing() is used to initialize pairing data.

void fmna_adv_init_pairing(void)
{
    fmna_pairing_adv_service_data_init();

    fmna_adv_platform_init_pairing((uint8_t *)&m_fmna_pairing_adv_payload,
                                   sizeof(m_fmna_pairing_adv_payload));
}

Payload for Nearby State

The accessory must enter the connected state after the Find My Network pairing successfully completes with the owner device. Then, the accessory shall advertise the Find My Network Bluetooth LE payload for nearby state. Payload for nearby state defined in:

static uint8_t nearby_adv_data[31] =
{
    0x03,
    0xFF,
    0x4C, 0x00,
};

The fmna_adv_init_nearby() is used to initialize nearby data.

void fmna_adv_init_nearby(uint8_t pubkey[FMNA_PUBKEY_BLEN])
{
    // Initialize Nearby manufacturing data with the public key
    fmna_nearby_adv_manuf_data_init(pubkey);

    fmna_adv_platform_init_nearby((uint8_t *)&m_fmna_nearby_adv_packet,
                                  sizeof(m_fmna_nearby_adv_packet));
}

Payload for Separated State

When the accessory is in the separated state, the accessory shall advertise the Find My Network LE payload.

static uint8_t separate_adv_data[31] =
{
    0x03,
    0xFF,
    0x4C, 0x00,
};

The fmna_adv_platform_init_separated() is used to initialize separated data.

void fmna_adv_platform_init_separated(uint8_t *separated_adv_manuf_data,
                                      size_t separated_adv_manuf_data_size)
{
    fmna_fast_adv_interval = fmna_separated_adv_fast_intv;
    fmna_slow_adv_interval = fmna_separated_adv_slow_intv;
    memcpy(separate_adv_data + MANU_DATA_OFFSET, separated_adv_manuf_data,
           separated_adv_manuf_data_size);
    separate_adv_data[0] = 3 + separated_adv_manuf_data_size;
    ble_ext_adv_mgr_set_adv_data(app_findmy_adv_get_adv_handle(), 3 + separated_adv_manuf_data_size + 1,
                                 (uint8_t *)separate_adv_data);
    FMNA_LOG_INFO("ADV Separate len %d", 3 + separated_adv_manuf_data_size + 1);
    FMNA_LOG_HEXDUMP_INFO(separate_adv_data, 31);
}

Find My Pairing

The accessory must be paired with an owner device before it can be located. The owner device initiates the standard Bluetooth LE encryption before accessing the Find My Network services.

Find My Pairing Mode

The accessory automatically enters pairing mode after power on. The app_findmy_enter_pair_mode() is used to enter pairing mode. The accessory automatically enters pairing mode after power on. The app_findmy_enter_pair_mode() is used to enter pairing mode.

void app_findmy_enter_pair_mode(void)
{
    APP_PRINT_INFO0("app_findmy_enter_pair_mode");

    if (app_cfg_nv.bud_role != REMOTE_SESSION_ROLE_SECONDARY)
    {
        start_pair_adv();
    }
}

Generate Pairing Data

The accessory must respond to a pairing session request using the Send_pairing_data opcode. The response from the accessory must be sent within 60 seconds.

typedef struct
{
    uint8_t  c1[C1_BLEN];
    uint8_t  e2[E2_BLEN];
} __attribute__((packed)) fmna_send_pairing_data_t;

The fm_crypto_ckg_gen_c1() is used to generate C1.

int fm_crypto_ckg_gen_c1(fm_crypto_ckg_context_t ctx, byte out[32])

The populate_e2_generation_encryption_msg() is used to generate E2.

static void populate_e2_generation_encryption_msg(void)

Send Pairing Data

The accessory must send the encrypted payload generated using Apple server encryption key (Q_E).

fmna_ret_code_t fmna_crypto_generate_send_pairing_data_params(void)

Finalize Pairing

The owner device initiates the finalize pairing process to complete pairing.

fmna_ret_code_t fmna_crypto_finalize_pairing(void)

Sound

Play sound requirements apply exclusively to accessories that are equipped with a sound maker.

typedef enum
{
    FMNA_SERVICE_OPCODE_SOUND_START                                       = 0x0200,
    FMNA_SERVICE_OPCODE_SOUND_STOP                                        = 0x0201,
    FMNA_SERVICE_OPCODE_SOUND_COMPLETED                                   = 0x020D,
} FMNA_Service_Opcode_t;

Start Sound

Click the Play Sound button after the accessory is connected. Click the Play Sound button after the accessory is connected.

The Sound_Start opcode is used to play the TONE_FINDMY_SOUND tone on the sound maker of the accessory. The Sound_Start opcode is used to play the TONE_FINDMY_SOUND tone on the sound maker of the accessory.

    case FMNA_SERVICE_OPCODE_SOUND_START:
        {
...
            {
                fmna_connection_update_connection_info(conn_handle, FMNA_MULTI_STATUS_PLAYING_SOUND, true);
                response_status = RESPONSE_STATUS_SUCCESS;
                fmna_state_machine_dispatch_event(FMNA_SM_EVENT_SOUND_START);
            }
        } break;

If no operation is performed, the sound will stop after ten seconds.

void fmna_sound_platform_start(void)
{
    APP_PRINT_INFO0("fmna_sound_platform_start: Sound starting...");
    app_audio_tone_type_play(TONE_FINDMY_SOUND, false, false);//play sound
    findmy_sound_state = FMNA_SOUND_PLAY;
    app_start_timer(&timer_idx_findmy_sound_stop, "findmy_stop",
                    findmy_timer_id, APP_TIMER_FINDMY_SOUND_STOP, 0, false,
                    10 * 1000);
}

Due to the lack of Find My sound sources, modifying the tone type is necessary.

typedef enum
{
    TONE_POWER_ON,                      //0x00
    TONE_POWER_OFF,                     //0x01
...
#if F_APP_FINDMY_FEATURE_SUPPORT
    TONE_FINDMY_SOUND                   = 0x61,   //resue of TONE_APT_EQ_0
#endif
} T_APP_AUDIO_TONE_TYPE;

Stop Sound

Click the Stop Sound button when playing the sound.

The Sound_Stop opcode is used to stop an ongoing sound request.

    case FMNA_SERVICE_OPCODE_SOUND_STOP:
        {
            if (!fmna_connection_is_status_bit_enabled(CONN_HANDLE_ALL, FMNA_MULTI_STATUS_PLAYING_SOUND))
            {
                response_status = RESPONSE_STATUS_INVALID_STATE;
            }
            else
            {
                fmna_state_machine_dispatch_event(FMNA_SM_EVENT_SOUND_STOP);
            }
        } break;

Then the accessory will be in the FMNA_SM_EVENT_SOUND_COMPLETE state.

void fmna_sound_platform_stop(void)
{
    ret_code_t ret_code = app_timer_stop(m_fmna_sound_timeout_timer_id);
    APP_ERROR_CHECK(ret_code);
    fmna_state_machine_dispatch_event(FMNA_SM_EVENT_SOUND_COMPLETE);
}

Sound Completed

The accessory will confirm the completion of the stop sound procedure by sending the Sound_Completed message.

uint32_t fmna_generic_evt_sound_complete_handler(FMNA_SM_Event_t fmna_evt, void *p_context)
{
    uint16_t sound_conn_handle = fmna_connection_get_conn_handle_with_multi_status_enabled(
                                     FMNA_MULTI_STATUS_PLAYING_SOUND);
    if (sound_conn_handle == CONN_HANDLE_INVALID)
    {
        return FMNA_SM_STATUS_SUCCESS;
    }

    if (fmna_connection_is_status_bit_enabled(sound_conn_handle, FMNA_MULTI_STATUS_ENCRYPTED))
    {
        fmna_gatt_send_indication(sound_conn_handle, FMNA_SERVICE_OPCODE_SOUND_COMPLETED, NULL, 0);
    }
    else
    {
        fmna_gatt_send_indication(sound_conn_handle, FMNA_SERVICE_NON_OWNER_OPCODE_SOUND_COMPLETED, NULL, 0);
    }
    fmna_connection_update_connection_info_all(FMNA_MULTI_STATUS_PLAYING_SOUND, false);
    return FMNA_SM_STATUS_SUCCESS;
}

SDK Usage with iOS Find My APP

The chapter will guide users through the process of testing and using the Find My function on iOS devices.

Command Operation

  1. To enter the Find My Network pairing mode and start pairing advertising when the accessory is in the unpaired state, send the command findmy enter_pairing. The default timeout for this process is 10 minutes.

    2023-07-28 16:19:59,073 INFO: input command: findmy enter_pairing
    2023-07-28 16:19:59,073 INFO: Parser cmdParser: cmd opcode: 2300 param: [00] name: CMD_FINDMY_FEATURE
    2023-07-28 16:19:59,073 INFO: Packet sendPacket: <<<send packet: AA 05 03 00 00 23 00 D5
    2023-07-28 16:19:59,088 INFO: AciHostCLI continuously_read: >>>receive packet: AA 02 05 00 00 00 00 23 00 D6
    2023-07-28 16:19:59,088 INFO: Parser eventParser: syncWord: AA,seqn: 02,len: 5,opcode: 0000,params: [00 23 00], check_sum: D6
    2023-07-28 16:19:59,088 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-28 16:19:59,088 INFO: Parser eventParser: event_id: [00 23]
    2023-07-28 16:19:59,088 INFO: Parser eventParser: status: [00]
    
  2. After the accessory is paired, send the command mmi freset to reset it to the default factory settings and clear all bonding information.

    2023-07-28 16:19:33,066 INFO: input command: mmi freset
    2023-07-28 16:19:33,066 INFO: Parser cmdParser: cmd opcode: 0004 param: [00 58] name: APP_CMD_MMI
    2023-07-28 16:19:33,066 INFO: Packet sendPacket: <<<send packet: AA 02 04 00 04 00 00 58 9E
    2023-07-28 16:19:33,082 INFO: AciHostCLI continuously_read: >>>receive packet: AA 02 05 00 00 00 04 00 00 F5
    2023-07-28 16:19:33,082 INFO: Parser eventParser: syncWord: AA,seqn: 02,len: 5,opcode: 0000,params: [04 00 00], check_sum: F5
    2023-07-28 16:19:33,082 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-28 16:19:33,082 INFO: Parser eventParser: event_id: [04 00]
    2023-07-28 16:19:33,082 INFO: Parser eventParser: status: [00]
    2023-07-28 16:19:33,598 INFO: AciHostCLI continuously_read: >>>receive packet: AA 03 03 00 07 00 00 F3
    2023-07-28 16:19:33,598 INFO: Parser eventParser: syncWord: AA,seqn: 03,len: 3,opcode: 0007,params: [00], check_sum: F3
    2023-07-28 16:19:33,598 INFO: Parser eventParser: event name: EVENT_DEVICE_STATE
    2023-07-28 16:19:33,598 INFO: Parser eventParser: device_state: [00]
    2023-07-28 16:19:33,598 INFO: Packet sendPacket: <<<send packet: AA 03 05 00 00 00 07 00 00 F1
    2023-07-28 16:19:35,186 ERROR: gap in packets, between 3 and 1 packet before: [170, 3, 3, 0, 7, 0, 0, 243] packet after: [170, 1, 8, 0, 35, 0, 19, 34, 119, 86, 34, 3, 173]
    2023-07-28 16:19:35,186 INFO: AciHostCLI continuously_read: >>>receive packet: AA 01 08 00 23 00 13 22 77 56 22 03 AD
    2023-07-28 16:19:35,186 INFO: Parser eventParser: syncWord: AA,seqn: 01,len: 8,opcode: 0023,params: [13 22 77 56 22 03], check_sum: AD
    2023-07-28 16:19:35,186 INFO: Parser eventParser: event name: EVENT_BT_READY
    2023-07-28 16:19:35,186 INFO: Parser eventParser: factory_addr: [13 22 77 56 22 03]
    2023-07-28 16:19:35,186 INFO: Packet sendPacket: <<<send packet: AA 04 05 00 00 00 23 00 00 D4
    
  3. After the accessory is separated, send the findmy put_serial_number command to initiate the serial number read state.

    2023-07-28 16:24:35,541 INFO: input command: findmy put_serial_number
    2023-07-28 16:24:35,541 INFO: Parser cmdParser: cmd opcode: 2300 param: [01] name: CMD_FINDMY_FEATURE
    2023-07-28 16:24:35,541 INFO: Packet sendPacket: <<<send packet: AA 22 03 00 00 23 01 B7
    2023-07-28 16:24:35,558 INFO: AciHostCLI continuously_read: >>>receive packet: AA 1F 05 00 00 00 00 23 00 B9
    2023-07-28 16:24:35,558 INFO: Parser eventParser: syncWord: AA,seqn: 1F,len: 5,opcode: 0000,params: [00 23 00], check_sum: B9
    2023-07-28 16:24:35,568 INFO: Parser eventParser: event name: APP_EVENT_ACK
    2023-07-28 16:24:35,568 INFO: Parser eventParser: event_id: [00 23]
    2023-07-28 16:24:35,568 INFO: Parser eventParser: status: [00]
    

Run the First Test

To test the Find My function, please launch the Find My APP on an iOS device and follow the steps below:

  1. Press the Add New Item button to enroll a new Tag device.

  2. Press the Other Supported Items button to start scanning for the pairing advertising sent by the accessory.

  3. Send the findmy enter pairing command to trigger pairing advertising. When the mobile application scans the pairing advertising, the following window will appear. Press the Connect button within the application.

  4. Press the Continue button, enter the name, and set the icon to complete the pairing session.

Users should be able to pair their Find My Network-enabled accessory and test the following features using the Find My APP:

  1. View location and remove the accessory.

  2. Try crowd-sourced locations - Move around with the accessory (Ensure other iOS devices running iOS 13 or later are in the vicinity).

  3. Play sound.

GFPS Finder

The GFPS Finder, a novel protocol launched by Google, delineates an end-to-end encryption method specifically for tracking beaconing Bluetooth LE devices. It represents an expansion of the existing GFPS specification.

This extension should be implemented by vendors who are keen to activate location tracking for their devices, ensuring compatibility with Eddystone-E2EE-EID.

This document is partitioned into the following sections for a comprehensive introduction:

Enable GFPS Finder Feature

To enable GFPS, users need to make the appropriate configurations in app_gfps_cfg.c and the project.

Parameters Configuration

GFPS Finder parameters can be configured in app_gfps_cfg.c:

void app_gfps_cfg_init(void)
{
    app_gfps_cfg.gfps_model_id[0] = 0;
    app_gfps_cfg.gfps_model_id[1] = 0;
    app_gfps_cfg.gfps_model_id[2] = 0;

    app_gfps_cfg.gfps_support = 1;
    app_gfps_cfg.gfps_finder_support = 1;
    app_gfps_cfg.gfps_le_device_support = 1;
    app_gfps_cfg.gfps_enable_tx_power = 1;
    app_gfps_cfg.gfps_tx_power = -6;
    app_gfps_cfg.tone_gfps_findme = 0x9C;//power_on.wav
    app_gfps_cfg.gfps_account_key_num = 5;
    app_gfps_cfg.gfps_discov_adv_interval = 32;
    app_gfps_cfg.gfps_not_discov_adv_interval = 100;

    app_gfps_cfg.gfps_battery_info_enable = 0;
    app_gfps_cfg.gfps_le_disconn_force_enter_pairing_mode = 0;
    app_gfps_cfg.gfps_le_device_mode = GFPS_LE_DEVICE_MODE_LE_MODE_WITHOUT_CSIP;

    uint8_t  gfps_public_key[64] = {0};
    uint8_t  gfps_private_key[32] = {0};
    memcpy(app_gfps_cfg.gfps_public_key, gfps_public_key, 64);
    memcpy(app_gfps_cfg.gfps_private_key, gfps_private_key, 32);

    app_gfps_cfg.tone_gfps_dult = 0x9C;//power_on.wav

    uint8_t  device_name[64] = {0};
    uint8_t  company_name[64] = {0};
    memcpy(app_gfps_cfg.gfps_company_name, company_name, sizeof(company_name));
    memcpy(app_gfps_cfg.gfps_device_name, device_name, sizeof(device_name));

    app_gfps_cfg.gfps_device_type = GFPS_LOCATOR_TRACKER;
}
  • Transport

    • app_gfps_cfg.gfps_support must be set to 1. Otherwise, the GFPS advertising will not be advertised, and there will be no GFPS function, which is equivalent to enabling/disabling the GFPS function.

  • Module ID/Anti-spoofing public key/Anti-spoofing private key (Hex):

    • app_gfps_cfg.gfps_model_id: Model ID information.

    • app_gfps_cfg.gfps_public_key: Public key information.

    • app_gfps_cfg.gfps_private_key: Private key information.

    The registered Model ID, public key, and private key must be filled in. These parameters shall not all be zero. Users need to register these parameters by themselves. The registration address is Nearby.

  • Enable TX power data in ADV:

    • app_gfps_cfg.gfps_tx_power: The mobile phone utilizes this TX power data to estimate the distance between itself and the device. If the distance surpasses a certain limit, the GFPS notification window will not appear. This value must invariably be provided. However, if the TX power data has already been specified while registering the Model ID on the Google Nearby Device console page, this value will be disregarded by the mobile phone. Consequently, abstaining from setting the TX power during the registration of the Model ID is recommended.

  • Discoverable/Not Discoverable advertising interval (0.625 ms/per unit):

    GFPS advertising interval setting must be filled in.

    • app_gfps_cfg.gfps_discov_adv_interval: Discoverable advertising interval. The default value is 32. If this value is set too large, it may affect the efficiency of the initial pairing.

    • app_gfps_cfg.gfps_not_discov_adv_interval: Not Discoverable advertising interval. The default value is 100. If wanting to minimize the power consumption in device idle, the maximum value can be set to 400. However, it may affect the efficiency of the subsequent pairing.

  • Account Key number:

    • app_gfps_cfg.gfps_account_key_num: The maximum number of GFPS account keys the device could store in the FTL, which must be filled in.

  • Enable Finder:

    • app_gfps_cfg.gfps_finder_support: Enable or disable the GFPS Finder feature.

  • Configure DULT informations:

    • app_gfps_cfg.gfps_company_name: The company name of the device series registered in the Nearby Console.

    • app_gfps_cfg.gfps_device_name: The device name of the device series registered in the Nearby Console.

    • app_gfps_cfg.gfps_device_type: Device type, which can be referred to T_GFPS_DEVICE_TYPE:

      typedef enum
      {
          GFPS_LOCATOR_TRACKER      = 1,
          GFPS_WATCH                = 146,
          GFPS_HEADPHONES           = 149,
          GFPS_EARPHONES            = 150,
      } T_GFPS_DEVICE_TYPE;
      

Add GFPS Finder Files

Copy the GFPS related files provided in 3rd_service_gfps to sdk.

Set up GFPS Finder Environment

Enable GFPS related flags in app_flags.h:

#undef CONFIG_REALTEK_GFPS_FEATURE_SUPPORT
#define CONFIG_REALTEK_GFPS_FEATURE_SUPPORT                1
#undef CONFIG_REALTEK_GFPS_FINDER_SUPPORT
#define CONFIG_REALTEK_GFPS_FINDER_SUPPORT                (1 && CONFIG_REALTEK_GFPS_FEATURE_SUPPORT)
#undef CONFIG_REALTEK_GFPS_LE_DEVICE_SUPPORT
#define CONFIG_REALTEK_GFPS_LE_DEVICE_SUPPORT             (1 && CONFIG_REALTEK_GFPS_FEATURE_SUPPORT)

Enable build gfps_lib in Keil project:

Find gfps_lib in Keil project –> Right click –> Options for File gfps_lib –> Tick in front of Include in Target Build.

Enable build gfps in Keil project:

Find the folder gfps in Keil project –> Right click –> Options for Group gfps –> Tick in front of Include in Target Build.

GFPS Finder Features

This chapter introduces GFPS Finder support features:

GFPS Finder Provisioning

Provisioning refers to the process from not supporting finder to supporting finder. For users intent on utilizing the GFPS Finder feature, commencement of the provisioning process is necessary.


T_GFPS_FINDER_CAUSE app_gfps_finder_cb(T_GFPS_FINDER_CB_DATA *p_data)
{
    T_GFPS_FINDER_CAUSE cause = GFPS_FINDER_CAUSE_SUCCESS;

    T_GFPS_FINDER_CB_DATA data;
    memcpy(&data, p_data, sizeof(T_GFPS_FINDER_CB_DATA));

    uint8_t evt = data.evt;
    uint8_t ret_err = 0;
    APP_PRINT_INFO1("app_gfps_finder_cb: evt %d", evt);

    switch (evt)
    {
    case GFPS_FINDER_EVT_SET_EIK:
        {
            memcpy(&p_app_gfps_finder->p_finder->eik, &data.msg_data.eik, sizeof(T_GFPS_EIK));

            int8_t save_ret = ftl_save_to_storage(&p_app_gfps_finder->p_finder->eik,
                                                  GFPS_FINDER_EIK_FLASH_OFFSET,
                                                  sizeof(T_GFPS_EIK));
            if (save_ret)
            {
                ret_err = 1;
                goto err;
            }

            T_BLE_EXT_ADV_MGR_STATE adv_state = gfps_finder_adv_get_adv_state();
            if (adv_state == BLE_EXT_ADV_MGR_ADV_DISABLED)
            {
                uint8_t hash;
                uint32_t counter = (p_app_gfps_finder->p_finder->clock_value / 1024) * 1024;
                app_gfps_finder_generate_adv_ei_and_hash(p_app_gfps_finder->p_finder->adv_ei,
                                                         p_app_gfps_finder->p_finder->eik.key, counter, &hash);
                gfps_finder_adv_update_adv_ei_hash(p_app_gfps_finder->p_finder->adv_ei, hash);
                gfps_finder_adv_start(0);
                app_gfps_finder_start_update_adv_ei_timer();
            }

            T_GFPS_FINDER test;
            memset(&test, 0, sizeof(T_GFPS_FINDER));
            int8_t load_ret = ftl_load_from_storage(&test.eik, GFPS_FINDER_EIK_FLASH_OFFSET,
                                                    sizeof(T_GFPS_EIK));
            if (load_ret)
            {
                APP_PRINT_ERROR1("app_gfps_finder_cb: load eik from ftl fail %d", load_ret);
            }
            APP_PRINT_INFO2("app_gfps_finder_cb: load eik %b, valid %d",
                            TRACE_BINARY(32, test.eik.key), test.eik.valid);

        }
        break;

    ......

    default:
        {

        }
        break;
    }
    return cause;

err:
    cause = GFPS_FINDER_CAUSE_INVALID_VALUE;
    APP_PRINT_ERROR1("app_gfps_finder_cb: err %d", ret_err);
    return cause;
}

GFPS Finder Ring

GFPS Finder supports the function of making the device ring. If users want to use this function, please refer to the following flow chart:


T_GFPS_FINDER_CAUSE app_gfps_finder_cb(T_GFPS_FINDER_CB_DATA *p_data)
{
    T_GFPS_FINDER_CAUSE cause = GFPS_FINDER_CAUSE_SUCCESS;

    T_GFPS_FINDER_CB_DATA data;
    memcpy(&data, p_data, sizeof(T_GFPS_FINDER_CB_DATA));

    uint8_t evt = data.evt;
    uint8_t ret_err = 0;
    APP_PRINT_INFO1("app_gfps_finder_cb: evt %d", evt);

    switch (evt)
    {
    ......
    case GFPS_FINDER_EVT_RING:
        {
            p_app_gfps_finder->gfps_finder_conn_id = data.msg_data.ring.conn_id;
            p_app_gfps_finder->gfps_finder_service_id = data.msg_data.ring.service_id;

            uint8_t ring_type = data.msg_data.ring.ring_type;
            uint16_t ring_time = data.msg_data.ring.ring_time;
            uint8_t ring_volume_level = data.msg_data.ring.ring_volume_level;

            /*the first byte may hold a special value of 0xFF to ring all components that can ring.*/
            if (ring_type == 0xFF)
            {
                ring_type = GFPS_ALL_RING;
            }

            app_gfps_msg_set_ring_timeout(ring_time);
            app_gfps_msg_handle_ring_event(ring_type);

            if ((ring_volume_level != GFPS_FINDER_RING_VOLUME_DEFAULT) &&
                (p_app_gfps_finder->p_finder->ring_volume_modify == GFPS_FINDER_RING_VOLUME_ENABLE))
            {
                p_app_gfps_finder->gfps_finder_ring_volume_level = ring_volume_level;
            }

            /*A byte indicating the new ringing state*/
            uint8_t ring_state;
            if (ring_type == GFPS_ALL_STOP)
            {
                ring_state = GFPS_FINDER_RING_GATT_STOP;
            }
            else
            {
                ring_state = GFPS_FINDER_RING_STARTED;
            }

            gfps_finder_rsp_ring_request(p_app_gfps_finder->gfps_finder_conn_id,
                                         p_app_gfps_finder->gfps_finder_service_id,
                                         ring_state, ring_type, ring_time);
        }
        break;

    ......
    default:
        {

        }
        break;
    }
    return cause;

err:
    cause = GFPS_FINDER_CAUSE_INVALID_VALUE;
    APP_PRINT_ERROR1("app_gfps_finder_cb: err %d", ret_err);
    return cause;
}

GFPS Finder Set UTP Mode

Unwanted Tracking Protection mode is intended to allow any client to identify abusive devices with no server communication. By default, the provider should rotate all identifiers as described in the ID Rotation chapter below. The server can decide to relay an Unwanted Tracking Protection mode activation request through a sighter of the provider. By doing so, it causes the provider to temporarily use a fixed MAC address, allowing clients to detect it and warn the user of possible unwanted tracking.

To activate or deactivate the unwanted tracking protection mode of the beacon, the seeker should perform a write operation to the characteristic.


T_GFPS_FINDER_CAUSE app_gfps_finder_cb(T_GFPS_FINDER_CB_DATA *p_data)
{
    T_GFPS_FINDER_CAUSE cause = GFPS_FINDER_CAUSE_SUCCESS;

    T_GFPS_FINDER_CB_DATA data;
    memcpy(&data, p_data, sizeof(T_GFPS_FINDER_CB_DATA));

    uint8_t evt = data.evt;
    uint8_t ret_err = 0;
    APP_PRINT_INFO1("app_gfps_finder_cb: evt %d", evt);

    switch (evt)
    {
    ......
    case GFPS_FINDER_EVT_UTP_ACTIVE:
        {
            gfps_finder_adv_update_frame_type(0x41);
            app_gfps_finder_upt_enable_start_update_rpa_timer();
        }
        break;

    case GFPS_FINDER_EVT_UTP_DEACTIVE:
        {
            gfps_finder_adv_update_frame_type(0x40);
            app_gfps_finder_upt_enable_stop_rpa_timer();
        }
        break;
    ......
    default:
        {

        }
        break;
    }
    return cause;

err:
    cause = GFPS_FINDER_CAUSE_INVALID_VALUE;
    APP_PRINT_ERROR1("app_gfps_finder_cb: err %d", ret_err);
    return cause;
}

GFPS Finder Unprovision

GFPS Finder Unprovision refers to the process of transitioning from supporting the Finder to not supporting it.

T_GFPS_FINDER_CAUSE app_gfps_finder_cb(T_GFPS_FINDER_CB_DATA *p_data)
{
    T_GFPS_FINDER_CAUSE cause = GFPS_FINDER_CAUSE_SUCCESS;

    T_GFPS_FINDER_CB_DATA data;
    memcpy(&data, p_data, sizeof(T_GFPS_FINDER_CB_DATA));

    uint8_t evt = data.evt;
    uint8_t ret_err = 0;
    APP_PRINT_INFO1("app_gfps_finder_cb: evt %d", evt);

    switch (evt)
    {
    ......
    case GFPS_FINDER_EVT_CLEAR_EIK:
        {
            memset(&p_app_gfps_finder->p_finder->eik, 0, sizeof(T_GFPS_EIK));
            uint8_t ret = ftl_save_to_storage(&p_app_gfps_finder->p_finder->eik, GFPS_FINDER_EIK_FLASH_OFFSET,
                                              sizeof(T_GFPS_EIK));

            if (ret)
            {
                ret_err = 2;
                goto err;
            }

            T_BLE_EXT_ADV_MGR_STATE adv_state = gfps_finder_adv_get_adv_state();
            if (adv_state == BLE_EXT_ADV_MGR_ADV_ENABLED)
            {
                gfps_finder_adv_stop(APP_STOP_ADV_CAUSE_GFPS_FINDER);
                app_gfps_finder_stop_update_adv_ei_timer();
                app_gfps_finder_stop_update_random_window_timer();
            }
        }
        break;

    ......
    default:
        {

        }
        break;
    }
    return cause;

err:
    cause = GFPS_FINDER_CAUSE_INVALID_VALUE;
    APP_PRINT_ERROR1("app_gfps_finder_cb: err %d", ret_err);
    return cause;
}

Test With Find My Device APP

  1. Factory reset and power on the device.

    • Factory reset: Input mmi freset in ACI Host CLI Tool to do factory reset.

    • Power on: Input mmi pwron in ACI Host CLI Tool to power on.

  2. Click connect button on the popup window to connect.

  3. Agree to user responsibility and enter screen lock.

  4. Add the device to the Find My Device APP.

One Wire UART

The purpose of this document is to give an overview of one wire UART function. This document will be divided into the following parts to introduce:

  • How to enable one wire UART will be introduced in chapter Configuration.

  • Source code of one wire UART will be introduced in chapter Code Overview.

Configuration

This chapter introduces how to enable one wire UART:

Peripheral Configuration

Firstly, the parameter app_cfg_const.one_wire_uart_support should be set to enable one wire UART.

app_cfg_const.one_wire_uart_support = 1;

Secondly, PINMUX should be configured as UART. If users want to enable two or more UARTs, the corresponding number of pins should be configured. Currently, only UART0 and UART2 are available. The macro ONE_WIRE_UART0_PINMUX is configured as UART0 and ONE_WIRE_UART2_PINMUX is configured as UART2.

#define ONE_WIRE_UART0_PINMUX        P3_0
#define ONE_WIRE_UART2_PINMUX        P3_1

Thirdly, baud rate should be configured the same as the other side. Currently, baud rate is configured as 115200 through parameter app_transfer_cfg.data_uart_baud_rate.

app_transfer_cfg.data_uart_baud_rate = BAUD_RATE_115200;

Macro Configuration

Set macro F_APP_ENABLE_TWO_ONE_WIRE_UART in app_flags.h:

#define F_APP_ENABLE_TWO_ONE_WIRE_UART            1

Code Overview

This chapter introduces one wire UART Source code:

One Wire UART Init

Initialization of one wire UART includes initialization of app_uart and setting of UART. Initializing flow is as below:

The function app_console_uart_init() is used for the APP to set parameters to UART.

static void app_console_uart_init(void)
{
    ...

    T_CONSOLE_UART_CONFIG console_uart_config;

    ...

    console_uart_config.one_wire_uart_support = app_cfg_const.one_wire_uart_support;
    console_uart_config.data_uart_baud_rate = app_transfer_cfg.data_uart_baud_rate;
    console_uart_config.callback = app_console_handle_wake_up;
    console_uart_config.uart_rx_dma_enable = false;
    console_uart_config.uart_tx_dma_enable = false;

	...

    console_uart_config_init(&console_uart_config);
}

The function app_uart_buffer_alloc() is used to initialize the APP database and configure one wire UART by calling function UART_OneWireConfig and register callback to UART to receive data.

void app_uart_init(void)
{
    app_uart_buffer_alloc(0);
    app_uart_buffer_alloc(2);
    console_uart_init(app_uart_callback);
}

When the app_task is created, the function app_one_wire_uart_open() is called to configure PINMUX mode and pad and initialize the UART driver by calling function app_console_uart_driver_init().

void app_one_wire_uart_open(uint8_t index)
{
    switch (index)
    {
    case T_IDX_UART0:
        {
            ...

            Pinmux_Deinit(ONE_WIRE_UART0_PINMUX);
            Pinmux_Config(ONE_WIRE_UART0_PINMUX, UART0_TX);
            Pad_Config(ONE_WIRE_UART0_PINMUX, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE,
                       PAD_OUT_LOW);
            Pad_PullConfigValue(ONE_WIRE_UART0_PINMUX, PAD_STRONG_PULL);

            app_console_uart_driver_init(0);

            UART_ClearRxFifo(UART0);
            UART_INTConfig(UART0, UART_INT_RD_AVA | UART_INT_IDLE,
                           ENABLE);//for normal pin, line status intr unnecessary

            ...
        }
        break;

    case T_IDX_UART2:
        {
            ...
        }
        break;

    default:
        break;
    }
}

One Wire UART Data Send

UART will automatically transition to TX mode before sending any data. Following data transmission, UART will enter RX mode.

If users want to send data by 2 one wire UARTs at the same time, these three functions shall be called in different conditions:

  1. If the command format is the same as current in the code, users can call app_report_uart_event() directly. The parameter index represents UART index:

    static void app_report_uart_event(uint16_t event_id, uint8_t *data, uint16_t len, uint8_t index)
    {
        if (app_cfg_const.enable_data_uart || app_cfg_const.one_wire_uart_support)
        {
            uint16_t total_len;
            uint8_t check_sum;
    
            typedef struct
            {
                uint8_t sync_byte;
                uint8_t seq;
                uint16_t pkt_len;
                uint16_t event_id;
                uint8_t data[0];
            }   __attribute__((packed)) T_SEND_BUF;
    
            ...
            send_buf->sync_byte = CMD_SYNC_BYTE;
            send_buf->seq = uart_tx_seqn[index];
            send_buf->pkt_len = len + sizeof(send_buf->event_id);
            send_buf->event_id = event_id;
            if (len)
            {
                 memcpy(send_buf->data, data, len);
            }
            check_sum = app_util_calc_checksum((uint8_t *)&send_buf->seq, total_len - 2);
            send_buf->data[len] = check_sum;
            if (app_push_data_transfer_queue(CMD_PATH_UART, (uint8_t *)send_buf, total_len, index) == false)
            {
                free(send_buf);
            }
        }
    }
    
  2. If the command format is different from current in the code, users can fix the command format in app_report_uart_event() or call app_push_data_transfer_queue(). The parameter index represents UART index. The function includes flow control in the APP.

  3. If users don’t need any flow control in the APP, the function console_uart_write() can be called. The parameter index represents UART index.

One Wire UART Data Receive

Data received from UART is sent to the callback app_uart_callback() and received data will be sent to the app_task:

RAM_TEXT_SECTION void app_uart_callback(T_CONSOLE_UART_EVENT evt, void *buf, uint16_t len, uint8_t index)
{
    APP_PRINT_INFO4("app_uart_callback len %x, index %x, evt %x, data %b", len, index, evt, TRACE_BINARY(len, buf));

    uint32_t s;

    switch (evt)
    {
    case CONSOLE_UART_EVENT_DATA_IND:
        {
            T_IO_MSG  msg;

            if (index == cmd_block[index].id)
            {
                ...
                msg.type    = IO_MSG_TYPE_UART;
                msg.subtype = 0;
                msg.u.param = index;

                app_io_msg_send(&msg);
            }
        }
        break;

    default:
        break;
    }
}

Data can be parsed in the function app_uart_parser() and specific commands shall be handled in app_handle_cmd_set() after parsing.

USB Mass Storage

This application note describes the functional implementation method and the employed USB Mass Storage descriptors. This USB Mass Storage addresses Bulk-Only transport, or in other words, transport of command, data, and status occurring solely via bulk endpoints (not via interrupt or control endpoints). This specification only uses the default pipe to clear a STALL condition on the bulk endpoints and to issue class-specific requests as defined below. This specification does not require the use of an interrupt endpoint.

Requirements

The device descriptors and related descriptors for USB Mass Storage are mostly introduced in this paragraph.

USB Device Configure Descriptor

Device descriptor describes general information about USB Device.

USB Mass Storage Configure Descriptor

This application exposes the following features:

  • USB Mass Storage interface descriptor.

    • Need to configure the mass storage class specification.

  • Endpoint Descriptor.

    • Configure endpoint packet size.

Source Code Overview

The following sections describe important parts of this application.

Initialization

The USB main function is invoked when the application is in the USB init flow, and it performs the following initialization functions.

void app_usb_init(void)
{
    memset(&app_usb_db, 0, sizeof(T_APP_USB_DB));

    usb_dm_cb_register(app_usb_dm_cb);
    adp_register_state_change_cb(ADP_DETECT_5V, (P_ADP_PLUG_CBACK)app_usb_adp_state_change_cb, NULL);

    usb_dev_init();

    T_USB_CORE_CONFIG config = {.speed = USB_SPEED_FULL, .class_set = {.hid_enable = 0, .uac_enable = 0}};
    config.speed = USB_SPEED_HIGH;

    usb_dm_core_init(config);

#if F_APP_USB_MSC_SUPPORT
    sd_config_init((T_SD_CONFIG *)&sd_card_cfg);
    sd_board_init();
    sd_card_init();

    extern int usb_ms_scsi_init(void);
    usb_ms_scsi_init();
    extern int usb_ms_disk_init(void);
    usb_ms_disk_init();
    usb_msc_init();
#endif
}

USB Device Configure

The USB device application can configure the descriptor.

USB Mass Storage Configure Descriptor

In analogy to the device descriptor, a mass storage configuration descriptor is applicable only in the case of MassStorage-only devices.

static T_USB_INTERFACE_DESC usb_msc_if_desc =
{
    .bLength = sizeof(T_USB_INTERFACE_DESC),
    .bDescriptorType = USB_DESC_TYPE_INTERFACE,
    .bInterfaceNumber = 0,
    .bAlternateSetting = 0,
    .bNumEndpoints = 2,
    .bInterfaceClass = USB_CLASS_MSC,
    .bInterfaceSubClass = 0x06, //SCSI
    .bInterfaceProtocol = 0x50, //BBB
    .iInterface = 4
};
static const T_USB_ENDPOINT_DESC usb_ms_bi_ep_desc_hs =
{
    .bLength = sizeof(T_USB_ENDPOINT_DESC),
    .bDescriptorType = USB_DESC_TYPE_ENDPOINT,
    .bEndpointAddress = MSC_BULK_IN_EP,
    .bmAttributes = USB_EP_TYPE_BULK,
    .wMaxPacketSize = 512,
    .bInterval = 4,
};
static const T_USB_ENDPOINT_DESC usb_ms_bo_ep_desc_hs =
{
    .bLength = sizeof(T_USB_ENDPOINT_DESC),
    .bDescriptorType = USB_DESC_TYPE_ENDPOINT,
    .bEndpointAddress = MSC_BULK_OUT_EP,
    .bmAttributes = USB_EP_TYPE_BULK,
    .wMaxPacketSize = 512,
    .bInterval = 4,
};

static const T_USB_ENDPOINT_DESC usb_ms_bi_ep_desc_fs =
{
    .bLength = sizeof(T_USB_ENDPOINT_DESC),
    .bDescriptorType = USB_DESC_TYPE_ENDPOINT,
    .bEndpointAddress = 0x82,
    .bmAttributes = USB_EP_TYPE_BULK,
    .wMaxPacketSize = 64,
    .bInterval = 1,
};

static const T_USB_ENDPOINT_DESC usb_ms_bo_ep_desc_fs =
{
    .bLength = sizeof(T_USB_ENDPOINT_DESC),
    .bDescriptorType = USB_DESC_TYPE_ENDPOINT,
    .bEndpointAddress = 0x02,
    .bmAttributes = USB_EP_TYPE_BULK,
    .wMaxPacketSize = 64,
    .bInterval = 1,
};

void usb_msc_init(void)
{
    usb_ms_driver_if_desc_register((T_USB_DESC_HDR **)usb_ms_if_descs_fs,
                                   (T_USB_DESC_HDR **)usb_ms_if_descs_hs);

    usb_ms_driver_init();
}

USB Ctrl

USB will boot up and successfully list all of its features when this API is run.

void app_usb_start(void)
{
    if (app_cfg_const.bud_role != REMOTE_SESSION_ROLE_SECONDARY)
    {
        app_usb_set_hp_mode();
        app_auto_power_off_disable(AUTO_POWER_OFF_MASK_USB_AUDIO_MODE);
        app_dlps_disable(APP_DLPS_ENTER_CHECK_USB);
#if (TARGET_RTL8773DO == 1)
        pmu_vcore3_pon_domain_enable(PMU_USB);
        usb_dm_start(false);
#else
        usb_dm_start(false);
#endif
        app_ipc_publish(USB_IPC_TOPIC, USB_IPC_EVT_PLUG, NULL);
    }
}

APP Configurable Functions

APP configurable functions are defined in app_flags.h. F_APP_USB_MSC_SUPPORT can enable the USB Mass Storage function in app_flags.h.

Test Procedure

Make sure that the USB Mass Storage functionality is implemented on the EVB and the system is properly configured. This may require software development and configuration on the EVB. Connect the EVB to the host using a USB cable. Ensure that the USB cable can transfer data correctly and that the EVB is recognized by the host.

Set up Test Environment

To set up a USB Mass Storage testing environment, the following components are needed: USB Mass Storage EVB, and the SD card connects with Evolution Board via SDIO. This is a hardware device that supports USB Mass Storage and is typically used to simulate a storage device.

USB Cable: This is used to connect the USB Mass Storage EVB to a USB port on a computer.

Computer: This is used to run the test code and communicate with the USB Mass Storage EVB.

Test USB Mass Storage

Open Device Manager (Windows) on the host to check if the connected USB device is enumerated correctly. Files can be copied, erased, and other operations performed in the mass storage.

LE HID Host

The purpose of this document is to provide an overview of the Bluetooth LE HID host application based on HOGP. HOGP defines the procedures and features that are utilized by Bluetooth LE HID devices through GATT, as well as Bluetooth HID hosts through GATT. This profile shall operate over an LE transport only.

HID Roles

HOGP defines three roles: HID Device, Boot Host, and Report Host.

  • The HID Device shall be a GATT server.

  • The Boot Host shall be a GATT client.

  • The Report Host shall be a GATT client.

Use of the term HID Host refers to both host roles: Boot Host, and Report Host. A Report Host is required to support a HID Parser and be able to handle arbitrary formats for data transfers (known as reports) whereas a Boot Host is not required to support a HID Parser as all data transfers (reports) for Boot Protocol mode are of predefined length and format.

Roles/Service Relationships

The relationship between services and the profile roles is shown below:

../../_images/Boot_Host_HID_Device_Relationship.png
../../_images/Report_Host_HID_Device_Relationships.png

Note

Profile roles are represented by yellow boxes and services are represented by orange boxes.

The Report Host supports the Scan Client role of the Scan Parameters Profile. The Boot Host shall not support the Scan Client role of the Scan Parameters Profile.

LE HID Host Configuration

This chapter provides an introduction on how to enable the LE HID host feature.

Set macro BLE_HID_CLIENT_SUPPORT and F_APP_BLE_HID_HOST_SUPPORT in app_flags.h.


  #define BLE_HID_CLIENT_SUPPORT            1
  #define F_APP_BLE_HID_HOST_SUPPORT        1

API Introduction

This chapter defines the APIs for the LE HID host.

HID Interaction

Below is a flow chart depicting the interaction between an HID host and an HID device based on Low Energy connections.

../../_images/hid_host_hid_device_Interaction.png

HID Client Init

To initialize the HID client and configure the maximum number of HID links, the following interface can be used:


  bool hids_add_client(P_FUN_HIDS_CLIENT_APP_CB app_cb, uint8_t link_num)
  {
      T_ATTR_UUID srv_uuid = {0};
      srv_uuid.is_uuid16 = true;
      srv_uuid.p.uuid16 = GATT_UUID_HIDS;

      if (gatt_client_spec_register(&srv_uuid, hids_client_cbs) == GAP_CAUSE_SUCCESS)
      {
          /* register callback for profile to inform application that some events happened. */
          hids_client_cb = app_cb;
          hids_client_link_num = link_num;
          hids_table = calloc(1, link_num * sizeof(T_HIDS_LINK));
          return true;
      }

      return false;
  }

HID Read Report Map

After the HID discovery is completed, the report map can be read using the characteristic UUID.


  T_APP_RESULT app_ble_hid_service_cback(uint16_t conn_handle, uint8_t type,
                                         void *p_data)
  {
      T_APP_RESULT app_result = APP_RESULT_SUCCESS;

      if (type == GATT_MSG_HIDS_CLIENT_DIS_DONE)
      {
          T_HIDS_CLIENT_DIS_DONE *p_dis_done = (T_HIDS_CLIENT_DIS_DONE *)p_data;
          APP_PRINT_TRACE1("app_ble_hid_service_cback: discover state %d",
                           p_dis_done->is_found);
          if (p_dis_done->is_found)
          {
              hid_conn_handle = conn_handle;

              for (uint8_t i = 0; i < p_dis_done->srv_instance_num; i++)
              {
                  hids_client_read_report_map_value(conn_handle, i);
              }
          }
      }
      else if (type == GATT_MSG_HIDS_CLIENT_READ_RESULT)
      {
          T_HIDS_CLIENT_READ_RESULT *p_read_result = (T_HIDS_CLIENT_READ_RESULT *)p_data;
          APP_PRINT_TRACE1("app_ble_hid_service_cback: char_uuid 0x%x",
                           p_read_result->char_uuid);

          if (p_read_result->char_uuid == GATT_UUID_CHAR_REPORT_MAP)
          {
            app_ble_hid_host_read_report_map_handle(conn_handle,
                                                    p_read_result->data.hids_report_map.p_hids_report_map,
                                                    p_read_result->data.hids_report_map.hids_report_map_len);
          }
      }
      return app_result;
  }

Send the report map of the HID device to the ACI host via UART path.


  void app_ble_hid_host_read_report_map_handle(uint16_t conn_handle, uint8_t *report_buf,
                                               uint16_t report_len)
  {
      T_APP_LE_LINK *p_link;
      p_link = app_link_find_le_link_by_conn_handle(conn_handle);

      if (p_link != NULL)
      {
          APP_PRINT_INFO3("app_ble_hid_host_read_report_map_handle: le_addr %s, conn_handle 0x%x, len %d",
                          TRACE_BDADDR(p_link->bd_addr), conn_handle, report_len);

          if ((report_buf == NULL) || (report_len == 0))
          {
              return;
          }

          struct
          {
              uint16_t    conn_handle;
              uint16_t    pkt_len;
              uint8_t     payload[];
          } __attribute__((packed)) *rpt = NULL;

          rpt = calloc(1, report_len + sizeof(*rpt));
          rpt->conn_handle = conn_handle;
          rpt->pkt_len = report_len;

          memcpy(&rpt->payload, report_buf, report_len);
          app_report_event(CMD_PATH_UART, EVENT_BLE_HID_READ_REPORT_MAP, 0, (uint8_t *)rpt,
                           report_len + sizeof(*rpt));
          free(rpt);

      }
  }

HID Read Report

After the HID discovery is complete, users can read the HID report by using the characteristic UUID.


  T_APP_RESULT app_ble_hid_service_cback(uint16_t conn_handle, uint8_t type,
                                         void *p_data)
  {
      if (type == GATT_MSG_HIDS_CLIENT_READ_RESULT)
      {
          T_HIDS_CLIENT_READ_RESULT *p_read_result = (T_HIDS_CLIENT_READ_RESULT *)p_data;
          APP_PRINT_TRACE1("app_ble_hid_service_cback: char_uuid 0x%x",
                           p_read_result->char_uuid);

          if (p_read_result->char_uuid == GATT_UUID_CHAR_REPORT)
          {
            app_ble_hid_host_read_feature_report_handle(conn_handle,
                                                        p_read_result->data.hids_report.p_hids_report_value,
                                                        p_read_result->data.hids_report.hids_report_value_len,
                                                        p_read_result->data.hids_report.report_id);
          }
      }
  }

To send the HID device report to the ACI Host via UART path.


  void app_ble_hid_host_read_feature_report_handle(uint16_t conn_handle, uint8_t *p_value,
                                                   uint16_t length, uint8_t report_id)
  {
      T_APP_LE_LINK *p_link;
      p_link = app_link_find_le_link_by_conn_handle(conn_handle);

      if (p_link != NULL)
      {
          APP_PRINT_INFO3("app_ble_hid_host_read_feature_report_handle: le_addr %s, conn_handle 0x%x, len %d",
                          TRACE_BDADDR(p_link->bd_addr), conn_handle, length);
          struct
          {
              uint16_t    conn_handle;
              uint8_t     report_id;
              uint16_t    pkt_len;
              uint8_t     payload[];
          } __attribute__((packed)) *rpt = NULL;

          rpt = calloc(1, length + sizeof(*rpt));
          rpt->conn_handle = conn_handle;
          rpt->report_id = report_id;
          rpt->pkt_len = length;

          memcpy(&rpt->payload, p_value, length);
          app_report_event(CMD_PATH_UART, EVENT_BLE_HID_READ_REPORT, 0, (uint8_t *)rpt,
                           length + sizeof(*rpt));
          free(rpt);
      }
  }

HID Input Report

After the HID device sends the report data, the HID host will receive the input reports.

  T_APP_RESULT app_ble_hid_service_cback(uint16_t conn_handle, uint8_t type,
                                         void *p_data)
  {
      if (type == GATT_MSG_HIDS_CLIENT_NOTIFY_IND)
      {
          T_HIDS_CLIENT_NOTIFY_DATA *p_notify_data = (T_HIDS_CLIENT_NOTIFY_DATA *)p_data;
          APP_PRINT_TRACE3("app_ble_hid_service_cback: report id 0x%x, data length %d, data %b",
                           p_notify_data->report_id, p_notify_data->data_len,
                           TRACE_BINARY(p_notify_data->data_len, p_notify_data->p_data));

          app_ble_hid_host_inreport_handle(conn_handle, p_notify_data->p_data,
                                         p_notify_data->data_len, p_notify_data->report_id);
      }
  }

To send the HID input report data to the ACI Host via UART path.


  void app_ble_hid_host_inreport_handle(uint16_t conn_handle, uint8_t *p_value,
                                        uint16_t length, uint8_t report_id)
  {
      T_APP_LE_LINK *p_link;
      p_link = app_link_find_le_link_by_conn_handle(conn_handle);

      if (p_link != NULL)
      {
          APP_PRINT_INFO3("app_ble_hid_host_inreport_handle: le_addr %s, conn_handle 0x%x, len %d",
                          TRACE_BDADDR(p_link->bd_addr), conn_handle, length);
          struct
          {
              uint16_t    conn_handle;
              uint8_t     report_id;
              uint16_t    pkt_len;
              uint8_t     payload[];
          } __attribute__((packed)) *rpt = NULL;

          rpt = calloc(1, length + sizeof(*rpt));
          rpt->conn_handle = conn_handle;
          rpt->report_id = report_id;
          rpt->pkt_len = length;

          memcpy(&rpt->payload, p_value, length);
          app_report_event(CMD_PATH_UART, EVENT_BLE_HID_IN_REPORT, 0, (uint8_t *)rpt,
                           length + sizeof(*rpt));
          free(rpt);
      }
  }

Application Controller Interface Commands and Events

This chapter introduces the functional specifications for the Application Controller interface (ACI), which provides a uniform command method for the Host to access Device capabilities and control connections with other Devices. The commands (Host -> Device) and events (Device -> Host) are sent between the Host and the Device.

Retransmission

To enhance the reliability of packet transmission and reception, a retransmission mechanism has been implemented on the Device side. When the Device sends an event (excluding ACI_EVENT_ACK) to the Host, the Host shall respond with an ACI_CMD_ACK; failure to do so will trigger retransmission, with the number of retries determined by the DT_RESEND_NUM parameter. This feature is enabled by default in sdk\src\mcu\module\data_transfer\data_transfer.c.

#define DT_RESEND_NUM           20

Similarly, when the Host sends a command (excluding ACI_CMD_ACK) to the Device, the Device responds with an ACI_EVENT_ACK. If the ACI_EVENT_ACK is not received, the decision to trigger retransmission and the number of retransmissions are determined by the Host.

ACI Data Formats

The ACI Command packet is used to send commands to the Device from the Host. The ACI Event packet is used to send events to the Host from the Device. The format of the ACI Command and Event packet is shown below, and the definition of each field is explained below.

SyncWord:

Size: 1 octet

Value

Parameter Description

0xAA

Sync word.

SeqN:

Size: 1 octet

Value

Parameter Description

0xXX

Sequence number (range: 1~255).

Length:

Size: 2 octets

Value

Parameter Description

0xXX

The total length of the Opcode field and the Parameter field in octets (range: 1~255).

Opcode:

Size: 2 octets

Value

Parameter Description

0xXX

Opcode of ACI Command and Events.

Parameter 0 - N:

Size: Parameter_Total_Length

Value

Parameter Description

0xXX

Each command or event has a specific number of parameters associated with it. These parameters and the size of each of the parameters are defined for each command or event. Each parameter is an integer number of octets in size.

CheckSum:

Size: 1

Value

Parameter Description

0xXX

The CheckSum is obtained by calculating through app_util_calc_checksum, and the data between SeqN and Parameter N shall be involved in the operation.

Note

In this packet model, it is recommended that the length of the Parameter does not exceed 1024 bytes.

uint8_t app_util_calc_checksum(uint8_t *dataPtr, uint16_t len)
{
	uint8_t check_sum;

	check_sum = 0;
	while (len)
	{
		check_sum += *dataPtr;
		dataPtr++;
		len--;
	}
	return (0xff - check_sum + 1); //((~check_sum)+1);
}

Example: ACI_CMD_MMI

ACI Command data packet:

AA 04 04 00 04 00 00 54 A0

ACI Commands and Events

ACI Commands

Summary of ACI Commands

Opcode

Command

Available

0x0000

ACI_CMD_ACK

Y

0x0002

ACI_CMD_BT_CREATE_CONNECTION

Y

0x0003

ACI_CMD_BT_DISCONNECT

Y

0x0004

ACI_CMD_MMI

Y

0x0005

ACI_CMD_LEGACY_DATA_TRANSFER

Y

0x0006

ACI_CMD_ASSIGN_BUFFER_SIZE

Y

0x0009

ACI_CMD_BT_GET_REMOTE_NAME

Y

0x0012

ACI_CMD_SET_CFG

Y

0x0017

ACI_CMD_GET_CFG_SETTING

Y

0x0018

ACI_CMD_GET_STATUS

Y

0x001B

ACI_CMD_BT_HFP_DIAL_WITH_NUMBER

Y

0x001C

ACI_CMD_GET_BD_ADDR

Y

0x001E

ACI_CMD_STRING_MODE

Y

0x001F

ACI_CMD_SET_VP_VOLUME

Y

0x0020

ACI_CMD_SET_AND_READ_DLPS

Y

0x0022

ACI_CMD_INQUIRY

Y

0x0030

ACI_CMD_XM_SET_MODE

Y

0x0040

ACI_CMD_BT_HFP_SCO_MAG

Y

0x0102

ACI_CMD_LE_DATA_TRANSFER

Y

0x0103

ACI_CMD_LE_START_SCAN

Y

0x0104

ACI_CMD_LE_STOP_SCAN

Y

0x0109

ACI_CMD_LE_START_PAIR

Y

0x010E

ACI_CMD_LE_CREATE_CONN

Y

0x0111

ACI_CMD_ANCS_GET_NOTIFICATION_ATTR

Y

0x0112

ACI_CMD_ANCS_GET_APP_ATTR

Y

0x0113

ACI_CMD_ANCS_PERFORM_NOTIFICATION_ACTION

Y

0x0115

ACI_CMD_AMS_WRITE_REMOTE_CMD

Y

0x0116

ACI_CMD_AMS_WRITE_ENTITY_UPD_CMD

Y

0x0161

ACI_CMD_LE_MODIFY_WHITELIST

Y

0x0162

ACI_CMD_LE_MODIFY_WHITELIST_BY_IDX

Y

0x0163

ACI_CMD_LE_MODIFY_RESOLVELIST_BY_IDX

Y

0x0164

ACI_CMD_LE_SET_RESOLUTION

Y

0x020A

ACI_CMD_SET_VOLUME

Y

0x0308

ACI_CMD_GET_FW_VERSION

Y

0x0309

ACI_CMD_BT_BOND_INFO_CLEAR

Y

0x030F

ACI_CMD_GET_PACKAGE_ID

Y

0x0310

ACI_CMD_SWITCH_TO_HCI_DOWNLOAD_MODE

Y

0x0400

ACI_CMD_SEND_DTMF

Y

0x0403

ACI_CMD_SEND_VGM

Y

0x0404

ACI_CMD_SEND_VGS

Y

0x0480

ACI_CMD_HFP_AG_CONNECT_SCO

Y

0x0481

ACI_CMD_HFP_AG_DISCONNECT_SCO

Y

0x0482

ACI_CMD_HFP_AG_CALL_INCOMING

Y

0x0483

ACI_CMD_HFP_AG_CALL_ANSWER

Y

0x0484

ACI_CMD_HFP_AG_CALL_TERMINATE

Y

0x0488

ACI_CMD_HFP_AG_MIC_GAIN_LEVEL_SET

Y

0x0489

ACI_CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET

Y

0x0420

ACI_CMD_PBAP_DOWNLOAD

Y

0x0423

ACI_CMD_PBAP_CONNECT

Y

0x0426

ACI_CMD_PBAP_DISCONNECT

Y

0x0A0E

ACI_CMD_TRI_DONGLE_CMD

Y

0x2300

ACI_CMD_FINDMY_FEATURE

Y

0x2400

ACI_CMD_GFPS_FINDER_FEATURE

Y

0x3200

ACI_CMD_SPI_INIT

Y

0x3201

ACI_CMD_SPI_SLAVE_TRIGGER

Y

0x3220

ACI_CMD_A2DP_XMIT_ROUTE_OUT_CTRL

Y

0x3223

ACI_CMD_A2DP_XMIT_SET_ROUTE_OUT

Y

0x3020

ACI_CMD_LEA_BSRC_INIT

Y

0x3021

ACI_CMD_LEA_BSRC_START

Y

0x3022

ACI_CMD_LEA_BSRC_STOP

Y

0x3023

ACI_CMD_LEA_SCAN

Y

0x3024

ACI_CMD_LEA_CIS_START_MEDIA

Y

0x3025

ACI_CMD_LEA_CIS_STOP_STREAM

Y

0x3026

ACI_CMD_LEA_CIS_ULL_MODE

Y

0x3027

ACI_CMD_LEA_CSIS_MEMBER_SCAN

Y

0x3028

ACI_CMD_LEA_CSIS_GROUP_SCAN_STOP

Y

0x3029

ACI_CMD_LEA_BST_START

Y

0x302A

ACI_CMD_LEA_BST_STOP

Y

0x302B

ACI_CMD_LEA_BST_REMOVE

Y

0x302C

ACI_CMD_LEA_GVCS_VOLUME

Y

0x302D

ACI_CMD_LEA_GVCS_MUTE

Y

0x302E

ACI_CMD_LEA_GMIC_MUTE

Y

0x302F

ACI_CMD_LEA_BAAS_SCAN

Y

0x3030

ACI_CMD_LEA_PA_SYNC_DEV

Y

0x3031

ACI_CMD_LEA_CIS_START_CONVERSATION

Y

0x3032

ACI_CMD_LEA_CCP_ACTION

Y

0x3033

ACI_CMD_LEA_MCP_STATE

Y

0x3034

ACI_CMD_LEA_MCP_NOTIFY

Y

0x3250

ACI_CMD_LEA_ADV_START

Y

0x3251

ACI_CMD_LEA_ADV_STOP

Y

0x3252

ACI_CMD_LEA_CCP_CALL_CP

Y

0x3253

ACI_CMD_LEA_MCP_MEDIA_CP

Y

0x3254

ACI_CMD_LEA_SYNC_INIT

Y

0x3255

ACI_CMD_LEA_SYNC

Y

0x3256

ACI_CMD_LEA_VCS_SET

Y

0x3270

ACI_CMD_UART_DFU

Y

0x3300

ACI_CMD_SRC_PLAY_SET_SRC_ROUTE

Y

0x3301

ACI_CMD_SRC_PLAY_GET_SRC_ROUTE

Y

0x3302

ACI_CMD_SRC_PLAY_SET_PLAY_ROUTE

Y

0x3303

ACI_CMD_SRC_PLAY_GET_PLAY_ROUTE

Y

0x3304

ACI_CMD_SRC_PLAY_ROUTE_IN_START

Y

0x3305

ACI_CMD_SRC_PLAY_ROUTE_IN_STOP

Y

0x3306

ACI_CMD_SRC_PLAY_ROUTE_OUT_START

Y

0x3307

ACI_CMD_SRC_PLAY_ROUTE_OUT_STOP

Y

0x3801

ACI_CMD_MAP_CONNECT

Y

0x3802

ACI_CMD_MAP_GET_FOLDER_LISTING

Y

0x3803

ACI_CMD_MAP_DISCONNECT

Y

0x3805

ACI_CMD_MAP_GET_MESSAGE_LISTING

Y

0x3809

ACI_CMD_MAP_REG_MSG_NOTIFICATION

Y

0x380A

ACI_CMD_MAP_GET_MESSAGE

Y

0x3810

ACI_CMD_MAP_PUSH_MESSAGE

Y

0x5008

ACI_CMD_SET_FRAME_INFO

N

0x5009

ACI_CMD_SET_FRAME_CONTENT

N

0x8000

ACI_CMD_XM_ENTER_HCI_MODE

Y

0x8001

ACI_CMD_XM_DEVICE_REBOOT

Y

0x8004

ACI_CMD_XM_MMI

Y

0x8005

ACI_CMD_XM_BT_SET_ADDR

Y

0x8006

ACI_CMD_XM_SPP_DATA_TRANSFER

Y

0x8007

ACI_CMD_XM_GATT_ACI

Y

0x8009

ACI_CMD_XM_SNIFF_MODE_CTRL

Y

0x80C3

ACI_CMD_XM_GET_FACTORY_RESET

Y

0x8013

ACI_CMD_XM_USER_CFM_REQ

Y

0x8040

ACI_CMD_XM_LE_START_ADVERTISING

Y

0x8041

ACI_CMD_XM_LE_STOP_ADVERTISING

Y

0x8042

ACI_CMD_XM_LE_DISC

Y

0x8043

ACI_CMD_XM_LE_CONN_PARAM_UPDATE

Y

0x8044

ACI_CMD_XM_LE_ADV_DATA_UPDATE

Y

0x8045

ACI_CMD_XM_LE_SCAN_RSP_DATA_UPDATE

Y

0x8046

ACI_CMD_XM_LE_ADV_INTVAL_UPDATE

Y

0x8047

ACI_CMD_XM_LE_ATT_GET_MTU

Y

0x8048

ACI_CMD_XM_LE_GET_ADDR

Y

0x8049

ACI_CMD_XM_LE_USER_CFM_REQ

Y

0x804A

ACI_CMD_XM_LE_BOND_DEL

Y

0x804B

ACI_CMD_XM_LE_ADV_CREATE

Y

0x804C

ACI_CMD_XM_LE_BOND_DEL_ALL

Y

0x8080

ACI_CMD_XM_MUSIC

Y

0x8081

ACI_CMD_XM_TTS

Y

0x8082

ACI_CMD_XM_START_RECORD

Y

0x8083

ACI_CMD_XM_STOP_RECORD

Y

0x8084

ACI_CMD_XM_START_RECORD_PLAY

Y

0x8085

ACI_CMD_XM_STOP_RECORD_PLAY

Y

0x8086

ACI_CMD_XM_RECORD_PLAY_DATA

Y

0x8088

ACI_CMD_XM_SET_VOLUME_LEVEL

Y

0x8089

ACI_CMD_XM_AUDIO_TEST_GET_PA_ID

Y

0x808A

ACI_CMD_XM_AUDIO_TEST_BYPASS

Y

0x80C0

ACI_CMD_XM_DISABLE_VERBOSE_LOG

Y

0x8100

ACI_CMD_CHARGING_CASE_LE_CONTROL

Y

ACI_CMD_ACK

Command

Opcode

Command Parameters

Return Event

ACI_CMD_ACK

0x0000

event_id, status

None

Description

This command is used for the Host to acknowledge the received event.

Command Parameters

event_id:

Size: 2 octets

Value

Parameter Description

0xXX

The acknowledged event_id.

status:

Size: 1 octet

Value

Parameter Description

0x00

Command complete: MCU can handle this command.

0x01

Command disallow: MCU cannot handle this command.

0x02

Unknown CMD.

0x03

Parameters error .

0x04

Busy.

0x05

Process fail.

0x06

One wire extend.

0x08

Music req.

ACI_CMD_BT_CREATE_CONNECTION

Command

Opcode

Command Parameters

Return Event

ACI_CMD_BT_CREATE_CONNECTION

0x0002

profile, bd_addr

ACI_EVENT_PROFILE_CONN_STATUS

Description

This command is used to trigger the linkback behavior for specific profiles.

Command Parameters

profile:

Size: 4 octets

Value Parameter Description
0xXXXXXXXX Bit mask (only used for Bluetooth Audio Transceiver function).
0x00000001: A2DP_SINK.
0x00000002: AVRCP_CONTROLLER.
0x00000004: HFP_HF.
0x00000080: HSP_AG.
0x00000200: MAP_MSE.
0x00000400: A2DP_SRC.
0x00000800: AVRCP_TARGET.
0x00001000: HFP_AG.
0x00002000: PBAP_PSE.
0x00004000: HSP_HF.

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

MAC address (Little-Endian) of the dedicated device.

ACI_CMD_BT_DISCONNECT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_BT_DISCONNECT

0x0003

profile, bd_addr

ACI_EVENT_PROFILE_CONNECT_FAIL_STATUS

Description

This command is used to cancel the ongoing linkback procedure or disconnect the linked profiles. BTM will disconnect the ACL link if all of the profiles are disconnected.

Command Parameters

profile:

Size: 4 octets

Value Parameter Description
0xXXXXXXXX Bit mask (only used for Bluetooth Audio Transceiver function).
0x00000001: A2DP_SINK.
0x00000002: AVRCP_CONTROLLER.
0x00000004: HFP_HF.
0x00000080: HSP_AG.
0x00000200: MAP_MSE.
0x00000400: A2DP_SRC.
0x00000800: AVRCP_TARGET.
0x00001000: HFP_AG.
0x00002000: PBAP_PSE.
0x00004000: HSP_HF.
0xffffffff: All profile.

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXX

MAC address (Little-Endian) of the target device.

ACI_CMD_MMI

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MMI

0x0004

reserved, action

None

Description

MMI action, the user can add the corresponding MMI action according to specific needs based on sdk\src\sample\bt_audio_trx\app\app_mmi.h.

Command Parameters

reserved:

Size: 1 octet

Value

Parameter Description

0xXX

Reserved.

action:

Size: 1 octet

Value

Parameter Description

Return Event

0x02

MMI_FORCE_END_OUTGOING_CALL

ACI_EVENT_HFP_CALL_STATUS

0x03

MMI_ANSWER_CALL

ACI_EVENT_HFP_CALL_STATUS

0x04

MMI_REJECT_CALL

ACI_EVENT_HFP_CALL_STATUS

0x05

MMI_END_ACTIVE_CALL

None

0x0E

MMI_QUERY_CURRENT_CALL_LIST

None

0x32

MMI_AV_PLAY_PAUSE

None

0x54

MMI_DEV_POWER_ON

ACI_EVENT_AUDIO_DEVICE_STATE

0x56

MMI_DEV_POWER_OFF

ACI_EVENT_AUDIO_DEVICE_STATE

0x58

MMI_DEV_FACTORY_RESET_TO_DEFAULT

ACI_EVENT_AUDIO_DEVICE_STATE

0xA1

MMI_DUT_TEST_MODE

None

0xBB

MMI_DULT_ENTER_ID_READ_STATE

None


Command Detail:
  • MMI_FORCE_END_OUTGOING_CALL: End call without checking SCO status.

  • MMI_ANSWER_CALL: Answer an incoming call.

  • MMI_REJECT_CALL: Reject an incoming call.

  • MMI_END_ACTIVE_CALL: Add SCO if SCO doesn’t exist, otherwise end the call.

  • MMI_QUERY_CURRENT_CALL_LIST: Query call list.

  • MMI_AV_PLAY_PAUSE: Play or pause the audio stream.

  • MMI_DEV_POWER_ON: Change the device to power on state.

  • MMI_DEV_POWER_OFF: Change the device to power off state.

  • MMI_DEV_FACTORY_RESET_TO_DEFAULT: Reset the device to factory settings.

  • MMI_DUT_TEST_MODE: Enter device test mode.

  • MMI_DULT_ENTER_ID_READ_STATE: Make the device enter ID read state.

ACI_CMD_LEGACY_DATA_TRANSFER

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEGACY_DATA_TRANSFER

0x0005

link_id,
type,
total_length,
payload_length,
payload

None

Description

This command is used to send to SPP.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Link index, which will be informed when the link is established (event: ACI_EVENT_PROFILE_CONN_STATUS).

type:

Size: 1 octet

Value

Parameter Description

0x00

Single packet.

0x01

Fragmented start packet.

0x02

Fragmented continue packet.

0x03

Fragmented end packet.

total_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total payload length.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Value

Parameter Description

payload

N octets of the payload in this packet.

ACI_CMD_ASSIGN_BUFFER_SIZE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_ASSIGN_BUFFER_SIZE

0x0006

rx_buffer_size

None

Description

Host indicates to the Device about the max UART RX buffer size. The default value is 256 Bytes.

Command Parameters

rx_buffer_size:

Size: 2 octets

Value

Parameter Description

0xXX

The max UART RX buffer size of Host MCU.

ACI_CMD_BT_GET_REMOTE_NAME

Command

Opcode

Command Parameters

Return Event

ACI_CMD_BT_GET_REMOTE_NAME

0x0435

bd_addr

None

Description

Get the remote device name.

Command Parameters

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXX

The remote device Bluetooth address.

ACI_CMD_SET_CFG

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SET_CFG

0x0012

cfg_type, cfg_data

None

Description

Set device’s LE/legacy name.

Command Parameters

cfg_type:

Size: 1 octet

Value

Parameter Description

0x00

Set the LE display name.

0x01

Set the BR/EDR display name.

cfg_data:

Size: N octets

Value

Parameter Description

Name_length

Must be less than 39.

Name

Name with length.

ACI_CMD_GET_CFG_SETTING

Command

Opcode

Command Parameters

Return Event

ACI_CMD_GET_CFG_SETTING

0x0017

get_type

ACI_EVENT_REPORT_CFG_TYPE

Description

Get config setting of device’s LE/legacy name.

Command Parameters

get_type:

Size: 1 octet

Value

Parameter Description

0x00

GET_CFG_LE_NAME

0x01

GET_CFG_LEGACY_NAME

ACI_CMD_GET_STATUS

Command

Opcode

Command Parameters

Return Event

ACI_CMD_GET_STATUS

0x0018

status_index

ACI_EVENT_REPORT_STATUS

Description

Report some status information.

Command Parameters

status_index:

Size: 1 octet

Value

Parameter Description

0x02

Report device battery.

0x04

Report application state.

0x0F

Report factory reset status.

0x10

Report reject connect request status.

0x11

Report radio mode.

0x12

Report SCO status.

0x13

Report MIC mute status.

0xA1

Report device volume.

ACI_CMD_BT_HFP_DIAL_WITH_NUMBER

Command

Opcode

Command Parameters

Return Event

ACI_CMD_BT_HFP_DIAL_WITH_NUMBER

0x001B

dial_num_payload

None

Description

Dial out with number to outgoing call.

Command Parameters

dial_num_payload:

Size: 25 octets

Parameter Description

The number is ASCII format.

ACI_CMD_GET_BD_ADDR

Command

Opcode

Command Parameters

Return Event

ACI_CMD_GET_BD_ADDR

0x001C

None

ACI_EVENT_GET_BD_ADDR

Description

Get Bluetooth device address.

Command Parameters

None.

ACI_CMD_STRING_MODE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_STRING_MODE

0x001E

None

None

Description

This command is used to set string mode.

Command Parameters

None.

ACI_CMD_SET_VP_VOLUME

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SET_VP_VOLUME

0x001F

VP volume

None

Description

This command is used to set voice prompt volume.

Command Parameters

VP volume:

Size: 1 octet

Value

Parameter Description

0x00 ~ 0x0F

VP volume level.

ACI_CMD_SET_AND_READ_DLPS

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SET_AND_READ_DLPS

0x0020

action

ACI_EVENT_REPORT_DLPS_STATUS

Description

Enable/disable device auto-enter DLPS.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

Disable auto enter DLPS.

0x01

Enable auto enter DLPS.

ACI_CMD_XM_SET_MODE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_SET_MODE

0x0030

mode

None

Description

Set device mode.

Command Parameters

mode:

Size: 1 octet

Value

Parameter Description

0x00

Disable page scan and inquiry scan.

0x01

Enable inquiry scan.

0x02

Enable page scan.

0x03

Enable page scan and inquiry scan.

ACI_CMD_BT_HFP_SCO_MAG

Command

Opcode

Command Parameters

Return Event

ACI_CMD_BT_HFP_SCO_MAG

0x0040

link_id, cfm

None

Description

SCO connection management.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Link index, this index will be informed when the link established (event: ACI_EVENT_PROFILE_CONN_STATUS).

cfm:

Size: 1 octet

Value

Parameter Description

0x00

Reject the SCO connection indication.

0x01

Accept the SCO connection indication.

0x02

Send a request to disconnect the SCO connection.

ACI_CMD_LE_DATA_TRANSFER

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LE_DATA_TRANSFER

0x0102

link_id, type, total_length, payload_length, payload

None

Description

This command is used to send the data to remote devices via the LE link.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

type:

Size: 1 octet

Value

Parameter Description

0x00

Single packet.

0x01

Fragmented start packet.

0x02

Fragmented continue packet.

0x03

Fragmented end packet.

total_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total payload length.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Parameter Description

N octets of the payload in this packet.

ACI_CMD_LE_START_SCAN

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LE_START_SCAN

0x0103

local_addr_type,
phys,
filter_policy,
filter_duplicates,
scan_type of 1M PHY,
scan_interval of 1M PHY,
scan_window of 1M PHY,
scan_type of Coded PHY,
scan_interval of Coded PHY,
scan_window of Coded PHY

None

Description

Start LE scan.

Command Parameters

local_addr_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_LOCAL_ADDR_LE_PUBLIC

0x01

GAP_LOCAL_ADDR_LE_RANDOM

0x02

GAP_LOCAL_ADDR_LE_RPA_OR_PUBLIC

0x03

GAP_LOCAL_ADDR_LE_RPA_OR_RAND

phys:

Size: 1 octet

Value

Parameter Description

0x01

GAP_EXT_SCAN_PHYS_1M_BIT

0x04

GAP_EXT_SCAN_PHYS_CODED_BIT

0x05

GAP_EXT_SCAN_PHYS_ALL

filter_policy:

Size: 1 octet

Value

Parameter Description

0x00

GAP_SCAN_FILTER_ANY

0x01

GAP_SCAN_FILTER_WHITE_LIST

0x02

GAP_SCAN_FILTER_ANY_RPA

0x03

GAP_SCAN_FILTER_WHITE_LIST_RPA

ext_filter_duplicate:

Size: 1 octet

Value

Parameter Description

0x00

GAP_SCAN_FILTER_DUPLICATE_DISABLE

0x01

GAP_SCAN_FILTER_DUPLICATE_ENABLE

0x02

GAP_SCAN_FILTER_DUPLICATE_ENABLED_RESET_FOR_EACH_PERIOD

scan_type of 1M PHY:

Size: 1 octet

Value

Parameter Description

0x00

GAP_SCAN_MODE_PASSIVE

0x01

GAP_SCAN_MODE_ACTIVE

scan_interval of 1M PHY:

Size: 1 octet

Value

Parameter Description

0xXX

In units of 0.625ms, range: 0x0004 to 0xFFFF.

scan_window of 1M PHY:

Size: 1 octet

Value

Parameter Description

0xXX

In units of 0.625ms, range: 0x0004 to 0xFFFF.

scan_type of Coded PHY:

Size: 1 octet

Value

Parameter Description

0x00

GAP_SCAN_MODE_PASSIVE

0x01

GAP_SCAN_MODE_ACTIVE

scan_interval of Coded PHY:

Size: 1 octet

Value

Parameter Description

0xXX

In units of 0.625ms, range: 0x0004 to 0xFFFF.

scan_window of Coded PHY:

Size: 1 octet

Value

Parameter Description

0xXX

In units of 0.625ms, range: 0x0004 to 0xFFFF.

ACI_CMD_LE_STOP_SCAN

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_STOP_SCAN

0x0104

None

None

Description

Stop LE scan.

Command Parameters

None.

ACI_CMD_LE_START_PAIR

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_START_PAIR

0x0109

link_id

None

Description

This command is used to pair a connected device.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

ACI_CMD_LE_CREATE_CONN

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_CREATE_CONN

0x010E

init_phys,
remote_bd_type,
remote_bd[6],
local_bd_type,
scan_timeout

None

Description

This command is used to initiate connection to a specific device.

Command Parameters

init_phys:

Size: 1 octet

Value

Parameter Description

0xXX

Bit0: 1M PHY.
Bit1: 2M PHY.
Bit2: Codec PHY.

remote_bd_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_REMOTE_ADDR_LE_PUBLIC

0x01

GAP_REMOTE_ADDR_LE_RANDOM

0x02

GAP_REMOTE_ADDR_LE_PUBLIC_IDENTITY

0x03

GAP_REMOTE_ADDR_LE_RANDOM_IDENTITY

0x10

GAP_REMOTE_ADDR_CLASSIC

0xff

GAP_REMOTE_ADDR_LE_ANONYMOUS

remote_bd:

Size: 6 octet

Value

Parameter Description

0xXXXXXXXXXXXX

The address of device intended to connect.

local_bd_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_LOCAL_ADDR_LE_PUBLIC

0x01

GAP_LOCAL_ADDR_LE_RANDOM

0x02

GAP_LOCAL_ADDR_LE_RAP_OR_PUBLIC

0x03

GAP_LOCAL_ADDR_LE_RAP_OR_RAND

scan_timeout:

Size: 2 octet

Value

Parameter Description

0xXXXX

Scan timer in units of 10ms.

ACI_CMD_ANCS_GET_NOTIFICATION_ATTR

Command

Opcode

Command Parameters

Return Event

ACI_CMD_ANCS_GET_NOTIFICATION_ATTR

0x0111

link_id, notification_uid,
attribute_ids_len, attribute_id

ACI_EVENT_ANCS_NOTIFICATION

Description

This command is used to get the notification attribute.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

notification_uid:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

notification_uid

attribute_ids_len:

Size: 1 octet

Value

Parameter Description

0xXX

attribute_ids_len

attribute_ids:

Size: attribute_ids_len octets

Value

Parameter Description

0xXX, …

attribute_ids

ACI_CMD_ANCS_GET_APP_ATTR

Command

Opcode

Command Parameters

Return Event

ACI_CMD_ANCS_GET_APP_ATTR

0x0112

link_id,
app_identifier_len,
app_identifier,
attribute_ids_len, attribute id

ACI_EVENT_ANCS_NOTIFICATION

Description

This command is used to get the APP attribute.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

app_identifier_len:

Size: 1 octet

Value

Parameter Description

0xXX

app_identifier_len

app_identifier:

Size: N octets

Parameter Description

N octets of app_identifier.

attribute_ids_len:

Size: 1 octet

Value

Parameter Description

0xXX

attribute_ids_len

attribute_ids:

Size: N octets

Parameter Description

N octets of attribute_ids.

ACI_CMD_ANCS_PERFORM_NOTIFICATION_ACTION

Command

Opcode

Command Parameters

Return Event

ACI_CMD_ANCS_PERFORM_NOTIFICATION_ACTION

0x011

link_id,
notification_uid, action_id

ACI_EVENT_ANCS_ACTION_RESULT

Description

This command is used to perform the notification action.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

notification_uid:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

notification_uid

action_id:

Size: 1 octet

Value

Parameter Description

0xXX

action_id

ACI_CMD_AMS_WRITE_REMOTE_CMD

Command

Opcode

Command Parameters

Return Event

ACI_CMD_AMS_WRITE_REMOTE_CMD

0x0115

link_id, cmd_id

None

Description

This command is used to send remote CMD to iOS media APP.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

cmd_id:

Size: 1 octet

Value

Parameter Description

0x00

RemoteCommandIDPlay

0x01

RemoteCommandIDPause

0x02

RemoteCommandIDTogglePlayPause

0x03

RemoteCommandIDNextTrack

0x04

RemoteCommandIDPreviousTrack

0x05

RemoteCommandIDVolumeUp

0x06

RemoteCommandIDVolumeDown

0x07

RemoteCommandIDAdvanceRepeatMode

0x08

RemoteCommandIDAdvanceShuffleMode

0x09

RemoteCommandIDSkipForward

0x0A

RemoteCommandIDSkipBackward

0x0B

RemoteCommandIDLikeTrack

0x0C

RemoteCommandIDDislikeTrack

0x0D

RemoteCommandIDBookmarkTrack

Others

Reserved.

ACI_CMD_AMS_WRITE_ENTITY_UPD_CMD

Command

Opcode

Command Parameters

Return Event

ACI_CMD_AMS_WRITE_ENTITY_UPD_CMD

0x0116

link_id, value_len, value

None

Description

This command is used to send entity update CMD to iOS media APP.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

value_len:

Size: 1 octet

Value

Parameter Description

0xXX

Value_len

value:

Size: value_len octets

Value

Parameter Description

0xXX, …

Value.

ACI_CMD_LE_MODIFY_WHITELIST

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_MODIFY_WHITELIST

0x0161

operation, address, address_type

None

Description

This command is used to modify the white list.

Command Parameters

operation:

Size: 1 octet

Value

Parameter Description

0x00

Clear white list.

0x01

Add a device to the white list.

0x02

Remove a device from the white list.

address (Needless for clear white list):

Size: 6 octet

Value

Parameter Description

0xXXXXXXXXXXXX

Address.

remote_bd_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_REMOTE_ADDR_LE_PUBLIC

0x01

GAP_REMOTE_ADDR_LE_RANDOM

0x02

GAP_REMOTE_ADDR_LE_PUBLIC_IDENTITY

0x03

GAP_REMOTE_ADDR_LE_RANDOM_IDENTITY

0x10

GAP_REMOTE_ADDR_CLASSIC

0xff

GAP_REMOTE_ADDR_LE_ANONYMOUS

ACI_CMD_LE_MODIFY_WHITELIST_BY_IDX

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_MODIFY_WHITELIST_BY_IDX

0x0162

operation, bond_idx

None

Description

This command is used to modify white list by bond index.

Command Parameters

operation:

Size: 1 octet

Value

Parameter Description

0x00

Clear white list.

0x01

Add a device to white list.

0x02

Remove a device from white list.

bond_idx (Needless for clear white list):

Size: 1 octet

Value

Parameter Description

0xXX

Operate target device in the bond list by priority.

ACI_CMD_LE_MODIFY_RESOLVELIST_BY_IDX

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_MODIFY_RESOLVELIST_BY_IDX

0x0163

operation, bond_idx

None

Description

This command is used to modify the resolving list by bond index.

Command Parameters

operation:

Size: 1 octet

Value

Parameter Description

0x00

Clear resolving list.

0x01

Add a device to the resolving list.

0x02

Remove a device from the resolving list.

bond_idx (Needless for clear resolving list):

Size: 1 octet

Value

Parameter Description

0xXX

Operate target device in the bond list by priority.

ACI_CMD_LE_SET_RESOLUTION

Command

Opcode

Command Parameter

Return Event

ACI_CMD_LE_SET_RESOLUTION

0x0164

target_state

None

Description

This command is used to enable/disable resolution.

Command Parameters

target_state:

Size: 1 octet

Value

Parameter Description

0x00

Disable resolution.

0x01

Enable resolution.

ACI_CMD_SET_VOLUME

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SET_VOLUME

0x020A

volume level

ACI_EVENT_REPORT_STATUS

Description

Set playback or voice volume depending on the scenario.

Command Parameters

volume level:

Size: 1 octet

Value

Parameter Description

0xXX

0~maximum (volume level).

ACI_CMD_GET_FW_VERSION

Command

Opcode

Command Parameters

Return Event

ACI_CMD_GET_FW_VERSION

0x0308

type

ACI_EVENT_FW_VERSION

Description

Get the firmware version.

Command Parameters

type:

Size: 1 octet

Value

Parameter Description

0x00

Get FW version.

ACI_CMD_BT_BOND_INFO_CLEAR

Command

Opcode

Command Parameters

Return Event

ACI_CMD_BT_BOND_INFO_CLEAR

0x0309

link_type, bd_addr

ACI_EVENT_BT_BOND_INFO_CLEAR

Description

Clear the device’s link key of the target remote connection according to bd_addr.

Command Parameters

link_type:

Size: 1 octet

Value

Parameter Description

0x00

Clear BR/EDR bond info.

Others

Reserved.

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

MAC address of target device.

ACI_CMD_GET_PACKAGE_ID

Command

Opcode

Command Parameters

Return Event

ACI_CMD_GET_PACKAGE_ID

0x030F

None

ACI_EVENT_REPORT_PACKAGE_ID

Description

Get chip ID and package ID.

Command Parameters

None.

ACI_CMD_SWITCH_TO_HCI_DOWNLOAD_MODE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SWITCH_TO_HCI_DOWNLOAD_MODE

0x0310

None

None

Description

This command is used to enter HCI download mode and then reset.

Command Parameters

None.

ACI_CMD_INQUIRY

Command

Opcode

Command Parameters

Return Event

ACI_CMD_INQUIRY

0x0321

action, timeout

ACI_EVENT_BR_INQUIRY_STATE, ACI_EVENT_BR_INQUIRY_RESULT

Description

This request searches the neighbor’s Bluetooth devices.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

Start inquiry.

0x01

Stop inquiry.

timeout:

Size: 1 octet

Value Parameter Description
0x01 ~ 0x30 The maximum amount of time before the inquiry is halted.
Time = N * 1.28 sec. Range: 1.28 - 61.44 sec.
ACI_CMD_SEND_DTMF

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SEND_DTMF(abandon)

0x0400

number

None

Description

Send DTMF.

Command Parameters

number:

Size: 1 octet

Value

Parameter Description

0xXX

The DTMF character must be one from the set 0-9, #, *, A-D. For example, if the character is 3, the parameter number should be set to 0x33.

ACI_CMD_SEND_VGM

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SEND_VGM

0x0403

level

None

Description

Send VGM.

Command Parameters

level:

Size: 1 octet

Value Parameter Description
0xXX VGM value.
Range: 0 ~ 15.
ACI_CMD_SEND_VGS

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SEND_VGS

0x0404

level

None

Description

Send VGS.

Command Parameters

level:

Size: 1 octet

Value Parameter Description
0xXX VGS value, range: 0 ~ 15.
ACI_CMD_HFP_AG_CONNECT_SCO

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_CONNECT_SCO

0x0480

link_id

None

Description

HFP AG connects SCO.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

ACI_CMD_HFP_AG_DISCONNECT_SCO

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_DISCONNECT_SCO

0x0481

link_id

None

Description

HFP AG disconnects SCO.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

ACI_CMD_HFP_AG_CALL_INCOMING

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_CALL_INCOMING

0x0482

link_id

None

Description

Notify the incoming call.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

ACI_CMD_HFP_AG_CALL_ANSWER

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_CALL_ANSWER

0x0483

link_id

None

Description

Answer the incoming call.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

ACI_CMD_HFP_AG_CALL_TERMINATE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_CALL_TERMINATE

0x0484

link_id

None

Description

Terminate the call.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

ACI_CMD_HFP_AG_MIC_GAIN_LEVEL_SET

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_MIC_GAIN_LEVEL_SET

0x0488

link_id, action

None

Description

Mute or unmute the MIC.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

action:

Size: 1 octet

Value

Parameter Description

0x00

MIC_MUTE

0x0A

MIC_UNMUTE

ACI_CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET

Command

Opcode

Command Parameters

Return Event

ACI_CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET

0x0489

link_id, action

None

Description

Turn the SPK volume up or down.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00

Link ID.

action:

Size: 1 octet

Value

Parameter Description

0x00

SPK_VOL_UP

0x00

SPK_VOL_DOWN

ACI_CMD_PBAP_DOWNLOAD

Command

Opcode

Command Parameters

Return Event

ACI_CMD_PBAP_DOWNLOAD

0x0420

method

None

Description

PBAP download.

Command Parameters

method:

Size: 1 octet

Value Parameter Description
0x03 ~ 0x05 PBAP download method.
Range:
0x03: PBAP_DOWNLOAD_METHOD_ALL, download the phonebook of ME/SM and CCH.
0x04: PBAP_DOWNLOAD_METHOD_ALL_PB, download the phonebook of ME/SM.
0x05: PBAP_DOWNLOAD_METHOD_CCH, the Combined Calls History contains incoming/outgoing/missed call history.
ACI_CMD_PBAP_CONNECT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_PBAP_CONNECT

0x0423

None

None

Description

PBAP connect.

Command Parameters

None.

ACI_CMD_PBAP_DISCONNECT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_PBAP_DISCONNECT

0x0426

None

None

Description

PBAP disconnect.

Command Parameters

None.

ACI_CMD_TRI_DONGLE_CMD

Command

Opcode

Command Parameters

Return Event

ACI_CMD_TRI_DONGLE_CMD

0x0A0E

sub_command_id, sub_command_parameters

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

Description

Command Tri dongle legacy & LE operation.

Command Parameters

sub_command_id:

Size: 1 octet

Value

Parameter Description

Return Event

0x00

Command Tri dongle start LE scan.

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

0x01

Command Tri dongle stop LE scan.

None

0x02

Command Tri dongle start BR inquiry scan.

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

0x03

Command Tri dongle stop BR inquiry scan.

None

0x04

Command Tri dongle connect to target LE device.

None

0x05

Command Tri dongle disconnect to target LE device.

None

0x06

Command Tri dongle connect to target BR device.

None

0x07

Command Tri dongle disconnect to target BR device.

None

0x08

Command Tri dongle report connected LE device info.

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

0x09

Command Tri dongle report connected BR device info.

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

0x0A

Command Tri dongle clear all bond info.

None

0x0B

Command Tri dongle clear to target LE device.

None

0x0C

Command Tri dongle clear to target BR device.

None

0x0D

Command Tri dongle get passkey support info.

None

0x0E

Command Tri dongle BAS request to target LE device.

None

0x0F

Command Tri dongle DIS one UUID request to targe LE device.

None

0x10

Command Tri dongle LE RSSI to target LE device.

None

0x11

Command Tri dongle BR RSSI to target LE device.

None

0x12

Command Tri dongle LE scan status.

None

0x13

Command Tri dongle BR inquiry scan status.

None

0x14

Command Tri dongle LE bondlist info.

None

0x15

Command Tri dongle DIS all UUID request to target LE device.

None

0x16

Command Tri dongle BR bondlist info.

None

Only the following sub command ID are required to fill sub command parameters:

  • 0x02 (Command Tri dongle start BR inquiry scan).

  • 0x04 (Command Tri dongle connect to target LE device).

  • 0x05 (Command Tri dongle disconnect to target LE device).

  • 0x06 (Command Tri dongle connect to target BR device).

  • 0x07 (Command Tri dongle disconnect to target BR device).

  • 0x0B (Command Tri dongle clear to target LE device).

  • 0x0C (Command Tri dongle clear to target BR device).

  • 0x0E (Command Tri dongle BAS request to target LE device).

  • 0x0F (Command Tri dongle DIS one UUID request to target LE device).

  • 0x10 (Command Tri dongle LE RSSI to target LE device).

  • 0x11 (Command Tri dongle BR RSSI to target LE device).

  • 0x15 (Command Tri dongle DIS all UUID request to target LE device).

sub_command_parameters:

Size: 49 octets

Sub Command ID

Required Sub Command Parameter

0x02
Command Tri dongle start BR inquiry scan

continuous (1 octet, 0 = Disable, 1 = Enable)

0x04
Command connect to target LE device

bd_addr (6 octets, Little-Endian),
le_addr_type(1 octet),
LE name length (1 octet),
LE name (length correspond to LE name length)

0x05
Command disconnect to target LE device

bd_addr (6 octets, Little-Endian)

0x06
Command connect to target BR device

bd_addr (6 octets, Little-Endian)

0x07
Command disconnect to target BR device

bd_addr (6 octets, Little-Endian)

0x0B
Command clear to target LE device

bd_addr (6 octets, Little-Endian)

0x0C
Command clear to target BR device

bd_addr (6 octets, Little-Endian)

0x0E
Command BAS request to target LE device

bd_addr (6 octets, Little-Endian)

0x0F
Command DIS one UUID request to
target LE device

UUID (2 octets, Little-Endian),
bd_addr (6 octets, Little-Endian)

0x10
Command LE RSSI to target LE device

bd_addr (6 octets, Little-Endian)

0x11
Command BR RSSI to target LE device

bd_addr (6 octets, Little-Endian)

0x15
Command DIS all UUID request to
target LE device

bd_addr (6 octets, Little-Endian)

ACI_CMD_FINDMY_FEATURE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_FINDMY_FEATURE

0x2300

action

None

Description

Find My action.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

ENTER_PAIRING

0x01

MMI_PUT_SERIAL_NUMBER

Command Detail:

  • ENTER_PAIRING: Enter Find My pairing mode.

  • MMI_PUT_SERIAL_NUMBER: Put the state of the serial number.

ACI_CMD_GFPS_FINDER_FEATURE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_GFPS_FINDER_FEATURE

0x2400

action

None

Description

GFPS finder action.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

GFPS_FINDER_INVALID_ACTION

0x01

GFPS_FINDER_STOP_RING

Command Detail

  • GFPS_FINDER_STOP_RING: Stop ring.

ACI_CMD_SPI_INIT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SPI_INIT

0x3200

role

None

Description

SPI role init.

Command Parameters

None.

role:

Size: 1 octet

Value

Parameter Description

0x00

SPI_ROLE_MASTER

0x01

SPI_ROLE_SLAVE

ACI_CMD_SPI_SLAVE_TRIGGER

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SPI_SLAVE_TRIGGER

0x3201

None

None

Description

Trigger SPI transmission by the slave. This command is for the test.

Command Parameters

None.

ACI_CMD_A2DP_XMIT_SET_ROUTE_OUT

Command

Opcode

Command Parameters

Return Event

CMD_A2DP_XMIT_SET_ROUTE_OUT

0x3223

route_path

None

Description

Set transparent transmission music (from SPI) output route.

Command Parameters

type:

Size: 1 octet

Value

Parameter Description

0x00

XMIT_PLAY_ROUTE_A2DP_SRC

0x01

XMIT_PLAY_ROUTE_BIS

ACI_CMD_A2DP_XMIT_ROUTE_OUT_CTRL

Command

Opcode

Command Parameters

Return Event

ACI_CMD_A2DP_XMIT_ROUTE_OUT_CTRL

0x3220

type

None

Description

Enable playing transparent transmission music by A2DP source or BIS music (from SPI).

Command Parameters

type:

Size: 1 octet

Value

Parameter Description

0x00

XMIT_PLAY_STATE_START

0x01

XMIT_PLAY_STATE_IDLE

ACI_CMD_LEA_BSRC_INIT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BSRC_INIT

0x3020

codec_type, bis_num,
encryption

None

Description

Broadcast init.

Command Parameters

codec_type:

Size: 1 octet

Value

Parameter Description

0x0D

CODEC_CFG_ITEM_48_4

0x03

CODEC_CFG_ITEM_16_2

bis_num:

Size: 1 octet

Value

Parameter Description

0x01

bis_num = 1.

0x02

bis_num = 2.

encryption:

Size: 1 octet

Value

Parameter Description

0x00

False.

0x01

True.

ull_mode:

Size: 1 octet

Value

Parameter Description

0x00

False.

0x01

True.

pd:

Size: 2 octet

Value

Parameter Description

0xXXXX

Presentation delay (Effective when ull_mode is enabled).

ACI_CMD_LEA_BSRC_START

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BSRC_START

0x3021

None

None

Description

Start broadcasting.

Command Parameters

None.

ACI_CMD_LEA_BSRC_STOP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BSRC_STOP

0x3022

stop_option

None

Description

Stop broadcasting.

Command Parameters

release:

Size: 1 octet

Value

Parameter Description

0x00

Do not delete BIS configuration.

0x01

Delete BIS configuration.

ACI_CMD_LEA_SCAN

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_SCAN

0x3023

action

None

Description

Start or stop scanning devices supporting LE Audio.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

Start scanning.

0x01

Stop scanning.

ACI_CMD_LEA_CIS_START_MEDIA

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CIS_START_MEDIA

0x3024

group_idx

None

Description

Start CIS music.

Command Parameters

group_idx:

Size: 1 octet

Value

Parameter Description

0x00

start_group_idx_0: start CIS media on group 0.

0x01

start_group_idx_1: start CIS media on group 1.

ACI_CMD_LEA_CIS_STOP_STREAM

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CIS_STOP_STREAM

0x3025

group_idx and action

None

Description

Stop CIS streaming.

Command Parameters

group_idx and action:

Size: 1 octet

Value

Parameter Description

0x00

stop_group_idx_0: stop CIS media on group 0.

0x01

release_group_idx_0: Stop CIS media on group 0 and release CIS.

0x02

stop_group_idx_1: Stop CIS media on group 1.

0x03

release_group_idx_1: Stop CIS media on group 1 and release CIS.

ACI_CMD_LEA_CIS_ULL_MODE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CIS_ULL_MODE

0x3026

action

None

Description

Enable/Disable CIS media Ultra Low Latency mode. Please use this command before starting CIS media.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

Disable CIS ULL.

0x01

Enable CIS ULL.

ACI_CMD_LEA_CSIS_MEMBER_SCAN

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CSIS_MEMBER_SCAN

0x3027

group_idx

None

Description

Scan devices belonging to the same group.

Command Parameters

group_idx:

Size: 1 octet

Value

Parameter Description

0x00

group_idx_0

0x01

group_idx_1

ACI_CMD_LEA_CSIS_GROUP_SCAN_STOP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CSIS_GROUP_SCAN_STOP

0x3028

None

None

Description

Stop scanning devices that belong to the same group.

Command Parameters

None.

ACI_CMD_LEA_BST_START

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BST_START

0x3029

action

None

Description

Broadcast audio reception start procedure.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

group_0_sync_0: Start broadcast on group 0 and sync 0.

0x01

group_0_sync_1: Start broadcast on group 0 and sync 1.

0x02

group_1_sync_0: Start broadcast on group 1 and sync 0.

0x03

group_1_sync_1: Start broadcast on group 1 and sync 1.

ACI_CMD_LEA_BST_STOP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BST_STOP

0x302A

action

None

Description

Broadcast audio reception stop procedure.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

group_0_sync_0: Stop broadcast on group 0 and sync 0.

0x01

group_0_sync_1: Stop broadcast on group 0 and sync 1.

0x02

group_1_sync_0: Stop broadcast on group 1 and sync 0.

0x03

group_1_sync_1: Stop broadcast on group 1 and sync 1.

ACI_CMD_LEA_BST_REMOVE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BST_REMOVE

0x302B

action

None

Description

Broadcast audio reception removal procedure.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

0x00

group_0_sync_0: Remove broadcast on group 0 and sync 0.

0x01

group_0_sync_1: Remove broadcast on group 0 and sync 1.

0x02

group_1_sync_0: Remove broadcast on group 1 and sync 0.

0x03

group_1_sync_1: Remove broadcast on group 1 and sync 1.

ACI_CMD_LEA_GVCS_VOLUME

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_GVCS_VOLUME

0x302C

group_idx, volume

None

Description

Set VCS volume.

Command Parameters

group_idx:

Size: 1 octet

Value

Parameter Description

0xXX

Group handle index.

volume:

Size: 1 octet

Value

Parameter Description

0xXX

Set VCS volume to 0xXX.

ACI_CMD_LEA_GVCS_MUTE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_GVCS_MUTE

0x302D

group_idx, mute_state

None

Description

Set VCP mute state.

Command Parameters

group_idx:

Size: 1 octet

Value

Parameter Description

0xXX

Group handle index.

mute_state:

Size: 1 octet

Value

Parameter Description

0x00

Set unmute.

0x01

Set mute.

ACI_CMD_LEA_GMIC_MUTE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_GMIC_MUTE

0x302E

group_idx, mute_state

None

Description

Set GMIC MIC mute state.

Command Parameters

group_idx:

Size: 1 octet

Value

Parameter Description

0xXX

Group handle index.

mute_state:

Size: 1 octet

Value

Parameter Description

0x00

Set MIC unmute.

0x01

Set MIC mute.

ACI_CMD_LEA_BAAS_SCAN

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_BAAS_SCAN

0x302F

None

None

Description

Start extended scan for BAAS.

Command Parameters

None.

ACI_CMD_LEA_PA_SYNC_DEV

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_PA_SYNC_DEV

0x3030

dev_idx

None

Description

PA sync by device index.

Command Parameters

dev_idx:

Size: 1 octet

Value

Parameter Description

0x00

Dev0: PA sync with device 0.

0x01

Dev1: PA sync with device 1.

0x02

Dev2: PA sync with device 2.

ACI_CMD_LEA_CIS_START_CONVERSATION

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CIS_START_CONVERSATION

0x3031

group_idx

None

Description

Start CIS conversation.

Command Parameters

group_idx:

Size: 1 octet

Value

Parameter Description

0x00

Start CIS media on group 0.

0x01

Start CIS media on group 1.

ACI_CMD_LEA_CCP_ACTION

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CCP_ACTION

0x3032

call_action, call_index

None

Description

CCP control action.

Command Parameters

call_action:

Size: 1 octet

Value

Parameter Description

0x05

Incoming call action.

0x12

Local terminate.

0x14

Local accept.

call_index:

Size: 1 octet

Value

Parameter Description

0xXX

Call index.

ACI_CMD_LEA_MCP_STATE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_MCP_STATE

0x3033

media_state

None

Description

Update MCP state.

Command Parameters

media_state:

Size: 1 octet

Value

Parameter Description

0x01

The media player starts playing the current track.

0x02

The media player paused the current track.

ACI_CMD_LEA_MCP_NOTIFY

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_MCP_NOTIFY

0x3034

mcs_uuid, param

None

Description

Set MCP Notification.

Command Parameters

mcs_uuid:

Size: 2 octets

Value

Parameter Description

0x2B96

MCS_UUID_CHAR_TRACK_CHANGED

0x2B98

MCS_UUID_CHAR_TRACK_DURATION

0x2B99

MCS_UUID_CHAR_TRACK_POSITION

param:

Size: 1 octet

Value

Parameter Description

0x10

Track position.

0x60

Track duration.

ACI_CMD_LEA_ADV_START

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_ADV_START

0x3250

None

None

Description

Start LE Audio advertising, allowing the device to be scanned and connected by remote device.

Command Parameters

None.

ACI_CMD_LEA_ADV_STOP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_ADV_STOP

0x3251

None

None

Description

Stop LE Audio advertising, preventing it from being scanned by remote device.

Command Parameters

None.

ACI_CMD_LEA_CCP_CALL_CP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_CCP_CALL_CP

0x3252

conn_id, call_cp

ACI_APP_EVENT_CCP_CALL_STATUS

Description

Control the phone call of the connected remote device.

Command Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0xXX

Connection identity for connected remote device.

call_cp:

Size: 1 octet

Value

Parameter Description

0x00

Answer incoming call.

0x01

Terminate call.

0x02

Move call to local hold.

0x03

Move local hold call to active call.

0x04

Originate call.

0x05

Join calls.

ACI_CMD_LEA_MCP_MEDIA_CP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_MCP_MEDIA_CP

0x3253

conn_id, media_cp

ACI_APP_EVENT_MCP_MEDIA_STATE

Description

Control the active music player of connected remote device.

Command Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0xXX

Connection identity for connected remote device.

media_cp:

Size: 1 octet

Value

Parameter Description

0x01

Play current track.

0x02

Pause current track.

0x03

Fast rewind.

0x04

Fast forward.

0x05

Stop current track.

0x30

Move to previous track.

0x31

Move to next track.

ACI_CMD_LEA_SYNC_INIT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_SYNC_INIT

0x3254

bis_mode, bis_policy, addr

None

Description

Initialize the BIS parameters, including BIS role and BIS policy. The address field is only used when BIS policy is set to LEA_BIS_POLICY_SPECIFIC.

Command Parameters

bis_mode:

Size: 1 octet

Value

Parameter Description

0x01

LEA_BROADCAST_DELEGATOR

0x02

LEA_BROADCAST_SINK

bis_policy:

Size: 1 octet

Value

Parameter Description

0x00

LEA_BIS_POLICY_RANDOM

0x01

LEA_BIS_POLICY_SPECIFIC

addr:

Size: 6 octets

Value

Parameter Description

0xXX,0xXX,0xXX,0xXX,0xXX,0xXX

The source address that wants to sync.

ACI_CMD_LEA_SYNC

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_SYNC

0x3255

sync

None

Description

Start/stop syncing the broadcast audio stream.

Command Parameters

opcode:

Size: 2 octets

Value

Parameter Description

0x00

Sync = true.

0x01

Sync = false.

ACI_CMD_LEA_VCS_SET

Command

Opcode

Command Parameters

Return Event

ACI_CMD_LEA_VCS_SET

0x3256

conn_id, vol_type

None

Description

Change the volume of the local device’s audio and notify VCS audio volume state to the remote device.

Command Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0xXX

Connection identity for connected remote device.

vol_type:

Size: 1 octet

Value

Parameter Description

0x00

Volume up.

0x01

Volume down.

0x02

SPK mute.

0x03

SPK unmute.

ACI_CMD_UART_DFU

Command

Opcode

Command Parameters

Return Event

ACI_CMD_UART_DFU

0x3270

opcode

None

Description

Start/abort UART DFU, transmit DFU Data, enable test mode, get device’s version, and reboot the device.

Command Parameters

opcode:

Size: 2 octets

Value

Parameter Description

0x0000

UART_DFU_START_REQ, request to start DFU.

0x0001

UART_DFU_DATA_IND, send data packet.

0x0002

UART_DFU_ABORT, abort DFU.

0x0003

UART_DFU_REBOOT, reboot device.

0x0004

UART_DFU_TEST_EN, enable test mode.

0x0005

UART_DFU_GET_VER, get version of device.

ACI_CMD_SRC_PLAY_SET_SRC_ROUTE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_SET_SRC_ROUTE

0x3300

src_route

None

Description

Set source route.

Command Parameters

src_route:

Size: 2 octets

Value

Parameter Description

0x01, 0x00

mic

0x02, 0x00

line-in

0x03, 0x01

usb_ds

0x03, 0x02

usb_us

0x03, 0x03

usb_ds_us

0x04, 0x00

sd_card

0x05, 0x00

spdif

0x06, 0x00

I2S

ACI_CMD_SRC_PLAY_GET_SRC_ROUTE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_GET_SRC_ROUTE

0x3301

None

None

Description

Get source route.

Command Parameters

None.

ACI_CMD_SRC_PLAY_SET_PLAY_ROUTE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_SET_PLAY_ROUTE

0x3302

play_route

None

Description

Set play route.

Command Parameters

play_route:

Size: 1 octet

Value

Parameter Description

0x01

a2dp

0x02

hfp_ag

0x03

bis

0x04

cis

0x05

local

0x06

multi_a2dp

ACI_CMD_SRC_PLAY_GET_PLAY_ROUTE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_GET_PLAY_ROUTE

0x3303

None

None

Description

Get play route.

Command Parameters

None.

ACI_CMD_SRC_PLAY_ROUTE_IN_START

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_ROUTE_IN_START

0x3304

None

None

Description

Start route in the record.

Command Parameters

None.

ACI_CMD_SRC_PLAY_ROUTE_IN_STOP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_ROUTE_IN_STOP

0x3305

None

None

Description

Stop route in the record.

Command Parameters

None.

ACI_CMD_SRC_PLAY_ROUTE_OUT_START

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_ROUTE_OUT_START

0x3306

None

None

Description

Start to route out play.

Command Parameters

None.

ACI_CMD_SRC_PLAY_ROUTE_OUT_STOP

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SRC_PLAY_ROUTE_OUT_STOP

0x3307

None

None

Description

Stop route out play.

Command Parameters

None.

ACI_CMD_MAP_CONNECT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_CONNECT

0x3801

None

None

Description

Set up MAP connection.

Command Parameters

None.

ACI_CMD_MAP_GET_FOLDER_LISTING

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_GET_FOLDER_LISTING

0x3802

max_list_count, start_offset

None

Description

Get folder list through MAP.

Command Parameters

max_list_count:

Size: 1 octet

Value

Parameter Description

0x0A

Max list count.

start_offset:

Size: 1 octet

Value

Parameter Description

0x00

Start offset.

ACI_CMD_MAP_DISCONNECT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_DISCONNECT

0x3803

None

None

Description

Disconnect MAP connection.

Command Parameters

None.

ACI_CMD_MAP_GET_MESSAGE_LISTING

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_GET_MESSAGE_LISTING

0x3805

max_list_count, start_offset

None

Description

Get message list through MAP.

Command Parameters

max_list_count:

Size: 1 octet

Value

Parameter Description

0x0A

Max list count.

start_offset:

Size: 1 octet

Value

Parameter Description

0x00

Start offset.

ACI_CMD_MAP_REG_MSG_NOTIFICATION

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_REG_MSG_NOTIFICATION

0x3809

enable

None

Description

Register message notification through MAP.

Command Parameters

enable:

Size: 1 octet

Value

Parameter Description

0x01

Enable.

ACI_CMD_MAP_GET_MESSAGE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_GET_MESSAGE

0x380A

handle_len, msg_handle[]

None

Description

Get a message through MAP.

Command Parameters

handle_len:

Size: 1 octet

Value

Parameter Description

0x20

Length of message.

msg_handle:

Size

Value Parameter Description
msg_handle[] Array of message handles.
ACI_CMD_MAP_PUSH_MESSAGE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_MAP_PUSH_MESSAGE

0x3810

msg_len, msg[]

None

Description

Push message through MAP.

Command Parameters

msg_len

Size: 1 octet

Value

Parameter Description

0xXX

Length of a specific message to be pushed.

msg

Size

Value

Parameter Description

msg[]

Array of messages.

ACI_CMD_SET_FRAME_INFO

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SET_FRAME_INFO (abandon)

0x5008

format,
channel,
sample_counts,
sampling_freq,
bitrate,
version,
layer

ACI_EVENT_REQ_MEDIA_FRAME

Description

Set MP3 information and trigger media playing.

Command Parameters

format:

Size: 1 octet

Value

Parameter Description

0x30

MP3.

channel:

Size: 1 octet

Value

Parameter Description

0x00

Stereo.

0x01

Joint stereo.

0x02

Dual.

0x03

Mono.

sample_counts:

Size: 2 octets

Value

Parameter Description

0xXXXX

The frame size is the number of samples per frame, representing the number of samples in a frame of data.

sampling_freq:

Size: 4 octets

Value Parameter Description
48000, 44100, 32000,
24000, 22050, 16000,
11025, 12000, 8000
The sample rate for encoding or decoding.
The supported values are 32000, 44100, and 48000 in HZ for MPEG-1 Layer 3.
Additional 16000, 22050, and 24000 in HZ for MPEG-2 Layer 3, and
additional 8000, 11025, and 12000 in HZ for MPEG-2.5 Layer 3.

bitrate:

Size: 4 octets

Value

Parameter Description

8000 ~ 320000 bit/s

Bitrate for decoding.

version:

Size: 1 octet

Value

Parameter Description

0

MPEG Version 2.5 (unofficial).

1

Reserved.

2

MPEG Version 2 (ISO/IEC 13818-3).

3

MPEG Version 1 (ISO/IEC 11172-3).

layer:

Size: 1 octet

Value

Parameter Description

0

Reserved.

1

Layer 3.

2

Layer 2.

3

Layer 1.

ACI_CMD_SET_FRAME_CONTENT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_SET_FRAME_CONTENT(abandon)

0x5009

frame_content

ACI_EVENT_REQ_MEDIA_FRAME

Description

Set MP3 frames to play.

Command Parameters

frame_content:

Size: N octets

Parameter Description

N octets of each MP3 frame in the file.

ACI_CMD_XM_ENTER_HCI_MODE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_ENTER_HCI_MODE

0x8000

None

None

Description

Set the device into the HCI mode.

Command Parameters

None.

ACI_CMD_XM_DEVICE_REBOOT

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_DEVICE_REBOOT

0x8001

None

ACI_EVENT_AUDIO_DEVICE_STATE

Description

SW reboots after 1 sec.

Command Parameters

None.

ACI_CMD_XM_MMI

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_MMI

0x8004

action

None

Description

Makes MMI actions.

Command Parameters

action:

Size: 1 octet

Value

Parameter Description

Return Event

0x01

XM_MMI_MODE_LOCAL_PLAY

None

0x02

XM_MMI_MODE_A2DP_SOURCE

None

0x03

XM_MMI_BT_BOND_CLEAR_ALL

None

Command Detail:

  • XM_MMI_MODE_LOCAL_PLAY: Switch music mode to local playback.

  • XM_MMI_MODE_A2DP_SOURCE: Switch music mode to A2DP Source mode.

  • XM_MMI_BT_BOND_CLEAR_ALL: Delete all bond information in bond storage.

ACI_CMD_XM_BT_SET_ADDR

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_BT_SET_ADDR

0x8005

bt_addr

None

Description

Modify the Bluetooth address of the device (only can be used in the power on status, and will take effect after a factory reset).

Command Parameters

bt_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

MAC address.

ACI_CMD_XM_SPP_DATA_TRANSFER

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_SPP_DATA_TRANSFER

0x8006

link_id,
payload_length, payload

None

Description

Send vendor SPP data.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for BR/EDR link.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Value

Parameter Description

0xXXXX (N bytes)

N octets of the payload in this packet.

ACI_CMD_XM_GET_FACTORY_RESET

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_GET_FACTORY_RESET

0x80C3

None

ACI_EVENT_XM_FACTORY_RESET_STATUS

Description

Get factory reset status.

Command Parameters

None.

ACI_CMD_XM_USER_CFM_REQ

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_USER_CFM_REQ

0x8013

cfm_val

None

Description

The user confirms for BR/EDR pairing.

Command Parameters

cfm_val:

Size: 1 octet

Value

Parameter Description

1 or 0

True or false.

ACI_CMD_XM_LE_START_ADVERTISING

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_START_ADVERTISING

0x8040

duration

None

Description

Start LE advertising.

Command Parameters

duration:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE advertising duration in seconds, little endian.

ACI_CMD_XM_LE_STOP_ADVERTISING

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_STOP_ADVERTISING

0x8041

None

None

Description

Stop LE advertising.

Command Parameters

None.

ACI_CMD_XM_LE_DISC

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_DISC

0x8042

link_id

None

Description

Disconnect LE link(s).

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0x00-0xfe

Disconnect APP layer ID for LE link.

0xff

Disconnect all LE links.

ACI_CMD_XM_LE_CONN_PARAM_UPDATE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_CONN_PARAM_UPDATE

0x8043

link_id, conn_interval,
conn_latency,
conn_supervision_timeout

None

Description

Update LE connection params.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for a LE link.

conn_interval:

Size: 2 octets

Value

Parameter Description

0xXXXX

Set LE preferred connection interval to conn_interval * 1.25 ms, little endian.

conn_latency:

Size: 2 octets

Value

Parameter Description

0xXXXX

Set LE preferred connection latency to conn_latency, little endian.

conn_supervision_timeout:

Size: 2 octets

Value

Parameter Description

0xXXXX

Set LE preferred connection supervision timeout to conn_supervision_timeout * 10ms, little endian.

ACI_CMD_XM_LE_ADV_DATA_UPDATE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_ADV_DATA_UPDATE

0x8044

adv_data_len, adv_data

None

Description

Update LE advertising data.

Command Parameters

adv_data_len:

Size: 2 octets

Value

Parameter Description

0xXX

ADV data length, must be less than 31 bytes.

adv_data:

Size: adv_data_len octets

Parameter Description

New advertising data payload.

ACI_CMD_XM_LE_SCAN_RSP_DATA_UPDATE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_SCAN_RSP_DATA_UPDATE

0x8045

scan_rsp_data_len,
scan_rsp_data

None

Description

Update LE scan response data.

Command Parameters

scan_rsp_data_len:

Size: 2 octets

Value

Parameter Description

0xXX

Scan response data length, must be less than 31 bytes, little-endian.

scan_rsp_data:

Size: scan_rsp_data_len octets

Parameter Description

New scan response data payload.

ACI_CMD_XM_LE_ADV_INTVAL_UPDATE

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_ADV_INTVAL_UPDATE

0x8046

adv_interval

None

Description

Update LE advertising interval.

Command Parameters

adv_interval:

Size: 2 octets

Value

Parameter Description

0xXXXX

Set LE advertising interval to adv_interval * 0.625ms (must be between 20ms and 10.25s),
little endian.

ACI_CMD_XM_LE_ATT_GET_MTU

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_ATT_GET_MTU

0x8047

link_id

ACI_EVENT_XM_LE_ATT_MTU

Description

Get LE ATT MTU size.

Command Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for an LE link.

ACI_CMD_XM_LE_GET_ADDR

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_GET_ADDR

0x8048

None

ACI_EVENT_XM_LE_ADDR

Description

Get LE address.

Command Parameters

None.

ACI_CMD_XM_LE_BOND_DEL

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_BOND_DEL

0x804A

addr_type, addr

None

Description

Delete LE bond with the address.

Command Parameters

addr_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_REMOTE_ADDR_LE_PUBLIC

0x01

GAP_REMOTE_ADDR_LE_RANDOM

0x02

GAP_REMOTE_ADDR_LE_PUBLIC_IDENTITY

0x03

GAP_REMOTE_ADDR_LE_RANDOM_IDENTITY

0x10

GAP_REMOTE_ADDR_CLASSIC

0xff

GAP_REMOTE_ADDR_LE_ANONYMOUS

addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Address for every remote device.

ACI_CMD_XM_LE_ADV_CREATE

Command

Opcode

Command Parameters

Return Event

CMD_XM_LE_ADV_CREATE

0x804B

adv_handle, adv_prop, interval_min, interval_max, own_addr_type, own_addr, peer_addr_type, peer_addr, adv_data_len, adv_data, scan_rsp_len, scan_rsp

ACI_EVENT_XM_LE_ADV_CREATED

Description

Create a customized advertisement.

Command Parameters

adv_handle:

Size: 1 octet

Value

Parameter Description

0xXX

Handle for an ADV set. For this command, it is useless.

adv_prop:

Size: 1 octet

Value

Parameter Description

0x13

LE_EXT_ADV_LEGACY_ADV_CONN_SCAN_UNDIRECTED

0x15

LE_EXT_ADV_LEGACY_ADV_CONN_LOW_DUTY_DIRECTED

0x1D

LE_EXT_ADV_LEGACY_ADV_CONN_HIGH_DUTY_DIRECTED

0x12

LE_EXT_ADV_LEGACY_ADV_SCAN_UNDIRECTED

0x10

LE_EXT_ADV_LEGACY_ADV_NON_SCAN_NON_CONN_UNDIRECTED

interval_min, interval_max:

Size: 2 octet, in units of 0.625ms, range: 0x000020 to 0xFFFFFF

Value

Parameter Description

0xXXXX

ADV interval.

own_addr_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_LOCAL_ADDR_LE_PUBLIC

0x01

GAP_LOCAL_ADDR_LE_RANDOM

0x02

GAP_LOCAL_ADDR_LE_RAP_OR_PUBLIC

0x03

GAP_LOCAL_ADDR_LE_RAP_OR_RAND

own_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXXXX

own_addr

peer_addr_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_REMOTE_ADDR_LE_PUBLIC

0x01

GAP_REMOTE_ADDR_LE_RANDOM

0x02

GAP_REMOTE_ADDR_LE_PUBLIC_IDENTITY

0x03

GAP_REMOTE_ADDR_LE_RANDOM_IDENTITY

0x10

GAP_REMOTE_ADDR_CLASSIC

0xff

GAP_REMOTE_ADDR_LE_ANONYMOUS

peer_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXXXX

peer_addr

adv_data_len:

Size: 2 octets

Value

Parameter Description

0xXXXX

adv_data_len

adv_data:

Size: adv_data_len octet

Value

Parameter Description

0xXX…

adv_data

adv_data_len:

Size: 2 octets

Value

Parameter Description

0xXXXX

adv_data_len

adv_data:

Size: adv_data_len octet

Value

Parameter Description

0xXX…

adv_data

scan_rsp_len:

Size: 2 octet

Value

Parameter Description

0xXXXX

scan_rsp_len

scan_rsp:

Size: scan_rsp_len octet

Value

Parameter Description

0xXX…

scan_rsp

ACI_CMD_XM_LE_BOND_DEL_ALL

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_BOND_DEL_ALL

0x804C

None

None

Description

Delete all bond info.

ACI_CMD_XM_MUSIC

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_MUSIC

0x8080

type, seq, data

ACI_EVENT_XM_MUSIC_REQ_FRAME

Description

Control music session flow.

ACK

When the type is 0x05 (Music session send single frame), ACK status (ACI_EVENT_ACK) would be 0x08, which means request MCU for another music frame.

Command Parameters

type:

Size: 1 octet

Value

Parameter Description

0x00

Music session open.

0x01

Music session pause.

0x02

Music session resume.

0x03

Music session abort.

0x04

Music session close.

0x05

Music session send single frame.

Others

Reserved.

seq:

Size: 1 octet

Value Parameter Description
0x00 - 0xFF Seq is fixed at 0x00 when type is:
Music session open.
Music session pause.
Music session resume.
Music session abort.
Music session close.
Music session send single frame.

data:

Size: N octets

Parameter Description

N octets of music data.

ACI_CMD_XM_TTS

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_TTS

0x8081

type, seq, len, data

ACI_EVENT_XM_TTS_REQ_FRAME

Description

Control TTS session flow.

ACK

When the type is 0x05 (TTS session send single frame) or 0x08 (TTS session send end frame), ACK status (ACI_EVENT_ACK) would be 0x07, which means request MCU for another TTS frame.

Command Parameters

type:

Size: 1 octet

Value

Parameter Description

0x00

TTS Session Open.

0x01

TTS session pause.

0x02

TTS session resume.

0x03

TTS session abort.

0x04

TTS session close.

0x05

TTS session send single frame.

0x06

TTS session send start frame.

0x07

TTS session send continue frame.

0x08

TTS session send end frame.

Others

Reserved.

seq:

Size: 1 octet

Value Parameter Description
0x00 - 0xFF Seq is fixed at 0x00 when type is:
TTS session open.
TTS session pause.
TTS session resume.
TTS session abort.
TTS session close.
TTS session send single frame.
TTS session send start frame.
Seq is increased by 1 when type is:
TTS session send continue frame.
TTS session send end frame.

len:

Size: 2 octets

Value

Parameter Description

0x0000-0xFFFF

TTS encoded data length.

data:

Size: len octets

Parameter Description

TTS encoded data.

ACI_CMD_XM_START_RECORD

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_START_RECORD

0x8082

audio_type,
audio_params

ACI_EVENT_XM_RECORDING_DATA

Description

Start recording.

Command Parameters

audio_type:

Size: 1 octet

Value

Parameter Description

0x00

PCM

0x01

CVSD

0x02

mSBC

0x03

SBC

0x04

AAC

0x05

OPUS

0x06

FLAC

0x07

MP3

0x08

LC3

0x09

LDAC

pcm_params:

Sample Rate(Hz) [4 Bytes]

Frame Length(octets)
[2 Bytes]

Channel Number
[1 Byte]

Bit Width
[1 Byte]

Supported values are 8000, 16000, 44100, 48000,
and 96000.

xx.

1 (Mono) or 2 (Stereo).

16 or 24.

opus_params:

Sample Rate(Hz)
[4 Bytes]

Channel Num
[1 Byte]

CBR [1 byte]

CVBR [1 byte]

Supported value is 16000.

1 (Mono).

0 for VBR and 1 for CBR.

0 for VBR and 1 for CVBR.

Mode
[1 byte]

Complexity
[1 byte]

frame_duration [1 byte]

Bitrate [4 bytes]

The supported 3 for CELT-only.

From 0 to 3.

0 (2.5ms), 1 (5ms), 2 (10ms), 3 (20ms), 4 (40ms), 5 (60ms), 6 (80ms), 7 (100ms), 8 (120ms).

From 6000 bit/s to 510000 bit/s.

msbc_params or sbc_params:

Sample Rate(Hz) [4 Bytes]

Channel Number
[1 Byte]

block_length
[1 byte]

Supported values are 8000, 16000, 44100, and 48000 in Hz.

1 (Mono) or 2 (Stereo).

4, 8, 12, 16.

subband_num [1 byte]

allocation_method [1 byte]

Bitpool [1 byte]

4 or 8.

0 for Loudness and 1 for SNR.

from 2 to 250.

lc3_params:

Sample Rate(Hz) [4 Bytes]

Channel Allocation() [4 Byte]

frame_length [2 byte]

Supported values are 16000, 48000.

0 (Mono).

40 for 16k and 120 for 48k.

frame_duration [1 byte]

Presentation Delay [4 byte]

0 for 7.5ms and 1 for 10ms.

From 0 to 0xFFFFFFFF in microsecond units.

ACI_CMD_XM_STOP_RECORD

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_STOP_RECORD

0x8503

None

None

Description

Stop recording.

Command Parameters

None.

ACI_CMD_XM_START_RECORD_PLAY

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_START_RECORD_PLAY

0x8504

audio_type

None

Description

Start record play.

Command Parameters

audio_type:

Size: 1 octet

Value

Parameter Description

0x00

PCM

0x01

CVSD

0x02

mSBC

0x03

SBC

0x04

AAC

0x05

OPUS

0x06

FLAC

0x07

MP3

0x08

LC3

0x09

LDAC

pcm_params:

Sample Rate(Hz) [4 Bytes]

Frame Length
[2 Bytes]

Channel Number
[1 Byte]

Bit Width
[1 Byte]

8000, 16000, 44100, 48000,
96000.

xx.

1 (Mono) or 2 (Stereo).

16 or 24.

opus_params:

Sample Rate(Hz) [4 Bytes]

Channel Number
[1 Byte]

CBR [1 byte]

CVBR [1 byte]

8000, 16000, 44100, 48000,
96000.

1 (Mono) or 2 (Stereo).

0 for VBR and 1 for CBR.

0 for VBR and 1 for CVBR.

Mode [1 byte]

Complexity [1 byte]

1 for SILK-only.
2 for Hybrid (SILK+
CELT).
3 for CELT-only.

From 0 to 10.

frame_duration
[1 byte]

Bitrate [4 bytes]

0 (2.5ms), 1 (5ms), 2 (10ms), 3 (20ms), 4 (40ms), 5 (60ms), 6 (80ms), 7 (100ms), 8 (120ms).

From 6000 bit/s to 510000 bit/s.

ACI_CMD_XM_STOP_RECORD_PLAY

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_STOP_RECORD_PLAY

0x8505

None

None

Description

Stop record play.

Command Parameters

None.

ACI_CMD_XM_RECORD_PLAY_DATA

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_RECORD_PLAY_DATA

0x8086

record_data

None

Description

Send record data to play, need to start record play first.

Command Parameters

record_data:

Size: 1024 octets

Parameter Description

1024 octets of PCM data.

ACI_CMD_XM_SET_VOLUME_LEVEL

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_SET_VOLUME_LEVEL

0x8088

volume, type

None

Description

Set playback or voice volume depending on the scenario.

Command Parameters

volume:

level Size: 1 octet

Value

Parameter Description

0xXX

0~15 (volume level).

type:

Size: 1 octet

Value

Parameter Description

0x00

HFP_VOL

0x01

LOCAL_VOL

0x02

A2DP_SRC_VOL

0x03

RINGTONE_VOL

0x04

VP_VOL

0x05

TTS_VOL

0x06

RECORD_VOL

0x07

RECORD_MIC_VOL

ACI_CMD_XM_AUDIO_TEST_GET_PA_ID

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_AUDIO_TEST_GET_PA_ID

0x8089

None

ACI_EVENT_XM_AUDIO_TEST_PA_ID

Description

Get PA ID.

Command Parameters

None.

ACI_CMD_XM_AUDIO_TEST_BYPASS

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_AUDIO_TEST_BYPASS

0x808A

audio_mode

None

Description

Set audio algorithm bypass mode or normal mode.

Command Parameters

audio_mode:

Size: 1 octet

Value

Parameter Description

0x00

Normal mode.

0x01

Bypass mode.

ACI_CMD_XM_GATT_ACI

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_GATT_ACI

0x8007

conn_handle, cid, pkt_type,
handle_index, total_length,
payload_length, payload

None

Description

Transfer GATT data from UART.

Command Parameters

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

The connection handle from HCI, 0x01 for BR/EDR and 0x13 for LE.

cid:

Size: 2 octets

Value

Parameter Description

0xXXXX

The channel ID for corresponding L2CAP channel, For BR/EDR, set it to 0x0000 for test. For LE, it is fixed to 0x0004.

type:

Size: 1 octet

Value

Parameter Description

0x00

Single packet.

0x01

Fragmented start packet.

0x02

Fragmented continue packet.

0x03

Fragmented end packet.

handle_index:

Size: 1 octet

Value

Attribute

Parameter Description

0x01

fd04

Service 02fd.

0x11

4

Service unlock.

0x12

7

Service unlock.

0x21

2

Service factory.

0x61

17

Service HID.

0x71

2

Service HRS.

0x81

4

Service goodix.

total_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total payload length.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Value

Parameter Description

0xXXXX (N bytes)

N octets of the payload in this packet.

ACI_CMD_XM_SNIFF_MODE_CTRL

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_SNIFF_MODE_CTRL

0x8009

sniff_mode_enabled,
sniff_mode_interval

None

Description

Enable or disable sniff mode for all BR/EDR links.

Command Parameters

sniff_mode_enabled:

Size: 1 octet

Value

Parameter Description

0 or 1

Means false or true to enable sniff mode.

sniff_mode_interval:

Size: 2 octets

Value

Parameter Description

0xXXXX

Sniff mode interval.

ACI_CMD_XM_LE_USER_CFM_REQ

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_LE_USER_CFM_REQ

0x8013

conn_id, cfm_result

None

Description

Confirm LE Connection.

Command Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0x00

Default.

cfm_result:

Size: 1 octet

Value

Parameter Description

0x00

False.

0x01

True.

ACI_CMD_XM_DISABLE_VERBOSE_LOG

Command

Opcode

Command Parameters

Return Event

ACI_CMD_XM_DISABLE_VERBOSE_LOG

0x80C0

log_type, log_key, module,
level, turnon

None

Description

Close/open the log.

Command Parameters

log_type:

Size: 1 octet

Value

Parameter Description

0x01

Close/open all current logs.

0x02

Close/open different module logs.

log_key:

Size: 1 octet

Value

Parameter Description

0x00

Close all current logs.

0x01

Open all previously closed logs.

module:

Size: 1 octet

Value

Parameter Description

0x00~0x09

Platform modules.

0x0c~0x23

Device modules.

0x30~0x3f

Stack modules.

level:

Size: 1 octet

Value

Parameter Description

0x00

LEVEL_ERROR

0x01

LEVEL_WARN

0x02

LEVEL_INFO

0x03

LEVEL_TRACE

turn on:

Size: 1 octet

Value

Parameter Description

0x00

Turn off.

0x01

Turn on.

ACI_CMD_CHARGING_CASE_LE_CONTROL

Command

Opcode

Command Parameters

Return Event

ACI_CMD_CHARGING_CASE_LE_CONTROL

0x8100

cmd_id, cmd_data

None

Description

Send CMD to the headset by LE.

Command Parameters

cmd_id:

Size: 2 octets

Value

Parameter Description

0x0004

CMD_MMI

0x001F

CMD_SET_VP_VOLUME

0x0205

CMD_AUDIO_EQ_INDEX_SET

0x020A

CMD_SET_VOLUME

0x0704

CMD_SET_KEY_MMI_MAP

mmi_data:

Size: 1 octet

Value

Parameter Description

0x02

End an outgoing call.

0x03

Answer an incoming call.

0x04

Reject an incoming call.

0x05

End an active call.

0x06

MIC mute toggle.

0x07

MIC mute.

0x08

MIC unmute.

0x30

Volume up.

0x31

Volume down.

0x32

AV play/pause.

0x34

AV forward.

0x35

AV backward.

0x36

AV fast forward.

0x37

AV rewind.

0x80

Switch to gaming mode.

0xD3

Light sensor on/off.

vp_volume_data:

Size: 1 octet

Value

Parameter Description

0x00 ~ 0x0F

VP volume level.

eq_set_data:

Size: 1 octet

Value

Parameter Description

0xXX

EQ index.

volume_data:

Size: 1 octet

Value

Parameter Description

0xXX

0~maximum (volume level).

mmi_map_data:

Size: 1 octet

Value

Parameter Description

0x30

Set MFB as volume up button.

0x31

Set MFB as volume down button.

ACI Events

Summary of ACI Events

Opcode

Command

Available

0x0000

ACI_EVENT_ACK

Y

0x0001

ACI_EVENT_BT_REPLY_PAIRED_RECORD

Y

0x0002

ACI_EVENT_LEGACY_DATA_TRANSFER

Y

0x0003

ACI_EVENT_PROFILE_CONN_STATUS

Y

0x0004

ACI_EVENT_PROFILE_CONNECT_FAIL_STATUS

Y

0x0005

ACI_EVENT_HFP_CALLER_ID

Y

0x0007

ACI_EVENT_AUDIO_DEVICE_STATE

Y

0x0009

ACI_EVENT_BR_REMOTE_NAME

Y

0x000A

ACI_EVENT_HFP_CALL_STATUS

Y

0x000B

ACI_EVENT_AUDIO_PLAYER_STATUS

Y

0x0013

ACI_EVENT_VOLUME_SYNC

Y

0x0014

ACI_EVENT_BR_LINK_STATUS

Y

0x0018

ACI_EVENT_REPORT_CFG_TYPE

Y

0x0019

ACI_EVENT_REPORT_STATUS

Y

0x001A

ACI_EVENT_GET_BD_ADDR

Y

0x001C

ACI_EVENT_REPORT_DLPS_STATUS

Y

0x001D

ACI_EVENT_REPORT_KEY_ACTION

Y

0x0020

ACI_EVENT_AUDIO_VOL_CHANGE

Y

0x0023

ACI_EVENT_BT_READY

Y

0x0025

ACI_EVENT_BR_INQUIRY_STATE

Y

0x0026

ACI_EVENT_SERVICES_SEARCH_STATE

Y

0x002B

ACI_EVENT_BR_INQUIRY_RESULT

Y

0x0100

ACI_EVENT_LE_CONNECTED

Y

0x0101

ACI_EVENT_LE_DISCONNECTED

Y

0x0102

ACI_EVENT_LE_PAIR_STATUS

Y

0x0103

ACI_EVENT_LE_VENDOR_DATA_TRANSFER

Y

0x0110

ACI_EVENT_ANCS_REGISTER_COMPLETE

Y

0x0111

ACI_EVENT_ANCS_NOTIFICATION

Y

0x0112

ACI_EVENT_ANCS_ACTION_RESULT

Y

0x0120

ACI_EVENT_AMS_REGISTER_COMPLETE

Y

0x0121

ACI_EVENT_AMS_ENTITY_UPD_NOTIFY

Y

0x0122

ACI_EVENT_AMS_ENTITY_UPD_NOTIFY_EN

Y

0x0123

ACI_EVENT_AMS_REMOTE_CMD_NOTIFY

Y

0x0124

ACI_EVENT_AMS_REMOTE_CMD_NOTIFY_EN

Y

0x0140

ACI_EVENT_LE_AUDIO_SCAN_INFO

Y

0x0141

ACI_EVENT_LE_AUDIO_BAP_STATE

Y

0x0142

ACI_EVENT_LE_AUDIO_BAP_DISCOVERY_DONE

Y

0x0143

ACI_EVENT_LE_AUDIO_CSIS_SCAN_STATE

Y

0x0144

ACI_EVENT_LE_AUDIO_ADD_GROUP

Y

0x0145

ACI_EVENT_LE_AUDIO_ADD_SYNC_HANDLE

Y

0x0146

ACI_EVENT_LE_AUDIO_BAAS_SCAN_INFO

Y

0x0147

ACI_EVENT_LE_AUDIO_PA_SYNC_STATE

Y

0x0300

ACI_EVENT_SCO_STATE

Y

0x0301

ACI_EVENT_CALL_WAITING

Y

0x0306

ACI_EVENT_SUBSCRIBER_NUMBER

Y

0x0307

ACI_EVENT_CURRENT_CALLS

Y

0x0308

ACI_EVENT_DTMF

Y

0x0381

ACI_EVENT_HFP_AG_CONN_CMPL

Y

0x0389

ACI_EVENT_HFP_AG_SUPPORTED_FEATURES

Y

0x038D

ACI_EVENT_HFP_AG_CURR_CALLS_LIST_QUERY

Y

0x0396

ACI_EVENT_HFP_AG_NETWORK_NAME_FORMAT_SET

Y

0x3160

ACI_EVENT_DFU_START_RSP

Y

0x3161

ACI_EVENT_DFU_DATA_REQ

Y

0x3162

ACI_EVENT_DFU_RESULT

Y

0x3163

ACI_EVENT_DFU_LOCAL_VERSION

Y

0x0A0E

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

Y

0x3252

ACI_APP_EVENT_CCP_CALL_STATUS

Y

0x3253

ACI_APP_EVENT_MCP_MEDIA_STATE

Y

0x3256

ACI_APP_EVENT_VCS_STATE

Y

0x0904

ACI_EVENT_BT_BOND_INFO_CLEAR

Y

0x0909

ACI_EVENT_FW_VERSION

Y

0x0911

ACI_EVENT_REPORT_PACKAGE_ID

Y

0x5001

ACI_EVENT_REQ_MEDIA_FRAME

Y

0x8000

ACI_EVENT_XM_SPP_DATA_TRANSFER

Y

0x8001

ACI_EVENT_XM_SPP_CONNECT_STATUS

Y

0x8002

ACI_EVENT_XM_SPP_DISCONNECT_STATUS

Y

0x8003

ACI_EVENT_XM_BR_ATT_CONNECTED

Y

0x8004

ACI_EVENT_XM_BR_ATT_DISCONNECTED

Y

0x8005

ACI_EVENT_XM_GATT_DATA_TRANSFER

Y

0x8006

ACI_EVENT_XM_GATT_CREDIT_UPDATE

Y

0x8040

ACI_EVENT_XM_LE_ADV_STATE

Y

0x8041

ACI_EVENT_XM_LE_ATT_MTU

Y

0x8042

ACI_EVENT_XM_LE_ADDR

Y

0x8043

ACI_EVENT_XM_LE_CON_STATE

Y

0x8044

ACI_EVENT_XM_LE_CON_PARAM

Y

0x8045

ACI_EVENT_XM_GATT_CON_NOTIFY

Y

0x8046

ACI_EVENT_XM_LE_USER_CONFIRMATION_REQ

Y

0x8048

ACI_EVENT_XM_LE_ADV_CREATED

Y

0x80C0

ACI_EVENT_XM_FACTORY_RESET_STATUS

Y

0x8500

ACI_EVENT_XM_MUSIC_REQ_FRAME

Y

0x8501

ACI_EVENT_XM_TTS_REQ_FRAME

Y

0x8502

ACI_EVENT_XM_RECORDING_DATA

Y

0x8600

ACI_EVENT_XM_AUDIO_TEST_PA_ID

Y

0x8700

ACI_EVENT_XM_BT_AVRCP_STATUS

Y

0x8800

ACI_EVENT_XM_USER_CONFIRMATION_REQ

Y

ACI_EVENT_ACK

Event

Opcode

Event Parameters

ACI_EVENT_ACK

0x0000

cmd_id, status

Description

Acks the received command for device.

Event Parameters

cmd_id:

Size: 2 octets

Value

Parameter Description

0xXX

The command ID to ACK.

status:

Size: 1 octet

Value

Parameter Description

0x00

Command complete: BTM can handle this command.

0x01

Command disallow: BTM cannot handle this command.

0x02

Unknown CMD.

0x03

Parameters error.

0x04

Busy.

0x05

Process fail maybe due to stack resource.

0x07

TTS frame send success and request for another TTS frame.

0x08

Music frame send success and request for another music frame.

0x09

SPP transfer success when sent to phone.

0x10

SPP transfer failed when sent to phone.

0x11

GATT transfer can continue sending to phone.

0x12

GATT transfer cannot continue sending to phone.

Others

Reserved.

ACI_EVENT_BT_REPLY_PAIRED_RECORD

Event

Opcode

Event Parameters

ACI_EVENT_BT_REPLY_PAIRED_RECORD

0x0001

paired_device_number, paired_record

Description

Reply to the Read_Paired_Device_Information command.

Event Parameters

paired_device_number:

Size: 1 octet

Value

Parameter Description

0xXX

paired_device_number

paired_record:

Size: (8*total_record) octets

Value Parameter Description
byte0 Link priority: 1 is the highest (newest device) and 4 (or 8) is the lowest (oldest
device).
byte1 bond_flag:
Bit0: HFP or HSP profile bond.
Bit1: A2DP profile bond.
Bit2: SPP or IAP profile bond.
Bit3: Reserved for PBAP.
Bit4: Remote device supports content protection.
Bit5: Remote device supports delay report.
Bit6: Link key type is authenticated type.
Bit7: Reserved.
byte2~byte7 Linked device Bluetooth address.
ACI_EVENT_LEGACY_DATA_TRANSFER

Command

Opcode

Event Parameters

ACI_EVENT_LEGACY_DATA_TRANSFER

0x0002

link_id, payload_length,
payload

Description

Report SPP data to the MCU host.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Link_id, this index will be informed when the link is established (event: ACI_EVENT_PROFILE_CONN_STATUS).

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Parameter Description

N octets of the payload in this packet.

ACI_EVENT_PROFILE_CONN_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_PROFILE_CONN_STATUS

0x0003

link_id, connect_status,
address

Description

Report the current Bluetooth profiles connect status.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Bluetooth profile link ID.

connect_status:

Size: 4 octets

Value

Parameter Description

0x00

Reserved.

0x00000001

A2DP_SINK_PROFILE_MASK

0x00000002

AVRCP_CONTROLLER_PROFILE_MASK

0x00000004

HFP_HF_PROFILE_MASK

0x00000080

HSP_AG_PROFILE_MASK

0x00000200

MAP_MSE_PROFILE_MASK

0x00000400

A2DP_SRC_PROFILE_MASK

0x00000800

AVRCP_TARGET_PROFILE_MASK

0x00001000

HFP_AG_PROFILE_MASK

0x00002000

PBAP_PSE_PROFILE_MASK

0x00004000

HSP_HF_PROFILE_MASK

address:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

The remote device Bluetooth address.

ACI_EVENT_PROFILE_CONNECT_FAIL_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_PROFILE_CONNECT_FAIL_STATUS

0x0004

link_id, disconnect_status,
address, cause

Description

Report the Bluetooth profile’s disconnect status.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Bluetooth profile link ID.

connect_status:

Size: 1 octet

Value

Parameter Description

0x00

Reserved.

0x00000001

A2DP_SINK_PROFILE_MASK

0x00000002

AVRCP_CONTROLLER_PROFILE_MASK

0x00000004

HFP_HF_PROFILE_MASK

0x00000080

HSP_AG_PROFILE_MASK

0x00000200

MAP_MSE_PROFILE_MASK

0x00000400

A2DP_SRC_PROFILE_MASK

0x00000800

AVRCP_TARGET_PROFILE_MASK

0x00001000

HFP_AG_PROFILE_MASK

0x00002000

PBAP_PSE_PROFILE_MASK

0x00004000

HSP_HF_PROFILE_MASK

address:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

The remote device Bluetooth address.

cause:

Size: 2 octets

Value

Parameter Description

0xXX

Reason for disconnect.

ACI_EVENT_HFP_CALLER_ID

Event

Opcode

Event Parameters

ACI_EVENT_HFP_CALLER_ID

0x0005

reserved, type, length, string

Description

Report the caller’s phone number and the caller’s name.

Event Parameters

reserved:

Size: 1 octet

Value

Parameter Description

0xFF

Reserved.

type:

Size: 1 octet

Value

Parameter Description

0x00

Caller phone number.

0x01

Caller name.

Others

Reserved.

length:

Size: 1 octet

Value

Parameter Description

0xXX

Length of caller ID unit in byte.

string:

Size: N octets

Parameter Description
N octets of caller ID.
If the type is number, the encoder is ASCII.
If the type is name, the encoder is UTF-8.
ACI_EVENT_AUDIO_DEVICE_STATE

Event

Opcode

Event Parameters

ACI_EVENT_AUDIO_DEVICE_STATE

0x0007

state

Description

Report the device state.

Event Parameters

state:

Size: 1 octet

Value

Parameter Description

0x00

APP_STATE_OFF

0x01

APP_STATE_ON

0x02

APP_DEVICE_STATE_OFF_ING

Others

Reserved.

ACI_EVENT_BR_REMOTE_NAME

Event

Opcode

Event Parameters

ACI_EVENT_BR_REMOTE_NAME

0x0009

status, bd_addr, name

Description

Report the remote device name when Bluetooth connected.

Event Parameters

status:

Size: 1 octet

Value

Parameter Description

0x00

Success.

Others

Fail.

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Remote device address with low byte first.

name:

Size: N octets

Parameter Description

N octets of UTF-8 string with NULL terminate.

ACI_EVENT_HFP_CALL_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_HFP_CALL_STATUS

0x000A

bd_addr, prev_status, curr_status

Description

Report the call status of the connected device.

Event Parameters

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

MAC address of the remote connected device whose call status has changed.

prev_status:

Size: 1 octet

Value

Parameter Description

0x00

CALL_IDLE

0x01

VOICE_ACTIVATION_ONGOING

0x02

INCOMING_CALL_ONGOING

0x03

OUTGOING_CALL_ONGOING

0x04

CALL_ACTIVE

0x05

CALL_ACTIVE_WITH_CALL_WAITING

0x06

CALL_ACTIVE_WITH_CALL_HOLD

Others

Reserved.

curr_status:

Size: 1 octet

Value

Parameter Description

0x00

CALL_IDLE

0x01

VOICE_ACTIVATION_ONGOING

0x02

INCOMING_CALL_ONGOING

0x03

OUTGOING_CALL_ONGOING

0x04

CALL_ACTIVE

0x05

CALL_ACTIVE_WITH_CALL_WAITING

0x06

CALL_ACTIVE_WITH_CALL_HOLD

Others

Reserved.

ACI_EVENT_AUDIO_PLAYER_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_AUDIO_PLAYER_STATUS

0x000B

reserved, status, reserved

Description

Report the current play status.

Event Parameters

reserved:

Size: 6 octets

Value

Parameter Description

0xXX

Reserved.

status:

Size: 1 octet

Value

Parameter Description

0x00

Stop.

0x01

Playing.

0x02

Paused.

reserved:

Size: 1 octet

Value

Parameter Description

0xXX

Reserved.

ACI_EVENT_VOLUME_SYNC

Event

Opcode

Event Parameters

ACI_EVENT_VOLUME_SYNC

0x0013

address, volume

Description

Report volume setting to sync with the remote device during calls.

Event Parameters

address:

Size: 6 octets

Value

Parameter Description

0xXX

The remote device Bluetooth address.

volume:

Size: 1 octet

Value

Parameter Description

0xXX

HFP volume.

ACI_EVENT_REPORT_CFG_TYPE

Event

Opcode

Event Parameters

ACI_EVENT_REPORT_CFG_TYPE

0x0018

get_type, name_len, name

Description

Report configuration settings.

Event Parameters

get_type:

Size: 1 octet

Value

Parameter Description

0x00

LE name.

0x01

Legacy name.

name_len:

Size: 1 octet

Value

Parameter Description

0xXX

Name length.

name:

Size: name_len octets

Parameter Description

Name payload.

ACI_EVENT_REPORT_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_REPORT_STATUS

0x0019

status_index,
status_value0,
status_value1,

Description

Report status information.

Event Parameters

status_index:

Size: 1 octet

Value

Parameter Description

0xA1

Volume.

volume:

Size: 1 octet

Value

Parameter Description

0xXX

0~maximum gain.

maximum gain:

Size: 1 octet

Value

Parameter Description

0xXX

Maximum gain.

ACI_EVENT_GET_BD_ADDR

Event

Opcode

Event Parameters

ACI_EVENT_GET_BD_ADDR

0x001A

bd_addr

Description

Report the Bluetooth device address.

Event Parameters

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Bluetooth address.

ACI_EVENT_REPORT_DLPS_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_REPORT_DLPS_STATUS

0x001C

dlps_status

Description

Report DLPS status.

Event Parameters

dlps_status:

Size: 1 octet

Value

Parameter Description

0x00

DLPS disabled.

0x01

DLPS enabled.

ACI_EVENT_REPORT_KEY_ACTION

Event

Opcode

Event Parameters

ACI_EVENT_REPORT_KEY_ACTION

0x001D

key_mask, scenario, action

Description

Report GPIO key action.

Event Parameters

key_mask:

Size: 1 octet

Value Parameter Description
0xXX Bit mask:
0x01: KEY0_MASK.
0x02: KEY1_MASK.
0x04: KEY2_MASK.
0x08: KEY3_MASK.
0x10: KEY4_MASK.
0x20: KEY5_MASK.
0x40: KEY6_MASK.
0x80: KEY7_MASK.

scenario:

Size: 1 octet

Value Parameter Description
0xXX 0x00: Short click.
0x01: Long press.
0x03: 2 clicks.
0x04: 3 clicks.
0x05: 4 clicks.
0x06: 5 clicks.

action:

Size: 1 octet

Value Parameter Description
0xXX MMI action.
ACI_EVENT_AUDIO_VOL_CHANGE

Event

Opcode

Event Parameters

ACI_EVENT_AUDIO_VOL_CHANGE

0x0020

status, current_vol

Description

Report volume change information to the remote device.

Event Parameters

status:

Size: 1 octet

Value

Parameter Description

0x00

VolChangeNone

0x01

VolChangeUp

0x02

VolChangeDown

0x03

VolChangeMax

0x04

VolChangeMin

current_vol:

Size: 1 octet

Value

Parameter Description

0xXX

Current volume.

ACI_EVENT_BT_READY

Event

Opcode

Event Parameters

ACI_EVENT_BT_READY

0x0023

bd_addr

Description

Report both Bluetooth and Bluetooth LE stacks are checked ready.

Event Parameters

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Bluetooth address.

ACI_EVENT_BR_INQUIRY_STATE

Event

Opcode

Event Parameters

ACI_EVENT_BR_INQUIRY_STATE

0x0025

state

Description

Report the inquiry state.

Event Parameters

state:

Size: 1 octet

Value

Parameter Description

0x00

Inquiry process has been completed.

0x01

Inquiry process has been canceled.

0x02

Inquiry process contains a valid inquiry result.

0x03

Inquiry process failed.

ACI_EVENT_SERVICES_SEARCH_STATE

Event

Opcode

Event Parameters

ACI_EVENT_SERVICES_SEARCH_STATE

0x0026

state, bd_addr

Description

Report the service search state.

Event Parameters

state:

Size: 1 octet

Value

Parameter Description

0x00

Service search process success.

0x01

Service search process fail.

0x02

Service search process stop.

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Bluetooth address.

ACI_EVENT_BR_INQUIRY_RESULT

Event

Opcode

Event Parameters

ACI_EVENT_BR_INQUIRY_RESULT

0x002B

bd_addr, cod, name_len, name

Description

Report inquiry results.

Event Parameters

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXX

MAC address of inquired device.

cod:

Size: 4 octets

Value

Parameter Description

0xXX

Class of device.

name_len:

Size: 1 octet

Value

Parameter Description

0xXX

Length of the inquired device.

name:

Size: name_len octets

Value

Parameter Description

0xXX

Device name of the inquired device.

ACI_EVENT_LE_CONNECTED

Event

Opcode

Event Parameters

ACI_EVENT_LE_CONNECTED

0x0100

link_id

Description

Indicates LE link connected.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

ACI_EVENT_LE_DISCONNECTED

Event

Opcode

Event Parameters

ACI_EVENT_LE_DISCONNECTED

0x0101

link_id, result_code

Description

Indicates LE link disconnection.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

result_code:

Size: 2 octets

Value

Parameter Description

0xXXXX

Disconnect cause.

ACI_EVENT_LE_PAIR_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_LE_PAIR_STATUS

0x0102

link_id, status

Description

Indicate LE link pair status.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP link ID for LE link.

status:

Size: 2 octets

Value

Parameter Description

0x00

Success.

Others

Fail.

ACI_EVENT_LE_VENDOR_DATA_TRANSFER

Command

Opcode

Event Parameters

ACI_EVENT_LE_VENDOR_DATA_TRANSFER

0x0103

link_id, pkt_type, total_length, payload_length = total_length, payload

Description

Send data to SPP by LE link.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Link_id, the identifier for LE link.

type:

Size: 1 octet

Value

Parameter Description

0x00

Single packet.

0x02

Fragmented continue packet.

0x03

Fragmented end packet.

total_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total payload length.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: payload_length octets

Parameter Description

N octets of the payload in this packet.

ACI_EVENT_ANCS_REGISTER_COMPLETE

Event

Opcode

Event Parameters

ACI_EVENT_ANCS_REGISTER_COMPLETE

0x0110

link_id, result

Description

Inform the ANCS discovery completed.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

result:

Size: 1 octet

Value

Parameter Description

0x00

Register success.

ACI_EVENT_ANCS_NOTIFICATION

Event

Opcode

Event Parameters

ACI_EVENT_ANCS_NOTIFICATION

0x0111

link_id,
ancs_data_type,
pkt_type,
total len,
pkt_len,
pkt_data

Description

Send the ANCS notification data.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

ancs_data_type:

Size: 1 octet

Value

Parameter Description

0x00

ANCS_FROM_DATA_SOURCE

0x01

ANCS_FROM_NOTIFICATION_SOURCE

pkt_type:

Size: 1 octet

Value

Parameter Description

0x00

PKT_TYPE_SINGLE

0x01

PKT_TYPE_START

0x02

PKT_TYPE_CONT

0x03

PKT_TYPE_END

total len:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total len.

pkt_len:

Size: 2 octets

Value

Parameter Description

0xXXXX

pkt_len

pkt_data:

Size: 2 octets

Value

Parameter Description

0xXX, …

pkt_data

ACI_EVENT_ANCS_ACTION_RESULT

Event

Opcode

Event Parameters

ACI_EVENT_ANCS_ACTION_RESULT

0x0112

link_id, cause

Description

Inform the action result.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

cause:

Size: 1 octet

Value

Parameter Description

0x00

Success.

0x4A0

Command ID was not recognized by the NP.

0x4A1

Command was improperly formatted.

0x4A2

One of the parameters (for example, the NotificationUID) does not refer to an existing object on the NP.

0x4A3

The action was not performed.

ACI_EVENT_AMS_ENTITY_UPD_NOTIFY

Event

Opcode

Event Parameters

ACI_EVENT_AMS_ENTITY_UPD_NOTIFY

0x0121

link_id, pkt_type, total len, pkt_len, pkt_data

Description

Notify the entity to update data.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

pkt_type:

Size: 1 octet

Value

Parameter Description

0x00

PKT_TYPE_SINGLE

0x01

PKT_TYPE_START

0x02

PKT_TYPE_CONT

0x03

PKT_TYPE_END

total len:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total len.

pkt_len:

Size: 2 octets

Value

Parameter Description

0xXXXX

pkt_len

pkt_data:

Size: 2 octets

Value

Parameter Description

0xXX, …

pkt_data

ACI_EVENT_AMS_ENTITY_UPD_NOTIFY_EN

Event

Opcode

Event Parameters

ACI_EVENT_AMS_ENTITY_UPD_NOTIFY_EN

0x0122

link_id

Description

Entity update notification was enabled.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

ACI_EVENT_AMS_REMOTE_CMD_NOTIFY

Event

Opcode

Event Parameters

ACI_EVENT_AMS_REMOTE_CMD_NOTIFY

0x0123

link_id, pkt_type, total len, pkt_len, pkt_data

Description

Notify the remote CMD data.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

pkt_type:

Size: 1 octet

Value

Parameter Description

0x00

PKT_TYPE_SINGLE

0x01

PKT_TYPE_START

0x02

PKT_TYPE_CONT

0x03

PKT_TYPE_END

total len:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total len.

pkt_len:

Size: 2 octets

Value

Parameter Description

0xXXXX

pkt_len

pkt_data:

Size: 2 octets

Value

Parameter Description

0xXX, …

pkt_data

ACI_EVENT_AMS_REMOTE_CMD_NOTIFY_EN

Event

Opcode

Event Parameters

ACI_EVENT_AMS_REMOTE_CMD_NOTIFY_EN

0x0124

link_id

Description

This event means the remote command notification is enabled.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

ACI_EVENT_LE_AUDIO_SCAN_INFO

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_SCAN_INFO

0x0140

event_type,
addr_type,
addr,
name_len,
name

Description

Report advertisements from devices supporting LE Audio.

Event Parameters

event_type:

Size: 2 octets

Value

Parameter Description

0xXXXX

Reported ADV type.

addr_type:

Size: 1 octet

Value

Parameter Description

0xXX

Advertiser address type.

addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Advertiser address.

name_len:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Length of advertiser name.

name:

Size: 40 octets

Value

Parameter Description

0xXX, …

Advertiser name.

ACI_EVENT_LE_AUDIO_BAP_STATE

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_BAP_STATE

0x0141

group_handle, state

Description

Report BAP state.

Event Parameters

group_handle:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

Group handle.

state:

Size: 1 octet

Value

Parameter Description

0xXX

BAP streaming state.

ACI_EVENT_LE_AUDIO_BAP_DISCOVERY_DONE

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_BAP_DISCOVERY_DONE

0x0142

link_id

Description

Indicates the BAP related info has been completely discovered.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

Link ID.

ACI_EVENT_LE_AUDIO_CSIS_SCAN_STATE

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_CSIS_SCAN_STATE

0x0143

group_handle, state

Description

Reports the group scan state of the group handle.

Event Parameters

group_handle:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

Group handle.

state:

Size: 1 octet

Value

Parameter Description

0x00

Scan stopped.

0x01

Scan started.

ACI_EVENT_LE_AUDIO_ADD_GROUP

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_ADD_GROUP

0x0144

group_handle_count

Description

Report the count of group handles.

Event Parameters

group_handle_count:

Size: 1 octet

Value

Parameter Description

0xXX

The count of group handles.

ACI_EVENT_LE_AUDIO_ADD_SYNC_HANDLE

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_ADD_SYNC_HANDLE

0x0145

sync_handle_count

Description

Report the count of sync handles.

Event Parameters

sync_handle_count:

Size: 1 octet

Value

Parameter Description

0xXX

The count of sync handles.

ACI_EVENT_LE_AUDIO_BAAS_SCAN_INFO

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_BAAS_SCAN_INFO

0x0146

scan_baas_dev_count,
addr_type,
addr,
name_len,
name

Description

Report advertisement information of BAAS scan.

Event Parameters

scan_baas_dev_count:

Size: 2 octets

Value

Parameter Description

0xXXXX

Device count of BAAS scan.

addr_type:

Size: 1 octet

Value

Parameter Description

0xXX

Advertiser address type.

addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Advertiser address.

name_len:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Length of advertiser name.

name:

Size: 40 octet

Value

Parameter Description

0xXX, …

Advertiser name.

ACI_EVENT_LE_AUDIO_PA_SYNC_STATE

Event

Opcode

Event Parameters

ACI_EVENT_LE_AUDIO_PA_SYNC_STATE

0x0147

sync_state

Description

Report PA sync state.

Event Parameters

sync_state:

Size: 1 octet

Value

Parameter Description

0x04

GAP_PA_SYNC_STATE_SYNCHRONIZED

0x05

GAP_PA_SYNC_STATE_TERMINATING

ACI_EVENT_SCO_STATE

Event

Opcode

Event Parameters

ACI_EVENT_SCO_STATE

0x0300

connect_status, address

Description

Report SCO connect state.

Event Parameters

connect_status:

Size: 1 octet

Value

Parameter Description

0x00

SCO connect indication.

0x01

SCO link established.

0x02

SCO link disconnect.

address:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

The remote device Bluetooth address.

ACI_EVENT_CALL_WAITING

Event

Opcode

Event Parameters

ACI_EVENT_CALL_WAITING

0x0301

num_len, number

Description

Report the third call information (can add other info if needed).

Event Parameters

num_len:

Size: 1 octet

Value

Parameter Description

num_len

Number length.

number:

Size: num_len * 1 octet

Value

Parameter Description

0x00…

Caller phone number.

ACI_EVENT_SUBSCRIBER_NUMBER

Event

Opcode

Event Parameters

ACI_EVENT_SUBSCRIBER_NUMBER

0x0306

service, type,
num_len,
number

Description

Report local phone information.

Event Parameters

service:

Size: 1 octet

Value

Parameter Description

0xXX

Service.

type:

Size: 1 octet

Value

Parameter Description

0xXX

Type.

num_len:

Size: 1 octet

Value

Parameter Description

0xXX

Length of phone number.

number:

Size: N octets

Parameter Description

N octets of caller number.

ACI_EVENT_CURRENT_CALLS

Event

Opcode

Event Parameters

ACI_EVENT_CURRENT_CALLS

0x0307

call_idx,
dir_incoming,
status,
mode,
mpty,
type,
num_len,
number

Description

Report current call info.

Event Parameters

call_idx:

Size: 1 octet

Value

Parameter Description

0xXX

call_idx

dir_incoming:

Size: 1 octet

Value

Parameter Description

0x00

Outgoing.

0x01

Incoming.

status:

Size: 1 octet

Value

Parameter Description

0x00

Active.

0x01

Held.

0x02

Dialing.

0x03

Alerting.

0x04

Incoming.

0x05

Waiting.

0x06

Call held by response and hold.

mode:

Size: 1 octet

Value

Parameter Description

0x00

Voice.

0x01

Data.

0x03

Fax.

mpty:

Size: 1 octet

Value

Parameter Description

0x00

Call is not a member of a multi-party call.

0x01

Call is a member of a multi-party call.

type:

Size: 1 octet

Value

Parameter Description

0xXX

Type.

num_len:

Size: 1 octet

Value

Parameter Description

0xXX

num_len

number:

Size: N octets

Parameter Description

N octets of number.

ACI_EVENT_DTMF

Event

Opcode

Event Parameters

ACI_EVENT_DTMF

0x0308

Vchar

Description

Report the key value entered by the user.

Event Parameters

Vchar:

Size: 1 octet

Value

Parameter Description

0xXX

Vchar.

ACI_EVENT_HFP_AG_CONN_CMPL

Event

Opcode

Event Parameters

ACI_EVENT_HFP_AG_CONN_CMPL

0x0381

bd_addr

Description

Report the key value entered by the user.

Event Parameters

bd_addr:

Size: 6 octets

Value

Parameter Description

0xXX

MAC address of HFP AG connection.

ACI_EVENT_HFP_AG_SUPPORTED_FEATURES

Event

Opcode

Event Parameters

ACI_EVENT_HFP_AG_SUPPORTED_FEATURES

0x0389

link_id, feature_bitmap

Description

This event is used to describe the HFP AG support features.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for BR/EDR link.

feature_bitmap:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

HFP AG support features.

ACI_EVENT_HFP_AG_CURR_CALLS_LIST_QUERY

Event

Opcode

Event Parameters

ACI_EVENT_HFP_AG_CURR_CALLS_LIST_QUERY

0x038D

link_id

Description

Report the current calls list query.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for BR/EDR link.

ACI_EVENT_HFP_AG_NETWORK_NAME_FORMAT_SET

Event

Opcode

Event Parameters

ACI_EVENT_HFP_AG_NETWORK_NAME_FORMAT_SET

0x0396

link_id

Description

Report the network name format set.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for BR/EDR link.

ACI_EVENT_DFU_START_RSP

Event

Opcode

Event Parameters

ACI_EVENT_DFU_START_RSP

0x3160

status

Description

Accept or reject DFU request.

Event Parameters

status:

Size: 1 octet

Value

Parameter Description

0x00

UART_DFU_REJECT

0x01

UART_DFU_ACCEPT

ACI_EVENT_DFU_DATA_REQ

Event

Opcode

Event Parameters

ACI_EVENT_DFU_DATA_REQ

0x3161

offset, length

Description

Request specific DFU data.

Event Parameters

offset:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

next_block_offset

length:

Size: 2 octets

Value

Parameter Description

0xXX

next_block_length

ACI_EVENT_DFU_RESULT

Event

Opcode

Event Parameters

ACI_EVENT_DFU_RESULT

0x3162

result

Description

Report DFU result.

Event Parameters

result:

Size: 1 octet

Value

Parameter Description

0x00

UART_DFU_FAIL

0x01

UART_DFU_SUCCESS

ACI_EVENT_DFU_LOCAL_VERSION

Event

Opcode

Event Parameters

ACI_EVENT_DFU_LOCAL_VERSION

0x3163

local_version

Description

Report device’s local version.

Event Parameters

local_version:

Size: 1 octet

Value

Parameter Description

0xXXXXXXXX

Version.

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

Event

Opcode

Event Parameters

ACI_APP_EVENT_TRI_DONGLE_EVENT_REPORT

0x0A0E

sub_report_event_id,
sub_event_report_parameters

Description

Report event related to Tri dongle.

Event Parameters

sub_report_event_id:

Size: 1 octet

Value

Parameter Description

0x00

LE scan report.

0x01

BR scan report.

0x02

LE BAS not support report.

0x03

LE RSSI not support report.

0x04

LE DIS info report.

0x05

LE BAS info report.

0x06

HF battery info report.

0x07

Connected LE link info report.

0x08

Connected BR link info report.

0x09

LE connection info report.

0x0A

PASSKEY value report.

0x0B

LE RSSI info report.

0x0C

BR RSSI info report.

0x0D

LE scan status report.

0x0E

BR inquiry scan status report.

0x0F

USB reset status report.

0x10

PASSKEY status report.

0x11

ACL authen success report.

0x12

LE bond list report.

0x13

LE DIS not support report.

0x14

LE DIS SYSTEM info report.

0x15

LE DIS PNP info report.

0x16

BR bond list report.

0x17

BR RSSI not support report.

sub_event_report_parameters:

Size: 50 octets

Sub_report_event_id

Sub Event Report Parameter Description

0x00
LE scan report

bd_addr (6 octets, Little-Endian),
RSSI (1 octet),
le_addr_type (1 octet),
device_type_len (1 octet),
device_type (2 octets, Little-Endian, 03C1 = Keyboard,
03C2 = Mouse),
name_len (1 octet),
name (correspond to name len)

0x01
BR scan report

bd_addr (6 octets, Little-Endian),
RSSI (1 octet),
name_len (1 octet),
name (correspond to name len)

0x02
LE BAS not support report

bd_addr (6 octets for 1 Device)

0x03
LE RSSI not support report

bd_addr (6 octets for 1 Device)

0x04
LE DIS info report

UUID (2 octets, Little-Endian),
bd_addr (6 octets for 1 Device),
dis_info_len (2 octets, Little-Endian),
dis_info (correspond to dis_info len)

0x05
LE BAS info report

battery_level (1 octet),
bd_addr (6 octets for 1 Device)

0x06
Hf battery info report

battery_level (1 octet),
bd_addr (6 octets for 1 Device)

0x07
Connected LE link info report

Connected_LE_link_num (1 octet),
bd_addr (6 octets for 1 Device, if has multiple devices connected,
the next device bd_addr will append after)

0x08
Connected BR link info report

Connected_BR_link_num (1 octet),
bd_addr (6 octets)

0x09
LE connection info report

LE connection status (1 octet, 0 = disconnect, 1 = connected),
bd_addr (6 octets)

0x0A
LE PAIR PASSKEY info report

PASSKEY INFO (3 octets, Little-Endian)

0x0B
LE RSSI info report

RSSI (1 octet),
bd_addr (6 octets for 1 Device)

0x0C
BR RSSI info report

RSSI (1 octet),
bd_addr (6 octets for 1 Device)

0x0D
LE scan status report

status (1 octet, 0 = stop, 1 = start)

0x0E
BR inquiry scan status report

status (1 octet, 0 = stop, 1 = start)

0x0F
USB reset status report

status (1 octet, 0 = ready, 1 = reset)

0x10
PASSKEY status report

status (1 octet, 0 = disable, 1 = enable)

0x11
ACL authen success report

bd_addr (6 octets for 1 Device),
link_id (1 octet),
conn_handle (2 octets)

0x12
LE bond list report

LE device number (1 octet)

0x13
LE DIS not support report

UUID (2 octets, Little-Endian),
bd_addr (6 octets for 1 Device)

0x14
LE DIS SYSTEM info report

UUID (2 octets, Little-Endian),
bd_addr (6 octets for 1 Device),
dis_system_len (2 octets, Little-Endian),
mid (5 octets),
oui (3 octets)

0x15
LE DIS PNP info report

UUID (2 octets, Little-Endian),
bd_addr (6 octets for 1 Device),
dis_pnp_len (2 octets, Little-Endian),
vendor_id (2 octets),
product_id (2 octets),
product_version (2 octets),
vendor_id_source (1 octet)

0x16
BR bond list report

BR device number (1 octet),
bd_addr (6 octets for 1 Device, if has multiple devices connected,
the next device bd_addr will append after)

0x17
BR RSSI not support report

bd_addr (6 octets for 1 Device)

ACI_APP_EVENT_CCP_CALL_STATUS

Event

Opcode

Event Parameters

ACI_APP_EVENT_CCP_CALL_STATUS

0x3252

conn_id, call_status

Description

Report the device current call status.

Event Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0xxx

Connect ID.

call_status:

Size: 1 octet

Value

Parameter Description

0x00

APP_CALL_IDLE

0x01

APP_VOICE_ACTIVATION_ONGOING

0x02

APP_CALL_INCOMING

0x03

APP_CALL_OUTGOING

0x04

APP_CALL_ACTIVE

0x05

APP_CALL_ACTIVE_WITH_CALL_WAITING

0x06

APP_CALL_ACTIVE_WITH_CALL_HELD

0x07

APP_MULTILINK_CALL_ACTIVE_WITH_CALL_WAIT

0x08

APP_MULTILINK_CALL_ACTIVE_WITH_CALL_HELD

ACI_APP_EVENT_MCP_MEDIA_STATE

Event

Opcode

Event Parameters

ACI_APP_EVENT_MCP_MEDIA_STATE

0x3253

conn_id, media_state

Description

Report the device current media state.

Event Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0xxx

Connect ID.

media_state:

Size: 1 octet

Value

Parameter Description

0x00

MCS_MEDIA_STATE_INACTIVE

0x01

MCS_MEDIA_STATE_PLAYING

0x02

MCS_MEDIA_STATE_PAUSED

0x03

MCS_MEDIA_STATE_SEEKING

ACI_APP_EVENT_VCS_STATE

Event

Opcode

Event Parameters

ACI_APP_EVENT_VCS_STATE

0x3253

vol_setting, mute

Description

Report the device current audio volume.

Event Parameters

vol_setting:

Size: 1 octet

Value

Parameter Description

0xXX

Current volume value of the audio.

mute:

Size: 1 octet

Value

Parameter Description

0x00

SPK unmute state.

0x01

SPK mute state.

ACI_EVENT_BT_BOND_INFO_CLEAR

Event

Opcode

Event Parameters

ACI_EVENT_BT_BOND_INFO_CLEAR

0x0904

status

Description

Return the result of clearing the link keys of the target remote connection.

Event Parameters

status:

Size: 1 octet

Value

Parameter Description

0x00

Clear link keys successful.

0x01

Fail to clear link keys, or if there are no link keys, the device will return fail if still using clear band info CMD.

ACI_EVENT_FW_VERSION

Event

Opcode

Event Parameters

ACI_EVENT_FW_VERSION

0x0909

fw_version(app, patch, app_ui)

Description

Report firmware version information.

Event Parameters

app:

Size: 5 octets

Value

Parameter Description

0xXXXXXXXXXX

APP version.

patch:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

Patch version.

app_ui:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

APP UI version.

ACI_EVENT_REPORT_PACKAGE_ID

Event

Opcode

Event Parameters

ACI_EVENT_REPORT_PACKAGE_ID

0x0911

chip_id, package_id

Description

Report chip ID and package ID.

Event Parameters

chip_id:

Size: 1 octet

Value

Parameter Description

0x1B

RTL87x3E.

package id:

Size: 1 octet

Value

Parameter Description

0x04

Reserved.

ACI_EVENT_REQ_MEDIA_FRAME

Event

Opcode

Event Parameters

ACI_EVENT_REQ_MEDIA_FRAME

0x5001

audio_queue_state, water_level

Description

Report SCO connect state.

Event Parameters

audio_queue_state:

Size: 1 octet

Value

Parameter Description

0x00

STATE_PRELOAD

0x01

STATE_CONSUME

0x02

STATE_CHARGE

0x03

STATE_OFFLOAD

0x04

STATE_EMPTY

water_level:

Size: 2 octets

Value

Parameter Description

0xXXXX

Counts of buffered frames.

ACI_EVENT_XM_SPP_DATA_TRANSFER

Command

Opcode

Event Parameters

ACI_EVENT_XM_SPP_DATA_TRANSFER

0x8000

link_id, payload_length, payload

Description

This command is used to report vendor SPP data to the MCU host.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for BR/EDR link.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Parameter Description

N octets of the payload in this packet.

ACI_EVENT_XM_SPP_CONNECT_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_XM_SPP_CONNECT_STATUS

0x8001

connect_status, address

Description

Report vendor SPP connect status.

Event Parameters

connect_status:

Size: 1 octet

Value

Parameter Description

0x00

Reserved.

0x10

VENDOR_SPP_PROFILE_MASK

address:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

The remote device Bluetooth address.

ACI_EVENT_XM_SPP_DISCONNECT_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_XM_SPP_DISCONNECT_STATUS

0x8002

disconnect_status, address,
cause

Description

Report vendor SPP disconnect status.

Event Parameters

connect_status:

Size: 1 octet

Value

Parameter Description

0x00

Reserved.

0x10

VENDOR_SPP_PROFILE_MASK

address:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

The remote device Bluetooth address.

cause:

Size: 2 octets

Value

Parameter Description

0xXX

Reason of disconnect.

ACI_EVENT_XM_LE_ADV_STATE

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_ADV_STATE

0x8040

adv_state, adv_stop_cause

Description

Report LE advertising state, adv_stop_cause only valid when adv_state is 0x00.

Event Parameters

adv_state:

Size: 1 octet

Value

Parameter Description

0x00

Advertising disabled.

0x01

Advertising enabled.

adv_stop_cause:

Size: 1 octet

Value

Parameter Description

0x00

LE ADV stop cause UNKNOWN.

0x01

LE ADV stop cause APP, user terminate ADV.

0x02

LE ADV stop cause CONN, connection establish.

0x03

LE ADV stop cause TIMEOUT, ADV timeout.

0x04

LE ADV stop cause ENABLE_FAILED, ADV enable failed.

ACI_EVENT_XM_LE_ATT_MTU

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_ATT_MTU

0x8041

mtu_size

Description

Report LE ATT MTU size, only valid when LE is connected.

Event Parameters

mtu_size:

Size: 2 octets

Value

Parameter Description

0xXX

LE ATT MTU size.

ACI_EVENT_XM_LE_ADDR

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_ADDR

0x8042

le_addr

Description

Report the LE address.

Event Parameters

le_addr:

Size: 6 octets

Value

Parameter Description

0xXX

LE address.

ACI_EVENT_XM_LE_CON_STATE

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_CON_STATE

0x8043

conn_state,
link_id,
conn_handle,
role,
remote_type,
remote_addr,
connInterval,
connLatency,
supTimeout

Description

Report LE connect state after LE is connected.

Event Parameters

conn_state:

Size: 1 octet

Value

Parameter Description

0x00

LE_LINK_STATE_DISCONNECTED

0x01

LE_LINK_STATE_CONNECTING

0x02

LE_LINK_STATE_CONNECTED

0x03

LE_LINK_STATE_DISCONNECTING

link_id:

Size: 1 octet

Value

Parameter Description

0xxx

APP layer ID for LE link.

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

It starts from 0x0013. For only one LE link, it will be 0x0013.

role:

Size: 1 octet

Value

Parameter Description

0x00

GAP_LINK_ROLE_UNDEFINED

0x01

GAP_LINK_ROLE_MASTER

0x02

GAP_LINK_ROLE_SLAVE

remote_type:

Size: 1 octet

Value

Parameter Description

0x00

GAP_LINK_ROLE_UNDEFINED

0x01

GAP_LINK_ROLE_MASTER

0x02

GAP_LINK_ROLE_SLAVE

remote_type:

Size: 1 octet

Value

Parameter Description

0x00

LE Public device address type.

0x01

LE Random device address type.

0x02

LE Public identity address type.

0x03

LE Random identity address type.

0x04

BR/EDR device address type.

0x05

LE anonymous device address type.

remote_addr:

Size: 6 octets

Value

Parameter Description

0xxx 0xxx 0xxx 0xxx 0xxx 0xxx

Remote device address.

connInterval:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE preferred connection interval to conn_interval * 1.25 ms, little endian.

connLatency:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE preferred connection latency to conn_latency, little endian.

supTimeout:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE preferred connection supervision timeout to conn_supervision_timeout * 10ms,
little endian.

ACI_EVENT_XM_LE_CON_PARAM

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_CON_PARAM

0x8044

link_id,
connInterval_min,
connInterval_max,
connLatency,
supTimeout

Description

Report the LE Parameter state after LE update parameters.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xxx

APP layer ID for LE link.

connInterval_min:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE preferred connection interval to conn_interval * 1.25 ms, little endian.

connInterval_max:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE preferred connection interval to conn_interval * 1.25 ms, little endian.

connLatency:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE prefer connection latency to conn_latency, little endian.

supTimeout:

Size: 2 octets

Value

Parameter Description

0xXXXX

LE prefer connection supervision timeout to conn_supervision_timeout * 10ms,
little endian.

ACI_EVENT_XM_GATT_CON_NOTIFY

Event

Opcode

Event Parameters

ACI_EVENT_XM_GATT_CON_NOTIFY

0x8045

conn_handle, cid, xm_service,
attr_index, value

Description

Report GATT service notify state.

Event Parameters

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

The connection handle from HCI (for a simple test, it is 0x01 for BR/EDR and 0x13 for LE).

cid:

Size: 2 octets

Value

Parameter Description

0xXXXX

The channel ID for corresponding L2CAP channel. For BR/EDR, it is allocated dynamically. For LE, however, it is fixed to 0x0004.

xm_service:

Size: 1 octet

Value

Parameter Description

0x00

T_DEVICE_SERVICE

0x01

T_XM_UNLOCK_SERVICE

0x02

T_XM_FACTORY_SERVICE

0x03

T_XM_SERVICE

0x04

T_XM_ALIPAY_SERVICE

0x05

T_XM_WECHAT_SERVICE

0x06

T_HID_SERVICE

0x07

T_HRS_SERVICE

0x08

T_GOODIX_SERVICE

attr_index:

Size: 1 octet

Value

Parameter Description

0xXX

Each service has its attr and show this latter.

value:

Size: 1 octet

Value

Parameter Description

0x01

Enable.

0x02

Disable.

ACI_EVENT_XM_GATT_DATA_TRANSFER

Event

Opcode

Event Parameters

ACI_EVENT_XM_GATT_DATA_TRANSFER

0x8005

conn_handle,
cid,
type,
handle_index,
total_length,
payload_length,
payload

Description

Report GATT data to UART.

Event Parameters

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

The connection handle from HCI (for a simple test, it is 0x01 for BR/EDR and 0x13 for LE).

cid:

Size: 2 octets

Value

Parameter Description

0xXXXX

The channel ID for corresponding L2CAP channel. For BR/EDR, it is allocated dynamically. For LE, however, it is fixed to 0x0004.

type:

Size: 1 octet

Value

Parameter Description

0x00

Single packet.

0x01

Fragmented start packet.

0x02

Fragmented continue packet.

0x03

Fragmented end packet.

handle_index:

Size: 1 octet

Value

Attribute

Parameter Description

0x01

fd04

Service 02fd.

0x11

4

Service unlock.

0x12

7

Service unlock.

0x21

2

Service factory.

0x61

20

Service HID.

0x71

7

Service HRS.

0x81

2

Service goodix.

total_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Total payload length.

payload_length:

Size: 2 octets

Value

Parameter Description

0xXXXX

Payload length in this packet.

payload:

Size: N octets

Parameter Description

N octets of the payload in this packet.

ACI_EVENT_XM_GATT_CREDIT_UPDATE

Event

Opcode

Event Parameters

ACI_EVENT_XM_GATT_CREDIT_UPDATE

0x8006

conn_handle,
cid,
credit

Description

Report GATT credit updated.

Event Parameters

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

The connection handle from HCI (for a simple test, it is 0x01 for BR/EDR and 0x13 for LE).

cid:

Size: 2 octets

Value

Parameter Description

0xXXXX

The channel ID for the corresponding L2CAP channel. For BR/EDR, it is allocated dynamically. For LE, however, it is fixed to 0x0004.

credit:

Size: 2 octets

Value

Parameter Description

0xXXXX

Number of credit for GATT TX.

ACI_EVENT_XM_FACTORY_RESET_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_XM_FACTORY_RESET_STATUS

0x80c0

freset_done

Description

Report device factory reset status.

Event Parameters

freset_done:

Size: 1 octet

Value

Parameter Description

0x00

Factory reset not done.

0x01

Factory reset done.

ACI_EVENT_XM_MUSIC_REQ_FRAME

Event

Opcode

Event Parameters

ACI_EVENT_XM_MUSIC_REQ_FRAME

0x8500

None

Description

Request MCU to send the next music frame.

Event Parameters

None.

ACI_EVENT_XM_TTS_REQ_FRAME

Event

Opcode

Event Parameters

ACI_EVENT_XM_TTS_REQ_FRAME

0x8501

tts_state

Description

Request MCU to send the next TTS frame.

Event Parameters

tts_state:

Size: 1 octet

Value

Parameter Description

0x01

TTS_STATE_STARTED

0x04

TTS_STATE_RESUMED

0x06

TTS_STATE_ABORTING

0x07

TTS_STATE_STOPPED

ACI_EVENT_XM_RECORDING_DATA

Event

Opcode

Event Parameters

ACI_EVENT_XM_RECORDING_DATA

0x8502

recording_data

Description

Report recording data format.

Event Parameters

recording_data:

Size: 1024 octets

Parameter Description

1024 octets of recording data.

ACI_EVENT_XM_AUDIO_TEST_PA_ID

Event

Opcode

Event Parameters

ACI_EVENT_XM_AUDIO_TEST_PA_ID

0x8600

pa_id

Description

Report PA ID.

Event Parameters

pa_id:

Size: 1 octet

Value

Parameter Description

0x76

PA ID.

ACI_EVENT_XM_BT_AVRCP_STATUS

Event

Opcode

Event Parameters

ACI_EVENT_XM_BT_AVRCP_STATUS

0x8700

avrcp_state,
vol_number,
address

Description

Report the AVRCP command status.

Event Parameters

avrcp_state:

Size: 1 octet

Value

Parameter Description

0x01

AVRCP_STATE_PLAY

0x02

AVRCP_STATE_PAUSE

0x03

AVRCP_STATE_STOP

0x04

AVRCP_STATE_FORWARD

0x05

AVRCP_STATE_BACKWARD

0x06

AVRCP_STATE_VOL_CHANGED

vol_number:

Size: 1 octet

Value

Parameter Description

0xXX

Only AVRCP_STATE_VOL_CHANGED have the Parameters.

address:

Size: 6 octets

Value

Parameter Description

0xXX

The remote device Bluetooth address.

ACI_EVENT_XM_BR_ATT_CONNECTED

Event

Opcode

Event Parameters

ACI_EVENT_XM_BR_ATT_CONNECTED

0x8003

conn_handle,
cid

Description

Reports the BR/EDR ATT protocol is connected.

Event Parameters

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

It starts from 0x0001. For only one BR/EDR link, it will be 0x0001.

cid:

Size: 2 octets

Value

Parameter Description

0xXXXX

The L2CAP channel ID, it is currently set to 0x0000.

ACI_EVENT_XM_BR_ATT_DISCONNECTED

Event

Opcode

Event Parameters

ACI_EVENT_XM_BR_ATT_DISCONNECTED

0x8006

conn_handle,
cid

Description

Report that the BR/EDR ATT protocol is disconnected.

Event Parameters

conn_handle:

Size: 2 octets

Value

Parameter Description

0xXXXX

It starts from 0x0001. For only one BR/EDR link, it will be 0x0001.

cid:

Size: 2 octets

Value

Parameter Description

0xXXXX

The L2CAP channel ID, it is currently set to 0x0000.

ACI_EVENT_XM_USER_CONFIRMATION_REQ

Event

Opcode

Event Parameters

ACI_EVENT_XM_USER_CONFIRMATION_REQ

0x8800

remote_addr,
cfmcode,
handle_idx

Description

Request confirmation to connect.

Event Parameters

remote_addr:

Size: 6 octets

Value

Parameter Description

0xXXXXXXXXXXXX

Remote address.

cfmcode:

Size: 4 octets

Value

Parameter Description

0xXXXXXXXX

Confirm code, need to convert to decimal.

handle_idx:

Size: 1 octet

Value

Parameter Description

0xXX

Connect handle_idx.

ACI_EVENT_XM_LE_USER_CONFIRMATION_REQ

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_USER_CONFIRMATION_REQ

0x8046

conn_id,
display_value

Description

Request LE confirmation to connect.

Event Parameters

conn_id:

Size: 1 octet

Value

Parameter Description

0xxx

Connect ID.

display_value:

Size: 4 octets

Value

Parameter Description

0xxxxxxxxx

Confirm code, need to convert to decimal.

ACI_EVENT_XM_LE_ADV_CREATED

Event

Opcode

Event Parameters

ACI_EVENT_XM_LE_ADV_CREATED

0x8048

adv_handle

Description

Report adv_handle for the ADV created by ACI_CMD_XM_LE_ADV_CREATE.

Event Parameters

adv_handle:

Size: 1 octet

Value

Parameter Description

0xXX

adv_handle

ACI_EVENT_AMS_REGISTER_COMPLETE

Event

Opcode

Event Parameters

ACI_EVENT_AMS_REGISTER_COMPLETE

0x0120

link_id,
result

Description

Report AMS discovery completed.

Event Parameters

link_id:

Size: 1 octet

Value

Parameter Description

0xXX

APP layer ID for LE link.

result:

Size: 1 octet

Value

Parameter Description

0x00

Register success.

ACI Host CLI Tool

ACI Host CLI Tool is a test tool running on PC under the path RTL87X3E-MCU-SDK-Common-v3.1x.x.xx_20xxxxxx\tool\AciHostCLI-v1.0.0.xx-Common_SDK, which is used to demo ACI usage. It can perform CMD/event communication tests with ACI Device through USB serial port.

The steps to run ACI Host CLI Tool are as follows:

  1. Open config.yml to modify the device’s serial port and baud rate settings.

  2. Run AciHostCLI.exe to start the application.

  3. Execute mmi freset to perform a factory reset.

  4. Enter mmi pwron to power on the device.

  5. Wait for EVENT_DEVICE_STATE to return 1 (Power on).

Command Introduction

BR Connection

Use case: Connection and Linkback Function.

Command Description ACI Command
connect headset_sample Connect to a BUD with a specific address. ACI_CMD_BT_CREATE_CONNECTION
connect idx Need inquiry first, select an index, connect to that BUD.
connect phone_sample Connect to a phone with a specific address.
disconnect headset_sample Disconnect BUD. ACI_CMD_BT_DISCONNECT
disconnect phone_sample Disconnect phone.

Man Machine Interface

Command Description ACI Command
mmi end_outgoing_call End an outgoing call. ACI_CMD_MMI
mmi answer Answer an incoming call.
mmi reject Reject an incoming call.
mmi end_active_call End an active call.
mmi pwron Power on the device.
mmi pwroff Power off the device.
mmi freset Device factory reset.

SPP Transfer

Command Description ACI Command
spp t0_sig Send single frame data to ACI_Device and relay to phone via SPP profile. ACI_CMD_LEGACY_DATA_TRANSFER
spp t2_start Send start frame data to ACI_Device and relay to phone via SPP profile.
spp t3_con Send continue frame data to ACI_Device and relay to phone via SPP profile.
spp t4_end Send end frame data to ACI_Device and relay to phone via SPP profile.

Assign RX Buffer Size

Command Description ACI Command
assign buffer Assign UART RX buffer size, if set to 128, SPP/LE data will split into several frames with max size 128. ACI_CMD_ASSIGN_BUFFER_SIZE

Set Configuration

Command Description ACI Command
set le_name Set the LE name (represented in UTF-8), which will be effective after restart. ACI_CMD_SET_CFG
set legacy_name Set Bluetooth legacy name, which will be effective after restart.

Get Configuration

Command Description ACI Command
get le_name Get the LE name (represented in UTF-8). ACI_CMD_GET_CFG_SETTING
get legacy_name Get Bluetooth legacy device name.

Get Status

Command Description ACI Command
get volume Get playback or HFP volume depending on scenario. ACI_CMD_GET_STATUS

Phone Call

Use case: HFP Function.

Command Description ACI Command
call 10086 Make phone call to 10086. ACI_APP_CMD_BT_HFP_DIAL_WITH_NUMBER
call 10010 Make phone call to 10010.

Send Msg During Phone Call

Use case: Send numbers during a call, adjust SPK volume, and adjust MIC volume.

Command Description ACI Command
dtmf num_2 Send number 2 to phone. ACI_CMD_SEND_DTMF
VGS num_1 Send VGS 1 to phone and set SPK. ACI_CMD_SEND_VGS
VGS num_10 Send VGS 10 to phone and set SPK.
VGM num_6 Send VGM 6 to phone and set MIC. ACI_CMD_SEND_VGM
VGM num_10 Send VGM 10 to phone and set MIC.

Bluetooth Address Get/Set

Command Description ACI Command
get bd_addr Get Bluetooth address set by MCUConfig Tool. ACI_CMD_GET_BD_ADDR
set Bluetooth address Update Bluetooth MAC to new address. ACI_CMD_XM_BT_SET_ADDR

Voice Prompt Volume

Command Description ACI Command
VP volume1 Set voice prompt volume level to 1. ACI_CMD_SET_VP_VOLUME
VP volume9 Set voice prompt volume level to 9.

Deep Low Power State Control

Command Description ACI Command
dlps enable Allow device to enter DLPS mode automatically. ACI_CMD_SET_AND_READ_DLPS
dlps disable Disallow device to enter DLPS mode.

Device Mode

Command Description ACI Command
mode idle Disable page scan and inquiry scan. ACI_APP_CMD_XM_SET_MODE
mode inq_scan Enable inquiry scan only.
mode page_scan Enable page scan only.
mode all_enable Enable inquiry scan and page scan.

SCO Manage

Command Description ACI Command
hfp reject Reject SCO connection indication. ACI_CMD_BT_HFP_SCO_MAG
hfp agree Accept SCO connection indication.
hfp disc Disconnect SCO connection.

LE Data Transfer

Command Description ACI Command
le send1 Send LE data to phone via transmit service. ACI_CMD_LE_DATA_TRANSFER

Volume Control

Command Description ACI Command
volume level0 Set volume to level 0. ACI_CMD_SET_VOLUME
volume level3 Set volume to level 3.
volume level7 Set volume to level 7.
volume level10 Set volume to level 10.

Firmware Version

Command Description ACI Command
fw version Get firmware version. ACI_CMD_GET_FW_VERSION

Clear Bond Info

Command Description ACI Command
clear ufo Clear a device bond info named 'ufo'. ACI_CMD_BT_BOND_INFO_CLEAR

HCI Mode

Command Description ACI Command
hci download Enter HCI download mode. ACI_CMD_SWITCH_TO_HCI_DOWNLOAD_MODE

Inquiry

Use case: Connect to BUD.

Command Description ACI Command
inquiry start Start inquiry Bluetooth devices. ACI_APP_CMD_INQUIRY
inquiry stop Stop inquiry Bluetooth devices.

RF Test

Command Description ACI Command
hci enter Enter HCI mode for RF test. ACI_CMD_XM_ENTER_HCI_MODE

Device

Command Description ACI Command
device reboot Software reboot. ACI_CMD_XM_DEVICE_REBOOT

XMMI

Command Description ACI Command
xmmi local Switch to local playback mode. ACI_CMD_XM_MMI
xmmi source Switch to A2DP Source music mode.
xmmi clear Delete all bond information in bond storage.

LE Advertising

Use case: Bluetooth Low Energy Function.

Command Description ACI Command
le advstart Create customized LE advertising. ACI_CMD_XM_LE_ADV_CREATE
le advstart Start LE advertising. ACI_CMD_XM_LE_START_ADVERTISING
le advstop Stop LE advertising. ACI_CMD_XM_LE_STOP_ADVERTISING
le adv_data Update LE advertising data. ACI_CMD_XM_LE_ADV_DATA_UPDATE
le scan_rsp_data Update LE scan response data. ACI_CMD_XM_LE_SCAN_RSP_DATA_UPDATE
le adv500ms Change LE advertising interval to 500ms. ACI_CMD_XM_LE_ADV_INTVAL_UPDATE
le adv200ms Change LE advertising interval to 200ms.

LE Connect

Use case: Bluetooth Low Energy Function.

Command Description ACI Command
le disconn Disconnect LE link. ACI_CMD_XM_LE_DISC
le conn_param Update LE connection parameters. ACI_CMD_XM_LE_CONN_PARAM_UPDATE
le mtu Get LE MTU size. ACI_CMD_XM_LE_ATT_GET_MTU

Music Control

Use case: Music Play Function.

Command Description ACI Command
music open Open and start music session. ACI_CMD_XM_MUSIC
music pause Pause music session.
music resume Resume music session.
music abort Abort music session when an unexpected situation happens.
music close Close music session.
music single Send single MP3 frame to device.

Recording

Command Description ACI Command
rc start_pcm Start recording with the format of PCM. ACI_CMD_XM_START_RECORD
rc start_opus Start recording with the format of OPUS.
rc start_msbc Start recording with the format of mSBC.
rc start_sbc Start recording with the format of SBC.
rc start_lc3 Start recording with the format of LC3.
rc stop Stop recording. ACI_CMD_XM_STOP_RECORD
rc play Initialize record playing. ACI_CMD_XM_START_RECORD_PLAY
rc s Stop record playing. ACI_CMD_XM_STOP_RECORD_PLAY

Audio Test

Command Description ACI Command
pa id Get PA chip ID. ACI_CMD_XM_AUDIO_TEST_GET_PA_ID
algo bypass Set PA and DSP into bypass mode. ACI_CMD_XM_AUDIO_TEST_BYPASS
algo normal Set PA and DSP into normal mode.

Others Debug Only

Command Description ACI Command
dis log Disable verbose log. ACI_CMD_XM_DISABLE_VERBOSE_LOG

A2DP Transfer

Transfer to A2DP Source

Use case: A2DP Transparent Transmission (A2DP Output).

Command Description ACI Command
a2dpxmitroute a2dpsrc Set A2DP Source as a transparent transmission play path (from SPI). ACI_CMD_A2DP_XMIT_SET_ROUTE_OUT
a2dpxmitctrl start Enable A2DP Source music (from SPI). ACI_CMD_A2DP_XMIT_ROUTE_OUT_CTRL
a2dpxmitctrl stop Disable A2DP Source music (from SPI).
Transfer to LE Audio (Broadcast Source)

Use case: A2DP Transparent Transmission (BIS Output).

Command Description ACI Command
bsrcinit 48k_1bis Initialize broadcast source ACI_CMD_LEA_BSRC_INIT
a2dpxmitroute bis Set broadcast source as transparent transmission play path (from SPI). ACI_CMD_A2DP_XMIT_SET_ROUTE_OUT
a2dpxmitctrl start Enable broadcast source music (from SPI). ACI_CMD_A2DP_XMIT_ROUTE_OUT_CTRL
a2dpxmitctrl stop Disable broadcast source music (from SPI).

Source Play

Use case: Source Play Function.

Command Description ACI Command
set_route_in mic Set input route as MIC. ACI_CMD_SRC_PLAY_SET_SRC_ROUTE
set_route_in linein Set input route as line-in.
set_route_in usb Set input route as USB.
set_route_in sd_card Set input route as SD card.
set_route_out A2DP Set output route as A2DP. ACI_CMD_SRC_PLAY_SET_PLAY_ROUTE
set_route_out hfp_ag Set output route as HFP AG.
set_route_out bis Set output route as BIS.
set_route_out cis Set output route as CIS.
set_route_out local Set output route as Local.
route_in start Start input route source. ACI_CMD_SRC_PLAY_ROUTE_IN_START
route_in stop Stop input route source. ACI_CMD_SRC_PLAY_ROUTE_IN_STOP
route_out start Start output route play. ACI_CMD_SRC_PLAY_ROUTE_OUT_START
route_out stop Stop output route play. ACI_CMD_SRC_PLAY_ROUTE_OUT_STOP

String Mode

Command Description ACI Command
set string_mode Enter string mode. ACI_CMD_STRING_MODE

HFP Transfer

Use case: HFP Transparent Transmission.

Command Description ACI Command
hfpag conn Connect SCO between device and BUD. ACI_CMD_HFP_AG_CONNECT_SCO
hfpag disconn Disconnect SCO between device and BUD. ACI_CMD_HFP_AG_DISCONNECT_SCO
hfpag call_incoming Notify the incoming call. ACI_CMD_HFP_AG_CALL_INCOMING
hfpag call_answer Answer the incoming call. ACI_CMD_HFP_AG_CALL_ANSWER
hfpag call_terminate Terminate the outgoing call. ACI_CMD_HFP_AG_CALL_TERMINATE
hfpag mic_mute Mute the MIC. ACI_CMD_HFP_AG_MIC_GAIN_LEVEL_SET
hfpag mic_unmute Unmute the MIC.
hfpag spk_vol_up Turn the SPK volume up. ACI_CMD_HFP_AG_SPEAKER_GAIN_LEVEL_SET
hfpag spk_vol_down Turn the SPK volume down.

Find My Action

Command Description ACI Command
findmy enter_pairing Enter Find My pairing mode. ACI_CMD_FINDMY_FEATURE
findmy put_serial_number Put the state of serial number.

GFPS Finder Action

Command Description ACI Command
gfps_finder_ring_stop Stop ring. ACI_CMD_GFPS_FINDER_FEATURE

LEA Advertising

Command Description ACI Command
lea_adv_start Start LE Audio advertising. ACI_CMD_LEA_ADV_START
lea_adv_stop Stop LE Audio advertising. ACI_CMD_LEA_ADV_STOP

LEA CCP(F_APP_CCP_SUPPORT, CLIENT)

Command Description ACI Command
lea_call_cp accept Answer the incoming call on the specified link. ACI_CMD_LEA_CCP_CALL_CP
lea_call_cp terminate Terminate the call on the specified link.
lea_call_cp local_hold Move the call on the specified link to local hold status.
lea_call_cp local_retrieve Move the call on the specified link from local hold status to active status.
lea_call_cp originate Originate call on the specified link.
lea_call_cp join Join the call on the specified link.

LEA MCP(F_APP_MCP_SUPPORT, CLIENT)

Command Description ACI Command
lea_media_cp play Play current track. ACI_CMD_LEA_MCP_MEDIA_CP
lea_media_cp pause Pause current track.
lea_media_cp fast_rewind Fast rewind.
lea_media_cp fast_forward Fast forward.
lea_media_cp stop Stop current track.
lea_media_cp previous_track Move to previous track.
lea_media_cp next_track Move to next track.

LEA SYNC INIT

Command Description ACI Command
bis_sync_init random Init the role as a sink, which will sync any device around. ACI_CMD_LEA_SYNC_INIT
bis_sync_init spec Init the role as a sink, which will sync a specific device according to the address.
bis_sync_init delegator Init the role as a scan delegator.

LEA SYNC

Command Description ACI Command
bis_sync start Start syncing broadcast according to the init policy. ACI_CMD_LEA_SYNC
bis_sync stop Stop syncing the broadcast.

CHARGING CASE COMMANDS

Command Description ACI Command
chargingcase end_outgoing_call End an outgoing call. ACI_CMD_LEA_MCP_MEDIA_CP
chargingcase answer_call Answer an incoming call.
chargingcase reject_call Reject an incoming call.
chargingcase end_active_call End an active call.
chargingcase mic_mute_unmute MIC mute toggle.
chargingcase mic_mute MIC mute.
chargingcase mic_unmute MIC unmute.
chargingcase volume_up Volume up.
chargingcase volume_down Volume down.
chargingcase play_pause AV play/pause.
chargingcase av_fwd AV forward.
chargingcase av_bwd AV backward.
chargingcase av_fastforward AV fast forward.
chargingcase av_rewind AV rewind.
chargingcase gaming_mode_switch Switch to gaming mode.
chargingcase light_sensor_on_off Light sensor on/off.
chargingcase vp_level3 Set voice prompt volume level to 3.
chargingcase vp_level10 Set voice prompt volume level to 10.
chargingcase audio_eq_index_set0 Set audio EQ index to 0.
chargingcase audio_eq_index_set1 Set audio EQ index to 1.
chargingcase volume_level0 Set volume to level 0.
chargingcase volume_level3 Set volume to level 3.
chargingcase volume_level7 Set volume to level 7.
chargingcase volume_level10 Set volume to level 10.
chargingcase volume_level15 Set volume to level 15.
chargingcase set_key_mmi_map_volume_up Set MFB as volume up button.
chargingcase set_key_mmi_map_volume_down Set MFB as volume down button.

LEA BAP

Command Description ACI Command
bst_start group_0_sync_0 Start broadcast on group 0 and sync 0. ACI_CMD_LEA_BST_START
bst_start group_0_sync_1 Start broadcast on group 0 and sync 1.
bst_start group_1_sync_0 Start broadcast on group 1 and sync 0.
bst_start group_1_sync_1 start broadcast on group 1 and sync 1
bst_stop group_0_sync_0 Stop broadcast on group 0 and sync 0. ACI_CMD_LEA_BST_STOP
bst_stop group_0_sync_1 Stop broadcast on group 0 and sync 1.
bst_stop group_1_sync_0 Stop broadcast on group 1 and sync 0.
bst_stop group_1_sync_1 Stop broadcast on group 1 and sync 1.
bst_remove group_0_sync_0 Remove broadcast on group 0 and sync 0. ACI_CMD_LEA_BST_REMOVE
bst_remove group_0_sync_1 Remove broadcast on group 0 and sync 1.
bst_remove group_1_sync_0 Remove broadcast on group 1 and sync 0.
bst_remove group_1_sync_1 Remove broadcast on group 1 and sync 1.
baas scan Start extended scan for BAAS. ACI_CMD_LEA_BAAS_SCAN
pa_sync dev0 PA sync with device 0. ACI_CMD_LEA_PA_SYNC_DEV
pa_sync dev1 PA sync with device 1.
pa_sync dev2 PA sync with device 2.

LEA VCP VOLUME CONTROL

Command Description ACI Command
gvcs volume Set VCS volume. ACI_CMD_LEA_GVCS_VOLUME
gvcs mute Set VCS mute. ACI_CMD_LEA_GVCS_MUTE
gvcs unmute Set VCS unmute.

UART DFU

Command Description ACI Command
dfu start Start DFU process through UART. ACI_CMD_UART_DFU
dfu abort Abort DFU process.
dfu get_ver Get device's version.
dfu test_enable Enable test mode to downgrade.

LEA VCS

Command Description ACI Command
lea_vcs vol_up Volume up. ACI_CMD_LEA_VCS_SET
lea_vcs vol_down Volume down.
lea_vcs spk_mute SPK mute.
lea_vcs spk_unmute SPK unmute.

LEA CCP(CCP_CALL_CONTROL_SERVER)

Command Description ACI Command
ccp_action incomingcall Incoming call action. ACI_CMD_LEA_CCP_ACTION
ccp_action local_accept1 Local accept call index 1.
ccp_action local_accept2 Local accept call index 2.
ccp_action local_terminate1 Local terminate call index 1.
ccp_action local_terminate2 Local terminate call index 2.

LEA MCP(MCP_MEDIA_CONTROL_SERVER)

Command Description ACI Command
mcp_state playing The media player starts playing the current track. ACI_CMD_LEA_MCP_STATE
mcp_state paused The media player paused the current track.
mcp_notify track_changed Send track changed notification. ACI_CMD_LEA_MCP_NOTIFY
mcp_notify track_duration Send track duration notification.
mcp_notify track_position Send track position notification.

LEA MICP MIC CONTROL

Command Description ACI Command
gmic mute Set GMIC MIC mute. ACI_CMD_LEA_GMIC_MUTE
gmic unmute Set GMIC MIC unmute.