• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Audio
2
3
4## Audio Driver Overview
5
6A multimedia system is an indispensable part in Internet of Things (IoT) devices. Audio is an important module of the multimedia system, and building an audio driver model is particularly important in device development.
7
8This document describes the audio driver architecture and functional modules and how to develop audio drivers based on the Hardware Driver Foundation (HDF). Chip vendors can develop their own drivers and invocation of Hardware Abstraction Layer (HAL) APIs based on the driver architecture.
9
10
11
12## Audio Driver Architecture
13
14The audio driver architecture is implemented based on the [HDF](driver-hdf-overview.md). The audio driver architecture is as follows:
15
16![](figures/Audio_architecture.png)
17
18The driver architecture consists of the following:
19- Hardware Device Interface (HDI) adapter: implements the audio HAL driver (HDI adaptation) and provides hardware driver capability interfaces for the audio service (frameworks). The HDI adapter provides interface objects such as Audio Manager, Audio Adapter, Audio Control, Audio Capture, and Audio Render.
20- Audio Interface Lib: works with the Audio Driver Model (ADM) in the kernel to control audio hardware, read recording data, and write playback data. The **Stream_ctrl_common** in the Audio Interface Lib interacts with the audio HDI adapter layer.
21- ADM: helps system developers to develop scenario-specific applications for the multimedia audio subsystem. With the ADM, codec and DSP device vendors can adapt their driver code based on the unified interfaces provided by the ADM and implement quick development and easy adaptation to the OpenHarmony system.
22- Audio Control Dispatch: dispatches the control instructions from the Audio Interface Lib to the driver layer.
23- Audio Stream Dispatch: dispatches the data from the Audio Interface Lib to the driver layer.
24
25- Card Manager: manages multiple audio adapters. Each audio adapter consists of the digital audio interface (DAI), platform, codec, accessory, DSP, and Smart Audio Power Manager (SAPM) modules.
26- Platform Drivers: driver adaptation layer.
27- SAPM: optimizes the power consumption policy of the ADM.
28
29## Audio Driver Development
30
31The following uses the Hi3516D V300 as an example to describe how to develop drivers based on the audio driver architecture.
32
33### Audio ADM Architecture
34The audio driver provides the **hdf_audio_render**, **hdf_audio_capture**, and **hdf_audio_control** services for the HDI layer. The driver service nodes in the **dev** directory of the development board are as follows:
35
36```c
37# ls -l hdf_audio*
38crw-rw---- 1 system system 248, 6 1970-01-01 00:00 hdf_audio_capture // Voice recording service.
39crw-rw---- 1 system system 248,   4 1970-01-01 00:00 hdf_audio_codec_dev0 // Name of audio adapter 0.
40crw-rw---- 1 system system 248,   4 1970-01-01 00:00 hdf_audio_codec_dev1 // Name of audio adapter 1.
41crw-rw---- 1 system system 248, 5 1970-01-01 00:00 hdf_audio_control // Audio control service.
42crw-rw---- 1 system system 248,   7 1970-01-01 00:00 hdf_audio_render     // Audio playback service.
43```
44
45The audio adapters have the following driver services:
46
47hdf\_audio\_codec\_dev0
48- **dma\_service\_0**: direct memory access (DMA) service
49- **dai_service**: CPU DAI service
50- **codec\_service\_0**: codec service (built-in codec)
51- **dsp\_service\_0**: DSP service (optional)
52
53hdf\_audio\_codec\_dev1
54- **dma\_service\_0**: DMA service
55- **dai_service**: CPU DAI service
56- **codec\_service\_1**: accessory service (SmartPA)
57- **dsp\_service\_0**: DSP service (optional)
58
59#### Startup Process
60
61![](figures/ADM_startup_flowchart.png)
62
631. When the system starts, the platform, codec, accessory, DSP, and DAI drivers of the audio module are loaded first. Each driver obtains the configuration information from its configuration file and saves the obtained information to the data structures.
64
652. Each driver module calls the ADM registration interface to add itself to the linked list of the driver module.
66
673. The ADM obtains the hdf_audio_driver_0 and hdf_audio_driver_1 configuration and loads the devices of each module.
68
694. The ADM module initializes each module device by calling the initialization API of the respective module.
70
715. The initialized audio devices are added to the cardManager linked list.
72
73#### Playback Process
74
75![=](figures/ADM_playback_flowchart.png)
76
771. The Audio Interface Lib sends the **Render Open** instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to deliver the instruction.
78
792. The Audio Interface Lib sends a path select instruction to the Control Dispatch service. The Control Dispatch service calls the DAI API to set the path.
80
813. The Audio Interface Lib sends hardware parameters to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to set the hardware parameters.
82
834. The Audio Interface Lib sends the start playing instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to perform related settings for each module.
84
855. The Audio Interface Lib sends audio data to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the **Platform AudioPcmWrite** API to send the audio data to DMA.
86
876. The Audio Interface Lib sends the stop playing instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the stop API of each module to perform related stop settings for each module.
88
897. The Audio Interface Lib sends the **Render Close** instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the **Platform AudioRenderClose** API to release resources.
90
91#### Control Process
92
93![](figures/ADM_control_flowchart.png)
94
951. When the volume needs to be adjusted, the Audio Interface Lib sends an instruction for obtaining the volume range to the Control Dispatch service. The Control Dispatch service parses the instruction and calls **get()** of the codec module to obtain the volume range.
962. The Audio Interface Lib sends an instruction for setting the volume to the Control Dispatch service. The Control Dispatch service parses the instruction and calls **Set()** of the codec module to set the volume.
97
98### Audio Driver Development Procedure
99
100#### Development on an Adapted Platform
101
102The following figure shows the process for developing the codec or accessory (SmartPA) driver on a chip platform (Hi3516D V300) to which the ADM has adapted.
103
104![](figures/audio_development_flowchart_1.png)
105
106- Add register information to the private HDF configuration source (HCS) of the codec or SmartPA based on the chip description.
107
108- If the workflow of the newly added codec or SmartPA is the same as that of the existing codec or SmartPA, you do not need to implement the operation function set or configure the compilation file for the newly added codec or SmartPA.
109
110- Perform build, debugging, and testing.
111
112#### Development on a New Platform
113
114The following figure shows the driver development process if the ADM has not adapted to the platform.
115
116![](figures/audio_development_flowchart_2.png)
117
118The codec (optional), DAI, DMA, DSP (optional), and SmartPA (optional) modules of the audio adapter need to be adapted to the new platform.
119
120- Add register information of each module driver to the private configuration file of the respective module according to the chip description.
121
122- Implement the operation function set of each module.
123
124- Modify the compilation file of the audio module.
125
126- Perform build, debugging, and testing.
127
128
129
130## Audio Driver Development Examples
131
132Code path: **drivers/peripheral/audio**
133
134The following uses Hi3516D V300 as an example to describe how to develop the audio codec driver, accessory driver, DAI driver, and platform driver.
135
136### Codec Driver Development Example
137Code path: **drivers/peripheral/audio/chipsets/hi3516dv300/codec**
138
139The major steps for developing the codec driver are as follows:
1401. Define and fill in a codec instance.
1412. Implement callbacks for the codec instance.
1423. Register and bind the codec instance to the HDF.
1434. Configure the HCS and makefile.
144
145#### Filling in Codec Data Structures
146
147Fill in the following data structures for the codec module:
148
149- **g_codecData**: operation function set and private data set of the codec device.
150
151- **g_codecDaiDeviceOps**: codec DAI device operation function set, including APIs for starting transmission and setting parameters.
152
153- **g_codecDaiData**: operation function set and private data set of the digital audio interface of the codec.
154
155```c
156struct CodecData g_codecData = {
157  .Init = CodecDeviceInit,     // Initialize the codec device (need to be implemented for a new platform).
158  .Read = AudioDeviceReadReg,  // Read the register (already implemented in the existing framework and no adaptation needed).
159  .Write = AudioDeviceWriteReg,  // Write the register (already implemented in the existing framework and no adaptation needed).
160};
161
162struct AudioDaiOps g_codecDaiDeviceOps = {
163  .Startup = CodecDaiStartup,   // Start transmission (need to be implemented for a new platform).
164  .HwParams = CodecDaiHwParams, // Set parameters (need to be implemented for a new platform).
165};
166
167struct DaiData g_codecDaiData = {
168  .DaiInit = CodecDaiDeviceInit,  // Initialize the codec DAI device (need to be implemented for a new platform).
169  .ops = &g_codecDaiDeviceOps,  // codec DAI device operation function set.
170};
171```
172
173#### Initializing codecDevice and codecDai
174
175**CODECDeviceInit** sets audio input/audio output (AIAO), initializes registers, inserts **g_audioControls** into the control linked list, initializes the power management, and selects a path.
176
177```c
178int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec)
179{
180  	...
181	/* Register set() and get() of the AIAO module on the Hi3516 platform. */
182	CodecSetCtlFunc(codec->devData, AudioCodecAiaoGetCtrlOps, AudioCodecAiaoSetCtrlOps)
183  	...
184	/* Hi3516 codec register IoRemap */
185	CodecHalSysInit();
186  	...
187	/* Initialize the codec registers of the Hi3516 platform. */
188	CodecRegDefaultInit(codec->devData->regCfgGroup);
189  	...
190	/* Insert g_audioControls of the Hi3516 platform to the controller linked list.*/
191  	AudioAddControls(audioCard, codec->devData->controls, codec->devData->numControls);
192  	...
193	/* Load the codec of the Hi3516 platform to the SAPM. */
194	AudioSapmNewComponents(audioCard, codec->devData->sapmComponents, codec->devData->numSapmComponent);
195  	...
196	/* Insert the codec of the Hi3516 platform to the audioRoutes linked list. */
197  	AudioSapmAddRoutes(audioCard, g_audioRoutes, HDF_ARRAY_SIZE(g_audioRoutes);
198   	...
199	AudioSapmNewControls(audioCard);
200  	...
201	/* Hi3516 codec power management */
202  	AudioSapmSleep(audioCard);
203   	...
204   	return HDF_SUCCESS;
205}
206```
207
208**CodecDaiDeviceInit** initializes the codec DAI device. This API is not used on the Hi3516 and is reserved.
209
210```c
211int32_t CodecDaiDeviceInit(struct AudioCard *card, const struct DaiDevice *device)
212
213{
214  	...
215	AUDIO_DRIVER_LOG_DEBUG("codec dai device name: %s\n", device->devDaiName);
216  	(void)card;
217  	return HDF_SUCCESS;
218}
219```
220
221#### Implementing the Codec Operation Function Set
222
223The codec module is encapsulated with the **read()** and **write()** functions of the read and write registers at the operating system abstraction layer (OSAL).
224
225If the new platform cannot use the OSAL **read()** and **write()** functions to operate registers, you should implement them.
226
227```c
228int32_t AudioDeviceReadReg(unsigned long virtualAddress, uint32_t reg, uint32_t *val)
229{
230  ...
231  *val = OSAL_READL((void *)((uintptr_t)(virtualAddress + reg)));
232  return HDF_SUCCESS;
233}
234
235int32_t AudioDeviceWriteReg(unsigned long virtualAddress, uint32_t reg, uint32_t value)
236{
237  OSAL_WRITEL(value, (void *)((uintptr_t)(virtualAddress + reg)));
238  return HDF_SUCCESS;
239}
240```
241
242**CodecDaiStartup** completes startup settings.
243
244```c
245int32_t CodecDaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
246{
247  int32_t ret;
248  ...
249  (void)card;
250  ret = CodecSetAdcTuneEnable(device->devData->regCfgGroup);
251  ...
252  return HDF_SUCCESS;
253}
254```
255
256**CodecDaiHwParams** sets parameters, including the sampling rate and bit width.
257
258```c
259int32_t CodecDaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
260{
261  unsigned int bitWidth;
262  struct CodecDaiParamsVal codecDaiParamsVal;
263  ...
264  int ret = AudioFormatToBitWidth(param->format, &bitWidth);
265  ...
266  codecDaiParamsVal.frequencyVal = param->rate;
267  codecDaiParamsVal.formatVal = bitWidth;
268  ret = CodecDaiParamsUpdate(card->rtd->codecDai->devData->regCfgGroup, codecDaiParamsVal);
269  ...
270  return HDF_SUCCESS;
271}
272```
273
274#### Registering and Binding Codec to HDF
275
276This process depends on the driver implementation mode of the HDF. For details, see [HDF](driver-hdf-overview.md).
277
278Fill in the **g_codecDriverEntry** structure. Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. Implement the pointers to the **Bind**, **Init**, and **Release** functions.
279
280drivers/peripheral/audio/chipsets/hi3516dv300/codec/src/hi3516_codec_adapter.c
281
282```c
283struct HdfDriverEntry g_codecDriverEntry = {
284   .moduleVersion = 1,
285   .moduleName = "CODEC_HI3516",
286   .Bind = CodecDriverBind,
287   .Init = CodecDriverInit,
288   .Release = CodecDriverRelease,
289};
290HDF_INIT(g_codecDriverEntry);
291```
292
293**CodecDriverBind** binds the device in the HDF to the codec and registers the codec service with the HDF.
294
295```c
296static int32_t CodecDriverBind(struct HdfDeviceObject *device)
297{
298  struct CodecHost *codecHost = (struct CodecHost *)OsalMemCalloc(sizeof(*codecHost));
299  ...
300  codecHost->device = device;
301  device->service = &codecHost->service;
302  return HDF_SUCCESS;
303}
304```
305
306**CodecDriverInit** obtains the **codecService** name and private register configuration, and inserts them into the linked list by using **AudioRegisterCodec**.
307
308```c
309static int32_t CodecDriverInit(struct HdfDeviceObject *device)
310{
311  ...
312  CodecGetConfigInfo(device, &g_codecData);
313  CodecSetConfigInfo(&g_codecData, &g_codecDaiData);
314  CodecGetServiceName(device, &g_codecData.drvCodecName);
315  CodecGetDaiName(device, &g_codecDaiData.drvDaiName);
316  AudioRegisterCodec(device, &g_codecData, &g_codecDaiData);
317  ...
318  return HDF_SUCCESS;
319}
320```
321
322**CodecDriverRelease** releases driver resources.
323
324```c
325static void CodecDriverRelease(struct HdfDeviceObject *device)
326{
327   codecHost = (struct CodecHost *)device->service;
328   OsalMemFree(codecHost);
329}
330```
331
332#### Configuring HCS<a name="section4115"></a>
333
334Configure the driver node, loading sequence, and service name in the .hcs file. For details about the HCS syntax, see [Driver Configuration Management](driver-hdf-manage.md) in the HDF.
335
336Path of the standard-system configuration file:
337
338**vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/**
339
340Path of the small-system configuration file:
341
342**vendor/hisilicon/hispark_taurus/hdf_config/**
343
344**Configuring Codec Device Information in device_info.hcs**
345
346Add codec node configuration. Modify **moduleName** in the configuration file. The value must be the same as **moduleName** in the **HdfDriverEntry** structure. Generally, the value should present the hardware platform. For example, moduleName = "CODEC_HI3516".
347
348The code snippet is as follows:
349
350```c
351     audio :: host {
352      device_codec :: device {
353         device0 :: deviceNode {
354           policy = 1;   // The codec module provides services only for the kernel.
355           priority = 50;  // The codec module must be loaded before the load of the HDF_AUDIO module.
356           preload = 0;
357           permission = 0666;
358           moduleName = "CODEC_HI3516"; // The value must be the same as moduleName in HdfDriverEntry.
359           serviceName = "codec_service_0"; // Name of the service provided externally.
360           deviceMatchAttr = "hdf_codec_driver"; // Name of the private attribute, which is used to match the corresponding private data (including the register configuration).
361         }
362       }
363```
364
365**Configuring Dependencies in audio_config.hcs**
366
367Configure dependencies between the codec, platform, DAI, DSP, and accessory for the audio adapters.
368
369The code snippet is as follows:
370
371```c
372root {
373    platform {
374        ...
375        controller_0x120c1001 :: card_controller {
376            // Set the private data attribute name, which must be the same as deviceMatchAttr in device_info.hcs.
377            match_attr = "hdf_audio_driver_1";
378            serviceName = "hdf_audio_smartpa_dev0"; // Name of the service provided externally.
379            accessoryName = "codec_service_1"; // External codec service name.
380            platformName = "dma_service_0"; // DMA service.
381            cpuDaiName = "dai_service"; // CPU DAI service.
382            accessoryDaiName = "accessory_dai"; // External DAI.
383            dspName = "dsp_service_0"; // DSP service name.
384            dspDaiName = "dsp_dai"; // DSP DAI.
385        }
386    }
387}
388```
389
390**Configuring Private Registers in codec_config.hcs**
391
392The configuration matches **deviceMatchAttr** of the codec configured in **device_info.hcs**. It includes the register configuration.
393
394Binding the control functionality configuration is to configure the control functionalities and their register parameters in the .hcs file according to unified structure specifications. The configuration can be obtained and parsed, and added to the controller linked list.
395
396- **regConfig**: register and control functionality configuration
397
398- **ctrlParamsSeqConfig**: control functionality register configuration
399
400- **daiStartupSeqConfig**: DAI startup configuration
401
402- **daiParamsSeqConfig**: playback parameter configuration
403
404- **resetSeqConfig**: reset process register configuration
405
406- **initSeqConfig**: initialization process register configuration
407
408- **controlsConfig**: control functionality configuration. The **array index** (specific service scenario) and **iface** (same as the HAL) are of fixed values.
409
410```
411array index
4120: Main Playback Volume
4131: Main Capture Volume
4142: Playback Mute
4153: Capture Mute
4164: Mic Left Gain
4175: Mic Right Gain
4186: External Codec Enable
4197: Internally Codec Enable
4208: Render Channel Mode
4219: Capture Channel Mode
422iface
4230: virtual dac device
4241: virtual adc device
4252: virtual adc device
4263: virtual mixer device
4274: Codec device
4285: PGA device
4296: AIAO device
430```
431
432**ctrlParamsSeqConfig**: control function register configuration. The **item** sequence corresponds to the **item** sequence in **controlsConfig**, indicating the register configuration corresponding to a function.
433
434```c
435 root {
436    platform {
437        template codec_controller {
438            match_attr = "";
439            serviceName = "";
440            codecDaiName = "";
441        }
442        controller_0x120c1030 :: codec_controller {
443            match_attr = "hdf_codec_driver";
444            serviceName = "codec_service_0";
445            codecDaiName = "codec_dai";
446
447	        /* Base address of the Hi3516 register*/
448            idInfo {
449                chipName = "hi3516";        // Codec name
450                chipIdRegister = 0x113c0000;  // Codec base address
451                chipIdSize = 0x1000;        // Codec address offset
452            }
453
454	       /* Register configuration, including configuration of registers */
455            regConfig {
456               /*  reg: register address
457                    rreg: register address
458                    shift: shift bits
459                    rshift: rshift bits
460                    min: min value
461                    max: max value
462                    mask: mask of value
463                    invert: enum InvertVal 0-uninvert 1-invert
464                    value: value
465                */
466
467                /* reg, value */
468                initSeqConfig = [
469                    0x14,    0x04000002,
470                    0x18,    0xFD200004,
471                    0x1C,    0x00180018,
472                    0x20,    0x83830028,
473                    0x24,    0x00005C5C,
474                    0x28,    0x00130000,
475                    0x30,    0xFF035A00,
476                    0x34,    0x08000001,
477                    0x38,    0x06062424,
478                    0x3C,    0x1E1EC001,
479                    0x14,    0x04000002
480                ];
481
482                /* Control functionality configuration
483                   array index, iface, enable*/
484                controlsConfig = [
485                    0,  0,  0,
486                    1,  1,  1,
487                    2,  0,  1,
488                    3,  1,  1,
489                    4,  2,  1,
490                    5,  2,  1,
491                    8,  6,  0,
492                    9,  6,  0,
493                ];
494                /* Control functionality register configuration
495                   reg, rreg, shift, rshift, min, max, mask, invert, value */
496                ctrlParamsSeqConfig = [
497                    0x3c, 0x3c, 24, 24, 0x0, 0x57, 0x7F, 1, 0,   //"Main Capture Volume"
498                    0x38, 0x38, 31, 31, 0x0, 0x1, 0x1, 0, 0,     //"Playback Mute"
499                    0x3c, 0x3c, 31, 31, 0x0, 0x1, 0x1, 0, 0,      //"Capture Mute"
500                    0x20, 0x20, 16, 16, 0x0, 0xF, 0x1F, 0, 0,     //"Mic Left Gain"
501                    0x20, 0x20, 24, 24, 0x0, 0xF, 0x1F, 0, 0,     // "Mic Right Gain"
502                    0x2000, 0x2000, 16, 16, 0x0, 0x7, 0x7, 0, 0,  // "Render Channel Mode"
503                    0x1000, 0x1000, 16, 16, 0x0, 0x7, 0x7, 0, 0  //"Capture Channel Mode"
504                ];
505
506                /* After the upper layer delivers parameters, write audio-related data to registers.
507	               reg, rreg, shift, rshift, min, max, mask, invert, value */
508                daiParamsSeqConfig = [
509                    0x30, 0x30, 13, 13, 0x0, 0x1F, 0x1F, 0, 0x0,    // i2s_frequency
510                    0x1C, 0x1C, 6, 6, 0x0, 0x3, 0x3, 0, 0x0,       // adc_mode_sel
511                    0x30, 0x30, 22, 22, 0x0, 0x3, 0x3, 0, 0x0,     // i2s_datawith
512                ];
513
514                /* Configuration of the power management function register.
515                   reg, rreg, shift, rshift, min, max, mask, invert, value */
516                ctrlSapmParamsSeqConfig = [
517                    0x20, 0x20, 23, 23, 0x0, 0x1, 0x1, 0, 0,  //LPGA MIC 0 -- connect MIC
518                    0x20, 0x20, 31, 31, 0x0, 0x1, 0x1, 0, 0,  //RPGA MIC 0 -- connect MIC
519                    0x30, 0x30, 27, 27, 0x0, 0x1, 0x1, 0, 0,  //dacl to dacr mixer
520                    0x30, 0x30, 26, 26, 0x0, 0x1, 0x1, 0, 0  //dacr to dacl mixer
521                ];
522
523        		/*
524                 Power management component configuration
525                 componentName: function name, {"ADCL", "ADCR", "DACL", "DACR", "LPGA", "RPGA", "SPKL", "SPKR", "MIC"} array index.
526                 sapmType,compNameIndex,reg, mask,shift,invert, kcontrolNews,kcontrolsNum
527                */
528                sapmComponent = [
529                    10,  0,  0x20,  0x1,  15,  1,  0,  0,    //ADCL
530                    10,  1,  0x20,  0x1,  14,  1,  0,  0,    //ADCR
531                    11,  2,  0x14,  0x1,  11,  1,  0,  0,    //DACL
532                    11,  3,  0x14,  0x1,  12,  1,  0,  0,    //DACR
533                    8,   4,  0x20,  0x1,  13,  1,  1,  1,    //LPGA
534                    8,   5,  0x20,  0x1,  12,  1,  2,  1,    //RPGA
535                    15,  6,  0,     0x1,  0,   0,  3,  1,    //SPKL
536                    15,  7,  0,     0x1,  0,   0,  4,  1,    //SPKR
537                    0,   8,  0,     0x1,  0,   0,  0,  0     //MIC
538                ];
539
540	          /* Power management function configuration
541                   array index,  iface,  enable
542              */
543                sapmConfig = [
544        	        0,    5,    1,
545                    1,    5,    1,
546                    2,    0,    1,
547                    3,    0,    1
548                ];
549            }
550        }
551    }
552}
553```
554
555Read the .hcs files in the C code to obtain register configuration.
556
557```c
558static int32_t CodecDriverInit(struct HdfDeviceObject *device)
559{
560  ...
561  CodecGetConfigInfo(device, &g_codecData) ;
562  CodecSetConfigInfo(&g_codecData, &g_codecDaiData);
563  ...
564  return HDF_SUCCESS;
565}
566```
567
568When the codec is registered, the input parameter **device** contains controller_0x120c1030 node information. You only need to parse the node to obtain the configuration information.
569
570```c
571int32_t CodecGetConfigInfo(const struct HdfDeviceObject *device, struct CodecData *codecData)
572{
573  codecData->regConfig = (struct AudioRegCfgData *)OsalMemCalloc(sizeof(*(codecData->regConfig)));
574  CodecGetRegConfig(device, codecData->regConfig);
575  return HDF_SUCCESS;
576}
577```
578
579Obtain the node configuration to configure the node.
580
581```c
582int32_t CodecGetRegConfig(const struct HdfDeviceObject *device, struct AudioRegCfgData *configData)
583{
584    ...
585    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
586    ...
587    idNode = drsOps->GetChildNode(root, "idInfo");
588    ParseAudioAttr(drsOps, idNode, &configData->audioIdInfo);
589    regCfgNode = drsOps->GetChildNode(root, "regConfig");
590    ...
591    DEV_RES_NODE_FOR_EACH_ATTR(regCfgNode, regAttr) {
592    ...
593    return HDF_SUCCESS;
594}
595```
596
597Obtain and use the configuration of the **regConfig** node. After the configuration files are parsed, the register information in the code can be directly updated.
598
599```c
600int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec)
601{
602...
603    if (CodecRegDefaultInit(codec->devData->regCfgGroup) != HDF_SUCCESS) {
604        AUDIO_DRIVER_LOG_ERR("CodecRegDefaultInit failed.");
605        return HDF_FAILURE;
606    }
607...
608    return HDF_SUCCESS;
609}
610```
611
612
613
614### Accessory Driver Development Example
615Code path: **drivers/peripheral/audio/chipsets/tfa9879/accessory**
616
617SmartPA is a type of accessory driver. The SmartPA development procedure is similar to the codec development procedure.
6181. Define and fill in an accessory instance.
6192. Implement callbacks for the accessory instance.
6203. Register and bind the accessory instance to the HDF.
6214. Configure the HCS and makefile.
622
623#### Filling in Accessory Data Structures
624
625Fill in the following data structures for the accessory module:
626
627- **g_tfa9879Data**: operation function set of the accessory device. It contains the configuration in the .hcs file, and defines and maps the functions for initializing the accessory device and reading and writing registers.
628
629- **g_tfa9879DaiDeviceOps**: data set of the DAI of the accessory device. It defines and maps the operation set of the accessory device DAI.
630
631- **g_tfa9879DaiData**: data set of the DAI of the accessory device. It defines and maps the driver name, initialization, and operation set of the data access interface of the accessory device.
632
633```c
634struct AccessoryData g_tfa9879Data = {
635    .Init = Tfa9879DeviceInit,
636    .Read = AccessoryDeviceRegRead,
637    .Write = AccessoryDeviceRegWrite,
638};
639
640struct AudioDaiOps g_tfa9879DaiDeviceOps = {
641    .Startup = Tfa9879DaiStartup,
642    .HwParams = Tfa9879DaiHwParams,
643};
644
645struct DaiData g_tfa9879DaiData = {
646    .drvDaiName = "accessory_dai",
647    .DaiInit = Tfa9879DaiDeviceInit,
648    .ops = &g_tfa9879DaiDeviceOps,
649};
650```
651
652#### Initializing accessoryDevice and accessoryDai
653
654As the entry function for device initialization, **Tfa9879DeviceInit** sets the address of the SmartPA I2C device, obtains configuration data, initializes (including resets) the device registers, and adds the control functionality to the controller linked list. The current demo also includes the initialization of the registers related to the Hi3516D V300 device, such as initialization of GPIO pins.
655
656```c
657int32_t Tfa9879DeviceInit(struct AudioCard *audioCard, const struct AccessoryDevice *device)
658{
659    int32_t ret;
660    ...
661    g_accessoryTransferData.i2cDevAddr = TFA9879_I2C_DEV_ADDR;  // 0x6D
662    // Obtain configuration data.
663    ret = AccessoryDeviceCfgGet(device->devData, &g_accessoryTransferData);
664    ...
665    // Initialize GPIO pins.
666    ret = Hi35xxGpioPinInit();
667    ...
668    // Initialize device registers.
669    ret = AccessoryDeviceCtrlRegInit();
670    ...
671    // Bind the control functionality configuration.
672    ret = AudioAddControls(audioCard, g_accessoryTransferData.accessoryControls,
673                           g_accessoryTransferData.accessoryCfgCtrlCount);
674    ...
675}
676```
677
678**AccessoryI2cReadWrite** reads and writes I2C registers.
679
680```c
681int32_t AccessoryI2cReadWrite(struct AudioAddrConfig *regAttr, uint16_t rwFlag)
682{
683    int32_t ret;
684    DevHandle i2cHandle;
685    int16_t transferMsgCount = 1;
686    uint8_t regs[I2C_REG_LEN];
687    struct I2cMsg msgs[I2C_MSG_NUM];
688    ...
689    i2cHandle = I2cOpen(I2C_BUS_NUM);
690    ...
691    if (rwFlag == I2C_FLAG_READ) {
692        transferMsgCount = I2C_MSG_NUM;
693    }
694    ret = AccessoryI2cMsgFill(regAttr, rwFlag, regs, msgs);
695    ...
696    ret = I2cTransfer(i2cHandle, msgs, transferMsgCount);
697    ...
698    AccessoryI2cRelease(msgs, transferMsgCount, i2cHandle);
699    return HDF_SUCCESS;
700}
701```
702
703#### Implementing the Accessory Operation Function Set
704
705The callbacks **AccessoryDeviceRegRead** and **AccessoryDeviceRegWrite** invoke **AccessoryI2cReadWrite** to read and write the control register values.
706
707```c
708int32_t AccessoryDeviceRegRead(const struct AccessoryDevice *codec, uint32_t reg, uint32_t *val)
709{
710    int32_t ret;
711    struct AudioAddrConfig regAttr;
712    ...
713    (void)codec;
714    regAttr.addr = (uint8_t)reg;
715    regAttr.value = 0;
716    ret = AccessoryI2cReadWrite(&regAttr, I2C_FLAG_READ);
717    if (ret != HDF_SUCCESS) {
718        AUDIO_DRIVER_LOG_ERR("failed.");
719        return HDF_FAILURE;
720    }
721    *val = regAttr.value;
722    ...
723    return HDF_SUCCESS;
724}
725
726int32_t AccessoryDeviceRegWrite(const struct AccessoryDevice *codec, uint32_t reg, uint32_t value)
727{
728    int32_t ret;
729    struct AudioAddrConfig regAttr;
730    (void)codec;
731    regAttr.addr = (uint8_t)reg;
732    regAttr.value = (uint16_t)value;
733    ret = AccessoryI2cReadWrite(&regAttr, 0);
734    ...
735    return HDF_SUCCESS;
736}
737```
738
739**Tfa9879DaiStartup** performs startup settings. The code snippet is as follows:
740
741```c
742int32_t Tfa9879DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
743{
744    int ret;
745    (void)card;
746	(void)device;
747	// Set the working status of SmartPA.
748    ret = Tfa9879WorkStatusEnable();
749    ...
750    return HDF_SUCCESS;
751}
752
753```
754
755**Tfa9879DaiHwParams** delivers playback parameters. The code snippet is as follows:
756
757```c
758int32_t Tfa9879DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
759{
760    int32_t ret;
761    uint16_t frequency, bitWidth;
762    struct DaiParamsVal daiParamsVal;
763    (void)card;
764	...
765	// Set the sampling rate.
766    ret = AccessoryDeviceFrequencyParse(param->rate, &frequency);
767	...
768	// Set the bit width.
769    ret = Tfa9879FormatParse(param->format, &bitWidth);
770    ...
771    daiParamsVal.frequencyVal = frequency;
772    daiParamsVal.formatVal = bitWidth;
773	daiParamsVal.channelVal = param->channels; // Set the audio channel.
774    ret = AccessoryDaiParamsUpdate(daiParamsVal);
775    ...
776    return HDF_SUCCESS;
777}
778```
779
780#### Registering and Binding Accessory to HDF
781
782This process depends on the driver implementation mode of the HDF. For details, see [HDF](driver-hdf-overview.md).
783
784Fill in the **g_tfa9879DriverEntry** structure. Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. Implement the pointers to the **Bind**, **Init**, and **Release** functions.
785
786drivers/peripheral/audio/chipsets/tfa9879/accessory/src/tfa9879_accessory_adapter.c
787
788```c
789static int32_t Tfa9879DriverBind(struct HdfDeviceObject *device)
790{
791    (void)device;
792    AUDIO_DRIVER_LOG_INFO("success!");
793    return HDF_SUCCESS;
794}
795
796static int32_t Tfa9879DriverInit(struct HdfDeviceObject *device)
797{
798    int32_t ret;
799    ...
800    // Obtain configuration data from .hcs files.
801    ret = AccessoryGetConfigInfo(device, &g_tfa9879Data);
802    ...
803    ret = ret = GetServiceName(device);
804    ...
805    ret = AudioRegisterAccessory(device, &g_tfa9879Data, &g_tfa9879DaiData);
806    ....
807    return HDF_SUCCESS;
808}
809
810/* HdfDriverEntry definitions */
811struct HdfDriverEntry g_tfa9879DriverEntry = {
812    .moduleVersion = 1,
813    .moduleName = "CODEC_TFA9879",
814    .Bind = Tfa9879DriverBind,
815    .Init = Tfa9879DriverInit,
816    .Release = NULL,
817};
818HDF_INIT(g_tfa9879DriverEntry);
819```
820
821#### Configuring HCS
822
823For details about the configuration process, see [Configuring HCS](#section4115) in **Codec Driver Development Example**.
824
825
826
827### Platform Driver Development Example
828Code path: **drivers/peripheral/audio/chipsets/hi3516dv300/soc**
829
830In audio driver development, the Platform module is configured to adapt to the DMA driver. The major steps for developing the platform driver are as follows:
8311. Define and fill in a platform instance.
8322. Implement callbacks for the platform instance.
8333. Register and bind the platform instance to the HDF.
8344. Configure the HCS and makefile.
835
836#### Filling in Platform Data Structures
837
838Fill in the following structures for the platform module:
839
840- **g_platformData**: private configuration of the platform device, including the initialization and operation functions of the platform device.
841
842- **g_dmaDeviceOps**: DMA device operation function set, including the encapsulation of some common DMA APIs.
843
844```c
845struct AudioDmaOps g_dmaDeviceOps = {
846    .DmaBufAlloc = Hi3516DmaBufAlloc,             // Apply for memory for the DMA device.
847    .DmaBufFree = Hi3516DmaBufFree,               // Release the memory of the DMA device.
848    .DmaRequestChannel = Hi3516DmaRequestChannel, // Request a DMA channel.
849    .DmaConfigChannel = Hi3516DmaConfigChannel,   // Configure the DMA channel.
850    .DmaPrep = Hi3516DmaPrep,                     // Prepare for DMA.
851    .DmaSubmit = Hi3516DmaSubmit,                 // Submit a DMA request.
852    .DmaPending = Hi3516DmaPending,               // Pend DMA.
853    .DmaPause = Hi3516DmaPause,                   // Pause or stop DMA.
854    .DmaResume = Hi3516DmaResume,                 // Resume DMA.
855    .DmaPointer = Hi3516DmaPointer,               // Obtain the current playing or recording position.
856};
857
858struct PlatformData g_platformData = {
859    .PlatformInit = AudioDmaDeviceInit, // Initialize the DMA device.
860    .ops = &g_dmaDeviceOps,
861};
862```
863
864#### Initializing dmaDevice
865
866**AudioDmaDeviceInit** initializes the DMA device, including setting the Hi3516 AIAO module.
867
868```c
869int32_t AudioDmaDeviceInit(const struct AudioCard *card, const struct PlatformDevice *platformDevice)
870{
871...
872    AiaoHalSysInit();
873    /* PIN MUX */
874    AiaoSysPinMux();
875    /* CLK reset */
876    AiaoClockReset();
877    /* AIAO initialization */
878    AiaoDeviceInit(chnId);
879...
880    return HDF_SUCCESS;
881}
882```
883
884#### Implementing the DMA Operation Function Set
885
886The DMA device operation function set includes the encapsulation of DMA common APIs. If the common APIs cannot meet development requirements, you can implement new DMA callbacks.
887
888```c
889int32_t Hi3516DmaBufAlloc(struct PlatformData *data, const enum AudioStreamType streamType);
890int32_t Hi3516DmaBufFree(struct PlatformData *data, const enum AudioStreamType streamType);
891int32_t Hi3516DmaRequestChannel(const struct PlatformData *data);
892int32_t Hi3516DmaConfigChannel(const struct PlatformData *data);
893int32_t Hi3516DmaPrep(const struct PlatformData *data);
894int32_t Hi3516DmaSubmit(const struct PlatformData *data);
895int32_t Hi3516DmaPending(struct PlatformData *data);
896int32_t Hi3516DmaPause(struct PlatformData *data);
897int32_t Hi3516DmaResume(const struct PlatformData *data);
898int32_t Hi3516DmaPointer(struct PlatformData *data, uint32_t *pointer);
899```
900
901#### Registering and Binding Platform to HDF
902
903This process depends on the driver implementation mode of the HDF. For details, see [HDF](driver-hdf-overview.md).
904
905- Fill in the **g_platformDriverEntry** structure.
906- Ensure that the value of **moduleName** is the same as that in **device_info.hcs**.
907- Implement the pointers to the **Bind**, **Init**, and **Release** functions.
908
909drivers/peripheral/audio/chipsets/hi3516dv300/soc/src/hi3516_dma_adapter.c
910
911```c
912static int32_t Hi3516DmaDriverInit(struct HdfDeviceObject *device)
913{
914...
915    OsalMutexInit(&g_platformData.renderBufInfo.buffMutex);
916    OsalMutexInit(&g_platformData.captureBufInfo.buffMutex);
917    g_platformData.platformInitFlag = false;
918    ret = AudioSocRegisterPlatform(device, &g_platformData);
919...
920    return HDF_SUCCESS;
921}
922
923static void Hi3516DmaDriverRelease(struct HdfDeviceObject *device)
924{
925    struct PlatformHost *platformHost = NULL;
926...
927    platformHost = (struct PlatformHost *)device->service;
928...
929    OsalMutexDestroy(&g_platformData.renderBufInfo.buffMutex);
930    OsalMutexDestroy(&g_platformData.captureBufInfo.buffMutex);
931    OsalMemFree(platformHost);
932}
933
934/* HdfDriverEntry definitions */
935struct HdfDriverEntry g_platformDriverEntry = {
936    .moduleVersion = 1,
937    .moduleName = "DMA_HI3516",
938    .Bind = Hi3516DmaDriverBind,
939    .Init = Hi3516DmaDriverInit,
940    .Release = Hi3516DmaDriverRelease,
941};
942HDF_INIT(g_platformDriverEntry);
943```
944
945#### Configuring HCS
946
947For details about the configuration process, see [Configuring HCS](#section4115) in **Codec Driver Development Example**.
948
949
950
951### DAI Driver Development Example
952Code path: **drivers/peripheral/audio/chipsets/hi3516dv300/soc**
953
954The major steps for developing the DAI driver are as follows:
9551. Define and fill in a DAI instance.
9562. Implement callbacks for the DAI instance.
9573. Register and bind the DAI instance to the HDF.
9584. Configure the HCS and makefile.
959
960#### Filling in DAI Data Structures
961
962Fill in the following structures for the DAI module:
963
964- **g_daiData**: private configuration of the DAI device, including the initialization of the DAI device, read/write of registers, and operation functions.
965
966- **g_daiDeviceOps**: DAI device operation function set, including setting DAI parameters and triggering and starting the DAI device.
967
968```c
969struct AudioDaiOps g_daiDeviceOps = {
970    .HwParams = DaiHwParams,
971    .Trigger = DaiTrigger,
972    .Startup = DaiStartup,
973};
974
975struct DaiData g_daiData = {
976    .DaiInit = DaiDeviceInit,
977    .Read = AudioDeviceReadReg,
978    .Write = AudioDeviceWriteReg,
979    .ops = &g_daiDeviceOps,
980};
981```
982
983#### Initializing daiDevice
984
985**DaiDeviceInit** initializes DAI configuration and adds the information to the controller linked list.
986
987```c
988int32_t DaiDeviceInit(struct AudioCard *audioCard, const struct DaiDevice *dai)
989{
990...
991    struct DaiData *data = dai->devData;
992    struct AudioRegCfgData *regConfig = dai->devData->regConfig;
993...
994    g_regCodecBase = OsalIoRemap(CODEC_REG_BASE, CODEC_MAX_REG_SIZE);
995...
996    data->regVirtualAddr = (uintptr_t)g_regCodecBase;
997    DaiSetConfigInfo(data);
998    AudioAddControls(audioCard, data->controls, data->numControls);
999	I2c6PinInit();
1000...
1001    data->daiInitFlag = true;
1002    return HDF_SUCCESS;
1003}
1004```
1005
1006#### Implementing the DAI Operation Function Set
1007
1008**AudioDeviceReadReg** and **AudioDeviceWriteReg** are not used on the Hi3516 and are reserved.
1009
1010**DaiHwParams** sets PCM stream information.
1011
1012```c
1013int32_t DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
1014{
1015    uint32_t bitWidth;
1016    struct DaiDevice *device = card->rtd->cpuDai;
1017...
1018    DaiCheckSampleRate(param->rate);
1019    struct DaiData *data = DaiDataFromCard(card);
1020    data->pcmInfo.channels = param->channels;
1021...
1022    AudioFormatToBitWidth(param->format, &bitWidth);
1023...
1024    data->pcmInfo.bitWidth = bitWidth;
1025    data->pcmInfo.rate = param->rate;
1026    data->pcmInfo.streamType = param->streamType;
1027    data->regVirtualAddr = (uintptr_t)g_regDaiBase;
1028...
1029	DaiParamsUpdate(device);
1030    data->regVirtualAddr = (uintptr_t)g_regCodecBase;
1031    return HDF_SUCCESS;
1032}
1033```
1034
1035**DaiTrigger** is not used on the Hi3516 and is reserved.
1036
1037**DaiStartup** updates the register configuration and configures the I2S.
1038
1039```c
1040int32_t DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
1041{
1042    struct AudioMixerControl *regCfgItem = NULL;
1043...
1044    regCfgItem = device->devData->regConfig->audioRegParams[AUDIO_DAI_STARTUP_PATAM_GROUP]->regCfgItem;
1045    itemNum = device->devData->regConfig->audioRegParams[AUDIO_DAI_STARTUP_PATAM_GROUP]->itemNum;
1046
1047    device->devData->regVirtualAddr = (uintptr_t)g_regDaiBase;
1048    for (int i = 0; i < itemNum; i++) {
1049        int ret = AudioUpdateDaiRegBits(device, &regCfgItem[i], regCfgItem[i].value);
1050        if (ret != HDF_SUCCESS) {
1051            AUDIO_DRIVER_LOG_ERR("set frequency fail.");
1052            return HDF_FAILURE;
1053        }
1054    }
1055    device->devData->regVirtualAddr = (uintptr_t)g_regCodecBase;
1056
1057    if (I2sPinInit() != HDF_SUCCESS) {
1058        AUDIO_DRIVER_LOG_ERR("I2sPinInit fail.");
1059    }
1060
1061    return HDF_SUCCESS;
1062}
1063```
1064
1065#### Registering and Binding DAI to HDF
1066
1067This process depends on the driver implementation mode of the HDF. For details, see [HDF](driver-hdf-overview.md).
1068
1069- Fill in the **g_daiDriverEntry** structure.
1070- Ensure that the value of **moduleName** is the same as that in **device_info.hcs**.
1071- Implement the pointers to the **Bind**, **Init**, and **Release** functions.
1072
1073drivers/peripheral/audio/chipsets/hi3516dv300/soc/src/hi3516_dai_adapter.c
1074
1075```c
1076static int32_t DaiDriverBind(struct HdfDeviceObject *device)
1077{
1078...
1079    struct DaiHost *daiHost = (struct DaiHost *)OsalMemCalloc(sizeof(*daiHost));
1080...
1081    daiHost->device = device;
1082    device->service = &daiHost->service;
1083    g_daiData.daiInitFlag = false;
1084...
1085    return HDF_SUCCESS;
1086}
1087
1088static int32_t DaiDriverInit(struct HdfDeviceObject *device)
1089{
1090...
1091    DaiGetConfigInfo(device, &g_daiData);
1092    DaiGetServiceName(device);
1093...
1094    OsalMutexInit(&g_daiData.mutex);
1095    AudioSocRegisterDai(device, &g_daiData);
1096...
1097    return HDF_SUCCESS;
1098}
1099
1100static void DaiDriverRelease(struct HdfDeviceObject *device)
1101{
1102...
1103    OsalMutexDestroy(&g_daiData.mutex);
1104...
1105    struct DaiHost *daiHost = (struct DaiHost *)device->service;
1106...
1107    OsalMemFree(daiHost);
1108}
1109
1110/* HdfDriverEntry definitions */
1111struct HdfDriverEntry g_daiDriverEntry = {
1112    .moduleVersion = 1,
1113    .moduleName = "DAI_HI3516",
1114    .Bind = DaiDriverBind,
1115    .Init = DaiDriverInit,
1116    .Release = DaiDriverRelease,
1117};
1118HDF_INIT(g_daiDriverEntry);
1119```
1120
1121#### Configuring HCS
1122
1123For details about the configuration process, see [Configuring HCS](#section4115) in **Codec Driver Development Example**.
1124
1125
1126
1127### Adding Compilation Configuration to Makefile
1128
1129Add the newly added files to the **Makefile** file to link them to the kernel image.
1130
1131Standard system (Linux): **drivers/adapter/khdf/linux/model/audio/Makefile**
1132
1133```makefile
1134obj-$(CONFIG_DRIVERS_HDF_AUDIO_CODEC) += \
1135$(KHDF_AUDIO_HI3516DV300_DIR)/../tfa9879/accessory/src/tfa9879_accessory_adapter.o \
1136$(KHDF_AUDIO_HI3516DV300_DIR)/../tfa9879/accessory/src/tfa9879_accessory_impl.o \
1137$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_adapter.o \
1138$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_impl.o \
1139$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_ops.o \
1140$(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_adapter.o \
1141$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_adapter.o \
1142$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_ops.o \
1143$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_aiao_impl.o \
1144$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_ops.o \
1145$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_adapter.o \
1146$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_adapter.o
1147```
1148
1149Small system (LiteOS): **drivers/adapter/khdf/liteos/model/audio/Makefile**
1150
1151```makefile
1152LOCAL_SRCS += \
1153$(KHDF_AUDIO_HI3516DV300_DIR)/../tfa9879/accessory/src/tfa9879_accessory_adapter.c \
1154$(KHDF_AUDIO_HI3516DV300_DIR)/../tfa9879/accessory/src/tfa9879_accessory_impl.c \
1155$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_adapter.c \
1156$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_impl.c \
1157$(KHDF_AUDIO_HI3516DV300_DIR)/codec/src/hi3516_codec_ops.c \
1158$(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_adapter.c \
1159$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_adapter.c \
1160$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_ops.c \
1161$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_aiao_impl.c \
1162$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_ops.c \
1163$(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_adapter.c
1164```
1165
1166
1167
1168### Source Code Structure and Directory
1169
1170The development example implements the functions in the header file of the driver interface. The following uses Hi3516 as an example to describe the directory structure.
1171
1172Path of the driver implementation sample code: **drivers\peripheral\audio\chipsets\**
1173
1174```
1175├── hi3516dv300
1176│   ├── codec
1177│   │   ├── include
1178│   │   │   ├── hi3516_codec_impl.h
1179│   │   │   └── hi3516_codec_ops.h
1180│   │   ├── src
1181│   │   │   ├── hi3516_codec_adapter.c  // Codec driver entry
1182│   │   │   ├── hi3516_codec_impl.c     // Implement codec hardware operations.
1183│   │   │   └── hi3516_codec_ops.c      // Implement codec driver APIs.
1184│   │   └── test
1185│   │       └── unittest
1186│   ├── dsp
1187│   │   └── include
1188│   │       └── dsp_ops.h
1189│   │   └── src
1190│   │       └── dsp_adapter.c           // DSP driver entry
1191│   │       └── dsp_ops.c
1192│   └── soc
1193│       ├── include
1194│       │   ├── hi3516_aiao_impl.h
1195│       │   ├── hi3516_dai_ops.h
1196│       │   └── hi3516_dma_ops.h
1197│       ├── src
1198│       │   ├── hi3516_aiao_impl.c
1199│       │   ├── hi3516_dai_adapter.c   // DAI driver entry
1200│       │   ├── hi3516_dai_ops.c
1201│       │   ├── hi3516_dma_adapter.c   // DMA driver entry
1202│       │   └── hi3516_dma_ops.c
1203│       └── test
1204│           └── unittest
1205└── tfa9879
1206    └── accessory
1207        ├── include
1208        │   └── tfa9879_accessory_impl.h
1209        └── src
1210            ├── tfa9879_accessory_adapter.c  // Accessory driver entry
1211            └── tfa9879_accessory_impl.c
1212```
1213
1214HCS Files and Directory
1215
1216```
1217Standard system:
1218vendor/hisilicon/hispark_taurus_standard/
1219└── hdf_config
1220    └── khdf
1221        ├── audio
1222        │   ├── audio_config.hcs
1223        │   ├── codec_config.hcs
1224        │   ├── dai_config.hcs
1225        │   ├── dma_config.hcs
1226        │   └── dsp_config.hcs
1227        ├── device_info
1228        │   └── device_info.hcs
1229        └── hdf.hcs
1230
1231Small system:
1232vendor/hisilicon/hispark_taurus/
1233├── config.json
1234└── hdf_config
1235    ├── audio
1236    │   ├── audio_config.hcs
1237    │   ├── codec_config.hcs
1238    │   ├── dai_config.hcs
1239    │   ├── dma_config.hcs
1240    │   └── dsp_config.hcs
1241    ├── device_info
1242    │   └── device_info.hcs
1243    └── hdf.hcs
1244```
1245
1246
1247
1248## HAL-based Development Procedure and Example
1249The Hardware Abstraction Layer (HAL) provides the following functions:
1250
12511. Provides audio HDIs for audio services to implement basic audio features on applications.
12522. Provides standard interfaces for device developers to comply with the HDI adapter standards. This promises a healthy evolution of the ecosystem.
1253
1254Code path: **drivers/peripheral/audio/hal**
1255
1256### Development procedure
1257
1258![](figures/HAL_flowchart.png)
1259
12601. Call **GetAudioManagerFuncs()** to obtain functions.
1261
12622. Call **GetAllAdapters()** to obtain information about the supported audio adapters and call **LoadAdapter()** to load the corresponding audio adapter.
1263
12643. Create an audio player class by calling **CreateRender()** or create a recorder class and deliver audio attributes.
1265
12664. Call the methods mounted to the created audio player class to call **render->control.Start()** and **render->RenderFrame()** to dispatch the start instruction and deliver audio data cyclically.
1267
12685. During the playback, call **render->control.Pause()**, **render->control.Resume()**, or **render->volume.SetVolume()** to control the audio player service, for example, pausing the playback, resuming the playback, and adjusting the volume.
1269
12706. After the audio player service is complete, stop the playback, destroy the audio player class, and unload the audio adapter.
1271
1272    1. render->control.Stop();
1273
1274    2. adapter->DestroyRender();
1275
1276    3. manager->UnloadAdapter();
1277
1278### Development Example
1279
1280```c
1281#include <string.h>
1282#include <stdio.h>
1283#include "audio_types.h"
1284#include <pthread.h>
1285#include "audio_manager.h"
1286
1287 /* Open the dynamic link to the so library. */
1288char *soPathHdi = "/system/lib/libhdi_audio.z.so";
1289void *g_handle = dlopen(soPathHdi , 1);
1290
1291int32_t FrameStart(void *param)
1292{
1293...
1294    /* Send audio data cyclically. */
1295    do {
1296        readSize = (remainingDataSize > bufferSize) ? bufferSize : remainingDataSize;
1297        numRead = fread(frame, 1, readSize, g_file);
1298        if (numRead > 0) {
1299            ret = render->RenderFrame(render, frame, numRead, &replyBytes);
1300            if (ret == HDF_ERR_INVALID_OBJECT) {
1301                LOG_FUN_ERR("Render already stop!");
1302                break;
1303            }
1304            remainingDataSize -= numRead;
1305        }
1306        /* Pause the playback and wait. */
1307        while (g_waitSleep) {
1308            printf("music pause now.\n");
1309            pthread_cond_wait(&g_functionCond, &g_mutex);
1310            printf("music resume now.\n");
1311        }
1312    } while (!g_closeEnd && numRead > 0 && remainingDataSize > 0);
1313...
1314}
1315
1316static void *hal_main()
1317{
1318    /* Map and call the entry function. */
1319    struct AudioManager *(*getAudioManager)() =
1320    (struct AudioManager *(*)())(dlsym(g_handle, "GetAudioManagerFuncs"));
1321    struct AudioManager *manager = getAudioManager();
1322
1323    /* Obtain the audio adapter list. */
1324    struct AudioAdapterDescriptor *descs = NULL;
1325    int32_t size = 0;
1326    int32_t ret = manager->GetAllAdapters(manager, &descs, &size);
1327
1328    /* Locate the audio adapter and port based on the specified audio adapter name and port description. */
1329    enum AudioPortDirection port = PORT_OUT;  // The port type OUT means to play the audio.
1330    struct AudioPort renderPort;
1331    char * adapterNameCase = "usb";
1332    int32_t index = SwitchAdapter(descs, adapterNameCase, port, &renderPort, size);
1333
1334    /* Load the audio adapter based on the matched audio adapter information. */
1335    struct AudioAdapter *adapter = NULL;
1336    struct AudioAdapterDescriptor *desc = &descs[index];  // Obtain the device based on the matched audio adapter information.
1337    manager->LoadAdapter(manager, desc, &adapter); // Load the audio adapter and obtain the audio adapter instance.
1338
1339    /* Create an audio player class. */
1340    struct AudioRender *render;
1341    struct AudioDeviceDescriptor devDesc;
1342    struct AudioSampleAttributes attrs;
1343    InitDevDesc(&devDesc, renderPort.portId);  // Initialize device parameters.
1344    WavHeadAnalysis(g_file, &attrs);  // Parse the audio file to set attributes.
1345    adapter->CreateRender(adapter, &devDesc, &attrs, &render);
1346
1347    /* Deliver the audio data to play. */
1348    render->control.Start((AudioHandle)render);   // Dispatch the start instruction and prepare for the action.
1349    pthread_create(&g_tids, NULL, (void *)(&FrameStart), &g_str); // Start the thread to play the audio clip.
1350
1351    /* Control instructions */
1352    render->control.Pause((AudioHandle)render);  // Pause the playback.
1353    render->control.Resume((AudioHandle)render); // Resume the playback.
1354    render->volume.SetVolume((AudioHandle)render, 0.5); // Set the volume.
1355
1356     /* Stop playback and destroy the audio player class. */
1357    render->control.Stop((AudioHandle)render);
1358    adapter->DestroyRender(adapter, render);
1359     /* Unload the audio adapter. */
1360    manager->UnloadAdapter(manager, adapter);
1361}
1362```
1363
1364
1365
1366## Summary
1367
1368This document provides all the key adaptations involved in the audio driver development. It elaborates how to adapt the audio driver and use HDI APIs. You can conduct development based on the chip you use. After reading this document, you will be able to master the audio driver development based on the HDF framework.
1369