Wiznet makers

WIZnet

Published May 17, 2023 ©

758 UCC

232 VAR

0 Contests

0 Followers

0 Following

Original Link

AirPlay audio playback based on STM32 and W5500

idea is to use the embedded solution STM32+W5500 to implement the AirPlay protocol, and use the I2S interface to connect to the PCM5102A aud

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

Idea is to use the embedded solution STM32+W5500 to implement the AirPlay protocol, and use the I2S interface to connect to the PCM5102A audio module to achieve audio playback. So I went online to check the information and found that there are not too many mature solutions. The existing solutions are all run on linux or windows. I selected them carefully and carefully.https://github.com/juhovh/shAirPlayThis AirPlay open source project is used as a reference, mainly because the code is more convenient to be ported to stm32 in C language.

Before we start, it is necessary to understand AirPlay. AirPlay is Apple’s acquisition of airtunes. On the basis of the airtunes agreement, it adds video and photo transmission, which becomes a complete AirPlay agreement. AirPlay can transmit pictures, audio, video, and mirror images on iOS devices such as iPhone, iPad, iPod touch, etc. to devices that support the AirPlay protocol for playback, enabling wireless streaming media transmission anytime, anywhere. In our project, we only need to implement the audio streaming part of the AirPlay protocol. AirPlay’s implementation process includes multiple sub-protocols, some of which are completely standard, some have been modified by Apple, and some are completely private.

• Multicast DNS: used to publish services, after starting, you can see the list of devices that support AirPlay in the iOS control center menu;

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

• NTP: Network Time Protocol, used for time synchronization;

• FAirPlay DRM encryption protocol: used for data encryption, this is a completely private encryption protocol.

Before starting work, we need to make some preliminary preparations, as shown below:

Figure 1 Hardware block diagram and wiring Figure 1 hardware block diagram and wiring

iPhone is used to play music and send audio stream through Airplay protocol. W5500EVB is WIZnet’s W5500 development board. In addition to the Ethernet MAC and PHY, the W5500 also has a built-in hardware TCP/IP protocol stack, which is currently a commonly used Ethernet solution. We use W5500EVB as a server to receive and decode audio data. For the operation of the development board, please refer to the routine in http://www.w5500.com. PCM5102A audio module can play the decoded audio data. After analysis, we want to achieve AirPlay audio playback mainly to achieve the following three aspects:

  1. The iPhone discovers the Airplay device (W5500EVB) 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;

Next we will implement these three steps separately:

1. Discover the Airplay device and establish a connection

AirPlay discovered the device based on the mDNS protocol (Multicast DNS). iPhone and W5500EVB need to be connected to the same network and W5500EVB must join the multicast group 224.0.0.251:5353 to receive mDNS messages. W5500EVB responds to the Response message after receiving the Querry query message from the iPhone. For the content of the message, please refer to the document “Unofficial AirPlay Protocol Specification” (http://nto.github.io/AirPlay.html), below are the mDNS device discovery and device registration codes:

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

2 {

3     uint8 ip[4];

4     uint16 len, port;

5     switch (getSn_SR(s)) {

6     case SOCK_CLOSED:/*turn onSOCKETAnd join the multicast group224.0.0.251*/

7         setDIPR(s,DIP);/* Set goalsIP 224.0.0.251*/

8         setDHAR(s,DHAR);/*Set goalsMAC 01:00:5e:00:00:FB */

9         setDPORT(s,DPORT);/*Set the target port5353*/

10         socket(s, Sn_MR_UDP, 5353,Sn_MR_MULTI);/*turn onSOCKETAnd join the multicast group*/

11         break;

12     case SOCK_UDP:

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

14             if (len > MAX_DNS_BUF_SIZE) {

15                 len = MAX_DNS_BUF_SIZE;

16             }

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

18             /*Check the received messageflagDetermine if the message is a query message*/

19             if ((BUFPUB[2]&0x80)==0) {

20                 len = mdns_makeresponse(0,name,rname,BUFPUB,MAX_DNS_BUF_SIZE);

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

22             }

23         }

24         break;

25     }

26     return DNS_RET_PROGRESS;

27 }

The case SOCK_CLOSED part of the state machine in the mdns_query() function is used to initialize the network and join mDNS multicast. When we click the AirPlay icon on the iOS playback page, a service request will be automatically sent. The function of line 19 in the case SOCK_UDP part is used to determine whether the mDNS service request is sent from the iPhone. The mdns_makeresponse() function on line 20 is used to stitch the response message. The response message contains device information and the type of RAOP service to be provided. RAOP service is AirPlay’s audio streaming protocol. RAOP is essentially a real-time streaming protocol. It only adds the authentication request-response step. The RAOP service uses two channels to realize streaming media: one is a control channel using a real-time streaming protocol; the other is a data channel used to send data. Through the sendto () function on line 21, the response message can be sent to the multicast group, and the iPhone can receive the response packet. By grabbing the response message through the packet capture tool, we can see the relevant information of the RAOP service, as shown below:

Figure 2 RAOP Service Message Figure 2 RAOP Service Message

among them:
Service: This field is the service name, format:MAC address@devicename._raop._tcp.local

Protocol: Type of service: _AirPlay is a video service (not used), _raop is an audio service.

Name: Data transmission protocol, which can be transmitted through TCP or UDP.

Port: The port number for RTSP command interaction is declared as 5005, and the client can establish a connection with the server through this port number.

If there is no error in this part, you should be able to see the AirPlay device we virtualized with W5500EVB on the music playback page of the iPhone’s control center, which is “wiznet” in the figure below.

� � � ��

The iPhone can connect to the device after successfully discovering the AirPlay device. At this time, we click on the device shown in the list. After the connection is successful, a check mark will be displayed behind the corresponding device, as shown in the following figure:

� � � � � ��

Although it is short, it is not easy at all. AirPlay’s handshake uses RTSP (Real-Time Stream Protocol) protocol, which is a text-based multimedia playback control protocol. In the process of discovering the device described above, the iPhone specified that RTSP communicates through TCP and the port number is 5005, so we need to create a TCP server with port number 5005 to receive the data packet and go through the following steps Complete the handshake:Apple-Challen

Figure 5 AirPlay handshake communication steps Figure 5 AirPlay handshake communication steps

The parsing of the RTSP data packet is performed by the rtsp_parase_request() function as shown in line 20 of the following code.

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;

9     case SOCK_ESTABLISHED:

10         if (getSn_IR(s) & Sn_IR_CON) {

11             setSn_IR(s, Sn_IR_CON);

12         }

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             /*ParsingRTSPPackets and stitching 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));

24             }

25         }

27         break;

28     case SOCK_CLOSE_WAIT:

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;

36     }

37 }

In order to prevent the access of other devices that are not allowed by Apple, Apple’s AirPlay protocol encrypts the transmitted data with an asymmetric RSA encryption algorithm. Asymmetric means that the encryption and decryption do not use the same key, RSA The encryption algorithm key is divided into a public key and a private key. The two have different contents and different uses. The public key is used for encryption and is generally used by the client; the private key is used for decryption and is generally managed by the server. The public key stored in the iPhone is used to encrypt the data stream output by the iPhone, and 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 use the private key that Baidu has deciphered. The implementation of RSA encryption algorithm can refer to the RSA encryption and decryption related functions in the open source project https://github.com/juhovh/shAirPlay project.

The iPhone will first send an OPTIONS request to determine the methods supported by the AirPlay device (W5500EVB). All the methods supported by the W5500EVB reply include ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER, etc. The specific meaning of the method can refer to the RTSP protocol Related documents. The following are the OPTIONS request message sent by the iPhone and the OPTIONS response message returned by the AirPlay device

iPhone OPTIONS request message:

OPTIONS * RTSP/1.0

CSeq: 0

DACP-ID: 4CB06073C86450D8

Active-Remote: 2937221397

User-Agent: AirPlay/373.9.1

AirPlay device OPTIONS response message:

RTSP/1.0 200 OK

CSeq: 0

Apple-Jack-Status: connected; type=analog

Public:ANNOUNCE,SETUP,RECORD,PAUSE,FLUSH,TEARDOWN,OPTIONS,GET_PARAMETER,SET_PARAMETER

After receiving the response message from W5500EVB, iPhone will send OPTIONS packet containing Apple-Challenge to W5500EVB. The parameters after Apple-Challenge are randomly generated a string and encrypted by RSA algorithm. W5500EVB needs to encrypt the information in Apple-Challenge The parameters are first decoded by base64, and the IP address and MAC address of W5500EVB are added at the end of the decoded data, and then encrypted by RSA private key and then encoded by base64. W5500EVB sends the encrypted data as parameters of Apple-Response to iPhone Verify the data. If the data is correct, proceed to the next step. If the data is incorrect, disconnect. The following picture shows the OPTIONS packet containing Apple-Challenge:

OPTIONS * RTSP/1.0

Apple-Challenge: UJPWMzMloBFr98cQQHX3OQ==

CSeq: 2

DACP-ID: 4CB06073C86450D8

Active-Remote: 2937221397

User-Agent: AirPlay/373.9.1

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 failedn”);

7         return;

8     }

9     memset(response,0x00,1024);

10     /*ObtainApple-Challengeparameter*/

11     mid(rcv_buffer,”Apple-Challenge: “,”rn”,CHALLENGE);

12     /*Get encryptedApple-Response*/

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

14     mid(rcv_buffer,”CSeq: “,”rn”,CHALLENGE);

15     sprintf(send_buffer,”RTSP/1.0 200 OKrnCSeq: %srnApple-Jack-Status:connected; type=analogrnApple-Response: %srnPublic: ANNOUNCE, SETUP,RECORD,PAUSE, FLUSH, TEARDOWN, OPTIONS,SET_PARAMETERrnrn”,CHALLENGE,response);

16 }

Use the mid() function at line 11 to obtain the parameters after Apple-Challenge. Then the rsakey_sign() function at line 14 encrypts and decrypts the acquired data, and the splicing of the RTSP response message is completed at line 15. The message generated by splicing is shown below:

RTSP/1.0 200 OK

CSeq: 2

Apple-Jack-Status: connected; type=analog

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

Public:ANNOUNCE,SETUP,RECORD,PAUSE,FLUSH,TEARDOWN,OPTIONS,SET_PARAMETER

After the iPhone receives the response from the AirPlay device, if it verifies that the Apple-Response data is correct and completes the handshake between the devices, the next step is to transmit the audio data to the AirPlay device.

2. Audio data receiving and decoding

After the iPhone is successfully connected with the AirPlay device, it starts to send audio data through the UDP protocol, but the audio data transmitted by the iPhone through AirPlay are encrypted. For the receiving end, the audio and video data needs to be decrypted correctly. The audio data is encrypted using the AES CBC128 algorithm. When decrypting the algorithm, the parameters rsaaeskey and aeskiv are required. These two parameters are obtained by parsing the ANNOUNCE request message sent by the iPhone based on the RTSP protocol. ANNOUNCE follows the SDP protocol during transmission. The SDP protocol is used to describe media information. The following figure is the ANNOUNCE request message

ANNOUNCE rtsp://192.168.1.150/1561243076001349804 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 192.168.1.100

s=AirTunes

i=Wenlong… iPhone

c=IN IP4 192.168.1.100

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 44100

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

W5500EVB parses the received ANNOUNCE request packet to obtain rsaaeskey, aesiv and decodes it.

1 void raop_announce(char *recv_buffer)

2 {

3     mid(recv_buffer,”Active-Remote: “,”rn”,remotestr);

4     mid(recv_buffer,”rtpmap:”,”rn”,rtpmapstr );

5     mid(recv_buffer,”fmtp:”,”rn”,fmtpstr);

6     mid(recv_buffer,”rsaaeskey:”,”rn”,rsaaeskeystr);

7     mid(recv_buffer,”aesiv:”,”rn”,aesivstr);

8     /*decodingaeskey*/

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

10     /*decodingaesiv*/

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

12     /*init alac*/

13     raop_buffer_init(&alac,fmtpstr);

14     return;

15 }

The iPhone will continue to send SETUP packets to W5500EVB. The packets include timing_port and control_port. timing_port is used to transmit the time synchronization packet of AirPlay, and can also actively request the current timestamp from the iPhone to calibrate the timestamp of the stream. control_port is the port used to send the resendTransmit Request, that is, when the receiving end finds that there is a missing frame in the received music stream packet, it can send a request of resendTransmit to the iPhone through the control port, and the iPhone will send the frame to the response Reissued back in. The following are the SETUP message sent by iPhone and the SETUP response message returned by W5500EVB.

SETUP rtsp://192.168.1.150/1561243076001349804 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

The server_port and server port in the response message returned by W5500EVB are 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

Session:DEADBEEF

After the SETUP data packet determines the audio streaming method and transmission port number, the iPhone will start sending audio data to the server_port 55641 port specified by W5500EVB. W5500EVB receives the audio data. After the decryption process, we will get AAC encoded audio data and the player will play AAC data also needs to be decoded, not much to say, directly through part of the code to explain the audio decryption process.

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;

12     }

13     /* Get correct seqnum for the packet */

14     if (use_seqnum) {

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

16     }

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;

41 }

In the program, W5500EVB will judge whether the length of the data packet is less than 12 each time it receives a data packet through the UDP port. Because the RTP header is 12 bytes, less than 12 bytes will be discarded directly, greater 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 playable data of 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 outputable data length outputlen, which will be used when we initialize the DMA function of I2S.

3. Playing of audio data

The DAC module of PCM5102A is used for audio playback. The module communicates through the I2S interface. Because the I2S2 pins of STM32 are multiplexed with SPI2, and SPI2 has been used to communicate with W5500, we can only choose the I2S3 interface, W5500EVB and The schematic diagram of PCM5102A module connection is as follows:

Figure 6: Module hardware connection diagram

The program can directly send the decoded data to the PCM5102A module. In order to communicate with the PCM512A module normally, the I2S3 interface of the W5500EVB must be initialized. Note that the clock pin PB3 of the I2S3 interface is the JTDO pin of JTAG by default. JTAG must be disabled during initialization to enable PB3 to be used as the clock pin of I2S3. The initialization code is as follows:

1 void I2S_Config(void)

2 {

3     I2S_InitTypeDef I2S_InitStructure;

4     GPIO_InitTypeDef GPIO_InitStruct;

5

6     /*Init GPIO*/

7     RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);

8     /*SPI*/

9     RCC_APB2PeriphClockCmd(

10     RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_

11     GPIOC|RCC_APB2Periph_AFIO, ENABLE);

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);

41 }

At line 12 of the code, JTAG is disabled by calling the GPIO_PinRemapConfig() function. At line 32, the mode configuration sends I2S_Mode_MasterTx to the master device, the communication standard is set to I2S_Standard_Phillips, the data format is the standard 16-bit format I2S_DataFormat_16b, the sampling frequency is set to 44kHz, and the I2S_AudioFreq_44k, I2S clock line is idle The status is low.

In order to improve the data transmission speed and efficiency, it is necessary to turn on the DMA sending function of IIS. Each time the SPI_I2S_DMAReq_Tx request is sent, the data in the specified buf0 will be sent to the DR data register of SPI3. This function is buf0, which is the audiobuf that stores audio data. Special attention is needed: our data is transmitted according to 16bit, and the data in audiobuf is uint8 type, so the num value is the effective data length in 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);

19   SPI_I2S_DMACmd(SPI3,SPI_I2S_DMAReq_Tx,ENABLE);

20 }

The process of audio streaming is to receive audio data packets through UDP, then decode the received data packets, store the decoded data to audiobuf, and send the data 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             /*ConfigurationDMA*/

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

15         }

16         break;

17     case SOCK_CLOSED:

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

19         break;

20     }

21 }

Download the compiled program to W5500EVB, insert the headset into the PCM5102A module, and then use the iPhone to search and connect the W5500EVB device, click to play music to listen to music with the headset or stereo, skip the metaphysical part directly, the old speaker finally has dead wood Feel it. Due to the rush of time, although the project in this article has realized the playback of music through AirPlay, there is still a lot of room for optimization. For example, the compatibility of various music players, QQ music, NetEase music and other implementations are not the same (this article Use Netease Cloud Music); volume setting problems during music playback; noise problems during music playback, etc. And because there is only the W5500EVB development board with STM32F103 in hand, the STM32F103 chip will be slower when running encryption and decryption, and the RAM space is relatively small. Occasional stagnation is caused by this part of the reason. Relatively speaking, the use of WiFi may be more suitable for this program, and I will continue to optimize this project to achieve a more stable playback effect.

Documents
  • AirPlay open source

Comments Write