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(®Attr, 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(®Attr, 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, ®CfgItem[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