STM32 implements Airplay music player

AirPlay is a set of wireless music solutions introduced by Apple. IPhone, iPad, even Apple Watch and other devices in our hands, as well as iTunes on the computer, support AirPlay, but audio devices that support AirPlay are more expensive. I am flat and naturally feel that it is not cost-effective to buy such expensive speakers. The last two days came to my mind. If the STM32 can support the AirPlay function, will it not allow me to enjoy the freedom of wireless music? So I immediately went to github and searched, and found that there are really solutions, but basically all the solutions run on linux or windows. After careful selection, I chose as the AirPlay open source Project, mainly the code is implemented in C language is more convenient to port to stm32.

Before we start, it is necessary to understand AirPlay. AirPlay is a protocol library that upgrades airtunes after Apple acquired airtunes. It adds video and photo transmission to airtunes, which is completely turned into airplay non-open source functions, enabling wireless home music anytime, anywhere. Streaming media transmission. AirPlay can transfer pictures, audio, video, and images on iOS devices such as iPhone, iPad, iPod touch and other devices to AirPlay-enabled devices for playback. The implementation of AirPlay includes multiple protocols, some of which are completely standard. Some protocols have been modified, while others are completely private.

• Multicast DNS is used to publish services. After startup, the corresponding device can be seen in the iOS Control Center menu;

• HTTP / RTSP / RTP for streaming media services, transmission of audio and video data, and playback control;

• NTP time synchronization;

• FairPlay DRM encryption A completely private encryption protocol.

We need to prepare an iphone and install Netease Cloud Music, W5500EVB development board (stm32f103 + W5500), and PCM5102A audio module. iPhone is used as a client to search for devices and send audio data. W5500EVB is a WIZnet development board with Ethernet function to receive audio data as a server. For the operation of the development board, please refer to the routines in The PCM5102A audio module plays the decoded audio data. After analysis, we want to realize Airplay audio playback mainly to achieve the following three aspects:

1. iPhone discovers the W5500 device on the network and establishes a connection

2.W5500EVB receives and decodes audio data

3.W5500EVB transmits audio to PCM5102A audio module through I2S interface

Discover devices and establish connections

Airplay finds that the device is implemented based on the MDNs protocol. The iPhone and W5500EVB need to be connected to the same network and the W5500EVB must join the multicast group to receive MDNs packets. W5500EVB responds to the response message after receiving the querry query message from the iPhone. The content of the message can refer to the document "Unofficial AirPlay Protocol Specification" ( ). The MDNS device discovery is below Code:

1uint8 dns_query (uint8 s, uint8 * name, uint8 * rname)

2 {

3 uint8 ip [4];

4 uint16 len, port;

5 switch (getSn_SR (s)) {

6 case SOCK_UDP:

7 if ((len = getSn_RX_RSR (s))> 0) {

8 if (len> MAX_DNS_BUF_SIZE) {



11 len = recvfrom (s, BUFPUB, len, ip, & port);

12 len = dns_makequery (0, name, rname, BUFPUB, MAX_DNS_BUF_SIZE);

13 sendto (s, BUFPUB, len, DIP, DPORT);

14 len = dns_makeresponse (0, name, rname, BUFPUB, MAX_DNS_BUF_SIZE);

15 sendto (s, BUFPUB, len, DIP, DPORT);


17 break;

18 case SOCK_CLOSED:

19 setDIPR (s, DIP); / * Set target IP * /

20 setDHAR (s, DHAR); / * Set target MAC 01: 00: 5e: 00: 00: FB * /

21 setDPORT (s, DPORT); / * Set target port 5353 * /

22 socket (s, Sn_MR_UDP, 5353, Sn_MR_MULTI); / * Open SOCKET to join the multicast group * /

23 break;

twenty four }



The dns_makequery () function in line 12 of the code is used to stitch the query message, and the dns_makeresponse () function in line 14 of the code is used to stitch the response message. We compile and download the code to W5500EVB and run it. Open the iPhone option list and click the music option. As shown in the figure below, click the upper right sign to search for devices under the same network. The interface is shown below:

Figure 1-1 iPhone option list

At this time, the iPhone sends a querry query message to the multicast group. After receiving the query message, the W5500EVB sends a response message to the multicast group. The response response message sent by the W5500EVB includes the RAOP service, which is used to project the audio stream. RAOP is essentially a real-time streaming protocol, but it adds the authentication request-response step. The RAOP service uses two channels to implement streaming media: one is the control channel of the real-time streaming protocol; the other is the data channel for sending. data. RAOP service name format: MAC address @ device name._raop._tcp.local. By capturing the response message through the packet capture tool, we can see the relevant information of the RAOP service.

Figure 1-2 RAOP service packet

The Service field is the service name. Protocol service categories: _airplay is a video service (not used), and _raop is an audio service. Name indicates the data transmission protocol, which can be transmitted through TCP or UDP. Port states that the port number for RTSP command interaction is 5005, and the client can establish a connection with the server through the port number. In the picture below, Wiznet is the device found by iPhone that supports AirPlay (W5500EVB).

Figure 1-3 iPhone discovery device

After the iPhone successfully discovers the W500 EVB device, you need to connect the device. At this time, we click on the device shown in the list. After the connection is successful, a check mark is displayed on the back of the corresponding device, as shown in the following figure:

Figure 1-4 iPhone connection device

The process of discovering the device introduced by the iPhone mentioned above specifies that RTSP communicates through TCP and the port number is 5005, so we need to create a TCP server with a port number of 5005 to receive data packets. The rtsp_parase_request () function is shown in line 20 below.

1 void do_tcp_server (SOCKET s, uint16 localport)

2 {

3 uint16 len;

4 uint8 send_buffer [1024];

5 switch (getSn_SR (s)) {

6 case SOCK_INIT:

7 listen (s);

8 break;


10 if (getSn_IR (s) & Sn_IR_CON) {

11 setSn_IR (s, Sn_IR_CON);


13 len = getSn_RX_RSR (s);

14 if (len> 0) {

15 memset (buffer, 0, sizeof (buffer));

16 querry_flag = 1;

17 recv (s, buffer, len);

18 memset (send_buffer, 0, sizeof (send_buffer));

19 / * Parse RTSP data packets and splice response data * /

20 rtsp_parase_request ((char *) buffer, (char *) send_buffer, s, len);

21 / * Send response packet * /

22 if (0 == send (s, send_buffer, strlen (send_buffer))) {

23 send (s, send_buffer, strlen (send_buffer));

twenty four }



27 break;


29 disconnect (s);

30 querry_flag = 0;

31 break;

32 case SOCK_CLOSED:

33 querry_flag = 0;

34 socket (s, Sn_MR_TCP, localport, Sn_MR_ND);

35 break;



Because Apple ’s AirPlay protocol prevents the access of other devices without Apple ’s permission, the transmitted data is encrypted with an asymmetric RSA encryption algorithm. Asymmetry means that the same key is used for encryption and decryption. RSA The keys of the encryption algorithm are divided into public and private keys, which have different contents and different uses. The public key is used for encryption and is usually given to the client; the private key is used for decryption and is usually managed by the server. A public key is stored in the iPhone to encrypt the data stream output by the iPhone. The receiving device uses the private key to decrypt the received data (audio) stream. W5500EVB is used as a server to receive data, so we only need to know the private key to parse the data. We can directly decode the private key already available on Baidu. The implementation of RSA encryption algorithm can refer to the RSA encryption and decryption related functions in the open source project project.

The iPhone will first send an OPTIONS request to determine the methods supported by the W5500EVB. All methods supported by the W5500EVB reply include ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER, etc. For the specific meaning of the methods, please refer to the RTSP protocol related documents.

iphone OPTIONS request message:


CSeq: 0

DACP-ID: 4CB06073C86450D8

Active-Remote: 2937221397

User-Agent: AirPlay / 373.9.1

Figure 1-5 OPTIONS request message

W5500EVB response message:

RTSP / 1.0 200 OK

CSeq: 0

Apple-Jack-Status: connected; type = analog


Figure 1-6 OPTIONS response message

After the iPhone receives the response from W5500EVB, it will send an OPTIONS packet containing Apple-Challenge to W5500EVB. The parameters after Apple-Challenge are randomly generated and encrypted by RSA algorithm. W550EVB will base64 decode the parameters in Apple-Challenge After adding the IP address and MAC address of the W5500EVB to the end of the decoded data, and then encrypting it with the RSA private key and encoding with base64, the W5500EVB sends the encrypted data as the Apple-Response parameter to the iPhone. The iPhone verifies the data and the data is correct. Then proceed to the next step and disconnect if the data is incorrect. The following figure is an OPTIONS packet containing Apple-Challenge:


Apple-Challenge: UJPWMzMloBFr98cQQHX3OQ ==

CSeq: 2

DACP-ID: 4CB06073C86450D8

Active-Remote: 2937221397

User-Agent: AirPlay / 373.9.1

Figure 1-7 Apple-Challenge message

After receiving the OPTIONS data packet, intercept the Apple-Challenge related data and decrypt the code as follows:

1if (strstr (rcv_buffer, "Apple-Challenge:")! = NULL)

2 {

3 rsakey_t * rsakey;

4 rsakey = rsakey_init_pem (pemstr);

5 if (! Rsakey) {

6 printf ("Initializing RSA failed \ n");

7 return;

8 }

9 memset (response, 0x00,1024);

10 / * Get Apple-Challenge parameters * /

11 mid (rcv_buffer, "Apple-Challenge:", "\ r \ n", CHALLENGE);

12 / * Get Encrypted Apple-Response * /

13 rsakey_sign (rsakey, response, sizeof (response), CHALLENGE, ipaddr, sizeof (ipaddr), hwaddr, sizeof (hwaddr));

14 mid (rcv_buffer, "CSeq:", "\ r \ n", CHALLENGE);

15 sprintf (send_buffer, "RTSP / 1.0 200 OK \ r \ nCSeq:% s \ r \ nApple-Jack-Status: connected; type = analog \ r \ nApple-Response:% s \ r \ nPublic: ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, SET_PARAMETER \ r \ n \ r \ n ", CHALLENGE, response);


Use the mid () function at line 11 to obtain the parameters after the Apple-Challenge, and then the rsakey_sign () function at line 14 to encrypt and decrypt the acquired data, and complete the splicing of the RTSP response message at line 15. The spliced ​​message is shown in the following figure:

RTSP / 1.0 200 OK

CSeq: 2

Apple-Jack-Status: connected; type = analog

Apple-Response: Dw5Jrbs1mhjks3YErCo1tSOUV8 / G8pOOShS3dUocjWzDGQR6DfqiSEovks + G4nHmCw9BccjlpVHzzRUINYZenWhUy8zlGsVGNwuO4okfi86PjGp5VAS6RPeYbW / CpAPgrzpDsVCblSGt8kQbn + sWuku9WMfa4gYU82DgfmL3laphZlidEIZd8D6FwzAth4pbRdtL3N8GuM2kWGRSpT6FL4VGk326a58g0kUNqNDxHp0fTa4ijk8VORzkyKO9ByFeysmZqGDBurLuSvDoAs0c1zR9aHAIXfJkWd0Ii3WviC2F0 + vEODcRgOh7gOvy / i5 + OOTiUfvHiDFIqlhVCRnZ2g


Figure 1-8 Apple-Response message

After iPhone receives the response from W5500EVB, it analyzes and verifies the content after Apple-Response. If the verification result is correct, the device can continue to send data after the connection is successful, otherwise it will disconnect.

2.Receiving and decoding audio data

After the iPhone and W5500EVB successfully established the connection, they started to send audio data through the UDP protocol, but the audio data transmitted by the iPhone through airplay was encrypted. For the receiving end, the audio and video data must be decrypted correctly. The audio data is encrypted using the AES CBC128 algorithm. To decrypt the algorithm, the parameters rsaaeskey and aeskiv must be entered. These two parameters are obtained by parsing the ANNOUNCE request sent by the iPhone. ANNOUNCE follows the SDP protocol when transmitting. The SDP protocol is used to describe media information. The figure below shows the ANNOUNCE request message.

ANNOUNCE rtsp: // RTSP / 1.0

Content-Length: 652

Content-Type: application / sdp

CSeq: 3

DACP-ID: 4CB06073C86450D8

Active-Remote: 2937221397

User-Agent: AirPlay / 373.9.1


v = 0

o = AirTunes 1561243076001349804 0 IN IP4

s = AirTunes

i = Wenlong … iPhone

c = IN IP4

t = 0 0

m = audio 0 RTP / AVP 96

a = rtpmap: 96 AppleLossless

a = fmtp: 96 352 0 16 40 10 14 2 255 0 0 44 100

a = rsaaeskey: bx0eKFGbphzETu16PLtXyP8s2CDKHpjIclJCmChdw6b12YSEvzDR3jlQwTWQdRRRrr99cek6JzdE0pgv0TzAF ++ FK8g63la8H9ioEcLFq84zWT / 7atIlPNFC7RELlQG5ff / yTXHJ7LkzxQF12DvzQzIPd8GMx5ik / rxnLObZ + GQAbB2xtW / By2JT5gapEMBsx8 + t + 0sZXNwA3GXrjcjF + h6 + oAD37A3U04rR / iK + Pvzglvy / 13ZOrXL1VJpTkE1O + TIflAzfl0BkBbtfd3lX / + Te + Og8 + gXXe516Dg4 / v1Veddj4HQYZ / vrxE / qYFGDZIFZUdmpBtmtVMqAYwt1n5w ==

a = aesiv: UohAefAQLdnT4BIBimuhfg ==

a = min-latency: 11025

a = max-latency: 88200

Figure 2-1 ANNOUNCE message

W5500EVB parses and receives ANNOUNCE request packet to obtain rsaaeskey, aesiv and decode.

1 void raop_announce (char * recv_buffer)

2 {

3 mid (recv_buffer, "Active-Remote:", "\ r \ n", remotestr);

4 mid (recv_buffer, "rtpmap:", "\ r \ n", rtpmapstr);

5 mid (recv_buffer, "fmtp:", "\ r \ n", fmtpstr);

6 mid (recv_buffer, "rsaaeskey:", "\ r \ n", rsaaeskeystr);

7 mid (recv_buffer, "aesiv:", "\ r \ n", aesivstr);

8 / * decode aeskey * /

9 rsakey_decrypt (rsakey, aeskey, sizeof (aeskey), rsaaeskeystr);

10 / * decode aesiv * /

11 rsakey_decode (rsakey, aesiv, sizeof (aesiv), aesivstr);

12 / * init alac * /

13 raop_buffer_init (& alac, fmtpstr);

14 return;


iPhone will continue to send SETUP data packets to W5500EVB, the data packet contains timing_port and control_port. timing_port is used to transmit AirPlay's time synchronization package. It can also actively request the current time stamp from the iPhone to calibrate the time stamp of the stream. control_port is the port used to send the respondTransmit Request, that is, when the receiving end finds that there is a missing frame in the received music stream data packet, it can send a request for respondTransmit to the iPhone through the control port. After the iPhone receives the frame, it will send the frame in the response Reissued back.

SETUP rtsp: // RTSP / 1.0

Transport: RTP / AVP / UDP; unicast; mode = record; timing_port = 55703; control_port = 56616

CSeq: 4

DACP-ID: 4CB06073C86450D8

Active-Remote: 2937221397

User-Agent: AirPlay / 373.9.1

Figure 2-2 SETUP message

W5500EVB server_port, server port in the response message is used to transmit audio stream data packets

RTSP / 1.0 200 OK

CSeq: 4

Apple-Jack-Status: connected; type = analog

Transport: RTP / AVP / UDP; unicast; mode = record; timing_port = 56461; events; control_port = 51196; server_port = 55641


Figure 2-3 SETUP response message

After the SETUP packet determines the audio stream transmission mode and transmission port number, the iPhone starts sending audio data to server_port 55641 designated by W5500EVB. W5500EVB receives the audio data. After the decryption process, we will get AAC encoded audio data, which the player plays. AAC data also needs to be decoded. Not much to say, the audio decryption process is explained directly by some codes.

1 int decode_audio_data (unsigned char * data, unsigned short

2 datalen, int use_seqnum)

3 {

4 unsigned short seqnum;

5 raop_buffer_entry_t entry;

6 int encryptedlen;

7 AES_CTX aes_ctx;

8 int outputlen;

9 / * Check packet data length is valid * /

10 if (datalen <12 || datalen> 1472) {

11 return -1;


13 / * Get correct seqnum for the packet * /

14 if (use_seqnum) {

15 seqnum = (data [2] << 8) | data [3];


17 / * Update the raop_buffer entry header * /

18 entry.flags = data [0];

19 entry.type = data [1];

20 entry.seqnum = seqnum;

21 entry.timestamp = (data [4] << 24) | (data [5] << 16) |

22 (data [6] << 8) | data [7];

23 entry.ssrc = (data [8] << 24) | (data [9] << 16) |

24 (data [10] << 8) | data [11];

25 entry.available = 1;

26 / * Decrypt audio data * /

27 encryptedlen = (datalen-12) / 16 * 16;

28 AES_set_key (& aes_ctx, aeskey, aesiv, AES_MODE_128);

29 AES_convert_key (& aes_ctx);

30 memset (packetbuf, 0, sizeof (data));

31 AES_cbc_decrypt (& aes_ctx, & data [12], (uint8 *) packetbuf,

32 encryptedlen);

33 memcpy (packetbuf + encryptedlen, & data [12 + encryptedlen],

34 datalen-12-encryptedlen);

35 / * Decode ALAC audio data * /

36 outputlen = audio_buffer_size;

37 alac_decode_frame (& alac, (uint8 *) packetbuf, audiobuf,

38 & outputlen);

39 entry.audio_buffer_len = outputlen;

40 return outputlen;


In the program, W5500EVB will determine whether the length of the data packet is less than 12 every time it receives a packet through the UDP port. Because the RTP header is 12 bytes, less than 12 bytes will be discarded directly. The larger than 12 bytes and less than 1472 ( The maximum length of the UDP packet) will decrypt the data through the 31-line AES_cbc_decrypt () function, and then convert the decrypted data into the data that can be played by the PCM5102A module through the alac_decode_frame () function and store the data in the audiobuf waiting to be sent to the audio module , Returns the playable data length outputlen, which will be used when we initialize the DMA function of I2S.

3.Playback of audio data

The DAC module of PCM5102A is used for audio playback. This module communicates through the I2S interface and directly sends the decoded data to the PCM5102A module. In order to communicate with the PCM512A module, the IIS interface of the W5500EVB needs to be initialized. The I2S3 interface is used in the project. Note that the clock pin PB3 of the I2S3 interface is the JTDO pin of JTAG by default. JTAG must be disabled during initialization. So that PB3 can be used as the clock pin of I2S, the initialization code is as follows:

  1 void I2S_Config (void) 

2 {

3 I2S_InitTypeDef I2S_InitStructure;

4 GPIO_InitTypeDef GPIO_InitStruct;


6 / * Init GPIO * /

7 RCC_APB1PeriphClockCmd (RCC_APB1Periph_SPI3, ENABLE);

8 // SPI

9 RCC_APB2PeriphClockCmd (

10 RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_


12 GPIO_PinRemapConfig (GPIO_Remap_SWJ_Disable, ENABLE);

13 / * GPIO_Pin7-> I2S_MCK * /

14 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;

15 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

16 GPIO_InitStruct.GPIO_Speed ​​= GPIO_Speed_50MHz;

17 GPIO_Init (GPIOC, & GPIO_InitStruct);

18 / * GPIO_Pin_15-> I2S3_WS * /

19 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;

20 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

21 GPIO_InitStruct.GPIO_Speed ​​= GPIO_Speed_50MHz;

22 GPIO_Init (GPIOA, & GPIO_InitStruct);

23 / * GPIO_Pin_3-> I2S3_CK

24 GPIO_Pin_5-> I2S3_SD

25 * /

26 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;

27 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

28 GPIO_InitStruct.GPIO_Speed ​​= GPIO_Speed_50MHz;

29 GPIO_Init (GPIOB, & GPIO_InitStruct);

30 / * Init IIS * /

31 SPI_I2S_DeInit (SPI3);

32 I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;

33 I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;

34 I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;

35 I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;

36 I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;

37 / * I2S clock steady state is low level * /

38 I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;

39 I2S_Init (SPI3, & I2S_InitStructure);

40 I2S_Cmd (SPI3, ENABLE);


Line 12 of the code disables JTAG by calling the GPIO_PinRemapConfig () function. The line 32 mode is configured to send I2S_Mode_MasterTx as the master device. The communication standard is set to I2S Philips standard I2S_Standard_Phillips. The data format is the standard 16-bit format I2S_DataFormat_16b. The sampling frequency is set to 44kHz. The idle state of the clock line is low.

In order to improve the data transmission speed and efficiency, the DMA transmission function of IIS should be turned on. After each SPI_I2S_DMAReq_Tx request is sent, the data in the specified buf0 is sent to the DR data register of SPI3. My function is buf0, which is the audiobuf that stores audio data. Because our data is transmitted in 16bit, the data in the audiobuf is uint8, so the num value is the effective data length in the audiobuf / 2.

1 void I2S2_TX_DMA_Init (u8 * buf0, u16 num)

2 {

3 NVIC_InitTypeDef NVIC_InitStructure;

4 DMA_InitTypeDef DMA_InitStructure;

5 RCC_AHBPeriphClockCmd (RCC_AHBPeriph_DMA2, ENABLE);

6 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) (& SPI3-> DR);

7 DMA_InitStructure.DMA_MemoryBaseAddr = (u32) buf0;

8 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

9 DMA_InitStructure.DMA_BufferSize = num;

10 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

11 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

12 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

13 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

14 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

15 DMA_InitStructure.DMA_Priority = DMA_Priority_High;

16 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

17 DMA_Init (DMA2_Channel2, & DMA_InitStructure);

18 DMA_Cmd (DMA2_Channel2, ENABLE);



The audio stream is processed by receiving audio data packets through UDP, then decoding the received data packets, and storing the decoded data in audiobuf. The data is sent to the PCM5102A module through the DMA function of I2S3, the code is as follows:

1 void do_raop (uint8 s)

2 {

3 int outputlen;

4 uint8 ip [4];

5 uint16 len, port;

6 switch (getSn_SR (s)) {

7 case SOCK_UDP:

8 if ((len = getSn_RX_RSR (s))> 0) {

9 / * Receive audio data * /

10 recvfrom (s, buffer, len, ip, & port);

11 / * Decode received audio data * /

12 outputlen = decode_audio_data (buffer, len, 1);

13 / * Configure DMA * /

14 I2S2_TX_DMA_Init ((uint8 *) audiobuf, outputlen / 2);


16 break;

17 case SOCK_CLOSED:

18 socket (s, Sn_MR_UDP, 55641,0);

19 break;


twenty one }

After the code is completed, a hardware connection is required. Since the SPI2 port of the W5500EVB is used to communicate with the W5500, we can only choose the I2S3 interface. The connection diagram of the I2S, W5500EVB and PCM5102A module is shown below:

Figure 3-1 Hardware connection diagram

Download the compiled program to the W5500EVB, plug the headset into the PCM5102A module, search for and connect to the W5500EVB device with your iPhone, and click to play music to listen to music with the headset.

The project in this article simply implements playing music through AirPlay. Due to the hurry of time, the function of the project can continue to be optimized, such as the compatibility of various music players. The implementation of QQ Music and Netease Music is not the same as that used in this project. It is Netease Cloud Music; volume setting problems during music playback; noise problems during music playback. Since there is only a W5500EVB development board with STM32F103 on hand, f103 chip will be slower when running encryption and decryption, and the RAM space is smaller . If you want to do it, it is recommended to choose a faster processing chip.