Przeglądaj źródła

component/bt: A2DP code original in example project moved to component/bt directory;

1. move btif and A2DP source code from project directory to bluetooth directory;
2. some updates of audio source code;
wangmengyang 9 lat temu
rodzic
commit
0ad3017df7
100 zmienionych plików z 9938 dodań i 1 usunięć
  1. 0 0
      components/bt/bluedroid/api/include/esp_a2dp_api.h
  2. 0 0
      components/bt/bluedroid/api/include/esp_bt_stack_manager.h
  3. 1 0
      components/bt/bluedroid/api/include/esp_gap_bt_api.h
  4. 0 0
      components/bt/bluedroid/btif/bta_av_co.c
  5. 0 0
      components/bt/bluedroid/btif/btif_avk.c
  6. 0 0
      components/bt/bluedroid/btif/btif_core.c
  7. 0 0
      components/bt/bluedroid/btif/btif_dm.c
  8. 0 0
      components/bt/bluedroid/btif/btif_media_task.c
  9. 0 0
      components/bt/bluedroid/btif/btif_profile_queue.c
  10. 0 0
      components/bt/bluedroid/btif/btif_sm.c
  11. 0 0
      components/bt/bluedroid/btif/btif_util.c
  12. 0 0
      components/bt/bluedroid/btif/include/btif_api.h
  13. 0 0
      components/bt/bluedroid/btif/include/btif_av.h
  14. 0 0
      components/bt/bluedroid/btif/include/btif_av_api.h
  15. 0 0
      components/bt/bluedroid/btif/include/btif_av_co.h
  16. 0 0
      components/bt/bluedroid/btif/include/btif_common.h
  17. 0 0
      components/bt/bluedroid/btif/include/btif_dm.h
  18. 0 0
      components/bt/bluedroid/btif/include/btif_media.h
  19. 0 0
      components/bt/bluedroid/btif/include/btif_profile_queue.h
  20. 0 0
      components/bt/bluedroid/btif/include/btif_sm.h
  21. 0 0
      components/bt/bluedroid/btif/include/btif_util.h
  22. 0 0
      components/bt/bluedroid/btif/include/stack_manager.h
  23. 0 0
      components/bt/bluedroid/btif/include/uinput.h
  24. 0 0
      components/bt/bluedroid/btif/stack_manager.c
  25. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_assert.h
  26. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_bitstream.h
  27. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_bt_spec.h
  28. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_codec_sbc.h
  29. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
  30. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_common.h
  31. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_cpu_dep.h
  32. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_modules.h
  33. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_osinterface.h
  34. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_status.h
  35. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_stddefs.h
  36. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_string.h
  37. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_time.h
  38. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/include/oi_utils.h
  39. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/alloc.c
  40. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/bitalloc-sbc.c
  41. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/bitalloc.c
  42. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/bitstream-decode.c
  43. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/decoder-oina.c
  44. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/decoder-private.c
  45. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/decoder-sbc.c
  46. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/dequant.c
  47. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/framing-sbc.c
  48. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/framing.c
  49. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/oi_codec_version.c
  50. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/readsamplesjoint.inc
  51. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/synthesis-8-generated.c
  52. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/synthesis-dct8.c
  53. 0 0
      components/bt/bluedroid/embdrv/sbc/decoder/srce/synthesis-sbc.c
  54. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_dct.h
  55. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
  56. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_encoder.h
  57. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_if.h
  58. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_types.h
  59. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_analysis.c
  60. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_dct.c
  61. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
  62. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
  63. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
  64. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
  65. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_encoder.c
  66. 0 0
      components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_packing.c
  67. 4 1
      components/bt/component.mk
  68. 1 0
      examples/09_a2dp/components/EspAudio/.gitignore
  69. 30 0
      examples/09_a2dp/components/EspAudio/Kconfig
  70. 4 0
      examples/09_a2dp/components/EspAudio/README.md
  71. 17 0
      examples/09_a2dp/components/EspAudio/component.mk
  72. 146 0
      examples/09_a2dp/components/EspAudio/include/EspAudio.h
  73. 78 0
      examples/09_a2dp/components/EspAudio/include/EspAudioCom.h
  74. 70 0
      examples/09_a2dp/components/EspAudio/include/EspAudioRecorder.h
  75. 855 0
      examples/09_a2dp/components/EspAudio/player/DownloadTask.c
  76. 1113 0
      examples/09_a2dp/components/EspAudio/player/EspAudio.c
  77. 318 0
      examples/09_a2dp/components/EspAudio/player/M3u8.c
  78. 370 0
      examples/09_a2dp/components/EspAudio/player/MediaDecoderTask.c
  79. 42 0
      examples/09_a2dp/components/EspAudio/player/inc/DecoderCom.h
  80. 46 0
      examples/09_a2dp/components/EspAudio/player/inc/DownloadTask.h
  81. 79 0
      examples/09_a2dp/components/EspAudio/player/inc/M3u8.h
  82. 66 0
      examples/09_a2dp/components/EspAudio/player/inc/MediaDecoderTask.h
  83. 300 0
      examples/09_a2dp/components/EspAudio/recorder/EspAudioRecorder.c
  84. 1301 0
      examples/09_a2dp/components/MediaHal/AP80/Ap80xx.c
  85. 53 0
      examples/09_a2dp/components/MediaHal/AP80/crc.c
  86. 387 0
      examples/09_a2dp/components/MediaHal/Driver/dma.c
  87. 350 0
      examples/09_a2dp/components/MediaHal/Driver/i2c_soft.c
  88. 615 0
      examples/09_a2dp/components/MediaHal/Driver/i2s.c
  89. 1077 0
      examples/09_a2dp/components/MediaHal/Driver/psram.c
  90. 827 0
      examples/09_a2dp/components/MediaHal/Driver/spi.c
  91. 469 0
      examples/09_a2dp/components/MediaHal/ES8388/ES7242.c
  92. 273 0
      examples/09_a2dp/components/MediaHal/ES8388/ES8388.c
  93. 388 0
      examples/09_a2dp/components/MediaHal/MediaHal.c
  94. 15 0
      examples/09_a2dp/components/MediaHal/component.mk
  95. 253 0
      examples/09_a2dp/components/MediaHal/include/AP80/Ap80xx.h
  96. 28 0
      examples/09_a2dp/components/MediaHal/include/AP80/crc.h
  97. 27 0
      examples/09_a2dp/components/MediaHal/include/ES8388/ES7242.h
  98. 78 0
      examples/09_a2dp/components/MediaHal/include/ES8388/ES8388.h
  99. 130 0
      examples/09_a2dp/components/MediaHal/include/MediaHal.h
  100. 127 0
      examples/09_a2dp/components/MediaHal/include/driver/dma.h

+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/include/esp_a2dp_api.h → components/bt/bluedroid/api/include/esp_a2dp_api.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/include/esp_bt_stack_manager.h → components/bt/bluedroid/api/include/esp_bt_stack_manager.h


+ 1 - 0
components/bt/bluedroid/api/include/esp_gap_bt_api.h

@@ -29,4 +29,5 @@ typedef enum {
 esp_err_t esp_bt_gap_set_scan_mode(bt_scan_mode_t mode);
 
 esp_err_t esp_bt_gap_set_device_name(const char *name);
+
 #endif /* __ESP_GAP_BT_API_H__ */

+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/co/bta_av_co.c → components/bt/bluedroid/btif/bta_av_co.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_avk.c → components/bt/bluedroid/btif/btif_avk.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_core.c → components/bt/bluedroid/btif/btif_core.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_dm.c → components/bt/bluedroid/btif/btif_dm.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_media_task.c → components/bt/bluedroid/btif/btif_media_task.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_profile_queue.c → components/bt/bluedroid/btif/btif_profile_queue.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_sm.c → components/bt/bluedroid/btif/btif_sm.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/btif_util.c → components/bt/bluedroid/btif/btif_util.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_api.h → components/bt/bluedroid/btif/include/btif_api.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_av.h → components/bt/bluedroid/btif/include/btif_av.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_av_api.h → components/bt/bluedroid/btif/include/btif_av_api.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_av_co.h → components/bt/bluedroid/btif/include/btif_av_co.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_common.h → components/bt/bluedroid/btif/include/btif_common.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_dm.h → components/bt/bluedroid/btif/include/btif_dm.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_media.h → components/bt/bluedroid/btif/include/btif_media.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_profile_queue.h → components/bt/bluedroid/btif/include/btif_profile_queue.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_sm.h → components/bt/bluedroid/btif/include/btif_sm.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/btif_util.h → components/bt/bluedroid/btif/include/btif_util.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/stack_manager.h → components/bt/bluedroid/btif/include/stack_manager.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/include/uinput.h → components/bt/bluedroid/btif/include/uinput.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/btif/stack_manager.c → components/bt/bluedroid/btif/stack_manager.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_assert.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_assert.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_bitstream.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_bitstream.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_bt_spec.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_bt_spec.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_codec_sbc.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_codec_sbc.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_codec_sbc_private.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_codec_sbc_private.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_common.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_common.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_cpu_dep.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_cpu_dep.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_modules.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_modules.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_osinterface.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_osinterface.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_status.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_status.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_stddefs.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_stddefs.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_string.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_string.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_time.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_time.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/include/oi_utils.h → components/bt/bluedroid/embdrv/sbc/decoder/include/oi_utils.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/alloc.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/alloc.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/bitalloc-sbc.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/bitalloc-sbc.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/bitalloc.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/bitalloc.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/bitstream-decode.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/bitstream-decode.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/decoder-oina.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/decoder-oina.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/decoder-private.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/decoder-private.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/decoder-sbc.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/decoder-sbc.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/dequant.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/dequant.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/framing-sbc.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/framing-sbc.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/framing.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/framing.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/oi_codec_version.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/oi_codec_version.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/readsamplesjoint.inc → components/bt/bluedroid/embdrv/sbc/decoder/srce/readsamplesjoint.inc


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/synthesis-8-generated.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/synthesis-8-generated.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/synthesis-dct8.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/synthesis-dct8.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/decoder/srce/synthesis-sbc.c → components/bt/bluedroid/embdrv/sbc/decoder/srce/synthesis-sbc.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/include/sbc_dct.h → components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_dct.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/include/sbc_enc_func_declare.h → components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_enc_func_declare.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/include/sbc_encoder.h → components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_encoder.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/include/sbc_if.h → components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_if.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/include/sbc_types.h → components/bt/bluedroid/embdrv/sbc/encoder/include/sbc_types.h


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_analysis.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_analysis.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_dct.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_dct.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_encoder.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_encoder.c


+ 0 - 0
examples/09_a2dp/components/bluedroid_demos/embdrv/sbc/encoder/srce/sbc_packing.c → components/bt/bluedroid/embdrv/sbc/encoder/srce/sbc_packing.c


+ 4 - 1
components/bt/component.mk

@@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS :=	bluedroid/bta/include			\
 				bluedroid/hci/include			\
 				bluedroid/osi/include			\
 				bluedroid/utils/include			\
+				bluedroid/embdrv/sbc/decoder/include	\
 				bluedroid/btc/core/include		\
 				bluedroid/btc/profile/esp/blufi/include		\
 				bluedroid/btc/profile/esp/include		\
@@ -18,6 +19,7 @@ COMPONENT_ADD_INCLUDEDIRS :=	bluedroid/bta/include			\
 				bluedroid/btc/profile/std/sdp/include	\
 				bluedroid/btc/profile/std/include	\
 				bluedroid/btc/include		\
+				bluedroid/btif/include			\
 				bluedroid/stack/btm/include		\
 				bluedroid/stack/btu/include		\
 				bluedroid/stack/gap/include		\
@@ -32,7 +34,7 @@ COMPONENT_ADD_INCLUDEDIRS :=	bluedroid/bta/include			\
 				bluedroid/stack/a2dp/include		\
 				bluedroid/stack/include			\
 				bluedroid/utils/include			\
-				bluedroid/api/include		\
+				bluedroid/api/include			\
 				bluedroid/include			\
 				include	
 
@@ -59,6 +61,7 @@ COMPONENT_SRCDIRS := 	bluedroid/bta/dm			\
 			bluedroid/hci				\
 			bluedroid/main				\
 			bluedroid/osi				\
+			bluedroid/embdrv/sbc/decoder/srce			\
 			bluedroid/btc/core		\
 			bluedroid/btc/profile/esp/blufi	\
 			bluedroid/btc/profile/std/gap		\

+ 1 - 0
examples/09_a2dp/components/EspAudio/.gitignore

@@ -0,0 +1 @@
+*.o

+ 30 - 0
examples/09_a2dp/components/EspAudio/Kconfig

@@ -0,0 +1,30 @@
+menu "EspAudio"
+
+config AUDIO_PLAYER_EN
+    bool "Enable ESP player"
+    default y
+config AUDIO_RECORDER_EN
+    bool "Enable ESP recorder"
+    default y
+config AUDIO_LOG_ERROR_EN
+    bool "Enable Audio error message"
+    default y
+    help
+        Disable it will redurce error information and run faster
+config AUDIO_LOG_WARN_EN
+    bool "Enable Audio warning message"
+    default y
+    help
+        Disable it will redurce warning information and run faster
+config AUDIO_LOG_INFO_EN
+    bool "Enable Audio normal message"
+    default y
+    help
+        Disable it will redurce normal information and run faster
+config AUDIO_LOG_DEBUG_EN
+    bool "Enable Audio debug message"
+    default n
+    help
+        Disable it will redurce debug information and run faster
+
+endmenu

+ 4 - 0
examples/09_a2dp/components/EspAudio/README.md

@@ -0,0 +1,4 @@
+#This is Espressif Audio Platform
+
+# Setting Up ESP-IDF
+

+ 17 - 0
examples/09_a2dp/components/EspAudio/component.mk

@@ -0,0 +1,17 @@
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, 
+# this will take the sources in the src/ directory, compile them and link them into 
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+COMPONENT_ADD_INCLUDEDIRS := include player/inc recorder/inc \
+                             ../media_hal/include \
+                             ../misc/include
+
+COMPONENT_SRCDIRS := player recorder
+
+include $(IDF_PATH)/make/component_common.mk
+
+

+ 146 - 0
examples/09_a2dp/components/EspAudio/include/EspAudio.h

@@ -0,0 +1,146 @@
+// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ESP_AUDIO
+#define ESP_AUDIO
+#include "esp_types.h"
+#include "EspAudioCom.h"
+
+
+
+/*
+ *  Maximum size of the URI, including null character.
+ */
+//#define MAX_URI_SIZE 1024
+
+/*
+ *  Defines various states that the ESP player can be.
+ */
+enum EspAudioState
+{
+    AUDIOSTATE_UNINITIALIZED = 0,               /*  player  is not initialized */
+    AUDIOSTATE_IDLE,                            /*  player is idle */
+    AUDIOSTATE_STOPPED,                         /*  player is stopled */
+    AUDIOSTATE_TRANSIT,                         /*  player is busy in a transition */
+    AUDIOSTATE_PLAYING,                         /*  player is currently playing */
+    AUDIOSTATE_PAUSED,                          /*  player is in the paused state for playback */
+    AUDIOSTATE_ENDED,                           /*  player finished decoding player, without user request. */
+    AUDIOSTATE_ERROR,                           /*  player was given a URI that could not be played */
+
+    AUDIOSTATE_UNKNOWN                          /* unknown playstate */
+};
+
+
+typedef enum
+{
+    InputSrcType_NetSpec    = 0,    ///< Specify audio file from internet.
+    InputSrcType_NetLiving  = 1,    ///< Living audio stream from internet,e.g.m3u8
+    InputSrcType_LocalFile  = 2,    ///< Local file which store in the SD card
+    InputSrcType_Stream     = 3,    ///< Only audio stream,e.g.PCM
+    InputSrcType_Max
+} InputSrcType;
+
+
+typedef enum
+{
+    EspAudioErr_NoErr                   =0,     ///< No error
+    EspAudioErr_InvalidPara,                    ///< Invalid parameters
+    EspAudioErr_NoMem,                          ///< Malloc failed
+    EspAudioErr_HardwareErr,                    ///< Hardware error
+    EspAudioErr_OutOfRange,                     ///< length of URI is too long.
+    EspAudioErr_NotSupport,                     ///< Not support the
+
+} EspAudioErr;
+
+
+/*
+ *  Initializes the ESP player library.
+ */
+void EspAudio_Init(void);
+
+/*
+ *  Cleans up the ESP player library.
+ */
+void EspAudio_UnInit(void);
+
+/*
+ *  Play, stop, pause the streaming and output of player
+ *  EspAudio_Init must be called before these methods work.
+ */
+int EspAudio_SetupStream(const char* URI, InputSrcType UriType);
+/*
+ *  Call this method to transition to playing state.
+ *
+ *  Returns nonzero if an error occurred.
+ */
+int EspAudio_Play(void);
+
+/*
+ *  Call this method to stop playing ESP player.
+ *
+ *  Returns nonzero if an error occurred.
+ */
+int EspAudio_Stop(void);
+
+/*
+ *  Call this method to pause the playing ESP player.
+ *
+ *  Returns nonzero if an error occurred.
+ */
+int EspAudio_Pause(void);
+
+/*
+ *  Returns the playstate of the ESP player library.
+ *  Returns MEDIA_UNKNOWN if the stream could not be found.
+ */
+enum EspAudioState EspAudio_GetPlayState(void);
+
+/*
+ *  Get the player volume level . Volume level is from 0 to 100.
+ *  Returns a negative value if the stream could not be found or the value is unknown.
+ */
+int EspAudio_GetVolume(int *level);
+
+/*
+ *  Set the player volume level . Volume level is from 0 to 100.
+ *  Returns a negative value if the stream could not be found or the value is unknown.
+ */
+int EspAudio_SetVolume(int level);
+
+/*
+ *  Call this method to configrate stream information.
+ *
+ *  Returns nonzero if an error occurred.
+ */
+EspAudioErr EspAudioPlayerStreamCfg(uint32_t rate, uint32_t channel,uint32_t bitLen);
+
+/*
+ *  Call this method to flush stream data to driver.
+ *
+ *  Returns nonzero if an error occurred.
+ *
+ *  Note:Timeout portMAX_DELAY-block; others,unblock.
+ */
+EspAudioErr EspAudioPlayerStreamWrite(uint8_t *inData, uint32_t inSize, uint32_t timeout);
+
+/*
+ *  Call this method to stop once stream write.
+ *
+ *  Returns nonzero if an error occurred.
+ *
+ */
+EspAudioErr EspAudioPlayerStreamWriteEnd(void);
+
+
+#endif

+ 78 - 0
examples/09_a2dp/components/EspAudio/include/EspAudioCom.h

@@ -0,0 +1,78 @@
+// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _ESPAUDIOCOM_H
+#define _ESPAUDIOCOM_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "audio_log.h"
+#include "EspAudioCom.h"
+
+#define ESP_AUDIO_RELEASE_MAJOR (0000)
+#define ESP_AUDIO_RELEASE_MINOR (52)
+#define ESP_AUDIO_RELEASE_VER   "0.52"
+
+// Specified audio buffer address
+#define AUDIO_BUFFER_ADDR   (0x3f800000) // For external RAM
+
+// Specified aduio buffer size
+#ifdef AUDIO_BUFFER_ADDR
+    #define AUDIO_BUFFER_SIZE   (1024*1024)
+#else
+    #define AUDIO_BUFFER_SIZE   (25000)
+#endif
+
+typedef struct
+{
+    uint32_t type;
+    char   str[1024];
+} UrlInfo;
+
+
+typedef enum {
+    StreamType_Opus,
+    StreamType_Pcm,  // it will be support
+    StreamType_Max,
+} StreamType;
+
+
+typedef enum {
+    StreamSampleRate_8k  = 8000,  
+    StreamSampleRate_16k = 16000, // This is support
+    StreamSampleRate_22K = 22050,
+    StreamSampleRate_32K = 32000,
+    StreamSampleRate_44k = 44100,
+    StreamSampleRate_48k = 48000,
+    StreamSampleRate_Max,
+} StreamSampleRate;
+
+
+typedef enum {
+    StreamBitLen_8BIT = 8,
+    StreamBitLen_16BIT = 16,
+    StreamBitLen_24BIT = 24,
+    StreamBitLen_32BIT = 32,
+    StreamBitLen_Max,
+} StreamBitLen;
+
+
+typedef enum {
+    StreamChannel_One, // it will be support
+    StreamChannel_Two,
+    StreamChannel_Max,
+} StreamChannel;
+
+#endif  /* _ESPAUDIOCOM_H */

+ 70 - 0
examples/09_a2dp/components/EspAudio/include/EspAudioRecorder.h

@@ -0,0 +1,70 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESPAUDIORECORDER_H__
+#define __ESPAUDIORECORDER_H__
+#include "esp_types.h"
+#include "EspAudio.h"
+
+
+//Type Definitions
+typedef void (*Callback_RecordData)(void *recBuf, uint32_t *recLen);
+
+typedef enum {
+    RecorderState_Unknown = 0,
+    RecorderState_Init,
+    RecorderState_Stoped,
+    RecorderState_Recording,
+    RecorderState_Paused,
+} RecorderState;
+
+typedef enum {
+    EncodeType_Opus = 1,
+    EncodeType_Pcm,
+    EncodeType_Max,
+} EncodeType;
+
+
+typedef enum {
+    RecorderSampleRate_8k  = 8000,  // it will be support
+    RecorderSampleRate_16k = 16000,
+    RecorderSampleRate_Max,
+} RecorderSampleRate;
+
+
+typedef enum {
+    RecorderChannel_One = 1, 
+    RecorderChannel_Two, // it will be support
+    RecorderChannel_Max,
+} RecorderChannel;
+
+
+typedef struct {
+    RecorderSampleRate rate;
+    RecorderChannel channel;
+    EncodeType encodeType;
+    Callback_RecordData func;
+} RecorderAttr;
+
+
+EspAudioErr EspAudioRecorderStart(RecorderAttr *recorderAttr);
+EspAudioErr EspAudioRecorderStop(void);
+EspAudioErr EspAudioRecorderPause(void);
+EspAudioErr EspAudioRecorderResume(void);
+EspAudioErr EspAudioRecorderStateGet(RecorderState *state);
+EspAudioErr EspAudioRecorderInit(void);
+EspAudioErr EspAudioRecorderUninit(void);
+
+
+#endif //__ESPAUDIORECORDER_H__

+ 855 - 0
examples/09_a2dp/components/EspAudio/player/DownloadTask.c

@@ -0,0 +1,855 @@
+#include <string.h>
+#include "esp_types.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+
+#include "lwip/sockets.h"
+#include "lwip/err.h"
+#include "lwip/dns.h"
+#include "lwip/netdb.h"
+#include "lwip/sys.h"
+#include "errno.h"
+#include "audio_log.h"
+#include "inc/DownloadTask.h"
+#include "inc/M3u8.h"
+#include "EspAudioCom.h"
+#include "EspAudio.h"
+
+#include "inc/MediaDecoderTask.h"
+#include "Storage.h"
+#include "MediaHal.h"
+#include "Utility.h"
+
+#define PRIO_DOWNLOAD               19
+#define DEFAULT_AAC_SEQ             0xFFFFFFFF
+#define REQUEST_BUF_LEN             1024
+#define RECV_BUF_LEN                1500
+
+
+#if 1
+#define DEBUGHTTP   printf
+#else
+#define DEBUGHTTP
+#endif
+
+
+uint32_t fileTaskState = 0;
+uint32_t m3u8TaskState = 0;
+void m3u8DownloadTask(void *pvParameters);
+void fileDownloadTask(void *pvParameters);
+
+typedef struct {
+    int    status;           // 1:downloading; 2:finished
+    char   *reqBuf;
+    char   *recvBuf;
+    int    blockQuit;
+    int    receivedSize;
+    uint32_t remaindSize;
+    uint32_t downloadedSize;
+    uint32_t contentTotalSize;
+    UriSrcAttr uri;
+} HttpObj;
+
+
+typedef struct {
+    TaskState state;
+    pthread_t thread;
+    int threadQuit;
+} DownloadInstance;
+
+
+static HttpObj localHttp;
+//static mutex_t downloadMutex;
+static UrlInfo actLiveUrl;
+
+DownloadInstance dlInstance = { 0 };
+
+typedef void (*Callback_Recv)(HttpObj *obj);
+
+int checkIsReqOk(char *buf)
+{
+    char *l = strstr(buf, "HTTP/1.1 2");
+    if (NULL == l) {
+        l = strstr(buf, "HTTP/1.0 2");
+        if (NULL == l) {
+            l = strstr(buf, "HTTP/1.0 3");
+            if (NULL == l) {
+                return -1;
+            }
+            return 1;
+        }
+    }
+    return 0;
+}
+int getLocation (const char *buf, char* dest)
+{
+    // Location: http://119.90.25.49/live.xmcdn.com/192.168.3.134/live/38/24/161118_174054_588.aac
+    char *l = strstr(buf, "Location:");
+    if (NULL == l) {
+        LOGE("Can't find Location:%s", buf);
+        return -1;
+    }
+    l += 10;
+    int i1 = 0;
+    if (l != NULL) {
+        while (*l != '\r') {
+            dest[i1++] = *(l++);
+            if (i1 > ESP_URI_LEN) {
+                break;
+            }
+        }
+    } else {
+        LOGE("Can't find Location:%s", buf);
+        return -1;
+    }
+    return 0;
+}
+
+int getFileLength(char *buf)
+{
+    char *l = strstr(buf, "Content-Length:");
+    if (NULL == l) {
+        LOGE("Can't find length:%s", buf);
+        return 0;
+    }
+    l += 16;
+    char len[32] = {0};
+    int i1 = 0;
+    if (l != NULL) {
+        while (*l != '\r') {
+            len[i1++] = *(l++);
+        }
+    } else {
+        LOGE("Can't find length:%s", buf);
+        return 0;
+    }
+    return atoi(len);
+
+}
+
+
+void ReqHead(char* outReqBuf, const char *url, char* host)
+{
+    LOGD("http HEAD requst\r\n");
+    sprintf(outReqBuf, "HEAD %s HTTP/1.1\r\n"
+            "Accept:*/*\r\n"
+            "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
+            "Host: %s\r\n"
+            "Connection:Keep-Alive\r\n"
+            "Cache-Control: no-cache\r\n"
+            "\r\n\r\n", url, host);
+    DEBUGHTTP(outReqBuf);
+}
+
+
+void ReqGetM3u8(char* outReqBuf, const char *url, char* host)
+{
+    LOGD("http GET requst:");
+    if ((NULL == url) || (NULL == host)) {
+        LOGE("NULL = url or NULL = host");
+        return;
+    }
+    sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
+            "Accept:*/*\r\n"
+            "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
+            "Host: %s\r\n"
+            "Connection: Close\r\n"     // Keep-Alive
+            "Cache-Control: no-cache\r\n"
+            "\r\n\r\n", url, host);
+    DEBUGHTTP(outReqBuf);
+}
+
+
+void ReqDataPre(char* outReqBuf, const char *url, char* host, uint32_t startLen, uint32_t endLen)
+{
+    if (0 != endLen) {
+        sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
+                "Accept:*/*\r\n"
+                "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
+                "Host: %s\r\n"
+                "Proxy-Connection: Keep-Alive\r\n"
+                "Cache-Control: no-cache\r\n"
+                "Range: bytes=%d-%d\r\n\r\n", url, host, startLen, endLen - 1);
+    } else {
+        sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
+                "Accept:*/*\r\n"
+                "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
+                "Host: %s\r\n"
+                "Proxy-Connection: Keep-Alive\r\n"
+                "Cache-Control: no-cache\r\n\r\n", url, host);
+    }
+
+    LOGD("http GET requst-%d:", strlen(outReqBuf));
+    //DEBUGHTTP(outReqBuf);
+}
+
+int getIpForHost(const char *host, struct sockaddr_in *ip)
+{
+    struct hostent *he;
+    struct in_addr **addr_list;
+    char str[200] ;
+
+    he = gethostbyname(host);
+    if (he == NULL) return 0;
+    addr_list = (struct in_addr **)he->h_addr_list;
+    if (addr_list[0] == NULL) return 0;
+    ip->sin_family = AF_INET;
+    memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
+    return 1;
+}
+
+int splitHostUrl(const char* url, char* host, uint16_t *port, char **path)
+{
+    if ((NULL == url) || (NULL == host)) {
+        LOGE("ERR:url=NULL or Host=NULL\n");
+        return -1;
+    }
+    char* temp1;
+    char* source = (char*)url;
+    char portBuf[10] = {0};
+    while (url) {
+        source = strstr(source, "//");
+        if (url == NULL) {
+            LOGE("ERR:strchr=NULL\n");
+            return -1;
+        }
+        source += 2;
+        temp1 = strchr(source, ':');
+        if (temp1 != NULL) {
+            // try to find '/'
+            strncpy(host, source, temp1 - source);
+            temp1 += 1;
+            source = strchr(source, '/');
+            if (source == NULL) {
+                LOGE("ERR:strchr=NULL\n");
+                return 0;
+            }
+            strncpy(portBuf, temp1, source - temp1);
+            *port = strtoul(portBuf, 0, 10);
+            *path = source;
+            LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
+        } else {
+            // try to find port
+            temp1 = strchr(source, '/');
+            if (temp1 == NULL) {
+                LOGE("ERR:strchr=NULL\n");
+                return -1;
+            }
+            strncpy(host, source, temp1 - source);
+            *port = 80;
+            *path = temp1;
+            LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
+        }
+        return 0;
+    }
+    return -1;
+}
+
+int connectToServer(const char* actUrl, const char* hostName, uint16_t port, int timeOut)
+{
+    struct sockaddr_in remote_ip;
+    int sock = -1;
+    int nNetTimeout = timeOut; // socket timeout 1 Sec
+    int retryCnt = 3;
+    while (retryCnt--) {
+        bzero(&remote_ip, sizeof(struct sockaddr_in));
+        if (1 != inet_aton(hostName, &remote_ip.sin_addr)) {
+            if (!getIpForHost(hostName, &remote_ip)) {
+                vTaskDelay(1000 / portTICK_RATE_MS);
+                LOGE("getIpForHost failed");
+                continue;
+            }
+        }
+        remote_ip.sin_family = AF_INET;
+        int sock = socket(PF_INET, SOCK_STREAM, 0);
+        if (sock == -1) {
+            LOGE("socket failed errno=%d", errno);
+            continue;
+        }
+//        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
+        struct timeval tv_out;
+         tv_out.tv_sec = 20; //Wait 20 seconds.
+         tv_out.tv_usec = 0;
+         setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out));
+
+        remote_ip.sin_port = htons(port);
+        LOGD("[sock=%d],connecting to server IP:%s,Port:%d...",
+             sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
+        if (connect(sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
+            close(sock);
+            LOGE("Conn err.\n");
+            vTaskDelay(1000 / portTICK_RATE_MS);
+            continue;
+        }
+        return sock;
+    }
+    LOGE("Lost host,connect and getIpForHost timeout");
+    return -2;
+}
+
+void resetDownloadAttr(char *src, uint32_t *type)
+{
+    localHttp.status = 0;
+    if (localHttp.blockQuit < 0) {        
+        localHttp.blockQuit = 0;
+    }
+    localHttp.receivedSize = 0;
+    localHttp.remaindSize = 0;
+    localHttp.downloadedSize = 0;
+    localHttp.uri.srcType = *type;
+    localHttp.contentTotalSize = 0;
+    memset(localHttp.uri.str, 0, ESP_URI_LEN);
+    strncpy(localHttp.uri.str, src, strlen(src));
+}
+
+void OnFileDataCB(HttpObj *obj)
+{
+    int ret;
+
+    do {
+        ret = audioBufWrite(obj->reqBuf, obj->receivedSize, 100);
+        if (ret) {
+            obj->remaindSize -= obj->receivedSize;
+            obj->downloadedSize += obj->receivedSize;
+//            uint32_t rd, wr;
+//            audioBufPosGet(&rd, &wr);
+//            LOGD("rd:%x,wr:%x,downloaded=%d, remaind=%d, total=%d, recvSize=%d",
+//                rd,wr,obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, obj->receivedSize);
+            break;
+        } else {
+            LOGE("audioBufWrite failed ret=%d. rcev=%d,remaind=%d, d=%d", ret,
+                 obj->receivedSize, obj->remaindSize, obj->downloadedSize);
+            break;
+        }
+    } while (0 == obj->blockQuit);
+}
+
+void OnM3u8DataCB(HttpObj *obj)
+{
+    obj->remaindSize -= obj->receivedSize;
+    obj->downloadedSize += obj->receivedSize;
+//    LOGD(":\n%s", obj->reqBuf);
+}
+
+char *GetValidUrl(M3u8Info *pActM3u8, M3u8Seq *actSeq)
+{
+    char *retUrl = NULL;
+    if ((NULL == actSeq)
+        || (NULL == pActM3u8)) {
+        LOGE("pActM3u8 or actSeq is NULL");
+        return retUrl;
+    }
+    int validM3u8 = -1;
+    for (uint8_t i = 0; i < 3; i++) {
+//        LOGD("M3u8 AAC URL,%dth,%s\n", i, pActM3u8->segList[i].url);
+        if ((actSeq->sub == DEFAULT_AAC_SEQ)
+            || (1 == m3u8CheckValid(&pActM3u8->segList[i].seq, (const M3u8Seq*)actSeq))) {
+            validM3u8 = 1;
+            retUrl = pActM3u8->segList[i].url;
+            memcpy(actSeq, &pActM3u8->segList[i].seq, sizeof(pActM3u8->segList[i].seq));
+            pActM3u8->segList[i].seq.sub = 0;
+            LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, actSeq->sub, retUrl);
+            if ((0 == actSeq->sub)
+                || (retUrl[0] == '\0')) {
+                retUrl = NULL;
+            }
+            return retUrl;
+        } else {
+//            LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, pActM3u8->segList[i].seq.sub, pActM3u8->segList[i].url);
+            pActM3u8->segList[i].seq.sub = 0;
+        }
+    }
+    if (validM3u8 != 1) {
+        LOGD("Can not found valid aac url, curtAacSeq=%x", actSeq->sub);
+    }
+    return retUrl;
+
+}
+
+int httpDownloading(HttpObj *obj, Callback_Recv recvCB)
+{
+    if ((NULL == obj)
+        || (NULL == obj->uri.str)
+        || (NULL == obj->reqBuf)
+        || (NULL == obj->recvBuf)
+        || (0 == strlen(obj->uri.str))) {
+        LOGE("Pointer is NULL,obj:%x,URL:%x reqbuf:%x recvBuf:%x,len:%d,blockQuit:%d",
+             obj, obj->uri.str, obj->reqBuf, obj->recvBuf, strlen(obj->uri.str), obj->blockQuit);
+        return -1;
+    }
+    char hostName[32] = { 0 };
+    int actSocket = -1;
+    uint32_t contrlDat = 0;
+    uint8_t modifyProFlag = 0;
+    int cnt = 0;
+    int n = 0;
+    LOGD("\n>>>>>Downloading start:%s,0x%x,remaind=%d,downloaded=%d,total=%d,fill=%d",
+         obj->uri.str, obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize, audioBufFillGet());
+    obj->status = 1;
+    uint16_t ipPort = 80;
+    char *uriPath = NULL;
+    do {
+        // Here will check exit event;
+
+Retry:  LOGD("retry new url size=%d", obj->remaindSize);
+        memset(hostName, 0, sizeof(hostName));
+        if (0 != splitHostUrl(obj->uri.str, hostName, &ipPort, &uriPath)) {
+            LOGE("splitHostUrl failed:%s", obj->uri.str);
+            continue;
+        }
+        LOGD("Hostname:%s", hostName);
+        if ((actSocket = connectToServer((const char*)obj->uri.str, hostName, ipPort, 10000)) >= 0) {
+            char * datPos = NULL;
+            bzero(obj->reqBuf, REQUEST_BUF_LEN);
+            ReqDataPre(obj->reqBuf, uriPath, hostName, obj->downloadedSize, obj->contentTotalSize);
+            LOGD("Hostname:%s++++++++", hostName);
+            write(actSocket, obj->reqBuf, strlen(obj->reqBuf));
+            LOGD("Hostname:%s--------", hostName);
+            bzero(obj->recvBuf, RECV_BUF_LEN);
+            datPos = NULL;
+            cnt = 0;
+            do {
+                bzero(obj->reqBuf, REQUEST_BUF_LEN);
+                n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
+                if ((n > 0) && (cnt <= RECV_BUF_LEN)) {
+//                    DEBUGHTTP("Head is: %s", obj->reqBuf);
+                    memcpy(obj->recvBuf + cnt, obj->reqBuf, n);
+                    datPos = strstr(obj->recvBuf, "\r\n""""\r\n");
+                    if (datPos) {
+                        //DEBUGHTTP("Find CRLF CRLF ok");                        
+//                        LOGD("Head is: %s", obj->recvBuf);
+                    } else {
+                        LOGE("Find CRLF CRLF failed,wait more data");
+                    }
+                }
+                cnt += n;
+            } while ((datPos == NULL) && (n > 0) && (cnt < RECV_BUF_LEN));
+            if (n < 0) {
+                close(actSocket);
+                continue;
+            }
+            if (NULL == datPos)  {
+//                datPos == strstr(obj->recvBuf, "\r\n""""\r\n");
+                LOGD("Head is: %s", obj->recvBuf);
+
+                if (NULL == datPos) {
+                    close(actSocket);
+                    LOGE("Can't Find CRLF CRLF,it's bad response,try again");
+                    continue;
+                }
+            }
+            int ret = checkIsReqOk(obj->recvBuf);
+            if (ret < 0) {
+                close(actSocket);
+                LOGE("Recv a bad resp:%s", obj->recvBuf);
+                continue;
+            } else if (ret == 1) {
+                close(actSocket);
+                LOGW("Recv a 3xx resp:%s", obj->recvBuf);
+                memset(obj->uri.str, 0, ESP_URI_LEN);
+                if (getLocation((const char*)obj->recvBuf, obj->uri.str) < 0) {
+                    LOGE("Find 3xx URL error");
+                } else {
+                    LOGW("Recv a 3xx resp:%s", obj->uri.str);
+                }
+                goto  Retry;
+            }
+            if (0 == obj->contentTotalSize) obj->contentTotalSize = getFileLength(obj->recvBuf);
+            datPos += 4;
+            cnt = cnt - (datPos - obj->recvBuf);
+            if (0 == obj->remaindSize) {
+                obj->remaindSize = obj->contentTotalSize;
+            }
+            // Save the tail data
+            bzero(obj->reqBuf, REQUEST_BUF_LEN);
+            memcpy(obj->reqBuf, datPos, cnt);
+
+            LOGD("downloaded=%d, remaind=%d, total=%d, cnt=%d",
+                 obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, cnt);
+            int writeComplete = 0;
+            do {
+                if (writeComplete) {
+                    bzero(obj->reqBuf, REQUEST_BUF_LEN);
+                    n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
+                    cnt = n;
+                    // DEBUGHTTP("recv,cnt:%d\n", cnt);
+                }
+                if (n > 0) {
+                    if (cnt > 0) {
+                        obj->receivedSize = cnt;
+                        recvCB(obj);
+                    }
+                    cnt = 0;
+                    writeComplete = 1;
+                }
+            } while ((n > 0) && (obj->remaindSize > 0) && (0 == obj->blockQuit));
+            close(actSocket);
+            LOGD("Sock[%d] has closed,n=%d,blockQuit=%d", actSocket, n, obj->blockQuit);
+        } else {
+            LOGE("Connect is error.");
+        }
+        LOGD("Connect closed,file size remaind=%d", obj->remaindSize);
+
+    } while ((obj->remaindSize != 0) && (0 == obj->blockQuit));
+    if (0 == obj->remaindSize) {
+        obj->status = 2;
+    } else {
+        obj->status = 3;
+    }
+    LOGD("\n<<<<<Downloading finish:%s,remaind=%d,downloaded=%d,total=%d fill=%d status=%d\n",
+         obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize,
+         audioBufFillGet(), obj->status);
+    return 0;
+}
+
+void fileDownloadTask(void *pvParameters)
+{
+    int n, cnt;
+    DownloadInstance *downloadObj = (DownloadInstance *)pvParameters;
+    LOGI("%s is running.%x %x", __func__, pvParameters, downloadObj->threadQuit);
+
+/////////////////////////////
+    M3u8Seq runningAacSeq = {0, 0, DEFAULT_AAC_SEQ};
+    M3u8Info *pUsingM3u8 = NULL;
+    uint32_t mediaSeq = DEFAULT_AAC_SEQ;
+
+    downloadObj->threadQuit = 0;
+    while (downloadObj->threadQuit == 0) {
+        switch (downloadObj->state) {
+        case TaskState_Ready:
+            if ((NULL == actLiveUrl.str)
+                || (actLiveUrl.str[0] == '\0')
+                || (NULL == localHttp.uri.str )) {
+                downloadObj->state  = TaskState_Idle;
+                vTaskDelay(200 / portTICK_RATE_MS);
+                LOGI("Downloading URL is NULL,downloading task paused");
+                break;
+            } else {
+                LOGI("Download task is ready.%s type:%d", actLiveUrl.str, actLiveUrl.type);
+            }
+            if (InputSrcType_NetSpec == actLiveUrl.type) {
+                resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
+                downloadObj->state = TaskState_Running;
+                audioBufWrRest();
+            } else if (InputSrcType_NetLiving ==  actLiveUrl.type) {
+                resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
+
+                audioBufWrRest();
+                mediaSeq = DEFAULT_AAC_SEQ;
+                downloadObj->state = TaskState_Running;
+                runningAacSeq.sub = DEFAULT_AAC_SEQ;
+                if (pUsingM3u8) {
+                    free(pUsingM3u8);
+                    pUsingM3u8 = NULL;
+                }
+                pUsingM3u8 = calloc(1, sizeof(M3u8Info));
+                if (pUsingM3u8 == NULL) {
+                    LOGE("recvBuf malloc error");
+                    break;
+                }
+
+            } else {
+                LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
+                downloadObj->state = TaskState_Idle;
+                vTaskDelay(200 / portTICK_RATE_MS);
+            }
+            break;
+        case TaskState_Pause:
+            LOGI("TaskState_Pause,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
+                 localHttp.downloadedSize,
+                 localHttp.remaindSize);
+            downloadObj->state = TaskState_Idle;
+            break;
+        case TaskState_Resume:
+            downloadObj->state = TaskState_Running;
+            LOGI("TaskState_Resume,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
+                 localHttp.downloadedSize,
+                 localHttp.remaindSize);
+            break;
+        case TaskState_Running:
+            if (InputSrcType_NetSpec == localHttp.uri.srcType) {
+                LOGI("Excute URL:%s", localHttp.uri.str);
+                httpDownloading(&localHttp, OnFileDataCB);
+                if (2 == localHttp.status) {
+                    downloadObj->state = TaskState_Idle;
+                    LOGI("Excute URL over, task will be idle.remind[%d]", localHttp.remaindSize);
+                }
+            } else if (InputSrcType_NetLiving == localHttp.uri.srcType) {
+                resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
+                memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
+                memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
+
+                LOGD("Excute URL:%s, actLiveUrl.str=%x", localHttp.uri.str, actLiveUrl.str);
+                httpDownloading(&localHttp, OnM3u8DataCB);
+
+                M3u8Info *pActM3u8 = m3u8Parser(localHttp.reqBuf, pUsingM3u8);
+                if (NULL == pActM3u8) {
+                    LOGE("Parser m3u8 is error");
+                    vTaskDelay(1000 / portTICK_RATE_MS);
+                    break;
+                }
+                if ((pActM3u8->mediaSeq <= mediaSeq) && (mediaSeq != DEFAULT_AAC_SEQ)) {
+                    LOGD("mediaSeq has not update,used=%d,new=%d", mediaSeq, pActM3u8->mediaSeq);
+                    vTaskDelay(1000 / portTICK_RATE_MS);
+                    break;
+                }
+                char *validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
+
+                LOGD("AAC URL,runningAacSeq:%x,%x,%x\n",
+                     runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
+                if (NULL == validUrl) {
+                    vTaskDelay(100 / portTICK_RATE_MS);
+                    LOGE("uri.str is NULL,state=%d", downloadObj->state);
+                    break;
+                }
+                DecoderObj decoder;
+                mediaDecoderTaskInfoGet(&decoder);
+                decoder.musicType = checkMediaType(validUrl);
+                if (decoder.musicType >= EspAudioMeidaType_M3u) {
+                    LOGE("%s,Music type[%d] is error", validUrl, decoder.musicType);
+                    vTaskDelay(100 / portTICK_RATE_MS);
+                    break;
+                } else {
+                    mediaDecoderTaskInfoSet(&decoder);
+                }
+                do {
+                    resetDownloadAttr(validUrl, &actLiveUrl.type);
+                    memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
+                    memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
+
+                    httpDownloading(&localHttp, OnFileDataCB);
+                    validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
+
+                    LOGD("AAC URL,runningAacSeq:%x,%x,%x\n", runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
+                    if (NULL == validUrl) {
+                        LOGD("uri.str is NULL,state=%d", downloadObj->state);
+                        break;
+                    }
+                } while (validUrl != NULL);
+                mediaSeq = pActM3u8->mediaSeq;
+            } else {
+                LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
+                downloadObj->state = TaskState_Idle;
+                vTaskDelay(200 / portTICK_RATE_MS);
+            }
+
+            break;
+        case TaskState_Stoped:
+            downloadObj->state = TaskState_Idle;
+            break;
+        case TaskState_Idle:
+        default:
+            vTaskDelay(250 / portTICK_RATE_MS);
+            //  LOGD("blockQuit[%d] state[%d]", localHttp.blockQuit, downloadObj->state);
+            break;
+        }
+    }
+    downloadObj->threadQuit = -1;
+    downloadObj->thread = NULL;
+    downloadObj->state = TaskState_Stoped;
+    if (pUsingM3u8) {
+        free(pUsingM3u8);
+        pUsingM3u8 = NULL;
+    }
+    LOGD("%s is ended...", __func__);
+    vTaskDelete(NULL);
+}
+
+TaskState downloadTaskStateGet()
+{
+    return dlInstance.state;
+}
+
+int downloadTaskHTTPStateGet()
+{
+    return localHttp.status;
+}
+
+void downloadTaskDownloadSizeSet(int *size)
+{
+    if (NULL == size) {
+        LOGE("Invalid para");
+        return ;
+    }
+//    localHttp.blockQuit = 1;
+    localHttp.downloadedSize = *size;
+    downloadTaskResume();
+}
+
+void downloadTaskContentSizeGet(uint32_t *size)
+{
+    if (NULL == size) {
+        LOGE("Invalid para");
+        return ;
+    }
+    *size = localHttp.contentTotalSize;
+}
+
+void downloadTaskInfoSet(UriSrcAttr *uri)
+{
+    if (NULL == uri) {
+        LOGE("Invalid para");
+        return ;
+    }
+    actLiveUrl.type = uri->srcType;
+    memset(actLiveUrl.str, 0 , ESP_URI_LEN);
+    strncpy(actLiveUrl.str, uri->str, strlen(uri->str));
+    localHttp.blockQuit = 0;
+    LOGD("Set url ok:%s", actLiveUrl.str);
+}
+
+void downloadTaskPause()
+{
+    if (0 == dlInstance.thread) {
+        dlInstance.state = TaskState_Unknown;
+        LOGE("dlInstance.thread is NULL");
+        return;
+    }
+    if (TaskState_Running == dlInstance.state) {
+        localHttp.blockQuit = -1;
+    }
+    dlInstance.state = TaskState_Pause;
+
+    LOGD("download task state=%d", dlInstance.state);
+}
+
+void downloadTaskResume()
+{
+    if (0 == dlInstance.thread) {
+        dlInstance.state = TaskState_Unknown;
+        LOGE("dlInstance.thread is NULL");
+        return;
+    }
+    if (TaskState_Pause == dlInstance.state) {
+        localHttp.blockQuit = 0;
+    }
+    dlInstance.state = TaskState_Resume;
+    LOGD("download task state=%d", dlInstance.state);
+}
+
+void downloadTaskCreate(int taskType)
+{
+    if (localHttp.reqBuf)  {
+        free(localHttp.reqBuf);
+    }
+    if (localHttp.recvBuf) {
+        free(localHttp.recvBuf);
+    }
+    if (localHttp.uri.str) {
+        free(localHttp.uri.str);
+    }
+    localHttp.reqBuf = calloc(1, REQUEST_BUF_LEN);
+    if (NULL == localHttp.reqBuf) {
+        LOGE("reqBuf malloc error");
+        return;
+    }
+    localHttp.recvBuf = calloc(1, RECV_BUF_LEN);
+    if (NULL == localHttp.recvBuf) {
+        LOGE("recvBuf malloc error");
+        free(localHttp.reqBuf);
+        return;
+    }
+    localHttp.uri.str = calloc(1, ESP_URI_LEN);
+    if (NULL == localHttp.uri.str) {
+        LOGE("uri.str malloc error");
+        free(localHttp.reqBuf);
+        free(localHttp.recvBuf);
+        return;
+    }
+//    mutex_init(&downloadMutex);
+//    configASSERT(downloadMutex);
+    xTaskCreate(fileDownloadTask, "fileDownloadTask", (6 * 1024), &dlInstance, PRIO_DOWNLOAD, &dlInstance.thread);
+    configASSERT(dlInstance.thread);
+    LOGD("download task state=%d", dlInstance.state);
+}
+
+int downloadTaskStart()
+{
+    if (0 == dlInstance.thread) {
+        dlInstance.state = TaskState_Unknown;
+        LOGE("dlInstance.thread is NULL");
+        return -1;
+    }
+    if ((actLiveUrl.str == NULL)
+        || (actLiveUrl.str[0] == '\0')) {
+        dlInstance.state = TaskState_Idle;
+        LOGE("uri.str task is NULL");
+        return -1;
+    }
+    dlInstance.state = TaskState_Ready;
+    LOGD("download task state=%d, %s, %d", dlInstance.state, actLiveUrl.str, localHttp.blockQuit);
+    audioBufWrRest();
+
+    return 0;
+}
+
+void downloadTaskStop(void *que)
+{
+    if (0 == dlInstance.thread) {
+        dlInstance.state = TaskState_Unknown;
+        LOGE("dlInstance.thread is NULL");
+        return;
+    }
+    if (dlInstance.state == TaskState_Unknown) {
+        LOGW("dlInstance.state is TaskState_Unknown");
+        return;
+    }
+    localHttp.blockQuit = 1;
+    dlInstance.state = TaskState_Stoped;
+    configASSERT(que);
+    xQueueSend(que, &localHttp.blockQuit, 0);
+
+    LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
+    while ((TaskState_Finished != dlInstance.state)
+           && (TaskState_Idle != dlInstance.state)) {
+        if ((TaskState_Idle == dlInstance.state)) {            
+            localHttp.blockQuit = 0;
+            break;
+        }
+        vTaskDelay(10 / portTICK_RATE_MS);
+    }
+    audioBufWrRest();
+    xQueueReset(que);
+    LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
+}
+
+void downloadTaskDestroy()
+{
+    if (0 == dlInstance.thread) {
+        dlInstance.state = TaskState_Unknown;
+        LOGE("dlInstance.thread is NULL");
+        return;
+    }
+
+    LOGD("download task +++++  blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
+    if (0 == dlInstance.threadQuit) {
+        localHttp.blockQuit = 1;
+        dlInstance.threadQuit = 1;
+        dlInstance.state = TaskState_Stoped;
+        while (1) {
+            if ((dlInstance.threadQuit == -1)) {                
+                localHttp.blockQuit = 0;
+                break;
+            }
+            vTaskDelay(200 / portTICK_RATE_MS);
+        }
+    }
+    if (localHttp.reqBuf) free(localHttp.reqBuf);
+    if (localHttp.recvBuf) free(localHttp.recvBuf);
+    if (localHttp.uri.str) free(localHttp.uri.str);
+
+    memset(&localHttp, 0, sizeof(localHttp));
+    localHttp.reqBuf = NULL;
+    localHttp.recvBuf = NULL;
+    localHttp.uri.str = NULL;
+    dlInstance.state = TaskState_Unknown;
+    dlInstance.thread = NULL;
+//    mutex_destroy(&downloadMutex);
+//    downloadMutex = NULL;
+    LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
+}
+

+ 1113 - 0
examples/09_a2dp/components/EspAudio/player/EspAudio.c

@@ -0,0 +1,1113 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "lwip/sys.h"
+#include <sys/types.h>
+
+#include "freertos/task.h"
+#include "EspAudio.h"
+#include "esp_system.h"
+#include "Storage.h"
+#include "audio_log.h"
+#include "MediaHal.h"
+#include "inc/DownloadTask.h"
+#include "EspAudioCom.h"
+#include "inc/MediaDecoderTask.h"
+#include "MyString.h"
+#include <string.h>
+#include "Utility.h"
+#include "freertos/semphr.h"
+#include "nvs.h"
+
+
+#define AUDIOLOOP_TSK_PRIO       8
+
+const char * pAudioVolume = "ESPAUDIOVOL";
+
+typedef enum {
+    PlayerCtrlPrio_Unknown = 0,
+    PlayerCtrlPrio_Auto    = 1,
+    PlayerCtrlPrio_User    = 2,
+} PlayerCtrlPrio;
+
+
+typedef enum {
+    PlayerWorkMode_Unknown          = 0,
+    PlayerWorkMode_Decoder          = 1,
+    PlayerWorkMode_Recorder         = 2,
+    PlayerWorkMode_Max,
+} PlayerWorkMode;
+
+
+/*
+ *  Set the player working mode,playback or recodring.
+ *  Nonzero value indicates successed.
+ */
+int EspAudio_SetMode(PlayerWorkMode mode);
+
+/*
+ *  Sets the time position in seconds.
+ */
+int EspAudio_SetPosition (int timePosition);
+
+/*
+ *  Returns the estimated current playing position in seconds.
+ *  Returns a negative value if the stream could not be found or the value is unknown.
+ */
+int EspAudio_GetTimePosition(uint32_t *timePos);
+
+/*
+ *  Returns the estimated total playing time of the track in seconds.
+ *  Returns a negative value if the stream could not be found or the value is unknown.
+ */
+int EspAudio_GetTimeTotalLength(uint32_t *timeTotalLen);
+
+void EspAudio_SetPlayStateChangeCb(void *func);
+
+void EspAudio_DurationChangeCb(void *func);
+
+void EspAudio_CanSetPositionCb(void *func);
+
+
+/*
+ *  Returns the current byte position of the decoding process.
+ *  Returns a negative value if the stream could not be found or the value is unknown.
+ */
+int EspAudio_GetBytePosition(uint32_t *bytePos);
+
+/*
+ *  Returns the total number of bytes for the file.
+ *  Returns a negative value if the stream could not be found or the value is unknown.
+ */
+int EspAudio_GetByteTotalLength(uint32_t *byteTotalLen);
+
+/*
+ *  Returns nonzero if the has the mute flag enabled.
+ */
+int EspAudio_GetMute(int *muteFlag);
+
+/*
+ *  Sets the mute flag for the specified stream.
+ *  Nonzero value indicates mute flag is on.
+ */
+int EspAudio_SetMute(int muteFlag);
+
+
+/*
+ *  The codec-framework defines a callback for processing a change in playstate for the codec-framework.
+ *  The callback executes on a thread owned by the codec-framework, so sink methods should only
+ *  perform lightweight tasks.
+ */
+typedef void (*Callback_EspAudio_StateChange)(enum EspAudioState newState, void* codecSpecific, void* streamTag);
+
+/*
+ *  The codec-framework defines a callback for updating the total duration of the current uri.
+ *  This is sometimes necessary as some filtergraphs determine the total duration of a track
+ *  asynchronously.
+ */
+typedef void (*Callback_EspAudio_DurationChange)(int duration, void* codecSpecific, void* streamTag);
+
+/*
+ *  The codec-framework defines a callback for indicating if the current stream supports
+ *  SetPosition.
+ */
+typedef void (*Callback_EspAudio_CanSetPosition)(int canSetPosition, void* codecSpecific, void* streamTag);
+
+
+
+/*
+ *  This counter tracks memory allocations used for
+ *  the codec wrapper.
+ */
+int g_audio_malloc_counter  = 0;
+
+/*
+ *  Codec wrapper malloc.
+ */
+void* ESP_AUDIO_MALLOC(int size)
+{
+    g_audio_malloc_counter++;
+#ifdef TRACK_MALLOC
+    printf("g_audio_malloc_counter=%d\r\n", g_audio_malloc_counter);
+#endif
+    //ToDo: Memory Appears to be leaking here
+    return malloc(size);
+}
+
+/*
+ *  Codec wrapper free.
+ */
+void ESP_AUDIO_FREE(void *freeThis)
+{
+    g_audio_malloc_counter--;
+#ifdef TRACK_MALLOC
+    printf("g_audio_malloc_counter=%d\r\n", g_audio_malloc_counter);
+#endif
+    free(freeThis);
+}
+
+/*
+ *  Codec wrapper string copy.
+ */
+char* ESP_AUDIO_SAFE_STRING_COPY(char* storeHere, const char* copyThis)
+{
+    if (storeHere == NULL) g_audio_malloc_counter++;
+#ifdef TRACK_MALLOC
+    printf("g_audio_malloc_counter=%d\r\n", g_audio_malloc_counter);
+#endif
+    //ToDo: Memory Appear to be leaking here
+    return SafeStringCopy1(storeHere, copyThis);
+}
+
+/*
+ *  Codec wrapper free that will reassign the
+ *  provided pointer (after dereferencing) to
+ *  a NULL value.
+ */
+void ESP_AUDIO_SAFE_FREE(void** freeThis)
+{
+    if (*freeThis != NULL) g_audio_malloc_counter--;
+#ifdef TRACK_MALLOC
+    printf("g_audio_malloc_counter=%d\r\n", g_audio_malloc_counter);
+#endif
+    SafeFree1(freeThis);
+}
+
+/*
+ *  This structure tracks the state of a stream.
+ */
+struct StreamInstance {
+    /*
+     *  User-specified void*. This value represents the
+     *  void* that the caller wants returned in
+     *  codecwrapper callbacks.
+     */
+    void*   Input_StreamTag;
+
+    /*
+     *  If this value is nonzero, then the codec wrapper
+     *  needs to start a new stream.
+     */
+    int     Input_ResetFlag;
+
+    /*
+     *  Method callback when the rendering framework changes state.
+     */
+    void *  Input_StateChangeCallback;
+
+
+    /*
+     *  Method callback when the rendering framework determines the
+     *  duration of the track.
+     */
+//    Callback_EspAudio_DurationChange    Input_DurationChangeCallback;
+    void *    Input_DurationChangeCallback;
+
+    /*
+     *  Method callback when the rendering framework determines the
+     *  duration of the track.
+     */
+//   Callback_EspAudio_CanSetPosition    Input_CanSetPositionCallback;
+    void*    Input_CanSetPositionCallback;
+
+    /*
+     *  This is the URI specified by the caller.
+     */
+    char*   Input_TrackUri;
+
+    /*
+     *  Semaphore to synchronize the input (executed on caller threads) and
+     *  the codec wrapper thread, which performs the tasks for emulating
+     *  a rendering operation.
+     */
+//    int   LockInput;
+
+    /*
+     *  Index into codewrapper_Streams.
+     *  If the value is -1, it means the stream's thread
+     *  should terminate.
+     *  If the value is -2, then it means the stream has ended.
+     */
+    int Index;
+
+    /*
+     *  streamTag that the caller provided in EspAudio_SetupStream().
+     *  Copied from the Input_StreamTag.
+     */
+    void* StreamTag;
+
+    /*
+     *  The current byte position in the stream decoding.
+     */
+    uint32_t BytePosition;
+
+    /*
+     *  The current time position in the stream decoding in seconds.
+     */
+    uint32_t TimePosition;
+
+    /*
+     *  The total number of bytes in the stream.
+     */
+    uint32_t TotalByteLength;
+
+    /*
+     *  The total time duration of the stream in seconds.
+     */
+    uint32_t TotalTimeLength;
+
+    /*
+     *  Current volume setting, between 0 and 100.
+     */
+    uint32_t Volume;
+
+    /*
+     *  Current URI for playback. Copied from Input_TrackUri.
+     */
+    char* Uri;
+
+    /*
+     *  Current play state - set only on the thread that executes
+     *  in DecodeStreamLoop().
+     */
+    enum EspAudioState PlayState;
+
+    /*
+     *  Target play state - value is set on caller threads
+     *  as well as codec/rendering thread
+     *  (which executes in DecodeStreamLoop method).
+     *  Thread safety achieved through LockInput.
+     */
+    enum EspAudioState TargetPlayState;
+
+    /*
+     *  This semaphore blocks when there is no media, state is stopped or paused.
+     *  Effectively provides "idle" behavior for rendering.
+     */
+//    int BlockLock;
+
+    /*
+     *  The thread that is performing the work for rendering the stream.
+     *  This thread executes in the DecodeStreamLoop method.
+     */
+    pthread_t Thread;
+
+    /*
+     *  Miscellaneous pointer for use in callbacks.
+     *  Not used now, but could be used later when
+     *  a rendering framework returns data in a struct
+     *  from a callback.
+     */
+    void* CodecStuff;
+
+    /*
+     *  Execute this callback when the state changes.
+     */
+    Callback_EspAudio_StateChange StateChangeCallback;
+
+    /*
+     *  Execute this callback when the track's duration information
+     *  is updated. (Sometimes, rendering frameworks need
+     *  an asynchronous way to report the duration of the track.)
+     */
+    Callback_EspAudio_DurationChange DurationChangeCallback;
+
+    /*
+     *  Average bytes per second - used for estimating time.
+     */
+    uint32_t BytesPerSecond;
+
+    /*
+     *  Nonzero value indicates that the rendering should be muted.
+     */
+    int MuteFlag;
+
+    uint32_t TrackRdPos;
+
+    uint32_t TrackWrPos;
+
+    int Input_UriSrcType;
+
+    EspAudioMeidaType Input_MusicType;
+
+    PlayerWorkMode Input_WorkMode;
+
+    PlayerWorkMode workMode; // 1:decoder; 2:recorder;
+
+    PlayerCtrlPrio  ctrlPrio;
+
+};
+
+/*
+ *  Maximum number of simultaneous streams.
+ *  Generally speaking, most rendering frameworks only
+ *  allow one rendering stream. However this implementation
+ *  it can support multiple simultaneous streams
+ *  when calling EspAudio_Init() the first time.
+ */
+int MAX_MEDIA_STREAMS = 1;
+#define STREAMINDEX     0
+static xQueueHandle wrQue;
+
+/*
+ *  Dynamic allocation of streams that can be handled by the wrapper.
+ *  Created in EspAudio_Init().
+ */
+struct StreamInstance *codecwrapperStreams;
+
+/*
+ *  This method changes the rendering framework's reported byte position.
+ */
+static void SetDecodeBytePosition(struct StreamInstance* si, int bytePos)
+{
+    /* position can be changed from multipel threads */
+//  sem_wait(&(si->LockInput));
+    si->BytePosition = bytePos;
+    if (si->BytesPerSecond != 0) {
+        si->TimePosition = si->BytePosition / si->BytesPerSecond;
+    } else {
+        si->TimePosition = 0;
+    }
+
+//  sem_post(&(si->LockInput));
+}
+//#include "CodecWrapper.h"
+extern void MROnStopCB(void);
+void MROnStopCB(void)
+{
+}
+
+extern void OnCodecWrapper_StateChange (enum CodecWrapperState newState, void* codecSpecific, void* streamTag);
+
+/*
+ *  This method changes the rendering framework's reported playstate.
+ */
+static void SetAudioPlayState(struct StreamInstance* si, enum EspAudioState newState)
+{
+    /*  Apply new state. */
+    si->PlayState = newState;
+    // OnCodecWrapper_StateChange(newState, NULL, NULL);
+    LOGD("si->PlayState=%d, newstate=%d", si->PlayState, newState);
+}
+
+// UriType:0 Not living;    1:living;   2:loacl file; 3:DLNA URI
+/* see header file */
+int EspAudio_SetupStream(const char* URI, InputSrcType UriType)
+{
+    struct StreamInstance *si = NULL;
+    int retVal = -1;
+    LOGD("Input_Uri:%s,Input source type=%d", URI, UriType);
+    if ((NULL == URI)
+        || (UriType > InputSrcType_Max)) {
+        LOGE("URI=%s,InSrcType=%d", URI, UriType);
+        return EspAudioErr_InvalidPara;
+    }
+    retVal = strlen(URI);
+    if (retVal >= ESP_URI_LEN) {
+        LOGE("URI out of range[%d]", retVal);
+        return EspAudioErr_OutOfRange;
+    }
+    EspAudioMeidaType mediaType = checkMediaType(URI);
+    if (EspAudioMeidaType_Unknown == mediaType) {
+        LOGE("%s,media type does not support", URI);
+        return EspAudioErr_NotSupport;
+    }
+
+    /*
+     *  Find the appropriate stream.
+     */
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+//      sem_wait(&(si->LockInput));
+        si->Input_ResetFlag = 1;
+        si->Input_StreamTag = NULL;
+        si->Input_TrackUri = ESP_AUDIO_SAFE_STRING_COPY(NULL, URI);
+        si->Input_StateChangeCallback = NULL;
+        si->Input_DurationChangeCallback = NULL;
+        si->Input_CanSetPositionCallback = NULL;
+        si->Input_UriSrcType = UriType;
+        si->Input_MusicType = mediaType;
+
+        si->ctrlPrio = PlayerCtrlPrio_Auto;
+        retVal = 0;
+        LOGD("Input source type=%d, music type=%d", UriType, mediaType);
+    }
+
+    return retVal;
+}
+
+/*
+ *  This method can execute on caller-threads or on the codecwrapper
+ *  thread that executes in DecodeStreamLoop.
+ *  This method sets the desired state for the rendering framework
+ *  to the specified state.
+ */
+int SetAudioDesiredState(enum EspAudioState state)
+{
+    int retVal = -1;
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+        si->TargetPlayState = state;
+        if ((si->Uri == NULL) || (si->Uri[0] == '\0')) {
+            si->TargetPlayState = AUDIOSTATE_UNINITIALIZED;
+        }
+        LOGD(">>>Wanted state[%d],TargetPlayState[%d] rdPos=%x", state, si->TargetPlayState, si->TrackRdPos);
+        retVal = 0;
+    }
+
+    return retVal;
+}
+
+/*  Instructs rendering framework to play a specified stream. */
+int EspAudio_Play(void)
+{
+    //TODO: enable trick modes with playSpeed
+
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    si->ctrlPrio = PlayerCtrlPrio_User;
+
+    return SetAudioDesiredState(AUDIOSTATE_PLAYING);
+}
+
+/*  Instructs rendering framework to stop a specified stream. */
+int EspAudio_Stop(void)
+{
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    si->ctrlPrio = PlayerCtrlPrio_User;
+    return SetAudioDesiredState(AUDIOSTATE_STOPPED);
+}
+
+/*  Instructs rendering framework to pause a specified stream. */
+int EspAudio_Pause(void)
+{
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    si->ctrlPrio = PlayerCtrlPrio_User;
+    return SetAudioDesiredState(AUDIOSTATE_PAUSED);
+}
+
+/*  Returns the current playstate for a given stream. */
+enum EspAudioState EspAudio_GetPlayState(void)
+{
+    enum EspAudioState retVal = AUDIOSTATE_UNKNOWN;
+    struct StreamInstance *si = NULL;
+
+    si = &(codecwrapperStreams[STREAMINDEX]);
+
+    if (si != NULL) {
+        retVal = si->PlayState;
+    }
+
+    return retVal;
+}
+
+/*  Sets the desired playback position (seek operation) for a given stream. */
+int EspAudio_SetPosition (int timePosition)
+{
+    struct StreamInstance *si = NULL;
+
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    int byteSize = si->BytesPerSecond * timePosition;
+    if (si != NULL) {
+        SetDecodeBytePosition(si, byteSize);
+        //downloadTaskDownloadSizeSet(&byteSize);
+    }
+
+    LOGD("Set time position=%d", timePosition);
+    return 0;
+}
+
+/*  Returns the current playback time position for a given stream. */
+int EspAudio_GetTimePosition(uint32_t *timePos)
+{
+    int retVal = -1;
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+        *timePos = (si->TimePosition);
+    }
+    LOGD("GetTimePosition=%d", *timePos);
+    return retVal;
+}
+
+/*  Returns the total time duration for a given stream. */
+int EspAudio_GetTimeTotalLength(uint32_t *timeTotalLen)
+{
+    int retVal = -1;
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+        *timeTotalLen = si->TotalTimeLength;
+    }
+
+    LOGD("TotalTimeLength=%d", *timeTotalLen);
+    return retVal;
+}
+
+/*  Returns the current playback position, in terms of bytes, for a given stream. -1 means unknown. */
+int EspAudio_GetBytePosition(uint32_t *bytePos)
+{
+    int retVal = -1;
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+        *bytePos = si->BytePosition;
+    }
+
+    LOGD("BytePosition=%d", *bytePos);
+    return retVal;
+}
+
+/*  Returns the total byte length of a given for a given stream. -1 means unknown. */
+int EspAudio_GetByteTotalLength(uint32_t *byteTotalLen)
+{
+    int retVal = -1;
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+        *byteTotalLen = si->TotalByteLength;
+    }
+    LOGD("TotalByteLength=%d", *byteTotalLen);
+    return retVal;
+}
+
+/*  Gets the volume level of the specified stream. */
+int  EspAudio_GetVolume(int *level)
+{
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+
+    if (si != NULL) {
+        *level = si->Volume;
+    }
+
+    return EspAudioErr_NoErr;
+}
+
+/*  Sets the volume for a specified stream. */
+int EspAudio_SetVolume(int level)
+{
+    struct StreamInstance *si = NULL;
+
+    si = &(codecwrapperStreams[STREAMINDEX]);
+
+    if (si != NULL) {
+        mediaHalVolumeSet(level);
+        if ((MediaErr_NoError == mediaHalVolumeSet(level))) {
+            si->Volume = level;
+            // Save data to flash.
+        }
+    }
+
+    return 0;
+}
+
+int EspAudio_SetMode(PlayerWorkMode mode)
+{
+    if (mode > PlayerWorkMode_Max) {
+        return -1;
+    }
+    struct StreamInstance *si = NULL;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    if (si != NULL) {
+        si->Input_WorkMode = mode;
+    }
+    return 0;
+}
+
+void Show_Ap80Info(MusicInfo* info)
+{
+    printf("\n AP80 music info:\n");
+    printf("stream_type  %d\n", info->stream_type);
+    printf("num_channels %d\n", info->num_channels);
+    printf("samplingrate %dHz\n", info->sampling_rate);
+    printf("bitrate      %dbps\n", info->bitrate);
+    printf("duration     %dms\n", info->duration);
+    printf("file_size    %dbytes\n", info->file_size);
+    printf("firmware_ver %d\n", info->firmware_ver);
+    printf("firmware_num %d\n", info->firmware_num);
+    printf("bufEmpty     %d\n", info->bufEmpty);
+    printf("RFU          %d\n", info->RFU);
+}
+
+
+uint32_t CalTotalTime(uint32_t totalByte, uint32_t position, uint32_t time)
+{
+    return 1;
+}
+
+void decodeTaskCallback(uint32_t *state)
+{
+    struct StreamInstance *si;
+    if (state) {
+        si = &(codecwrapperStreams[0]);        
+        si->TargetPlayState = AUDIOSTATE_STOPPED;
+        audioBufRestAll();
+        SetAudioPlayState(si, si->TargetPlayState);
+    }
+}
+
+
+static int countForTime;
+/*
+ *  This is where all of the interesting work occurs.
+ *  This method provides the execution loop for simulated
+ *  rendering.
+ */
+void EspAudioLoop(void* streamInstance)
+{
+    struct StreamInstance *si;
+    int uriChanged = 0;
+    int newPos;
+    enum EspAudioState oldState;
+    int uriEmpty = 0;
+    int finishedFlag = 0;
+    int preTime = 0;
+    int newTime = 0;
+    uint32_t decodePreTime = 0;
+    uint32_t intervalMS = 0; /* interval in milliseconds */
+    si = (struct StreamInstance*) streamInstance;
+    si->BytesPerSecond = 80000;
+    LOGI("DecodeStreamLoop is running.");
+
+    int musicInfoFlag = 0;
+    while (si->Index >= 0) {
+        if ((si->PlayState == AUDIOSTATE_UNINITIALIZED) ||
+            (si->PlayState == AUDIOSTATE_STOPPED) ||
+            (si->PlayState == AUDIOSTATE_PAUSED) ||
+            (si->PlayState == AUDIOSTATE_ENDED)) {
+            vTaskDelay(150);
+            // LOGD("it's delay......heap:%d", system_get_free_heap_size());
+        }
+        uriChanged = 0;
+
+//        LOGD("it's delay......heap:%d %d,state-%d %d", system_get_free_heap_size(), audioBufFillGet()
+//            , si->PlayState, si->ctrlPrio);
+        if (si->Input_ResetFlag != 0) {
+            /* transfer the URI to the official state */
+            ESP_AUDIO_SAFE_FREE((void**) & (si->Uri));
+            si->Uri = si->Input_TrackUri;
+            si->Input_TrackUri = NULL;
+            si->StateChangeCallback = si->Input_StateChangeCallback;
+            si->DurationChangeCallback = si->Input_DurationChangeCallback;
+            si->StreamTag = si->Input_StreamTag;
+            si->Input_ResetFlag = 0;
+            countForTime = 0;
+            uriChanged = 1;
+            musicInfoFlag = 1;
+            finishedFlag = 0;
+            LOGD("Excute Input_ResetFlag");
+        }
+        TaskState httpTaskState = downloadTaskStateGet();
+        TaskState mediaDecoderTaskState = mediaDecoderTaskStateGet();
+        if ((TaskState_Finished == mediaDecoderTaskState)
+            && (AUDIOSTATE_PLAYING == si->PlayState)) {
+            si->TargetPlayState = AUDIOSTATE_ENDED;
+            SetAudioPlayState(si, AUDIOSTATE_ENDED);
+
+            finishedFlag = 1;
+            LOGD("mediaDecoderTaskState has been stop");
+        }
+
+        if ((si->PlayState != AUDIOSTATE_PLAYING)
+            && (audioBufFillGet() > (1024 * 10))
+            && (si->ctrlPrio <= PlayerCtrlPrio_Auto)) {
+            si->TargetPlayState = AUDIOSTATE_PLAYING;
+            si->ctrlPrio = PlayerCtrlPrio_Auto;
+            LOGI("Set playing, AUDIOSTATE_PLAYING");
+        }
+        if (uriChanged != 0) {
+            UriSrcAttr uriAttr = { 0 };
+            DecoderObj decoder = { 0 };
+
+            TaskState httpTaskState = downloadTaskStateGet();
+            TaskState mediaDecoderTaskState = mediaDecoderTaskStateGet();
+
+            LOGD("InputType=%d,httpState=%d decoderState=%d",
+                 si->Input_UriSrcType,  httpTaskState, mediaDecoderTaskState);
+            downloadTaskStop(wrQue);
+            LOGD("****downloadTaskStop****");
+            mediaDecoderTaskStop();
+            LOGD("****mediaDecoderTaskStop****");
+
+            if ((TaskState_Unknown == httpTaskState)
+                && (InputSrcType_Stream != si->Input_UriSrcType)) {
+                downloadTaskCreate(si->Input_UriSrcType);
+            } else  {
+                LOGD("HttpObj task state:%d", httpTaskState);
+            }
+            if ((si->Uri == NULL) || (si->Uri[0] == '\0')) {
+                si->TotalByteLength = 0;
+                si->TotalTimeLength = 0;
+                uriEmpty = 1;
+                si->TargetPlayState = AUDIOSTATE_UNINITIALIZED;
+                LOGE("URL is empty");
+            } else {
+                // Set the sound sources URL and tpye
+                if (InputSrcType_Stream != si->Input_UriSrcType) {
+                    uriAttr.str = si->Uri;
+                    uriAttr.srcType = si->Input_UriSrcType;
+                    downloadTaskInfoSet(&uriAttr);
+                    downloadTaskStart();
+                }
+
+                mediaDecoderTaskInfoGet(&decoder);
+                decoder.srcType = si->Input_UriSrcType;
+                if (si->Input_MusicType != EspAudioMeidaType_M3u) {
+                    decoder.musicType = si->Input_MusicType;
+                } else {
+                    decoder.musicType = EspAudioMeidaType_Unknown;
+                }
+                decoder.totalByteLength = 0;
+                decoder.bytePosition = 0;
+                mediaDecoderTaskInfoSet(&decoder);
+
+                uriEmpty = 0;
+                si->TargetPlayState = AUDIOSTATE_TRANSIT;
+
+                si->TotalByteLength = 0;
+                si->TotalTimeLength = 0;
+            }
+
+            si->CodecStuff = NULL;
+            si->BytePosition = 0;
+            si->TimePosition = 0;
+
+            oldState = si->TargetPlayState;
+            if (NULL != si->DurationChangeCallback) {
+                si->DurationChangeCallback(si->TotalTimeLength, si, si->StreamTag);
+            }
+            /* set current position */
+            SetDecodeBytePosition(si, 0);
+
+            /* event that we're in transit or uninitialized */
+            SetAudioPlayState(si, si->TargetPlayState);
+            LOGD("***$$$***oldState=%x,%d", oldState, si->PlayState);
+
+            uriChanged = 0;
+        }
+
+        if (si->PlayState != si->TargetPlayState) {
+            LOGD("***it's here***oldstate=%d,new%d", si->PlayState, si->TargetPlayState);
+            UriSrcAttr http = { 0 };
+            TaskState httpTaskState;
+            TaskState mediaDecoderTaskState;
+            uint32_t contSize = 0;
+            switch (si->TargetPlayState) {
+            case AUDIOSTATE_ENDED:
+                LOGI("AUDIOSTATE_ENDED");
+                break;
+            case AUDIOSTATE_PLAYING:
+                // Ready to total bytes;
+
+                LOGI("AUDIOSTATE_PLAYING, PlayState[%d], TargetPlayState[%d]", si->PlayState, si->TargetPlayState);
+                downloadTaskContentSizeGet(&contSize);
+                if (contSize != si->TotalByteLength) {
+                    si->TotalByteLength = contSize;
+                }
+                DecoderObj decoder = { 0 };
+                mediaDecoderTaskInfoGet(&decoder);
+                if (contSize != decoder.totalByteLength) {
+                    decoder.totalByteLength = contSize;
+                    mediaDecoderTaskInfoSet(&decoder);
+                }
+
+                // Start
+                httpTaskState = downloadTaskStateGet();
+                mediaDecoderTaskState = mediaDecoderTaskStateGet();
+
+                LOGI("mediaDecoderTaskResume[%d] httpTaskState[%d]...", mediaDecoderTaskState, httpTaskState);
+                if (AUDIOSTATE_PAUSED == si->PlayState) {
+                    if ((TaskState_Running != httpTaskState)) {
+                        downloadTaskResume();
+                        LOGI("invoke downloadTaskResume[%d]...", httpTaskState);
+                    }
+                    if ((TaskState_Running != mediaDecoderTaskState)) {
+                        mediaDecoderTaskResume();
+                        LOGI("invoke mediaDecoderTaskResume[%d]...", mediaDecoderTaskState);
+                    }
+                } else {
+                    if ((TaskState_Running != httpTaskState)
+                        && (InputSrcType_Stream != si->Input_UriSrcType)) {
+                        downloadTaskStart();
+                        LOGI("invoke downloadTaskStart[%d]...", httpTaskState);
+                    }
+                    if ((TaskState_Running != mediaDecoderTaskState)) {
+                        mediaDecoderTaskStart();
+                        LOGI("invoke mediaDecoderTaskStart[%d]...", mediaDecoderTaskState);
+                    }
+                }
+
+                LOGI("Stream decoder is playing...,TotalByte=%d,fill=%d,totalTime=%d",
+                     si->TotalByteLength, audioBufFillGet(), si->TotalTimeLength );
+                break;
+            case AUDIOSTATE_PAUSED:
+                LOGI("AUDIOSTATE_PAUSED, PlayState:%d, TargetPlayState:%d", si->PlayState, si->TargetPlayState);
+                if (si->ctrlPrio == PlayerCtrlPrio_Auto) {
+                    if (1 == downloadTaskHTTPStateGet()) { // running
+                        mediaDecoderTaskPause();
+                    }
+                } else {
+                    mediaDecoderTaskPause();
+                    downloadTaskPause();
+                }
+                break;
+            case AUDIOSTATE_STOPPED:
+                LOGI("AUDIOSTATE_STOPPED");
+                mediaDecoderTaskStop();
+                downloadTaskStop(wrQue);
+
+                break;
+            case AUDIOSTATE_TRANSIT:
+
+                MROnStopCB();
+                break;
+            default:
+                vTaskDelay(100 / portTICK_PERIOD_MS);
+                break;
+            }
+
+            SetAudioPlayState(si, si->TargetPlayState);
+        }
+
+        if (((si->PlayState == AUDIOSTATE_PLAYING) || (finishedFlag))
+            && (InputSrcType_Stream != si->Input_UriSrcType)
+            && (InputSrcType_NetLiving != si->Input_UriSrcType)) {
+            newTime = system_get_time();
+//            LOGD("Ready to get decode time");
+            if (((newTime - preTime) > 980000)) { // 1 second
+                if (0/*MediaErr_NoError == mediaHalDecodeTimeGet(&intervalMS)*/) {
+                    if (intervalMS > 0) {
+                        preTime = system_get_time();
+                        if (countForTime <= 3) {
+                            si->TimePosition = intervalMS / 1000;
+                        }
+                        DecoderObj decoder = { 0 };
+                        mediaDecoderTaskInfoGet(&decoder);
+                        si->BytePosition = decoder.bytePosition;
+
+                        int perSec = si->BytePosition / intervalMS;
+                        int time = 0;
+                        if (perSec > 0) {
+                            time = si->TotalByteLength / perSec;
+                        }
+//                        LOGD("intervalMS%d,time%d,bytePos%d,perSec%d,totalTime%d",intervalMS,
+//                            si->TimePosition, si->BytePosition, perSec, time);
+                        si->TotalTimeLength = time / 1000;
+                        if (decodePreTime == si->TimePosition) {
+                            countForTime++;
+                            if (countForTime > 3) {
+                                si->TimePosition = si->TotalTimeLength;
+                                LOGD("countForTime TimePosition %d,state=%d", si->TimePosition, si->PlayState);
+                                finishedFlag = 0;
+                                countForTime = 0;
+                            }
+                        } else {
+                            countForTime = 0;
+                        }
+                        decodePreTime = si->TimePosition;
+
+                    } else {
+//                        LOGD("intervalMS=%d preTime=%d,%d,bytePostion%d",intervalMS, preTime,
+//                            si->TimePosition, si->BytePosition);
+                    }
+                }
+            }
+        }
+
+
+        vTaskDelay(100 / portTICK_PERIOD_MS);
+    }
+
+    LOGD("task is exit");
+    si->Index = -2;
+    vTaskDelete(NULL);
+}
+
+
+/*
+ *  Initializes the codecwrapper library to handle the specified number of streams.
+ */
+void EspAudio_Init(void)
+{
+    int i;
+    struct StreamInstance *si;
+    codecwrapperStreams = (struct StreamInstance*) ESP_AUDIO_MALLOC(MAX_MEDIA_STREAMS * sizeof(struct StreamInstance));
+    LOGI("| >>>>> EspAudio version is %s <<<<< |\r\n", ESP_AUDIO_RELEASE_VER);
+    /*
+     *  Initialize and reserve resources that could
+     *  be used for playback of streams.
+     */
+
+    mediaHalInit();
+    audioBufInit();
+    audioBufRestAll(); // may be not need to do.if the URL is working
+    MusicInfo info;
+    mediaHalMusicInfoGet(&info);
+    wrQue = xQueueCreate(2, 1);
+    configASSERT(wrQue);
+    LOGD("wrQue=%p", wrQue);
+    audioBufWrQuitCfg(wrQue);
+    if (MediaErr_NoError == mediaHalMusicInfoGet(&info)) {
+        LOGI(" *** AP80 firmware_ver=%d,firmware_num=%d ***\n", info.firmware_ver, info.firmware_num);
+    } else {
+        LOGE(" *** AP80 firmware got failed ***\n");
+    }
+
+    for (i = 0; i < MAX_MEDIA_STREAMS; i++) {
+        si = &(codecwrapperStreams[i]);
+
+        si->Input_ResetFlag = 0;
+        si->Input_StreamTag = NULL;
+        si->Input_TrackUri = NULL;
+        si->Volume = 0;
+
+        si->Index = i;
+        si->StreamTag = NULL;
+        si->BytePosition = 0;
+        si->TimePosition = 0;
+        si->TotalByteLength = 0;
+        si->TotalTimeLength = 0;
+        si->PlayState = AUDIOSTATE_UNINITIALIZED;
+        si->TargetPlayState = AUDIOSTATE_UNINITIALIZED;
+        si->CodecStuff = NULL;
+        si->StateChangeCallback = NULL;
+        si->DurationChangeCallback = NULL;
+        si->Input_CanSetPositionCallback = NULL;
+        si->Uri = NULL;
+        si->MuteFlag = 0;
+        si->ctrlPrio = PlayerCtrlPrio_Unknown;
+
+        audioBufPosGet(&si->TrackRdPos, &si->TrackWrPos);
+        xTaskCreate(EspAudioLoop, "EspAudioLoop", 3*1024, si, AUDIOLOOP_TSK_PRIO, &(si->Thread));
+
+        mediaDecoderTaskCreate();
+        EspAudio_SetVolume(30);
+        //    if (false == system_param_load(0x70,0,(void*)&si->Volume, sizeof(si->Volume))) {
+//            LOGD("system_param_load volume failed,set default value");
+        //    }
+
+    }
+
+}
+
+/*
+ *  Stops the codecwrapper thread and instructs appropriately
+ *  deallocates stuff.
+ */
+void EspAudio_UnInit(void)
+{
+    int i;
+    struct StreamInstance *si;
+    int numThreadsRunning = MAX_MEDIA_STREAMS;
+
+    /*
+     *  Instruct all decode threads to stop
+     *  by setting the index==-1, be
+     *  sure to wake each thread in case it's asleep.
+     */
+    for (i = 0; i < MAX_MEDIA_STREAMS; i++) {
+        si = &(codecwrapperStreams[i]);
+        si->Index = -1;
+        //PulseEspAudioThread(si);
+    }
+
+    downloadTaskDestroy();
+
+    mediaDecoderTaskDestroy();
+    /* spin here until all threads are done */
+    while (numThreadsRunning > 0) {
+        /* block for a short period of time */
+        // SleepMsTime(100);
+        numThreadsRunning = MAX_MEDIA_STREAMS;
+        for (i = 0; i < MAX_MEDIA_STREAMS; i++) {
+            si = &(codecwrapperStreams[i]);
+            if (si->Index == -2) {
+                numThreadsRunning--;
+            }
+        }
+    }
+
+    /* all threads are done, finish unitializing stream instances */
+
+    for (i = 0; i < MAX_MEDIA_STREAMS; i++) {
+        si = &(codecwrapperStreams[i]);
+        ESP_AUDIO_SAFE_FREE((void**) & (si->Input_TrackUri));
+        ESP_AUDIO_SAFE_FREE((void**) & (si->Uri));
+        si->StreamTag = NULL;
+        si->CodecStuff = NULL;
+        si->StateChangeCallback = NULL;
+        si->DurationChangeCallback = NULL;
+//      sem_destroy(&(si->BlockLock));
+//      sem_destroy(&(si->LockInput));
+        si->Thread = 0;
+    }
+    vQueueDelete(wrQue);
+    wrQue = NULL;
+    ESP_AUDIO_FREE(codecwrapperStreams);
+}
+
+/*
+ *  Returns the mute value for the specified stream.
+ */
+int EspAudio_GetMute(int *muteFlag)
+{
+    struct StreamInstance *si;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    *muteFlag = si->MuteFlag;
+    return EspAudioErr_NoErr;
+}
+
+/*
+ *  Sets tne mute value for the specified stream.
+ */
+int EspAudio_SetMute(int muteFlag)
+{
+    struct StreamInstance *si;
+    si = &(codecwrapperStreams[STREAMINDEX]);
+    si->MuteFlag = muteFlag;
+    return 0;
+}
+
+static uint32_t streamSize = 0;
+EspAudioErr EspAudioPlayerStreamCfg(uint32_t rate, uint32_t channel, uint32_t bitLen)
+{
+    StreamInfo info;
+    info.rate = rate;
+    info.ch = channel;
+    info.bitLen = bitLen;
+    info.size = 0xFFFFFFFF;
+    streamSize = 0;
+    mediaDecoderStreamInfoSet(&info);
+    mediaDecoderTaskCb(decodeTaskCallback);
+    return EspAudioErr_NoErr;
+}
+
+EspAudioErr EspAudioPlayerStreamWrite(uint8_t *inData, uint32_t inSize, uint32_t timeout)
+{
+    EspAudioErr ret = EspAudioErr_NoErr;
+    if ((NULL == inData) || (0 == inSize)) {
+        LOGE("Invalid para,inData=%x,inSize=%d", inData, inSize);
+        ret = EspAudioErr_InvalidPara;
+    } else {
+        int wr = audioBufWrite((char*)inData, inSize, timeout);
+        if (0 == wr) {
+            ret = EspAudioErr_NoMem;
+        } else {            
+            streamSize += inSize;
+        }
+    }
+    return ret;
+}
+
+EspAudioErr EspAudioPlayerStreamWriteEnd(void)
+{
+    mediaDecoderStreamSizeUpdate(&streamSize);
+    streamSize = 0;
+    return EspAudioErr_NoErr;
+}
+

+ 318 - 0
examples/09_a2dp/components/EspAudio/player/M3u8.c

@@ -0,0 +1,318 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "inc/M3u8.h"
+
+static int read_line_from_m3u8_info(char *m3u8_info, char *line_buffer, int buffer_size);
+static int m3u8_info_eof();
+static int parseSegFromUrl(M3u8Segment* tsp);
+static char * strdupmy(const char *s);
+unsigned int length;
+unsigned int offset;
+
+//////////////////////////////////////////////////////////////////////////////////////
+char* trim_str(char *str)
+{
+    char* tmp = str;
+
+    while (*str++ != '\r') {
+        if (*str == '\0' || *str == '\n') {
+            break;
+        }
+    }
+    *str = '\0';
+    return tmp;
+}
+
+// Must to be free memory
+static char * strdupmy(const char *s)
+{
+    size_t  len = strlen(s) + 1;
+    void *new = malloc(len);
+    if (new == NULL)
+        return NULL;
+    return (char *)memcpy(new, s, len);
+}
+
+char* split_url(char* url, char* seg_path, char* seg_name)
+{
+    char* temp1;
+    char rateStr[10] = {0};
+    int len = strlen(url);
+    while (url) {
+        temp1 = strrchr(url, '/');
+        if (temp1 == NULL) {
+            printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
+            return NULL;
+        }
+        temp1 += 1;
+        strncpy(seg_path, url, temp1 - url);
+        strncpy(seg_name, temp1, len - (temp1 - url));
+        return seg_path;
+    }
+
+    return NULL;
+}
+
+int is_blank(char *str)
+{
+    if (0 == strlen(str))
+        return 1;
+    else
+        return 0;
+}
+
+static int read_line_from_m3u8_info(char *m3u8_info, char *line_buffer, int buffer_size)
+{
+    int start;
+    int end = -1;
+    char cur_char = '\0';
+    int copy_size;
+
+    start = offset;
+    while (offset < length) {
+        cur_char = m3u8_info[offset];
+        if (cur_char == '\r' || cur_char == '\n') {
+            end = offset;
+            offset++;
+            break;
+        }
+        offset++;
+    }
+    if (end == -1) {
+        end = length;
+    }
+    if (cur_char == '\r') {
+        offset++;
+    }
+    memset(line_buffer, 0, buffer_size);
+    copy_size = end - start;
+    if (copy_size > buffer_size - 1) {
+        copy_size = buffer_size - 1;
+    }
+    strncpy(line_buffer, m3u8_info + start, copy_size);
+
+    return 1;
+}
+
+static int m3u8_info_eof()
+{
+    if (offset >= length) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+int parseSegFromUrl(M3u8Segment* tsp)
+{
+    int len = strlen(tsp->url);
+    int ret = -1;
+    char *segment_path = (char*)malloc(len);
+    char *segment_name = (char*)malloc(len);
+    if ((segment_path == NULL) | (segment_name == NULL)) {
+        goto SAVEEXIT;
+    }
+    memset(segment_path, 0, len);
+    memset(segment_name, 0, len);
+    split_url(tsp->url, segment_path, segment_name);
+    //http://live.xmcdn.com/192.168.3.134/live/12/24/160411_000003_15f9.ts
+    //http://live.xmcdn.com/192.168.3.134/live/75/24/160413_082919_12b0.aac
+    char* temp1 = strchr(segment_name, '.');
+    char* temp2 = strrchr(segment_name, '_');
+    if ((temp1 == NULL) | (temp2 == NULL)) {
+        printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
+        goto SAVEEXIT;
+    }
+    *temp1 = '\0';
+    temp1++;
+    if (strncmp(temp1, "aac", 3) == 0) {
+        tsp->fmt = AUDIOFMT_AAC;
+    } else if (strncmp(temp1, "ts", 3) == 0) {
+        tsp->fmt = AUDIOFMT_TS;
+    } else {
+        tsp->fmt = AUDIOFMT_UNKNOWN;
+    }
+    ///subSeq
+    temp2++;
+    tsp->seq.sub = strtoul(temp2, 0, 16);
+    ////mainSeq
+    temp2--;
+    *temp2 = '\0';
+    temp1 = strrchr(segment_name, '_');
+    if (temp1 == NULL) {
+        printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
+        goto SAVEEXIT;
+    }
+    temp1++;
+    tsp->seq.main = strtoul(temp1, 0, 16);
+    ///
+    temp2 = strchr(segment_name, '_');
+    if (temp2 == NULL) {
+        printf("ERR:strchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
+        goto SAVEEXIT;
+    }
+    *temp2 = '\0';
+    tsp->seq.date = strtoul(segment_name, 0, 16);
+
+    temp1 = strrchr(segment_path, '/');
+    if (temp1 == NULL) {
+        printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
+        goto SAVEEXIT;
+    }
+    *temp1 = '\0';
+    temp1 = strrchr(segment_path, '/');
+    if (temp1 == NULL) {
+        printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
+        goto SAVEEXIT;
+    }
+    temp1++;
+    tsp->rate = atoi(temp1);
+    ret = 0;
+SAVEEXIT:
+    if (segment_path) {
+        free(segment_path);
+    }
+    if (segment_name) {
+        free(segment_name);
+    }
+    return ret;
+}
+#define ONE_LINE_SIZE  1024
+M3u8Info *m3u8Parser(char *m3u8Str, M3u8Info* m3u8)
+{
+    int has_segment = 0;
+    if (NULL == m3u8) {
+        printf("malloc for M3u8Info failed.");
+        return NULL;
+    }
+
+    char *line = malloc(ONE_LINE_SIZE);
+    if (NULL == line) {
+        printf("zalloc for line failed.");
+        return NULL;
+    }
+    memset(line, 0, ONE_LINE_SIZE);
+    memset(m3u8, 0, sizeof(M3u8Info));
+    length = strlen(m3u8Str);
+    offset = 0;
+
+    while (!m3u8_info_eof()) {
+        int result = 0;
+        char *str = NULL;
+        if (m3u8->segCount >= MAX_SEGMENT_COUNT) {
+            printf("segCount >= MAX_SEGMENT_COUNT[%d].", MAX_SEGMENT_COUNT);
+            break;
+        }
+        result = read_line_from_m3u8_info(m3u8Str, line, ONE_LINE_SIZE);
+        if (!result) {
+            printf("ERR:read line error from m3u8 info.");
+            if (line) free(line);
+            return NULL;
+        }
+        if (is_blank(line)) {
+            continue;
+        }
+        str = trim_str(line);
+        if (has_segment) {
+            int size = strlen(str) + 1;
+            m3u8->segList[m3u8->segCount].seq.sub = m3u8->mediaSeq + m3u8->segCount;
+            // m3u8->segList[m3u8->segCount - 1].url = (char *)malloc(size);
+            memset(m3u8->segList[m3u8->segCount].url, 0, size);
+            strcpy(m3u8->segList[m3u8->segCount].url, str);
+            parseSegFromUrl(&m3u8->segList[m3u8->segCount]);
+            has_segment = 0;
+            m3u8->segCount++;
+        } else {
+            if (0 == strncmp(str, "#EXTM3U", strlen("#EXTM3U"))) {
+
+            } else if (0 == strncmp(str, "#EXT-X-VERSION:", strlen("#EXT-X-VERSION:"))) {
+
+            } else if (0 == strncmp(str, "#EXT-X-ALLOW-CACHE:", strlen("#EXT-X-ALLOW-CACHE:"))) {
+
+            } else if (0 == strncmp(str, "#EXT-X-TARGETDURATION:", strlen("#EXT-X-TARGETDURATION:"))) {
+                char *str_duration = str + strlen("#EXT-X-TARGETDURATION:");
+                m3u8->targetDuration = atoi(trim_str(str_duration));
+                // printf("Get the TARGETDURATION=%d\n", m3u8->targetDuration);
+            } else if (0 == strncmp(str, "#EXT-X-MEDIA-SEQUENCE:", strlen("#EXT-X-MEDIA-SEQUENCE:"))) {
+                char *str_sequence = str + strlen("#EXT-X-MEDIA-SEQUENCE:");
+                m3u8->mediaSeq = atol(trim_str(str_sequence));
+                //  printf("Get the MEDIA-SEQUENCE=%d\n", m3u8->mediaSeq);
+            } else if (0 == strncmp(str, "#EXTINF:", strlen("#EXTINF:"))) {
+                char *str_segment_duration = NULL;
+                int i = 0;
+                has_segment = 1;
+                str_segment_duration = str + strlen("#EXTINF:");
+                while (str_segment_duration[i] != 0) {
+                    if ((str_segment_duration[i] < '0') || (str_segment_duration[i] > '9')) {
+                        str_segment_duration[i] = 0;
+                        break;
+                    }
+                    i++;
+                }
+                m3u8->segList[m3u8->segCount].duration = atoi(str_segment_duration);
+            } else if (0 == strncmp(str, "#EXT-X-DISCONTINUITY", strlen("#EXT-X-DISCONTINUITY"))) {
+
+            } else if (0 == strncmp(str, "#EXT-X-ENDLIST", strlen("#EXT-X-ENDLIST"))) {
+
+            } else {
+                printf("unknown line: %s.", str);
+            }
+        }
+    }
+    if (line) free(line);
+    return m3u8;
+}
+
+uint8_t m3u8CheckValid(const M3u8Seq* new, const M3u8Seq* pre)
+{
+    if (pre->date < new->date) {
+        return 1;
+    } else if (pre->date == new->date) {
+        if (pre->main < new->main) {
+            return 1;
+        } else if (pre->main == new->main) {
+            if ((pre->sub & 0x0000FFFF) < (new->sub & 0x0000FFFF)) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else {
+            return 0;
+        }
+    } else {
+        return 0;
+    }
+
+}
+
+void m3u8Destroy(M3u8Info *m3u8)
+{
+    int i = 0;
+    if (m3u8 == NULL) {
+        return;
+    }
+    free(m3u8);
+}
+
+int m3u8_test(char* pStr)
+{
+    //char *m3u8Str = "#EXTM3U\n"
+    //                    "#EXT-X-TARGETDURATION:8\n"
+    //                    "#EXT-X-MEDIA-SEQUENCE:92595\n"
+    //                    "#EXTINF:8,\n"
+    //                    "20121120T182851-04-92595.ts\n"
+    //                    "#EXTINF:8,\n"
+    //                    "20121120T182851-04-92596.ts\n"
+    //                    "#EXTINF:8,\n"
+    //                    "20121120T182851-04-92597.ts\n"
+    //                    "#EXTINF:8,\n"
+    //                    "20121120T182851-04-92598.ts\n";
+
+
+    for (int i = 0; i < 10000; i++) {
+        // M3u8Info *m3u8 = m3u8Parser(pStr, m3u8);
+        // m3u8Destroy(m3u8);
+    }
+    return 1;
+}

+ 370 - 0
examples/09_a2dp/components/EspAudio/player/MediaDecoderTask.c

@@ -0,0 +1,370 @@
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+
+#include "esp_types.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "audio_log.h"
+
+#include "inc/DecoderCom.h"
+#include "EspAudioCom.h"
+#include "Storage.h"
+#include "Utility.h"
+#include "inc/MediaDecoderTask.h"
+
+
+#define  DECODER_TSK_PRIO       8
+#define  DATA_PKG_SIZE        (512*2)
+
+#if 0
+#define DEBUGPLY    printf
+#else
+#define DEBUGPLY
+#endif
+
+static xQueueHandle rdQue;
+
+void mediaDecoderTask(void *pvParameters);
+
+typedef struct {
+    TaskState state;
+    pthread_t thread;
+    int threadQuit;
+    TaskState lastState;
+    DecoderObj player;
+} MediaPlayerInstance;
+extern uint32_t rdpos;
+extern uint32_t wrpos;
+
+
+MediaPlayerInstance decoderInstance = { 0 };
+static StreamInfo streamInfo;
+
+typedef void (*mediaTaskCallback)(uint32_t *state);
+static mediaTaskCallback stateCB;
+
+
+void mediaDecoderTask(void *pvParameters)
+{
+    MediaPlayerInstance *MPI = (MediaPlayerInstance *)pvParameters;
+    LOGI("%s is running.%x %x", __func__, pvParameters, MPI->threadQuit);
+
+/////////////////////////////
+    MPI->threadQuit = 0;
+    int newPos = 0;
+    uint32_t wrPos, rdPos;
+    int isLoopNum = 0;
+    int readSize = DATA_PKG_SIZE;
+    int writeDataFinished = 0;
+    while (MPI->threadQuit == 0) {
+        switch (MPI->state) {
+        case TaskState_Ready:
+            if (MPI->player.musicType == EspAudioMeidaType_Unknown) {
+                vTaskDelay(100);
+                continue;
+            }
+            LOGD("MPI is here,rate=%d,channel=%d,bitLen=%x",
+                 streamInfo.rate,
+                 streamInfo.ch,
+                 streamInfo.bitLen);
+            MusicInfo setInfo;
+            setInfo.num_channels = streamInfo.ch;
+            setInfo.sampling_rate = streamInfo.rate;
+            mediaHalModeSet(MediaMode_Decode, &setInfo);
+            mediaHalPlay(MPI->player.musicType);
+            audioBufPosGet(&rdPos, &wrPos);
+            if ((InputSrcType_NetSpec == MPI->player.srcType)
+                || (InputSrcType_LocalFile == MPI->player.srcType)
+                || ((InputSrcType_Stream == MPI->player.srcType) &&  (MPI->player.totalByteLength != 0))) {
+                if ((MPI->player.totalByteLength - MPI->player.bytePosition) < DATA_PKG_SIZE) {
+                    readSize = MPI->player.totalByteLength - MPI->player.bytePosition;
+                } else {
+                    readSize = DATA_PKG_SIZE;
+                }
+            } else {
+                readSize = DATA_PKG_SIZE;
+            }
+            LOGD("rdPos=%x,wrPos=%x,readSize=%d, type=%d\r\n", rdPos, wrPos, readSize, MPI->player.srcType);
+            MPI->state = TaskState_Running;
+            writeDataFinished = 0;
+            isLoopNum  = 0;
+
+            MPI->lastState = TaskState_Ready;
+            break;
+        case TaskState_Pause:
+            mediaHalPause();
+            LOGI("Pause playing music....");
+            MPI->state = TaskState_Idle;
+            MPI->lastState = TaskState_Pause;
+            break;
+        case TaskState_Resume:
+            mediaHalPlay(MPI->player.musicType);
+            MPI->state = TaskState_Running;
+            MPI->lastState = TaskState_Resume;
+            LOGI("Resume playing music....");
+            break;
+        case TaskState_Running: {
+            if (1 == writeDataFinished) {
+                MusicInfo info;
+                mediaHalMusicInfoGet(&info);
+                if (1 == info.bufEmpty) {
+                    MPI->state = TaskState_Stoped;
+                    LOGI("Set state TaskState_Stoped");
+                } else {
+                    LOGI("Waiting for decoder empty...");
+                }
+                vTaskDelay(100 / portTICK_PERIOD_MS);
+                break;
+            }
+            int res = audioBufRead(MPI->player.dat, readSize, 100);
+            if (res == 0) {
+                MPI->state = TaskState_Stoped;
+                LOGD("audio buffer read quit");
+                break;
+            }
+            MediaErr ret = mediaHalDataWrite((uint8_t*)MPI->player.dat, readSize);
+            if (ret == MediaErr_NoError) {
+                MPI->player.bytePosition += readSize;
+                if ((InputSrcType_NetSpec == MPI->player.srcType)
+                    || (InputSrcType_LocalFile == MPI->player.srcType)
+                    || ((InputSrcType_Stream == MPI->player.srcType) && (MPI->player.totalByteLength != 0))) {
+                    newPos = MPI->player.bytePosition + DATA_PKG_SIZE;
+                    if (MPI->player.totalByteLength <= newPos) {
+                        writeDataFinished = 1;
+                        readSize = MPI->player.totalByteLength - MPI->player.bytePosition;
+
+                        MPI->player.bytePosition = MPI->player.totalByteLength;
+                        LOGD("Last byte Pos=%d total=%d", MPI->player.bytePosition, MPI->player.totalByteLength);
+                        break;
+                    } else {
+                        readSize = DATA_PKG_SIZE;
+                    }
+                }
+            } else if (MediaErr_CodecError == ret) {
+                uint32_t rdPOS, wrPOS;
+                audioBufPosGet(&rdPOS, &wrPOS);
+                LOGI("ap8048 init failed ret=%x.Try again.rdPOS=%x,wrPOS=%x", ret, rdPOS, wrPOS);
+                audioBufRdPosSet(&rdPos);
+                mediaHalStop();
+                MPI->state = TaskState_Ready;
+            } else {
+                LOGE("ap8048 ret error[%x]", ret);
+            }
+            MPI->lastState = TaskState_Running;
+        }
+
+        break;
+        case TaskState_Stoped: {
+            mediaHalStop();
+            newPos = 0;
+            if (MPI->player.bytePosition == MPI->player.totalByteLength) {
+                MPI->state = TaskState_Finished;
+                MPI->player.bytePosition = 0;
+                MPI->player.totalByteLength = 0;
+            } else {
+                MPI->state = TaskState_Idle;
+            }
+            LOGI("Stop playing music....state[%d]", MPI->state);
+            MPI->lastState = TaskState_Stoped;
+            if (stateCB) stateCB(&MPI->state);
+            break;
+        }
+        case TaskState_Finished:
+        case TaskState_Idle:
+        default:
+            vTaskDelay(300 / portTICK_PERIOD_MS);
+//            LOGD("MPI->state[%d]", MPI->state);
+            break;
+        }
+    }
+    MPI->threadQuit = -1;
+    MPI->thread = NULL;
+    MPI->state = TaskState_Unknown;
+    MPI->lastState = TaskState_Unknown;
+
+    LOGD("%s is ended...", __func__);
+
+    vTaskDelete(NULL);
+}
+
+void mediaDecoderTaskCb(void *func)
+{
+    stateCB = func;
+}
+TaskState mediaDecoderTaskStateGet()
+{
+    return decoderInstance.lastState;
+}
+
+void mediaDecoderTaskInfoGet(DecoderObj *obj)
+{
+    if (NULL == obj) {
+        LOGE("Invalid para");
+        return ;
+    }
+    memcpy(obj, &decoderInstance.player, sizeof(*obj));
+}
+
+void mediaDecoderStreamInfoSet(StreamInfo *info)
+{
+    if (NULL == info) {
+        LOGE("Invalid para");
+        return ;
+    }
+    memcpy(&streamInfo, info, sizeof(streamInfo));
+    decoderInstance.player.totalByteLength = 0;
+    LOGD("Set Stream info ok,rate=%d,channel=%d,bitLen=%x",
+         streamInfo.rate,
+         streamInfo.ch,
+         streamInfo.bitLen);
+}
+
+void mediaDecoderStreamSizeUpdate(uint32_t *size)
+{
+    if (NULL == *size) {
+        LOGE("Invalid para");
+        return ;
+    }
+    decoderInstance.player.totalByteLength = *size;
+    LOGD("Stream total size=%d", decoderInstance.player.totalByteLength);
+}
+
+
+void mediaDecoderTaskInfoSet(DecoderObj *obj)
+{
+    if (NULL == obj) {
+        LOGE("Invalid para");
+        return ;
+    }
+    memcpy(&decoderInstance.player, obj, sizeof(*obj));
+    
+    LOGD("Set DecoderObj ok,total=%d,type=%d,dat=%x music=%d",
+         decoderInstance.player.totalByteLength,
+         decoderInstance.player.srcType,
+         decoderInstance.player.dat,
+         decoderInstance.player.musicType);
+}
+
+void mediaDecoderTaskPause()
+{
+    if (0 == decoderInstance.thread) {
+        decoderInstance.state = TaskState_Unknown;
+        LOGE("decoderInstance.thread is NULL");
+        return;
+    }
+    if (TaskState_Running == decoderInstance.state) {
+        decoderInstance.state = TaskState_Pause;
+    }
+    LOGD("Task state=%d", decoderInstance.state);
+}
+
+void mediaDecoderTaskResume()
+{
+    if (0 == decoderInstance.thread) {
+        decoderInstance.state = TaskState_Unknown;
+        LOGE("decoderInstance.thread is NULL");
+        return;
+    }
+    decoderInstance.state = TaskState_Resume;
+    LOGD("Task state=%d", decoderInstance.state);
+}
+
+void mediaDecoderTaskCreate()
+{
+    if (NULL != decoderInstance.player.dat) {
+        free(decoderInstance.player.dat);
+    }
+    memset(&decoderInstance, 0, sizeof(decoderInstance));
+    memset(&streamInfo, 0, sizeof(streamInfo));
+    decoderInstance.player.dat = calloc(1, DATA_PKG_SIZE);
+    if (NULL == decoderInstance.player.dat) {
+        LOGE("decoderInstance.player.dat malloc error");
+        return;
+    }
+    xTaskCreate(mediaDecoderTask, "mediaDecoderTask", (5 * 1024), &decoderInstance, DECODER_TSK_PRIO, &decoderInstance.thread);
+    configASSERT(decoderInstance.thread);
+    LOGD("Task state=%d,dat:%x", decoderInstance.state, decoderInstance.player.dat);
+    rdQue = xQueueCreate(2, 1);
+    configASSERT(rdQue);
+    audioBufRdQuitCfg(rdQue);
+}
+
+
+int mediaDecoderTaskStart()
+{
+    if (0 == decoderInstance.thread) {
+        decoderInstance.state = TaskState_Unknown;
+        LOGE("decoderInstance.thread is NULL");
+        return -1;
+    }
+    if ((decoderInstance.player.srcType == InputSrcType_NetSpec)
+        || (decoderInstance.player.srcType == InputSrcType_LocalFile)) {
+        if (decoderInstance.player.totalByteLength == 0) {
+            LOGE("Player parameter is not ready");
+            decoderInstance.state = TaskState_Idle;
+            return -1;
+        }
+    }
+
+    decoderInstance.state = TaskState_Ready;
+    LOGD("Task state=%d", decoderInstance.state);
+    audioBufRdRest();
+    return 0;
+}
+
+void mediaDecoderTaskStop()
+{
+    if (0 == decoderInstance.thread) {
+        decoderInstance.state = TaskState_Unknown;
+        LOGE("decoderInstance.thread is NULL");
+        return;
+    }
+    if ((decoderInstance.lastState == TaskState_Unknown)
+        || (decoderInstance.lastState == TaskState_Stoped)) {
+        LOGW("dlInstance.state is [%d]", decoderInstance.state);
+        return;
+    }
+    decoderInstance.state = TaskState_Stoped;
+    configASSERT(rdQue);
+    xQueueSend(rdQue, &decoderInstance.state, 0);
+    LOGD("Task state=%d", decoderInstance.state);
+    while ((TaskState_Finished != decoderInstance.state)
+           && (TaskState_Idle != decoderInstance.state)) {
+        if ((TaskState_Idle == decoderInstance.state)) {
+            break;
+        }
+        vTaskDelay(10 / portTICK_RATE_MS);
+    }
+    audioBufRdRest();
+    int flag;
+    xQueueReceive(rdQue, &flag, 0);
+    LOGD("Task state=%d", decoderInstance.state);
+}
+
+void mediaDecoderTaskDestroy()
+{
+    if (0 == decoderInstance.threadQuit) {
+        decoderInstance.state = TaskState_Stoped;
+        decoderInstance.threadQuit = 1;
+        while (1) {
+            if ((decoderInstance.threadQuit == -1)) {
+                break;
+            }
+            vTaskDelay(100 / portTICK_RATE_MS);
+        }
+    }
+
+    if (NULL != decoderInstance.player.dat) {
+        free(decoderInstance.player.dat);
+    }
+    memset(&decoderInstance.player, 0, sizeof(decoderInstance.player));
+    memset(&streamInfo, 0, sizeof(streamInfo));
+    decoderInstance.player.dat = NULL;
+    decoderInstance.state = TaskState_Unknown;
+    vQueueDelete(rdQue);
+    rdQue =  NULL;
+    LOGD("Task state=%d", decoderInstance.state);
+}

+ 42 - 0
examples/09_a2dp/components/EspAudio/player/inc/DecoderCom.h

@@ -0,0 +1,42 @@
+/*****************************************************************************
+*
+* File Name : wm_http_client.h
+*
+* Description: Http client header file.
+*
+* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
+* All rights reserved.
+*
+* Author : wanghf
+*
+* Date : 2014-6-6
+*****************************************************************************/
+
+#ifndef __DECODER_COM_H__
+#define __DECODER_COM_H__
+#include "esp_types.h"
+
+
+
+// HTTP Type Definitions
+
+//#define pthread_t       sys_thread_t
+
+
+typedef enum {
+    TaskState_Unknown   = 0,
+    TaskState_Idle      = 1, // running state
+    TaskState_Running   = 2,
+    TaskState_Stoped    = 3,
+    TaskState_Finished  = 4,
+
+    TaskState_Ready     = 10, //control state
+    TaskState_Resume    = 11,
+    TaskState_Pause     = 12,
+
+} TaskState;
+
+
+
+
+#endif //__DECODER_COM_H__

+ 46 - 0
examples/09_a2dp/components/EspAudio/player/inc/DownloadTask.h

@@ -0,0 +1,46 @@
+/*****************************************************************************
+*
+* File Name : wm_http_client.h
+*
+* Description: Http client header file.
+*
+* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
+* All rights reserved.
+*
+* Author : wanghf
+*
+* Date : 2014-6-6
+*****************************************************************************/
+
+#ifndef HTTP_CLIENT_H
+#define HTTP_CLIENT_H
+#include "esp_types.h"
+#include "lwip/sys.h"
+#include "DecoderCom.h"
+
+#define ESP_URI_LEN                 1024
+
+typedef struct {
+    char   *str;
+    int    srcType;       // 0:specific net audio; 1:m3u8 files; 2:audio data files
+//    int    setStartBytePos;
+} UriSrcAttr;
+
+TaskState downloadTaskStateGet();
+
+void downloadTaskContentSizeGet(uint32_t *size);
+
+void downloadTaskInfoSet(UriSrcAttr *obj);
+int downloadTaskHTTPStateGet();
+
+void downloadTaskPause();
+
+void downloadTaskResume();
+
+int downloadTaskStart();
+void downloadTaskStop();
+
+void downloadTaskCreate(int taskType);
+void downloadTaskDestroy();
+
+#endif //

+ 79 - 0
examples/09_a2dp/components/EspAudio/player/inc/M3u8.h

@@ -0,0 +1,79 @@
+#ifndef _M3U8_H_
+#define _M3U8_H_
+#include "esp_types.h"
+
+#define MAX_SEGMENT_COUNT 3
+
+
+//
+typedef enum {
+    AUDIOFMT_UNKNOWN    = 0,
+    AUDIOFMT_AAC        = 1,
+    AUDIOFMT_TS         = 2,
+} AUDIOFMT;
+
+typedef struct {
+    size_t  date;
+    size_t  main;
+    size_t  sub;
+} M3u8Seq;
+//
+typedef struct {
+    int     duration;
+    int     rate;
+    AUDIOFMT fmt;
+    char    url[128];
+    char    name[256];
+    M3u8Seq seq;
+} M3u8Segment;
+
+//
+typedef struct _M3u8Info {
+    int     targetDuration;
+    size_t  mediaSeq;
+    int     segCount;
+    M3u8Segment segList[MAX_SEGMENT_COUNT];
+} M3u8Info;
+
+
+typedef struct _audioUrlObj {
+    AUDIOFMT        fmt;
+    uint32_t          uflag;  // 0-empty;1-ready;2-using;3-used;
+    uint32_t          idx;    // stream sequence
+//  uint32_t          totalTime;  // time of music,live:0
+    char            *url;
+    char            *radioName;
+    char            *musicName;
+    struct _audioUrlObj *next;
+} audioUrlObj;
+
+
+uint8_t m3u8CheckValid(const M3u8Seq* new, const M3u8Seq* pre);
+
+
+/**
+ * [m3u8_parser Parser the m3u8 string]
+ * @param  m3u8_string [To be parser string]
+ * @return             [m3u8 object, NULL->failed]
+ */
+M3u8Info *m3u8Parser(char *m3u8Str, M3u8Info* m3u8);
+
+/**
+ * [m3u8_destroy Destroy the m3u8 struct]
+ * @param m3u8 [m3u8 struct]
+ */
+void m3u8Destroy(M3u8Info *m3u8);
+
+/**
+ * [m3u8_save description]
+ * @param  m3u8                  [m3u8 struct]
+ * @param  m3u8_path             [file path]
+ * @param  ts_segment_url_prefix [prefix will be fill]
+ * @return                       [0->failed;1->successed]
+ */
+//int m3u8_save(M3u8Info *m3u8, char *m3u8_path, char *ts_segment_url_prefix);
+
+
+int m3u8_test(char* pStr);
+
+#endif

+ 66 - 0
examples/09_a2dp/components/EspAudio/player/inc/MediaDecoderTask.h

@@ -0,0 +1,66 @@
+/*****************************************************************************
+*
+* File Name : wm_http_client.h
+*
+* Description: Http client header file.
+*
+* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
+* All rights reserved.
+*
+* Author : wanghf
+*
+* Date : 2014-6-6
+*****************************************************************************/
+
+#ifndef __PLAYERTASK_H__
+#define __PLAYERTASK_H__
+#include "esp_types.h"
+#include "EspAudioCom.h"
+#include "EspAudio.h"
+#include "lwip/sys.h"
+#include "MediaHal.h"
+
+//Type Definitions
+
+typedef struct {
+    char                *dat;
+    InputSrcType        srcType;
+    EspAudioMeidaType   musicType;
+    uint32_t            totalByteLength;
+    uint32_t            bytePosition;
+    int                 codecVer;
+    int                 codecType;  // 0:hardware; 1:software
+} DecoderObj;
+
+typedef struct {
+    uint32_t rate;
+    uint32_t ch;
+    uint32_t bitLen;
+    uint32_t size; // 0xFFFFFFFF stream length is infinite 
+} StreamInfo;
+
+TaskState mediaDecoderTaskStateGet();
+void mediaDecoderStreamInfoSet(StreamInfo *info);
+
+void mediaDecoderTaskInfoGet(DecoderObj *obj);
+void mediaDecoderTaskInfoSet(DecoderObj *obj);
+void mediaDecoderTaskPause();
+void mediaDecoderTaskResume();
+
+int mediaDecoderTaskStart();
+void mediaDecoderTaskStop();
+
+void mediaDecoderTaskCreate();
+void mediaDecoderTaskDestroy();
+
+void mediaDecoderVolSet();
+void mediaDecoderVolGet();
+void mediaDecoderMusicInfoGet();
+void mediaDecoderDecodeTimeGet();
+void mediaDecoderModeSet();
+void mediaDecoderStreamSizeUpdate(uint32_t *size);
+void mediaDecoderTaskCb(void *func);
+
+
+
+#endif //__PLAYERTASK_H__

+ 300 - 0
examples/09_a2dp/components/EspAudio/recorder/EspAudioRecorder.c

@@ -0,0 +1,300 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "DecoderCom.h"
+#include "EspAudioCom.h"
+#include "MediaHal.h"
+#include "EspAudioRecorder.h"
+#include "Ap80xx.h"
+
+#define RECORD_TSK_PRIO            6
+#define RECORDER_PKG_SIZE          1024
+
+typedef enum {
+    RecorderEventType_Unknown,
+    RecorderEventType_Start,
+    RecorderEventType_Stop,
+    RecorderEventType_Pause,
+    RecorderEventType_Resume,
+    RecorderEventType_Quit,
+} RecorderEventType;
+
+typedef struct {
+    RecorderEventType type;
+    void *value;
+} RecorderEventInfo;
+
+static xTaskHandle recorderThread;
+static xQueueHandle recorderEventQue;
+static RecorderState recTaskState;
+static MusicInfo streamInfo;
+
+void MediaEncoderTask(void *pvParameters)
+{
+    LOGI("%s is running.%x %x", __func__);
+/////////////////////////////
+    RecorderEventInfo eventInfo ;
+    static RecorderAttr s_attr;
+    static int recordStartFlag = 0;
+    eventInfo.type = RecorderEventType_Unknown;
+    eventInfo.value = NULL;
+    uint8_t *recvData = malloc(RECORDER_PKG_SIZE);
+    if (NULL == recvData) {
+        LOGE("malloc failed");
+        return ;
+    }
+    memset(recvData, 0, RECORDER_PKG_SIZE);
+
+    while (1) {
+        if (xQueueReceive(recorderEventQue, &eventInfo, 10)) {
+            switch (eventInfo.type) {
+            case RecorderEventType_Start: {
+                MediaState mediaState;
+                mediaHalStatusGet(&mediaState);
+                LOGD("Start recording ...%d", mediaState);
+                if (MediaState_Initialized > mediaState) {
+                    mediaHalInit();                    
+                    LOGD("Need to init codec driver...[%d]", mediaState);
+                }
+                if (eventInfo.value) {
+                    memcpy(&s_attr, eventInfo.value, sizeof(s_attr));
+                    free(eventInfo.value);
+                    eventInfo.value =  NULL;
+                    LOGI("recv:channel=%d, rate=%d, encodeType=%d, func=%p",
+                         s_attr.channel, s_attr.rate, s_attr.encodeType, s_attr.func);
+                    streamInfo.sampling_rate =s_attr.rate;
+                    streamInfo.num_channels = s_attr.channel;
+                    streamInfo.stream_type = s_attr.encodeType;
+
+                    mediaHalModeSet(MediaMode_Encode, &streamInfo);
+                    recordStartFlag = 1;
+                    recTaskState = RecorderState_Recording;
+                    LOGI("Start recording ....");
+                } else {
+                    LOGE("eventInfo.value = NULL");
+                }
+                break;
+            }
+            case RecorderEventType_Pause: {
+                if (RecorderState_Recording == recTaskState) {
+                    recordStartFlag = 0;
+                    recTaskState = RecorderState_Paused;
+                    LOGI("Pause recording");
+                }
+                break;
+            }
+            case RecorderEventType_Resume: {
+                if (RecorderState_Paused == recTaskState) {
+                    recordStartFlag = 1;
+                    recTaskState = RecorderState_Recording;
+                    LOGI("Resume recording");
+                }
+                break;
+            }
+            case RecorderEventType_Stop: {
+                recordStartFlag = 0;
+                recTaskState = RecorderState_Stoped;
+                
+                apSetDecodeMode();
+                memset(&streamInfo, 0, sizeof(streamInfo));
+                LOGI("Stop recording");
+                break;
+            }
+            case RecorderEventType_Quit: {
+                recordStartFlag = 0;
+                recTaskState = RecorderState_Unknown;
+                LOGI("MediaEncoderTask will be quit");
+                goto encoderTaskQuit;
+            }
+            default:
+                vTaskDelay(250 / portTICK_RATE_MS);
+                LOGE("Event type does not support[%d]", eventInfo.type);
+                break;
+            }
+
+        }
+        
+//        LOGD("stack left %d byte\n", uxTaskGetStackHighWaterMark(NULL));
+        if (recordStartFlag) {
+            int len = 0;            
+            int ret = mediaHalDataRead(recvData, &len);
+            if ((ret != 0) || (len == 1)) {
+                LOGE("mediaHalDataRead failed,ret=%d len=%d", ret, len);
+                continue;
+            } else {
+//                LOGD("mediaHalDataRead ok,ret=%d len=%d", ret, len);
+                if (len>0) {
+                    s_attr.func(recvData, (uint32_t*)&len);
+                }
+            }
+        }
+    }
+encoderTaskQuit:
+    free(recvData);
+    recvData = NULL;
+    configASSERT(recorderEventQue);
+    vQueueDelete(recorderEventQue);
+    recorderEventQue = NULL;    
+    recorderThread = NULL;
+    LOGI("%s is ended...", __func__);
+    vTaskDelete(NULL);
+}
+
+EspAudioErr EspAudioRecorderStateGet(RecorderState *state)
+{
+    if (NULL == state) {
+        LOGE("Invalid para,%p", state);
+        return EspAudioErr_InvalidPara;
+    }
+    *state = recTaskState;
+
+    return EspAudioErr_NoErr;
+}
+
+EspAudioErr EspAudioRecorderInit(void)
+{
+    if (NULL == recorderThread) {
+        xTaskCreate(MediaEncoderTask, "MediaEncoderTask", (5*1024), NULL, RECORD_TSK_PRIO, &recorderThread);
+        configASSERT(recorderThread);
+    }
+    if (NULL == recorderEventQue) {
+        recorderEventQue = xQueueCreate(4, sizeof(RecorderEventInfo));
+        configASSERT(recorderEventQue);
+    }
+
+    LOGD("recorder has been created, %p,%p", recorderThread, recorderEventQue);
+    recTaskState = RecorderState_Init;
+    return EspAudioErr_NoErr;
+}
+
+EspAudioErr EspAudioRecorderStart(RecorderAttr *recorderAttr)
+{
+    if ((NULL == recorderAttr)
+        || (NULL == recorderThread)
+        || (NULL == recorderEventQue)) {
+        LOGE("Invalid para, %p,%p,%p", recorderAttr, recorderThread, recorderEventQue);
+        return EspAudioErr_InvalidPara;
+    }
+    if (NULL  == recorderAttr->func) {
+        LOGE("Invalid para, %p", recorderAttr->func);
+        return EspAudioErr_InvalidPara;
+    }
+    RecorderAttr *attr = malloc(sizeof(RecorderAttr));
+    if (NULL  == attr) {
+        LOGE("Malloc failed");
+        return EspAudioErr_NoMem;
+    }
+    attr->channel = recorderAttr->channel;
+    attr->rate = recorderAttr->rate;
+    attr->encodeType = recorderAttr->encodeType;
+    attr->func = recorderAttr->func;
+
+    RecorderEventInfo eventInfo ;
+    eventInfo.type = RecorderEventType_Start;
+    eventInfo.value = attr;
+    LOGD("channel=%d, rate=%d, encodeType=%d, func=%p",
+         attr->channel, attr->rate, attr->encodeType, attr->func);
+    configASSERT(recorderEventQue);
+    if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
+        LOGE("EspAudioRecorderStart, queue send failed");
+    } else {
+        LOGD("EspAudioRecorderStart, send sucessed");
+    }
+    return EspAudioErr_NoErr;
+}
+
+EspAudioErr EspAudioRecorderPause(void)
+{
+    if ((NULL == recorderThread)
+        || (NULL == recorderEventQue)) {
+        LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
+        return EspAudioErr_InvalidPara;
+    }
+    RecorderEventInfo eventInfo ;
+    eventInfo.type = RecorderEventType_Pause;
+    eventInfo.value = NULL;
+    configASSERT(recorderEventQue);
+    if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
+        LOGE("RecorderEventType_Pause, queue send failed");
+    } else {
+        LOGD("RecorderEventType_Pause, send sucessed");
+    }
+    return EspAudioErr_NoErr;
+}
+
+EspAudioErr EspAudioRecorderResume(void)
+{
+    if ((NULL == recorderThread)
+        || (NULL == recorderEventQue)) {
+        LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
+        return EspAudioErr_InvalidPara;
+    }
+    RecorderEventInfo eventInfo ;
+    eventInfo.type = RecorderEventType_Resume;
+    eventInfo.value = NULL;
+    configASSERT(recorderEventQue);
+    if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
+        LOGE("RecorderEventType_Resume, queue send failed");
+    } else {
+        LOGD("RecorderEventType_Resume, send sucessed");
+    }
+    return EspAudioErr_NoErr;
+
+}
+
+EspAudioErr EspAudioRecorderStop(void)
+{
+    if ((NULL == recorderThread)
+        || (NULL == recorderEventQue)) {
+        LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
+        return EspAudioErr_InvalidPara;
+    }
+    RecorderEventInfo eventInfo ;
+    eventInfo.type = RecorderEventType_Stop;
+    eventInfo.value = NULL;
+    configASSERT(recorderEventQue);
+    if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
+        LOGE("RecorderEventType_Stop, queue send failed");
+    } else {
+        LOGD("RecorderEventType_Stop, send sucessed");
+    }
+    return EspAudioErr_NoErr;
+}
+
+EspAudioErr EspAudioRecorderUninit(void)
+{
+    if ((NULL == recorderThread)
+        || (NULL == recorderEventQue)) {
+        LOGE("recorderThread=%p, recorderEventQue=%p", recorderThread, recorderEventQue);
+        return EspAudioErr_InvalidPara;
+    }
+    RecorderEventInfo eventInfo ;
+    eventInfo.type = RecorderEventType_Quit;
+    eventInfo.value = NULL;
+    configASSERT(recorderEventQue);
+    if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
+        LOGE("RecorderEventType_Quit, queue send failed");
+    } else {
+        LOGD("RecorderEventType_Quit, send sucessed");
+    }
+    return EspAudioErr_NoErr;
+}

+ 1301 - 0
examples/09_a2dp/components/MediaHal/AP80/Ap80xx.c

@@ -0,0 +1,1301 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "freertos/FreeRTOS.h"
+#include "soc/gpio_sig_map.h"
+#include "freertos/task.h"
+#include "AP80/Ap80xx.h"
+#include "driver/gpio.h"
+#include "driver/spi.h"
+#include "esp_timer.h"
+#include "Utility.h"
+#include "string.h"
+#include "crc.h"
+
+// Define the SPI port
+#define AUDIO_IFACE_PORT        SPI_NUM_SPI2
+#define TX_SPI_BUF_LEN          (2*1024)
+#define RX_SPI_BUF_LEN          (1024)
+
+#define RX_SPI_LEN              (1024)
+
+#define DECODETYPELEN           (4)
+#define RESENDCOUNT             (2)
+#define AP80GPIOINITNUM         (19)
+
+#define SPIM_STREAM_CONTROL_GET_STATUS() (gpio_get_level(GPIO_NUM_22))
+
+#define divDBG(level,fmt, ...) do {                     \
+        if(level > 3){                                  \
+            printf("[DECODE](%d) ", __LINE__);          \
+            printf(fmt, ##__VA_ARGS__);                 \
+            printf("\n");                               \
+        }                                               \
+    } while(0)
+    
+#define divByteS(level,indata,len) do {   \
+        if(level > 3){                    \
+            printfByteS(indata, len);     \
+        }                                 \
+    } while(0)
+
+uint8_t SPIM_SEND_BUFFER[sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + EAU_SEND_DATA_LENGTH + EAU_CRC_VALUE_LENGTH];
+uint8_t SPIM_RECV_BUFFFR_ALL[sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + EAU_SEND_DATA_LENGTH + EAU_CRC_VALUE_LENGTH];
+uint8_t SPIM_RECV_BUFFER[RX_SPI_LEN];
+
+EAUCmdContext         *CommandContext  = (EAUCmdContext *)SPIM_SEND_BUFFER;
+EAUCmdResponseContext *ResponseContext = (EAUCmdResponseContext *)SPIM_SEND_BUFFER;
+
+static bool spiRecv(uint8_t *RecvData, uint16_t Recvlen);
+static void uint8ChangeFormat(uint32_t *inData, uint8_t  *outData, uint16_t len);
+static void uint32ChangeFormat(uint8_t *inData, uint32_t *outData, uint16_t len);
+static uint8_t sendData(SSPP_CMD CMD, uint16_t value, uint8_t *sendData, uint16_t  sendLen,uint8_t *receiveData, uint16_t  *receiveLen);
+
+static uint32_t             g_waitTime    = 20000;
+static bool                 g_noResponse  = false;
+uint8_t                     g_enableDma   = 0;      //The default is not able to DMA
+static xSemaphoreHandle     ap80_mutex_sendData;
+
+#ifdef AP80XXENABLEDMA
+static spi_dma_attr_t       spiDmaAp80xxTxObj;
+static spi_dma_attr_t       spiDmaAp80xxRxObj;
+#endif
+
+static os_timer_t           timer;
+static bool                 divTimeOut      = false;
+xQueueHandle                apQueRecv       = NULL;
+xQueueHandle                apQueSend       = NULL;
+xQueueHandle                apFlowControl   = NULL;
+
+static void timerOut()
+{
+    divTimeOut = true;
+}
+
+#ifdef AP80XXENABLEDMA
+uint32_t sendcount0       = 0;
+uint32_t sendcount1       = 0;
+uint32_t recvCount        = 0;
+//#include "freertos/portmacro.h"
+static void spiDmaAp80xxIsr(void *para)
+{
+    uint32_t        regvalue;
+    uint32_t        statusW, statusR;    
+    char            pQueSend = 0x55;
+    portBASE_TYPE   xHigherPriorityTaskWoken;
+    
+    regvalue = spi_int_status_get(SPI_NUM_SPI2);
+    spi_int_clear(SPI_NUM_SPI2);
+    if (regvalue & SPI_INT_SRC_WR_BUF_DONE) {
+        divDBG(2, "SPI2_SLV_WR_BUF_DONE\n\r");
+    } else if (regvalue & SPI_INT_SRC_RD_BUF_DONE) {
+        divDBG(2, "SPI2_SLV_RD_BUF_DONE\n\r");
+    } else if (regvalue & SPI_INT_SRC_RD_STA_DONE) {
+        statusR = READ_PERI_REG(SPI_RD_STATUS_REG(SPI_NUM_SPI2));
+        statusW = READ_PERI_REG(SPI_SLV_WR_STATUS_REG(SPI_NUM_SPI2));
+        divDBG(2, "statusR %x statusW %x\n\r", statusR, statusW);
+    } else if (regvalue & SPI_INT_SRC_WR_STA_DONE) {
+        statusR = READ_PERI_REG(SPI_RD_STATUS_REG(SPI_NUM_SPI2));
+        statusW = READ_PERI_REG(SPI_SLV_WR_STATUS_REG(SPI_NUM_SPI2));
+        divDBG(2, "statusR %x statusW %x\n\r", statusR, statusW);
+    } else if ((regvalue & SPI_INT_SRC_TRANS_DONE) && ((regvalue & 0xf) == 0)) {
+        divDBG(2, "send SPI2_TRANS_DONE %d", sendcount0++);
+    }
+    
+    uint32_t spi2DmaIntStatus =  spi_dma_int_status_get(SPI_NUM_SPI2);
+    spi_dma_int_clear(SPI_NUM_SPI2);
+    if (SPI_INT_SRC_ONE_BUF_SEND_DONE == (spi2DmaIntStatus & SPI_INT_SRC_ONE_BUF_SEND_DONE)) {
+        if(xQueueSendFromISR(apQueSend, &pQueSend, &xHigherPriorityTaskWoken) == pdPASS)
+        {
+            //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+        }
+        //ets_printf("TX SPI2\n");
+    }
+
+    if (SPI_INT_SRC_ONE_BUF_RECV_DONE == (spi2DmaIntStatus & SPI_INT_SRC_ONE_BUF_RECV_DONE)) {
+        if(xQueueSendFromISR(apQueRecv, &pQueSend, &xHigherPriorityTaskWoken) == pdPASS)
+        {
+            //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+        }
+        //ets_printf("RX SPI2\n");
+    }
+    divDBG(2, "SPI2_INT_DONE");
+}
+
+static int32_t user_spi_dma_memcpy(spi_dma_attr_t *obj, void *src, uint32_t total, uint32_t *copied, uint32_t len)
+{
+    if ((NULL == obj)
+        || (NULL == src)) {
+        return -1;
+    }
+    uint32_t *bufAddress = NULL;
+    uint8_t *srcDat = (uint8_t*)src;
+    switch (obj->dir) {
+    case SPI_DMA_DIR_OUT: {
+        if (0 == *copied) {
+            divDBG(2, "len=%d, buflen=%d\r\n", len, obj->buf->len);
+            if (len <= obj->buf->len) {
+                dma_buf_len_set(obj->buf, obj->buf->ping, len);
+                memcpy(obj->buf->ping->buffer_addr, srcDat, len);
+                *copied = len;
+            } else {
+                dma_buf_len_set(obj->buf, obj->buf->ping, obj->buf->len);
+                memcpy(obj->buf->ping->buffer_addr, srcDat, obj->buf->len);
+                srcDat += obj->buf->len;
+                if (len < (obj->buf->len * 2)) {
+                    dma_buf_len_set(obj->buf, obj->buf->pong, (len - obj->buf->len));
+                    memcpy(obj->buf->pong->buffer_addr, srcDat, (len - obj->buf->len));
+                    *copied = len;
+                } else {
+                    dma_buf_len_set(obj->buf, obj->buf->pong, obj->buf->len);
+                    memcpy(obj->buf->pong->buffer_addr, srcDat, (obj->buf->len));
+                    *copied = obj->buf->len * 2;
+                }
+            }
+        } else {
+            if ((spi_dma_status_get(obj)) == obj->buf->ping->buffer_addr)  {
+                uint32_t remdLen = total - *copied;
+                if (remdLen < (obj->buf->len + total % obj->buf->len)) {
+                    dma_buf_len_set(obj->buf, obj->buf->ping, remdLen);
+                    memcpy(obj->buf->ping->buffer_addr, srcDat, remdLen);
+                    *copied += remdLen;
+                } else {
+                    memcpy(obj->buf->ping->buffer_addr, srcDat, obj->buf->len);
+                    *copied += obj->buf->len;
+                }
+                printf("Pi%d,remdLen%d,sent%d\r\n", len, remdLen, *copied);
+            } else if ((spi_dma_status_get(obj)) == obj->buf->pong->buffer_addr) {
+                uint32_t remdLen = total - *copied;
+                if (remdLen < (obj->buf->len + total % obj->buf->len)) {
+                    dma_buf_len_set(obj->buf, obj->buf->pong, remdLen);
+                    memcpy(obj->buf->pong->buffer_addr, srcDat, remdLen);
+                    *copied += remdLen;
+                } else {
+                    memcpy(obj->buf->pong->buffer_addr, srcDat, obj->buf->len);
+                    *copied += obj->buf->len;
+                }
+                divDBG(2, "Po%d,remdLen%d,sent%d\r\n", len, remdLen, *copied);
+            }
+
+        }
+        break;
+    }
+    case SPI_DMA_DIR_IN: {
+        if ((spi_dma_status_get(obj)) ==  obj->buf->ping->buffer_addr) {
+            bufAddress = obj->buf->ping->buffer_addr;
+            if (len < obj->buf->len) {
+                dma_buf_len_set(obj->buf, obj->buf->ping, len);
+            }
+        } else if ((spi_dma_status_get(obj)) == obj->buf->pong->buffer_addr) {
+            bufAddress = obj->buf->pong->buffer_addr;
+            if (len < obj->buf->len) {
+                dma_buf_len_set(obj->buf, obj->buf->pong, len);
+            }
+        } else {
+            bufAddress = obj->buf->ping->buffer_addr;
+            dma_buf_len_set(obj->buf, obj->buf->ping, len);
+            if (obj->buf_size < len) {
+                dma_buf_len_set(obj->buf, obj->buf->pong, (len - obj->buf_size));
+            }
+        }
+        if (bufAddress) {
+            memcpy(src, bufAddress, obj->buf_size);
+        }
+        break;
+    }
+    default:
+        len = 0;
+        break;
+    }
+    return len;
+}
+#endif
+
+/**
+ * For receiving data buf, format processing
+ */
+static void uint32ChangeFormat(uint8_t *inData, uint32_t *outData, uint16_t len)
+{
+    uint8_t i, j;
+    if (len == 0)
+    {
+        return;
+    }
+    for (i = 0; i < len / sizeof(uint32_t); i++)
+    {
+        outData[i] = (uint32_t) (inData[4 * i + 0] << 0) | (inData[4 * i + 1] << 8) | (inData[4 * i + 2] << 16) | (inData[4 * i + 3] << 24);
+    }
+    for (j = 0; j < (len % 4); j++)
+    {
+        outData[i] |= (inData[4 * i + j] << (8 * j));
+    }
+}
+
+/**
+ * For receiving data buf, format processing
+ */
+static void uint8ChangeFormat(uint32_t *inData, uint8_t *outData, uint16_t len)
+{
+    uint8_t i, j;
+    if (len == 0)
+    {
+        return;
+    }
+    for (i = 0; i < (len / sizeof(uint32_t)); i++)
+    {
+        outData[4 * i + 0] = inData[i] >> 0;
+        outData[4 * i + 1] = inData[i] >> 8;
+        outData[4 * i + 2] = inData[i] >> 16;
+        outData[4 * i + 3] = inData[i] >> 24;
+    }
+    for (j = 0; j < (len % 4); j++)
+    {
+        outData[4 * i + j] = (uint8_t)(inData[i] >> (8 * j));
+    }
+}
+
+static bool FindSpiStreamDataSyncWord()
+{
+    uint32_t SyncWord;
+    uint32_t Cnt = 0;
+    uint8_t *p = (uint8_t *)&SyncWord;
+
+    while (1)
+    {
+        SyncWord = 0;
+        if (spiRecv(p, 1))
+        {
+            if (p[0] == EAU_SYNC_BYTE)
+            {
+                return false;
+            }
+        }
+        if (Cnt++ > 100)
+        {
+            return false;
+        }
+    }
+}
+
+/**
+ * To send data by way of SPI
+ */
+static bool spiSend(uint8_t *sendData, uint16_t len)
+{
+    uint32_t      data[16] = { 0 };
+    spi_data_t  pDat;
+    if (len > 64)
+        return false;
+    pDat.cmd_len  = 0;
+    pDat.addr_len = 0;
+
+    pDat.tx_data_len = len;    
+    pDat.tx_data    = data;
+    
+    uint32ChangeFormat((uint8_t *)sendData, data, pDat.tx_data_len);
+    spi_master_send_data(AUDIO_IFACE_PORT, &pDat);
+
+    return true;
+}
+
+/**
+ * Receiving data by way of SPI
+ */
+static bool spiRecv(uint8_t *recvData, uint16_t len)
+{
+    uint32_t data[16] = { 0 };
+    spi_data_t pDat;
+    if (len > 64)
+        return false;
+    pDat.cmd_len  = 0;
+    pDat.addr_len = 0;
+
+    pDat.rx_data_len = len;
+    pDat.rx_data = data;
+    
+    spi_master_recv_data(AUDIO_IFACE_PORT, &pDat);
+
+    uint8ChangeFormat(data, recvData, len);
+    return true;
+}
+#ifdef AP80XXENABLEDMA
+/**
+ * Send data by way of SPI(Dma)
+ */
+static bool spiDmaSend(uint8_t *sendData, uint16_t sendLen)
+{    
+    uint32_t sendlen        = 0x00;
+    char     pQueSend       = 0x00;
+    uint8_t *pSendRd        = sendData;
+    if (sendLen > TX_SPI_BUF_LEN)
+        return false;
+    
+    spi_dma_rest(&spiDmaAp80xxTxObj);
+    user_spi_dma_memcpy(&spiDmaAp80xxTxObj, pSendRd, sendLen, &sendlen, sendLen);    
+    xQueueReset(apQueSend);
+    
+    spi_dma_start(&spiDmaAp80xxTxObj, sendLen);
+    
+    if(xQueueReceive(apQueSend, &pQueSend, 150 / portTICK_RATE_MS) == pdFALSE)
+    {
+        return false;
+    }    
+    return true;
+}
+
+/**
+ * Receiving data by way of SPI(Dma)
+ */
+static bool spiDmaRecv(uint8_t *recvData, uint16_t recvlen)
+{
+    uint8_t  *recvDataPtr   = recvData;
+    uint16_t wantedRecvLen  = recvlen;
+    uint32_t sendlen        = 0x00;
+    char     pQueRecv       = 0x00;
+    if (wantedRecvLen > RX_SPI_BUF_LEN)
+        return false;
+    wantedRecvLen = wantedRecvLen;
+    //printf("start recv\n");
+    //spi_dma_int_clear(SPI_NUM_SPI2);
+    xQueueReset(apQueRecv);
+    spi_dma_rest(&spiDmaAp80xxTxObj);
+    spiDmaAp80xxRxObj.dir = SPI_DMA_DIR_IN;    
+    spi_dma_dest_add_set(&spiDmaAp80xxRxObj);
+    spi_dma_start(&spiDmaAp80xxRxObj, wantedRecvLen);
+    
+    if(xQueueReceive(apQueRecv, &pQueRecv, 200 / portTICK_RATE_MS) == pdFALSE)
+    {
+        //printf("recv time out\n");
+        return false;
+    }
+    
+    user_spi_dma_memcpy(&spiDmaAp80xxRxObj, recvDataPtr, wantedRecvLen, &sendlen, wantedRecvLen);
+    
+    return true;
+}
+#endif
+typedef void (*xt_handler)(void *);
+
+static void ap_intr_callback(void *arg)
+{
+    //printf("in gpio_intr\n");
+    portBASE_TYPE   xHigherPriorityTaskWoken;
+    char            pQueSend = 0x55;
+    uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG);
+    SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG,  1 << GPIO_NUM_22);
+    
+    if(xQueueSendFromISR(apFlowControl, &pQueSend, &xHigherPriorityTaskWoken) == pdPASS)
+    {
+        ;
+    }
+}
+
+static void gpio_intr_init(uint8_t gpio_num)
+{
+    gpio_config_t gpio_test;
+	memset(&gpio_test,0,sizeof(gpio_test));
+    gpio_test.pin_bit_mask=(uint64_t)((uint64_t)(1)<<gpio_num);
+    
+	gpio_test.mode          = GPIO_MODE_INPUT;
+	gpio_test.intr_type     = GPIO_INTR_NEGEDGE;
+	gpio_test.pull_up_en    = GPIO_PULLUP_ENABLE;
+	gpio_test.pull_down_en  = GPIO_PULLDOWN_DISABLE;
+    gpio_config(&gpio_test);
+	//Register gpio intr callback
+    gpio_isr_register(AP80GPIOINITNUM, ap_intr_callback, NULL);
+    //gpio_isr_register(ap_intr_callback, NULL, 0, NULL);
+    //gpio_install_isr_service(0);
+    //gpio_isr_handler_add(22, ap_intr_callback, NULL);
+}
+
+uint32_t receivePulse(uint16_t timeOut)
+{
+    uint8_t     ret         = 0;
+    char        pQueSend    = 0;
+    uint32_t    currentTime = 0;
+#ifndef PORTING_LY_DONT
+    uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG);     //read status to get interrupt status for GPIO0-31
+
+    //printf("%08x\n",gpio_intr_status);
+    SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, 1 << GPIO_NUM_22);      //Clear intr for gpio0-gpio31            
+    gpio_intr_enable(GPIO_NUM_22);                                  //open intr
+    xQueueReset(apFlowControl);
+    
+    currentTime = system_get_time();
+    if(xQueueReceive(apFlowControl, &pQueSend, timeOut / portTICK_RATE_MS) == pdFALSE)
+    {
+        divDBG(4, "send data stup 04 %d gpio is %d",system_get_time() - currentTime,SPIM_STREAM_CONTROL_GET_STATUS());
+        ret = 1;
+    }
+    gpio_intr_disable(GPIO_NUM_22);                                 //close intr
+#else
+    if(SPIM_STREAM_CONTROL_GET_STATUS())
+    {
+        uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG);     //read status to get interrupt status for GPIO0-31
+
+        SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, 1 << GPIO_NUM_22);      //Clear intr for gpio0-gpio31            
+        gpio_intr_enable(GPIO_NUM_22);                                  //open intr
+        xQueueReset(apFlowControl);
+
+        currentTime = system_get_time();
+        if(xQueueReceive(apFlowControl, &pQueSend, timeOut / portTICK_RATE_MS) == pdFALSE)
+        {
+            divDBG(4, "send data stup 04 %d gpio is %d", system_get_time() - currentTime,SPIM_STREAM_CONTROL_GET_STATUS());
+            ret = 1;
+        }
+        gpio_intr_disable(GPIO_NUM_22);                                 //close intr        
+    }
+#endif
+    return ret;
+}
+
+/**
+ * Spi initialization
+ */
+void apInit()
+{
+    spi_attr_t hSpiAttr;
+    gpio_config_t  GPIO_InitStructure;
+    
+    memset(&GPIO_InitStructure, 0, sizeof(GPIO_InitStructure));
+    hSpiAttr.bit_order  = SPI_BIT_ORDER_MSB_FIRST;
+    hSpiAttr.speed      = SPI_SPEED_10MHZ;
+    hSpiAttr.mode       = SPI_MODE_MASTER;
+    hSpiAttr.sub_mode   = SPI_SUBMODE_0;
+    hSpiAttr.half_mode  = SPI_WORK_MODE_FULL;
+
+    spi_init(AUDIO_IFACE_PORT, &hSpiAttr);
+    
+    gpio_matrix_out(GPIO_NUM_18, HSPICLK_OUT_IDX,0,0);
+    gpio_matrix_out(GPIO_NUM_23, HSPID_OUT_IDX,  0,0);
+    gpio_matrix_in(GPIO_NUM_19,  HSPIQ_IN_IDX,   0);
+    gpio_matrix_out(GPIO_NUM_5,  HSPICS0_OUT_IDX, 0,0);
+
+    #if AP80XXENABLEINT
+    apFlowControl = xQueueCreate(1, sizeof(char));
+    gpio_intr_init(22);
+    gpio_intr_disable(GPIO_NUM_22);             //close intr
+    #else
+    GPIO_InitStructure.pin_bit_mask         = GPIO_SEL_22;
+    GPIO_InitStructure.mode        			= GPIO_MODE_INPUT;
+    GPIO_InitStructure.intr_type            = GPIO_PIN_INTR_DISABLE;
+    gpio_config(&GPIO_InitStructure);
+    #endif
+
+    os_timer_setfn(&timer, timerOut, NULL);
+
+    #ifdef AP80XXENABLEDMA
+    //if(g_enableDma)
+    {   //start spi dma init
+        spiDmaAp80xxTxObj.buf         = NULL;
+        spiDmaAp80xxTxObj.buf_size    = TX_SPI_BUF_LEN;
+        spiDmaAp80xxTxObj.mode        = SPI_MODE_MASTER;
+        spiDmaAp80xxTxObj.channel     = SPI_DMA_CHANNEL_0;
+        spiDmaAp80xxTxObj.dir         = SPI_DMA_DIR_OUT;
+        spiDmaAp80xxTxObj.spi_num     = AUDIO_IFACE_PORT;
+        
+        int dmaRegt = spi_dma_init(&spiDmaAp80xxTxObj, spiDmaAp80xxIsr);        
+        if (dmaRegt) {
+            printf("spi_dma_init init failed ret=%d\n", dmaRegt);
+            return ;
+        }
+        spi_dma_dest_add_set(&spiDmaAp80xxTxObj);
+        
+        spiDmaAp80xxRxObj.buf         = NULL;
+        spiDmaAp80xxRxObj.buf_size    = RX_SPI_BUF_LEN;
+        spiDmaAp80xxRxObj.mode        = SPI_MODE_MASTER;
+        spiDmaAp80xxRxObj.channel     = SPI_DMA_CHANNEL_0;
+        spiDmaAp80xxRxObj.dir         = SPI_DMA_DIR_IN;
+        spiDmaAp80xxRxObj.spi_num     = AUDIO_IFACE_PORT;
+        
+        dmaRegt = spi_dma_init(&spiDmaAp80xxRxObj, spiDmaAp80xxIsr);
+        if (dmaRegt) {
+            printf("spi_dma_init init failed ret=%d\n", dmaRegt);
+        }
+        spi_dma_dest_add_set(&spiDmaAp80xxRxObj);
+       
+        apQueRecv = xQueueCreate(1, sizeof(char));
+        apQueSend = xQueueCreate(1, sizeof(char));
+    }
+    #endif
+
+    if (sys_mutex_new(&ap80_mutex_sendData) != 0)
+    {
+        printf("pthread_mutex_init error\n");
+    }
+    printf("spi init master mode\n");
+}
+
+
+/**
+ * Audio playback process of sending data
+ */
+static uint8_t sendData(SSPP_CMD CMD, uint16_t value, uint8_t *sendData, uint16_t  sendLen,uint8_t *receiveData, uint16_t  *receiveLen)
+{
+#ifdef AP80XXENABLEDMA
+    sys_mutex_lock(&ap80_mutex_sendData);
+    EAUCmdContext        *CommandContext   = (EAUCmdContext *)SPIM_SEND_BUFFER;
+    EAUCmdResponseContext *ResponseContext = (EAUCmdResponseContext *)SPIM_RECV_BUFFER;
+    uint8_t  *sendDataFramePtr  = (uint8_t *) &SPIM_SEND_BUFFER[sizeof(EAUCmdContext)];
+    uint8_t  *ptr               = NULL;
+    uint8_t   result            = ERROR_TIME_OUT;
+    uint16_t  sendDataLen       = sendLen;
+    uint32_t  cnt               = 0;
+    bool      flag              = false;
+    int8_t    reSendCnt         = RESENDCOUNT;
+    int16_t   sendRemLen        = 0;
+    uint8_t   protocolMode      = 0;
+    divTimeOut                  = false;
+    
+    if(sendData == NULL && sendLen == 0 && receiveData == NULL)
+    {
+        protocolMode = 0;
+    }
+    else if(sendData != NULL && sendLen != 0 && receiveData == NULL)
+    {
+        protocolMode = 2;
+    }
+    else if(sendData == NULL && sendLen == 0 && receiveData != NULL)
+    {
+        protocolMode = 1;
+    }
+    else if(sendData != NULL && sendLen != 0 && receiveData != NULL)
+    {
+        protocolMode = 3;
+    } else {
+        result = ERROR_PROMODE;
+        goto error;
+    }
+
+    if(protocolMode & BIT1)
+    {
+        if (sendLen >= EAU_SEND_DATA_LENGTH - EAU_SEND_FARMA_LENGTH)
+        {
+            result = ERROR_PARAMETER;
+            goto error;
+        }
+    }
+    
+    do
+    {        
+        divDBG(2, "send data stup 01 %d",system_get_time());
+        
+        //1. Send EAU_CMD_DATA command
+        CommandContext->SyncWord  = EAU_SYNC_BYTE;
+        CommandContext->Command   = CMD;
+        if(CMD == EAU_CMD_VOL_SET)
+        {
+            CommandContext->Content   = value;
+        }
+        else
+        {
+            CommandContext->Content   = sendDataLen;
+        }
+
+        CommandContext->CrcValue  = GetCRC16NBS((uint8_t *)CommandContext, sizeof(EAUCmdContext) - EAU_CRC_VALUE_LENGTH);
+
+        if(protocolMode & BIT1)
+        {
+            *sendDataFramePtr         = EAU_SYNC_BYTE;
+
+            MEMCPY(sendDataFramePtr   + EAU_SYNC_WORD_LENGTH, sendData, sendDataLen);
+
+            uint16_t crc = GetCRC16NBS(sendDataFramePtr + 1, CommandContext->Content);
+            sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 0] = (uint8_t) crc;
+            sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 1] = crc >> 8;            
+            sendRemLen = sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + sendDataLen + EAU_CRC_VALUE_LENGTH;
+        } else {
+            sendRemLen = sizeof(EAUCmdContext);
+        }
+        #ifdef AP80DEBUG      
+        if((*sendData == 0xE7) && (*(sendData + 1) == 0x04))
+        {
+            //printfByteS(debugData, sendRemLen);
+            //printf("%x%x%x%x",SPIM_SEND_BUFFER[sendRemLen - 1],SPIM_SEND_BUFFER[sendRemLen - 2],SPIM_SEND_BUFFER[sendRemLen - 3],SPIM_SEND_BUFFER[sendRemLen - 4]);
+        }
+        #endif
+        
+#if AP80XXENABLEINT == 0
+        os_timer_arm(&timer, 1000, false);
+        while (SPIM_STREAM_CONTROL_GET_STATUS())
+        {
+            if(divTimeOut)
+            {
+                result = ERROR_DEVICE_TIME_OUT;
+                divDBG(4, "send data stup 04 %d",system_get_time());
+                goto error;
+            }
+        };
+#else
+        if(receivePulse(5000))
+        {
+            result = ERROR_DEVICE_TIME_OUT;
+            divDBG(4, "Hardware decoder busy %d",SPIM_STREAM_CONTROL_GET_STATUS());
+            goto error;
+        }
+#endif
+        divDBG(2, "stup 02 %d",system_get_time());
+        
+        if (!spiDmaSend((uint8_t *) SPIM_SEND_BUFFER, (uint16_t) sendRemLen))
+        {
+            divDBG(4, "send data time out (no dma int)");
+            goto error;
+        }
+        
+        divDBG(2, "stup 04 %d %x %x",system_get_time(),(uint32_t)spiDmaAp80xxTxObj.buf->ping->buffer_addr,(uint32_t)spiDmaAp80xxTxObj.buf->pong->buffer_addr);
+        //divDBG(4, "stup 04 %d %x %x",system_get_time(),(uint32_t)spiDmaAp80xxTxObj.buf->ping->buffer_addr,(uint32_t)spiDmaAp80xxTxObj.buf->pong->buffer_addr);
+        
+        memset(spiDmaAp80xxTxObj.buf->ping->buffer_addr, 0, TX_SPI_BUF_LEN);
+        memset(spiDmaAp80xxTxObj.buf->pong->buffer_addr, 0, TX_SPI_BUF_LEN);
+        memset(spiDmaAp80xxRxObj.buf->ping->buffer_addr, 0, RX_SPI_LEN);
+        memset(spiDmaAp80xxRxObj.buf->pong->buffer_addr, 0, RX_SPI_LEN);        
+
+        //if(g_noResponse)
+        {
+            result = OK_RESPONSE;
+            reSendCnt--;
+            goto error;
+        }
+#if AP80XXENABLEINT == 1
+        if(receivePulse(1000))
+        {
+            result = ERROR_TIME_OUT;
+            divDBG(4, "Hardware decoder no response");
+            goto error;
+        }
+#endif
+        
+        //3. Receive response
+        uint8_t    *pRecvRd         = SPIM_RECV_BUFFER;
+        uint8_t    *pRecvAllData    = SPIM_RECV_BUFFFR_ALL;
+        uint32_t    recvCount       = 0;
+        uint8_t     packetResponse  = 0;
+        uint16_t    packetDataLen   = 0;
+        uint16_t    recvBufValidLen = 0;
+        
+        ptr  = (uint8_t *)&ResponseContext->SyncWord;
+        cnt  = 0;
+        flag = false;
+        do {
+            //vTaskDelay(1 / portTICK_PERIOD_MS);
+            spiDmaRecv(pRecvRd, RX_SPI_LEN);
+            
+            divByteS(2, pRecvRd, RX_SPI_LEN);
+            
+            for(int i = 0; i < RX_SPI_LEN; i++)
+            {
+                if(pRecvRd[i] == EAU_SYNC_BYTE)
+                {
+                    memcpy(pRecvAllData, pRecvRd + i,RX_SPI_LEN - i);
+                    recvBufValidLen += (RX_SPI_LEN - i);
+                    divDBG(2, "decode recv response is 0:");
+                    if(i >= RX_SPI_LEN - sizeof(EAUCmdContext))
+                    {
+                        divDBG(2, "recv heard len is %d", i);
+                        spiDmaRecv(pRecvRd, RX_SPI_LEN);
+                        memcpy(pRecvAllData + RX_SPI_LEN - i, pRecvRd,RX_SPI_LEN);
+                        recvBufValidLen += RX_SPI_LEN;
+                    }
+                    ResponseContext = (EAUCmdResponseContext *) pRecvAllData;
+                    
+                    packetResponse  = ResponseContext->Response &  0x000F;
+                    packetDataLen   = (uint16_t) (ResponseContext->Response >> 0x04);
+                    divByteS(2, pRecvAllData, 0x10);
+                    while(packetDataLen > recvBufValidLen) {
+                        divDBG(2, "recv heard len is %d %d", i, recvBufValidLen);
+                        divByteS(2, pRecvAllData, 0x10);
+                        spiDmaRecv(pRecvRd, RX_SPI_LEN);
+                        memcpy(pRecvAllData + recvBufValidLen, pRecvRd,RX_SPI_LEN);
+                        recvBufValidLen += RX_SPI_LEN;
+                    }
+                    divDBG(2, "decode recv response is: %d", recvBufValidLen);
+                    divByteS(2, pRecvAllData, 0x60);
+                    flag = true;
+                    goto tag;
+                }
+            }
+            
+            if(++recvCount > 1000)
+            {
+                divDBG(4, "decode recv response time out");
+                break;
+            }
+        }while(1);
+
+        #ifdef AP80DEBUG
+        if(!flag)
+        {
+            divDBG(4, "send error01 %x",debugCRC);
+            printfByteS(debugData, 0x200);
+            divDBG(4, "send error02");
+            printfByteS(sendData, 0x80);            
+            divDBG(4, "1 recv heard is %x %x %x %x recvCount %d", sendData[0], sendData[1], sendData[2], sendData[3],recvCount);
+        }
+        #endif
+        
+    tag:
+        if(flag)
+        {
+            if (ResponseContext->Command == CMD)
+            {
+                ptr = (uint8_t *)&ResponseContext->SyncWord;
+                
+                //divDBG(4, "recv heard is %x %x %x %x recvCount %d", ptr[0], ptr[1], ptr[2], ptr[3],recvCount);
+                divDBG(2, "response = %d dataLen = %d recvCount = %d",packetResponse,packetDataLen,recvCount);
+                if(packetResponse == EAU_CMD_RESP_OKSEND || packetResponse == EAU_CMD_RESP_OKCMD)
+                {
+                    result = OK_RESPONSE;
+                    if(packetDataLen > 0 && (protocolMode & BIT0))
+                    {
+                        uint16_t     localCrc   = 0x00;
+                        uint16_t     recvCrc    = 0x00;
+
+                        ptr = pRecvAllData + sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH;
+                        localCrc = GetCRC16NBS(ptr, packetDataLen);
+                        recvCrc  = *(uint16_t*)(ptr + packetDataLen);
+                        if(localCrc == recvCrc)
+                        {
+                            if(*receiveLen != 0 && *receiveLen < packetDataLen)
+                            {
+                                result = ERROR_PARAMETER;
+                                goto reSend;
+                            }
+                            memcpy(receiveData, ptr, packetDataLen);
+                            *receiveLen = packetDataLen;
+                            
+                            divDBG(2, "recv ok packetDataLen is %d %d", *receiveLen,packetDataLen);
+                        }
+                        else
+                        {
+                            result = ERROR_CRC;
+                            divDBG(4, "[ERROR] recv CRC error localCrc %X recvCrc %X", localCrc, recvCrc);
+                            divByteS(2, ptr, packetDataLen);
+                            goto reSend;
+                        }
+                    }
+                }
+                else if (packetResponse == EAU_CMD_RESP_NEXTSEND)
+                {
+                    result = ERROR_STREAM_FULL;
+                }
+                else if (packetResponse == EAU_CMD_RESP_RESEND)
+                {
+                    result = ERROR_CRC;
+                }
+                else if(packetResponse == EAU_CMD_RESP_ERCMD)
+                {
+                    result = ERROR_OTHER;
+                }
+                else if(packetResponse == EAU_CMD_RESP_STATEERROR)
+                {
+                    result = ERROR_START;
+                }
+                else
+                {
+                    divDBG(4, "response = %d dataLen = %d",packetResponse,packetDataLen);
+                    result = ERROR_RESPONSE;
+                }
+
+                if (packetResponse == EAU_CMD_RESP_INITERROR)
+                {
+                    result = ERROR_INIT;
+                    goto reSend;
+                }
+            }
+            else
+            {
+                divDBG(4, "cmd = %x response = %x dataLen = %x",ResponseContext->Command,packetResponse,packetDataLen);
+                divByteS(2, pRecvAllData, 64);
+                result = ERROR_CMD;
+            }
+        }
+        reSend:
+        {
+            ;
+        }
+    }
+    while ((--reSendCnt >= 0) && (result != OK_RESPONSE));
+error:
+    os_timer_disarm(&timer);
+    if(reSendCnt != RESENDCOUNT - 1 && reSendCnt != RESENDCOUNT)
+        divDBG(4, "SPI resend %d %d",reSendCnt,sendLen);
+    sys_mutex_unlock(&ap80_mutex_sendData);
+    return result;
+    
+#else
+    
+    sys_mutex_lock(&ap80_mutex_sendData);
+    EAUCmdContext        *CommandContext   = (EAUCmdContext *)SPIM_SEND_BUFFER;
+    EAUCmdResponseContext *ResponseContext = (EAUCmdResponseContext *)SPIM_SEND_BUFFER;
+    uint8_t  *sendDataFramePtr = (uint8_t *) &SPIM_SEND_BUFFER[sizeof(EAUCmdContext)];
+    uint8_t  *ptr               = NULL;
+    uint8_t   result            = 1;
+    uint16_t  sendDataLen       = sendLen;
+    uint32_t  cnt               = 0;
+    bool      flag              = false;
+    uint16_t  timeOut           = g_waitTime;
+    int8_t   reSendCnt          = RESENDCOUNT;
+    int16_t  sendRemLen         = 0;
+    uint16_t  pos               = 0;
+    uint8_t   protocolMode      = 0;
+    divTimeOut                  = false;
+
+    if(sendData == NULL && sendLen == 0 && receiveData == NULL)
+    {
+        protocolMode = 0;
+    }
+    else if(sendData != NULL && sendLen != 0 && receiveData == NULL)
+    {
+        protocolMode = 2;
+    }
+    else if(sendData == NULL && sendLen == 0 && receiveData != NULL)
+    {
+        protocolMode = 1;
+    }
+    else if(sendData != NULL && sendLen != 0 && receiveData != NULL)
+    {
+        protocolMode = 3;
+    } else {
+        result = ERROR_PROMODE;
+        goto error;
+    }
+
+    if(protocolMode & BIT1)
+    {
+        if (sendLen >= EAU_SEND_DATA_LENGTH - EAU_SEND_FARMA_LENGTH)
+        {
+            result = ERROR_PARAMETER;
+            goto error;
+        }
+    }
+
+    do
+    {
+        //1. Send EAU_CMD_DATA command
+        CommandContext->SyncWord  = EAU_SYNC_BYTE;
+        CommandContext->Command   = CMD;
+        if(CMD == EAU_CMD_VOL_SET)
+        {
+            CommandContext->Content   = value;
+        }
+        else
+        {
+            CommandContext->Content   = sendDataLen;
+        }
+
+        CommandContext->CrcValue  = GetCRC16NBS((uint8_t *)CommandContext, sizeof(EAUCmdContext) - EAU_CRC_VALUE_LENGTH);
+
+        pos                       = 0;
+
+        if(protocolMode & BIT1)
+        {
+
+            *sendDataFramePtr         = EAU_SYNC_BYTE;
+
+            MEMCPY(sendDataFramePtr   + EAU_SYNC_WORD_LENGTH, sendData, sendDataLen);
+
+            uint16_t crc = GetCRC16NBS(sendDataFramePtr + 1, CommandContext->Content);
+            sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 0] = (uint8_t) crc;
+            sendDataFramePtr[sendDataLen + EAU_SYNC_WORD_LENGTH + 1] = crc >> 8;
+
+            sendRemLen = sizeof(EAUCmdContext) + EAU_SYNC_WORD_LENGTH + sendDataLen + EAU_CRC_VALUE_LENGTH;
+        } else {
+            sendRemLen = sizeof(EAUCmdContext);
+        }
+
+        os_timer_arm(&timer, 500, false);
+        while (SPIM_STREAM_CONTROL_GET_STATUS())
+        {
+            if(divTimeOut)
+            {
+                result = ERROR_DEVICE_TIME_OUT;
+                goto error;
+            }
+        };
+        divDBG(2, "stup 02");
+        
+        if(g_noResponse)
+        {
+            result = OK_RESPONSE;
+            reSendCnt--;
+            goto error;
+        }
+        
+        do
+        {
+            if(sendRemLen >= EAU_SEND_FARMA_LENGTH)
+            {
+                spiSend(SPIM_SEND_BUFFER + pos, EAU_SEND_FARMA_LENGTH);
+                pos += EAU_SEND_FARMA_LENGTH;
+            }
+            else
+            {
+                spiSend(SPIM_SEND_BUFFER + pos, sendRemLen);
+                break;
+            }
+            sendRemLen -= EAU_SEND_FARMA_LENGTH;
+        }
+        while(sendRemLen >= 0);
+        divDBG(2, "stup 03");
+
+        //3. Receive response
+        ptr = (uint8_t *)&ResponseContext->SyncWord;
+
+        cnt  = 0;
+        flag = false;
+
+        while (1)
+        {
+            spiRecv(ptr, 1);
+            if (ptr[0] == EAU_SYNC_BYTE)
+            {
+                spiRecv((uint8_t *)&ResponseContext->Command, (sizeof(EAUCmdContext) - EAU_SYNC_WORD_LENGTH));
+                divDBG(2, "Command:%02x Response:%04x\n",ResponseContext->Command,ResponseContext->Response);
+                if(ResponseContext->Command == CMD)
+                {
+                    flag = true;
+                    break;
+                }
+            }
+            if (cnt++ > timeOut)
+            {
+                divDBG(2, "Cnt %08x",cnt);
+                result = ERROR_TIME_OUT;
+                break;
+            }
+        }
+
+        if (flag)
+        {
+            if (ResponseContext->Command == CMD)
+            {
+                uint8_t response = ResponseContext->Response &  0x00FF;
+                uint8_t dataLen  = ResponseContext->Response >> 0x08;
+
+                divDBG(1, "response = %d dataLen = %d",response,dataLen);
+
+                if(response == EAU_CMD_RESP_OKSEND || response == EAU_CMD_RESP_OKCMD)
+                {
+                    result = OK_RESPONSE;
+                    if(dataLen > 0 && (protocolMode & BIT0))
+                    {
+                        uint8_t      recvLen    = 0x00;
+
+                        uint16_t     LocalCrc   = 0x00;
+                        uint16_t     recvCrc    = 0x00;
+                        uint8_t      recvCrcLen = 0x00;
+                        if(FindSpiStreamDataSyncWord())
+                        {
+                            uint8_t      *RecvBuff       = (uint8_t*)ResponseContext;
+                            int16_t  recvRemLen      = dataLen;
+                            pos                     = 0;
+
+                            do
+                            {
+                                if(recvRemLen >= EAU_SEND_FARMA_LENGTH)
+                                {
+                                    spiRecv(RecvBuff + pos, EAU_RECV_FARMA_LENGTH);
+                                    pos += EAU_SEND_FARMA_LENGTH;
+                                }
+                                else
+                                {
+                                    spiRecv(RecvBuff + pos, recvRemLen);
+                                    break;
+                                }
+                                recvRemLen -= EAU_SEND_FARMA_LENGTH;
+                            }while(recvRemLen >= 0);
+
+                            spiRecv((uint8_t *) &recvCrc, EAU_CRC_VALUE_LENGTH);
+
+                            LocalCrc = GetCRC16NBS(RecvBuff, dataLen);
+                            if(LocalCrc == recvCrc)
+                            {
+                                if(*receiveLen != 0 && *receiveLen < dataLen)
+                                {
+                                    result = ERROR_PARAMETER;
+                                    goto error;
+                                }
+                                memcpy(receiveData, RecvBuff, dataLen);
+                                *receiveLen = dataLen;
+                            }
+                            else
+                            {
+                                result = ERROR_CRC;
+                                goto error;
+                            }
+                        }
+                    }
+                }
+                else if (response == EAU_CMD_RESP_NEXTSEND)
+                {
+                    result = ERROR_STREAM_FULL;
+                }
+                else if (response == EAU_CMD_RESP_RESEND)
+                {
+                    result = ERROR_CRC;
+                }
+                else if(response == EAU_CMD_RESP_ERCMD)
+                {
+                    result = ERROR_OTHER;
+                }
+                else if(response == EAU_CMD_RESP_STATEERROR)
+                {
+                    result = ERROR_START;
+                }
+                else
+                {
+                    result = ERROR_RESPONSE;
+                }
+
+                if (response == EAU_CMD_RESP_INITERROR)
+                {
+                    result = ERROR_INIT;
+                    goto error;
+                }
+            }
+            else
+            {
+                result = ERROR_CMD;
+            }
+        }
+        else
+        {
+            result = ERROR_TIME_OUT;
+        }
+    }
+    while ((--reSendCnt >= 0) && (result != 0));
+error:
+    os_timer_disarm(&timer);
+    if(reSendCnt != RESENDCOUNT - 1)
+        divDBG(4, "SPI resend %d %d",reSendCnt,sendLen);
+    sys_mutex_unlock(&ap80_mutex_sendData);
+    return result;
+#endif
+    
+}
+
+/**
+ * Audio playback start
+ */
+uint8_t apPlayStart(const char *parameter, uint8_t len, DecoderType decType)
+{
+    uint8_t data[64];
+    if(len > 60)
+        return ERROR_PARAMETER;
+    memcpy(data + DECODETYPELEN, parameter, len);
+    *(uint32_t*) data = decType;
+    return  sendData(EAU_CMD_START, 0, data, len + DECODETYPELEN,NULL, 0);
+}
+
+/**
+ * Send the data
+ */
+uint8_t apSendData(uint8_t *sendBuf, uint16_t  sendLen)
+{
+    apSetResponse(false);
+    uint8_t ret = sendData(EAU_CMD_DATA, 0, sendBuf, sendLen , NULL, NULL);
+    apSetResponse(true);
+    return ret;
+}
+/**
+ * Set audio volume
+ */
+uint8_t apVolSet(uint16_t vol)
+{
+    // Vol range: 0~32
+    uint16_t apVol = vol;
+    return sendData(EAU_CMD_VOL_SET, apVol, NULL, 0,NULL, 0);
+}
+
+/**
+ * Set audio volume mute
+ */
+uint8_t apVolMuteEnable(void)
+{
+    return sendData(EAU_CMD_MUTE, 0, NULL, 0,NULL, 0);
+}
+
+/**
+ * Set audio volume unmute
+ */
+uint8_t apVolMuteDisable(void)
+{
+    return sendData(EAU_CMD_UNMUTE, 0, NULL, 0,NULL, 0);
+}
+
+/**
+ * Pause audio decode
+ */
+uint8_t apPlayPause(void)
+{
+     return sendData(EAU_CMD_PAUSE, 0, NULL, 0,NULL, 0);
+}
+
+/**
+ * Resume audio decode
+ */
+uint8_t apPlayResume(void)
+{
+    return  sendData(EAU_CMD_RESUME, 0, NULL, 0,NULL, 0);
+}
+
+/**
+ * Stop audio decode
+ */
+uint8_t apPlayStop(void)
+{
+    return sendData(EAU_CMD_STOP, 0, NULL, 0,NULL, 0);
+}
+
+/**
+ * get song file info
+ */
+uint8_t apGetInfo(SongInformation *songInfo)
+{
+    uint8_t   result    = 0;
+    uint16_t  revLen    = 0;
+    uint8_t   recvbuf[SPIDATABUFMAXLEN];
+
+    result = sendData(EAU_CMD_INFO_GET, 0, NULL, 0, recvbuf, &revLen);
+
+    if(result == OK_RESPONSE)
+        MEMCPY((uint8_t *) songInfo, recvbuf, revLen);
+
+    return     result;
+}
+
+/**
+ * rest decode time
+ */
+uint8_t apRestDecodeTime(void)
+{
+    return sendData(EAU_CMD_TIME_REST, 0, NULL, 0,NULL, 0);
+}
+
+/**
+ * get decode time
+ */
+uint8_t apGetDecodeTime(DecodeTime *time)
+{
+    uint8_t   result    = 1;
+    uint16_t  revLen    = sizeof(DecodeTime);
+    uint8_t   recvbuf[sizeof(DecodeTime)];
+
+    result = sendData(EAU_CMD_TIME_GET, 0, NULL, 0, recvbuf, &revLen);
+    if(result == OK_RESPONSE)
+        MEMCPY((uint8_t *) time, recvbuf, revLen);
+
+    return     result;
+}
+
+/**
+ * To set the current mode for encode
+ */
+uint8_t apSetEncodeMode(void)
+{
+    return  sendData(EAU_CMD_ENCODE_MODE, 0, NULL, 0, NULL, NULL);
+}
+
+/**
+ * To set the current mode for decode
+ */
+uint8_t apSetDecodeMode(void)
+{
+    return  sendData(EAU_CMD_DECODE_MODE, 0, NULL, 0, NULL, NULL);
+}
+
+/**
+ * Read the data from mic
+ */
+uint8_t apMicReadData(uint8_t *readData, uint16_t  *readLen)
+{
+    uint8_t   result    = 0;
+    uint16_t  revLen    = 0;
+    result = sendData(EAU_CMD_READ_DATA, 0, NULL, 0 , readData, &revLen);
+    if(result == OK_RESPONSE)
+    {
+        *readLen = revLen;
+    }
+    return result;
+}
+
+/**
+ * Lin Switch
+ */
+uint8_t apLinSwitch(void)
+{
+    return  sendData(EAU_CMD_LIN_SWITCH, 0, NULL, 0, NULL, NULL);
+}
+
+/**
+ * Mic Switch
+ */
+uint8_t apMicSwitch(void)
+{
+    return  sendData(EAU_CMD_MIC_SWITCH, 0, NULL, 0, NULL, NULL);
+}
+
+/**
+ * start encode
+ */
+uint8_t apEncodeStart(void)
+{
+    return  sendData(EAU_CMD_ENCODE_START, 0, NULL, 0, NULL, NULL);
+}
+
+/**
+ * set encode info such as num_channels bitrate
+ */
+uint8_t apSetEncodeInfo(setEnccodeInfo *encodeInfo)
+{
+    if(encodeInfo == NULL)
+        return ERROR_OTHER;
+    return  sendData(EAU_CMD_INFO_SET, 0, (uint8_t *)encodeInfo, sizeof(setEnccodeInfo), NULL, NULL);
+}
+
+/**
+ * set decode info such as num_channels bitrate
+ */
+uint8_t apSetDecodeInfo(setDecodeInfo *decodeInfo)
+{
+    if(decodeInfo == NULL)
+        return ERROR_OTHER;
+    return  sendData(EAU_CMD_INFO_SET, 0, (uint8_t *)decodeInfo, sizeof(setDecodeInfo), NULL, NULL);
+}
+
+/**
+ * The wait time setup command sent
+ */
+uint8_t apSetWaitTime(uint32_t waitTime)
+{
+    if(waitTime < 1000)
+        return ERROR_PARAMETER;
+    g_waitTime = waitTime;
+    return OK_RESPONSE;
+}
+
+void apSetResponse(bool responseEnable)
+{
+    g_noResponse = !responseEnable;
+}

+ 53 - 0
examples/09_a2dp/components/MediaHal/AP80/crc.c

@@ -0,0 +1,53 @@
+#include <stdint.h>
+
+static const uint16_t gCRC16TableNBS[256] =
+{
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+uint16_t GetCRC16NBS(uint8_t* data, uint32_t length)
+{
+	uint16_t crc = 0;
+	uint8_t	 temp;
+
+	while(length--)
+	{
+		temp  = (unsigned char)(crc >> 8);		// get high byte
+		crc <<= 8;						        // get low byte
+		crc  ^= gCRC16TableNBS[*data ^ temp];
+		data++;
+	}
+
+	return crc;
+}

+ 387 - 0
examples/09_a2dp/components/MediaHal/Driver/dma.c

@@ -0,0 +1,387 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dma.h"
+#include "rom/ets_sys.h"
+#include "string.h"
+#include "stdlib.h"
+
+#define QUEUE_BLOCK_LENGTH  (4096L)
+
+
+#define DMA_DBG_WARING_ENABLE (0)
+#define DMA_DBG_ERROR_ENABLE  (0)
+#define DMA_INFO_ENABLE       (0)
+#define DMA_DBG_ENABLE        (0)
+
+//DBG INFOR
+#if DMA_DBG_ENABLE
+#define DMA_DBG(format,...) do{\
+        ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define DMA_DBG(...)
+#endif
+#if DMA_INFO_ENABLE
+#define DMA_INFO(format,...) do{\
+        ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define DMA_INFO(...)
+#endif
+
+#if DMA_DBG_WARNING_ENABLE
+#define DMA_WARNING(format,...) do{\
+        ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define DMA_WARNING(...)
+#endif
+#if DMA_DBG_ERROR_ENABLE
+#define DMA_ERROR(format,...) do{\
+        ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define DMA_ERROR(...)
+#endif
+
+void dma_show_queue(ping_pong_buf_t *pcfg)
+{
+    uint32_t i;
+    DMA_INFO("obj=%x \r\n", pcfg);
+    DMA_INFO("ping bck que=%x buf=%x,next_link_ptr=%x\r\n", pcfg->ping->backup_queue, pcfg->ping->buffer_addr, pcfg->ping->backup_queue.next_link_ptr);
+    DMA_INFO("ping first_que=%x, %08x, buf=%x\r\n", pcfg->ping->first_queue,*pcfg->ping->first_queue, pcfg->ping->buffer_addr);
+    DMA_INFO("ping last_que=%x, %08x, buf=%x\r\n", pcfg->ping->last_queue, *pcfg->ping->last_queue, pcfg->ping->buffer_addr);
+
+    DMA_INFO("pong bck que=%x buf=%x,next_link_ptr=%x\r\n", pcfg->pong->backup_queue, pcfg->pong->buffer_addr, pcfg->pong->backup_queue.next_link_ptr);
+    DMA_INFO("pong first_que=%x, %08x, buf=%x\r\n", pcfg->pong->first_queue, *pcfg->pong->first_queue, pcfg->pong->buffer_addr);
+    DMA_INFO("pong last_que=%x, %08x, buf=%x\r\n", pcfg->pong->last_queue, *pcfg->pong->last_queue, pcfg->pong->buffer_addr);
+
+    dma_queue_t *addr = (dma_queue_t*)pcfg->ping->first_queue;
+    dma_queue_t *addr1 = (dma_queue_t*)pcfg->pong->first_queue;
+    for (i = 0; i < pcfg->queue_cnt; ++i) {
+        DMA_INFO("ping queue%d buf:%08x,len=%d,size=%d,cur_link:%08x,next_link:%08x\r\n", i,
+                 addr->buf_ptr,addr->data_length, addr->block_size, addr, addr->next_link_ptr);
+        addr = (dma_queue_t*)addr->next_link_ptr;
+    }
+    for (i = 0; i < pcfg->queue_cnt; ++i) {
+        DMA_INFO("pong queue%d buf:%08x,len=%d,size=%d,cur_link:%08x,next_link:%08x\r\n", i,
+                 addr1->buf_ptr,addr1->data_length, addr1->block_size, addr1, addr1->next_link_ptr);
+        addr1 = (dma_queue_t*)addr1->next_link_ptr;
+    }
+}
+
+/**
+ * @brief Fill a link
+ *
+ */
+static void fill_one_link(uint8_t own, uint8_t eof, uint8_t sub_sof, uint16_t size, uint16_t length,
+                          uint32_t *buf_ptr, dma_queue_t *nxt_ptr, dma_queue_t *i2s_queue)
+{
+    i2s_queue->owner = own;
+    i2s_queue->eof = eof;
+    i2s_queue->sub_sof = sub_sof;
+    i2s_queue->data_length = 0x0FFF & length;
+    i2s_queue->block_size = size ;
+    i2s_queue->buf_ptr = (uint32_t)buf_ptr;
+    i2s_queue->next_link_ptr = (uint32_t)nxt_ptr;
+    i2s_queue->unused = 0;
+}
+
+/**
+ * @brief Fill the queue
+ *
+ */
+static int dma_queue_fill(uint32_t cnt, uint32_t len, ping_pong_buf_t *cfg)
+{
+    if (0 == cnt) {
+        return -1;
+    }
+    // ping queue list
+    dma_queue_t *pingAry[cnt];
+    // pong queue list
+    dma_queue_t *pongAry[cnt];
+    uint32_t i, j;
+    memset(&pingAry, 0, sizeof(pingAry));
+    memset(&pongAry, 0, sizeof(pongAry));
+    cnt = 1;
+    for (i = 0; i < cnt; ++i) {
+        pingAry[i] = (dma_queue_t*)malloc(sizeof(dma_queue_t));
+        if (pingAry[i] == NULL) {
+            for (j = 0; j < i; ++j) {
+                free(pingAry[j]);
+                pingAry[j] = NULL;
+            }
+            return -2;
+        }
+    }
+    for (i = 0; i < cnt; ++i) {
+        pongAry[i] = (dma_queue_t*)malloc(sizeof(dma_queue_t));
+        if (NULL == pongAry[i]) {
+            for (j = 0; j < cnt; ++j) {
+                free(pingAry[j]);
+                pingAry[j] = NULL;
+            }
+            for (j = 0; j < i; ++j) {
+                free(pongAry[j]);
+                pongAry[j] = NULL;
+            }
+            return -2;
+        }
+    }
+
+    cfg->ping->first_queue = pingAry[0];
+    cfg->pong->first_queue = pongAry[0];
+    if (1 == cnt) {
+        cfg->ping->last_queue = pingAry[0];
+        cfg->pong->last_queue = pongAry[0];
+    } else {
+        cfg->ping->last_queue = pingAry[cnt - 1];
+        cfg->pong->last_queue = pongAry[cnt - 1];
+    }
+    uint32_t remainSize = len;
+    uint32_t bufSize = QUEUE_BLOCK_LENGTH;
+    for (i = 0; i < cnt; ++i) {
+        if (1 == cnt) {
+            // Queue list include only one link, and set up eof bit.
+            if (QUEUE_BLOCK_LENGTH == len) {
+                bufSize = len - 1;
+            } else {
+                bufSize = len;
+            }
+            fill_one_link(1, 1, 0, bufSize, bufSize, cfg->ping->buffer_addr, pongAry[i], pingAry[i]);
+            fill_one_link(1, 1, 0, bufSize, bufSize, cfg->pong->buffer_addr, pingAry[i], pongAry[i]);
+        } else {
+            if (i == (cnt - 1)) {
+                // ping/pong queue list last link connect to the pong/ping first link, and set up eof bit.
+                bufSize = remainSize;
+                fill_one_link(1, 1, 0, bufSize, bufSize, cfg->ping->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i),
+                              pongAry[0], pingAry[i]);
+                fill_one_link(1, 1, 0, bufSize, bufSize, cfg->pong->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i),
+                              pingAry[0], pongAry[i]);
+            } else {
+                // Conncet the next link.
+                fill_one_link(1, 0, 0, bufSize - 1, bufSize - 1, cfg->ping->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i), pingAry[i + 1], pingAry[i]);
+                fill_one_link(1, 0, 0, bufSize - 1, bufSize - 1, cfg->pong->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i), pongAry[i + 1], pongAry[i]);
+            }
+        }
+        remainSize -= bufSize;
+    }
+    return 0;
+}
+
+
+/**
+ * @brief Create a ping-pong buffer object used by DMA.
+ *
+ */
+ping_pong_buf_t* dma_buf_create(uint32_t bufLen)
+{
+    if (0 == bufLen) {
+        return NULL;
+    }
+    uint32_t i, j;
+    uint32_t queue_cnt ;
+    uint8_t * pBuf = NULL;
+    i = bufLen / QUEUE_BLOCK_LENGTH;
+    j = bufLen % QUEUE_BLOCK_LENGTH;
+    if (0 == j) {
+        queue_cnt = i;
+    } else {
+        queue_cnt = i + 1;
+    }
+    DMA_INFO("\r\nbufLen=%d queue_cnt=%d\r\n", bufLen, queue_cnt);
+
+    ping_pong_buf_t* pcfg;
+    pcfg = (ping_pong_buf_t*)malloc(sizeof(ping_pong_buf_t));
+    if (NULL == pcfg) {
+        return NULL;
+    }
+    pBuf = ((uint8_t*)malloc(bufLen * 2)); // buflen is number of bytes buffer.malloc ping and pong buffer.
+    pcfg->ping = (dma_element_t*)malloc(sizeof(dma_element_t));
+    pcfg->pong = (dma_element_t*)malloc(sizeof(dma_element_t));
+    if ((NULL == pBuf)
+        || (NULL == pcfg->pong)
+        || (NULL == pcfg->ping)) {
+        free(pBuf);
+        pBuf = NULL;
+        free(pcfg->pong);
+        pcfg->pong = NULL;
+        free(pcfg->ping);
+        pcfg->ping = NULL;
+        free(pcfg);
+        pcfg = NULL;
+        DMA_INFO("Malloc ping->buffer_addr failed");
+        return NULL;
+    }
+    memset(pBuf, 0, (bufLen * 2));    
+    memset(pcfg->ping, 0, sizeof(dma_element_t));
+    memset(pcfg->pong, 0, sizeof(dma_element_t));
+    pcfg->ping->buffer_addr = (uint32_t*)pBuf;
+    pcfg->pong->buffer_addr = (uint32_t*)(pBuf + bufLen);
+    pcfg->queue_cnt = queue_cnt;  // Number of queue
+    if (dma_queue_fill(queue_cnt, bufLen, pcfg) < 0) {
+        free(pcfg->ping->buffer_addr);
+        pcfg->ping->buffer_addr = NULL;
+        free(pcfg->pong->buffer_addr);
+        pcfg->pong->buffer_addr = NULL;
+        free(pBuf);
+        pBuf = NULL;
+        free(pcfg->pong);
+        pcfg->pong = NULL;
+        free(pcfg->ping);
+        pcfg->ping = NULL;
+        free(pcfg);
+        pcfg = NULL;
+        return NULL;
+    }
+    pcfg->len = bufLen;         // Buffer length
+    dma_show_queue(pcfg);
+    return pcfg;
+}
+static esp_err_t dma_queue_reset(int32_t que_size, dma_element_t *obj)
+{
+    if (NULL == obj) {
+        return ESP_FAIL;
+    }
+    // No need reset;
+    if (0 == obj->backup_queue.next_link_ptr) {
+        return ESP_OK;
+    }
+    dma_queue_t *dmaQueCur = obj->first_queue;
+    dma_queue_t *dmaQueNext = NULL;
+    if (que_size > 1) {
+        while (dmaQueNext != obj->first_queue) {
+            dmaQueNext = (dma_queue_t*)dmaQueCur->next_link_ptr;
+            if ((dma_queue_t*)obj->backup_queue.next_link_ptr == dmaQueNext) {
+                DMA_INFO("find next_link_ptr=%x \r\n", dmaQueNext);
+                break;
+            }
+            dmaQueCur = dmaQueNext;
+        }
+    }
+    memcpy(dmaQueCur, &obj->backup_queue, sizeof(obj->backup_queue));
+    memset(&obj->backup_queue, 0, sizeof(obj->backup_queue));
+
+    return ESP_OK;
+}
+
+/**
+ * @brief Reset the dma buffer length.
+ *
+ */
+esp_err_t dma_buf_len_reset(ping_pong_buf_t *obj)
+{
+    if (NULL == obj) {
+        return ESP_FAIL;
+    }
+    dma_queue_t *dmaQueCur = obj->ping->first_queue;
+    dma_queue_t *dmaQueNext = NULL;
+    esp_err_t ret = ESP_OK;
+    
+    DMA_INFO("next_link_ptr=%x lenght=%d\r\n", obj->ping->backup_queue.next_link_ptr, obj->ping->first_queue->data_length);
+    
+    obj->ping->first_queue->owner = 1;
+    obj->ping->last_queue->owner = 1;
+    obj->pong->first_queue->owner = 1;
+    obj->pong->last_queue->owner = 1;
+    
+    obj->pong->first_queue->data_length = 32;
+    obj->pong->last_queue->data_length = 32;
+    obj->ping->first_queue->data_length = 32;
+    obj->ping->last_queue->data_length = 32;
+    
+    ret = dma_queue_reset(obj->queue_cnt, obj->ping);
+    ret += dma_queue_reset(obj->queue_cnt, obj->pong);
+    
+    //dma_show_queue(obj);
+    DMA_INFO("[%s # %u lenght=%d]\r\n",__FUNCTION__,__LINE__, obj->ping->first_queue->data_length);
+
+    return ret;
+}
+
+/**
+ * @brief Set the buffer length before the start.
+ *
+ */
+esp_err_t dma_buf_len_set(ping_pong_buf_t *obj, dma_element_t *element, uint32_t len)
+{
+    if (NULL == obj) {
+        return ESP_FAIL;
+    }
+    if (len < obj->len) {
+        int i, k, cnt;
+        i = len / QUEUE_BLOCK_LENGTH;
+        k = len % QUEUE_BLOCK_LENGTH;
+        if (0 == k) {
+            cnt = i;
+        } else {
+            cnt = i + 1;
+        }
+        dma_queue_t *dmaQueCur = element->first_queue;
+        dma_queue_t *dmaQueNext = NULL;
+        while (--cnt) {
+            dmaQueNext = (dma_queue_t*)dmaQueCur->next_link_ptr;
+            dmaQueCur = dmaQueNext;
+        }
+        memcpy(&element->backup_queue, (dma_queue_t*)dmaQueCur, sizeof(element->backup_queue));
+        
+        dmaQueCur->next_link_ptr = 0;
+        dmaQueCur->data_length = k;
+    }
+    return ESP_OK;
+}
+
+/**
+ * @brief Destroy the ping-pong buffer instance.
+ *
+ */
+void dma_buf_destroy(ping_pong_buf_t *obj)
+{
+    ping_pong_buf_t *temp = obj;
+    dma_show_queue(temp);
+    if (NULL != temp) {
+        // Free the link list
+        uint32_t i = 0;
+        dma_queue_t *curtCfg = temp->ping->first_queue;
+        dma_queue_t *nextCfg = NULL;
+        for (i = 0; i < temp->queue_cnt; ++i) {
+            nextCfg = (dma_queue_t*)curtCfg->next_link_ptr;
+            free(curtCfg);
+            curtCfg =  NULL;
+            curtCfg = nextCfg;
+        }
+        curtCfg = temp->pong->first_queue;
+        nextCfg = NULL;
+        for (i = 0; i < temp->queue_cnt; ++i) {
+            nextCfg = (dma_queue_t*)curtCfg->next_link_ptr;
+            free(curtCfg);
+            curtCfg =  NULL;
+            curtCfg = nextCfg;
+        }
+        // Free the buffer
+        free(temp->ping->buffer_addr);
+        temp->ping->buffer_addr = NULL;
+        free(temp->ping);
+        temp->ping = NULL;
+        free(temp->pong);
+        temp->pong = NULL;
+        free(temp);
+        temp = NULL;
+    }
+}

+ 350 - 0
examples/09_a2dp/components/MediaHal/Driver/i2c_soft.c

@@ -0,0 +1,350 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "rom/ets_sys.h"
+#include "driver/gpio.h"
+#include "i2c_soft.h"
+
+static uint8_t m_nLastSDA;
+static uint8_t m_nLastSCL;
+
+/******************************************************************************
+ * FunctionName : i2c_master_setDC
+ * Description  : Internal used function -
+ *                    set i2c SDA and SCL bit value for half clk cycle
+ * Parameters   : uint8_t SDA
+ *                uint8_t SCL
+ * Returns      : NONE
+*******************************************************************************/
+static void i2c_master_setDC(uint8_t SDA, uint8_t SCL)
+{
+    SDA &= 0x01;
+    SCL &= 0x01;
+    m_nLastSDA = SDA;
+    m_nLastSCL = SCL;
+    //ETS_INTR_LOCK();
+    if ((0 == SDA) && (0 == SCL)) {
+        I2C_MASTER_SDA_LOW_SCL_LOW();
+    } else if ((0 == SDA) && (1 == SCL)) {
+        I2C_MASTER_SDA_LOW_SCL_HIGH();
+    } else if ((1 == SDA) && (0 == SCL)) {
+        I2C_MASTER_SDA_HIGH_SCL_LOW();
+    } else {
+        I2C_MASTER_SDA_HIGH_SCL_HIGH();
+    }
+    //ETS_INTR_UNLOCK();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_getDC
+ * Description  : Internal used function -
+ *                    get i2c SDA bit value
+ * Parameters   : NONE
+ * Returns      : uint8_t - SDA bit value
+*******************************************************************************/
+static uint8_t i2c_master_getDC(void)
+{
+    uint8_t sda_out;
+    //ETS_INTR_LOCK();
+    //sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
+    sda_out = gpio_get_level(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
+    //ETS_INTR_UNLOCK();
+    return sda_out;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_init
+ * Description  : initilize I2C bus to enable i2c operations
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void i2c_master_init(void)
+{
+    uint8_t i;
+
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+
+    // when SCL = 0, toggle SDA to clear up
+    i2c_master_setDC(0, 0) ;
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0) ;
+    i2c_master_wait(5);
+
+    // set data_cnt to max value
+    for (i = 0; i < 28; i++) {
+        i2c_master_setDC(1, 0);
+        i2c_master_wait(5); // sda 1, scl 0
+        i2c_master_setDC(1, 1);
+        i2c_master_wait(5); // sda 1, scl 1
+    }
+
+    // reset all
+    i2c_master_stop();
+    //return;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_gpio_init
+ * Description  : config SDA and SCL gpio to open-drain output mode,
+ *                mux and gpio num defined in i2c_master.h
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void i2c_master_gpio_init(void)
+{
+
+	gpio_config_t io_config;
+	io_config.pin_bit_mask= (I2C_MASTER_SDA_PIN) | (I2C_MASTER_SCL_PIN);
+	io_config.mode= GPIO_MODE_INPUT_OUTPUT_OD;
+	io_config.pull_up_en= GPIO_PULLUP_ENABLE;
+	io_config.pull_down_en= GPIO_PULLDOWN_DISABLE;
+	io_config.intr_type = GPIO_PIN_INTR_DISABLE;
+
+	gpio_config(&io_config);
+#if 0
+	io_config.gpio_intry_type_sel = GPIO_PIN_INTR_DISABLE;
+	io_config.gpio_mode_sel = GPIO_MODE_OUTPUT_OD;
+	io_config.gpio_pin_sel = I2C_MASTER_SCL_PIN;
+	io_config.gpio_pulldown_sel = GPIO_PULLDOWN_DISABLE;
+	io_config.gpio_pullup_sel  = GPIO_PULLUP_ENABLE;	
+
+    gpio_config(&io_config);
+#endif
+	#if 0
+     ETS_INTR_UNLOCK();
+    // Set to GPIO function
+    PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);
+    PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);    
+    // Enable input
+    SET_PERI_REG_MASK(I2C_MASTER_SDA_MUX, FUN_IE);
+    
+    GPIO_REG_WRITE(GPIO_PIN_ADDR(I2C_MASTER_SDA_GPIO),
+        GPIO_REG_READ(GPIO_PIN_ADDR(I2C_MASTER_SDA_GPIO)) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
+    GPIO_REG_WRITE(GPIO_ENABLE, GPIO_REG_READ(GPIO_ENABLE) | (1 << I2C_MASTER_SDA_GPIO));
+
+    GPIO_REG_WRITE(GPIO_PIN_ADDR(I2C_MASTER_SCL_GPIO),
+        GPIO_PIN_ADDR(I2C_MASTER_SCL_GPIO) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
+    GPIO_REG_WRITE(GPIO_ENABLE, GPIO_REG_READ(GPIO_ENABLE) | (1 << I2C_MASTER_SCL_GPIO));
+    I2C_MASTER_SDA_HIGH_SCL_HIGH();
+	PIN_PULLUP_EN(I2C_MASTER_SDA_MUX);
+	PIN_PULLUP_EN(I2C_MASTER_SCL_MUX);
+    ETS_INTR_UNLOCK();
+	#endif
+
+    i2c_master_init();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_start
+ * Description  : set i2c to send state
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void i2c_master_start(void)
+{
+    // ETS_INTR_UNLOCK();
+    i2c_master_setDC(1, m_nLastSCL);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5); // sda 1, scl 1
+    i2c_master_setDC(0, 1);
+    i2c_master_wait(5); // sda 0, scl 1
+    // ETS_INTR_UNLOCK();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_stop
+ * Description  : set i2c to stop sending state
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void i2c_master_stop(void)
+{
+    // ETS_INTR_UNLOCK();
+    i2c_master_wait(5);
+
+    i2c_master_setDC(0, m_nLastSCL);
+    i2c_master_wait(5); // sda 0
+    i2c_master_setDC(0, 1);
+    i2c_master_wait(5); // sda 0, scl 1
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5); // sda 1, scl 1
+    // ETS_INTR_UNLOCK();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_setAck
+ * Description  : set ack to i2c bus as level value
+ * Parameters   : uint8_t level - 0 or 1
+ * Returns      : NONE
+*******************************************************************************/
+void i2c_master_setAck(uint8_t level)
+{
+    // ETS_INTR_UNLOCK();
+
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(level, 0);
+    i2c_master_wait(5); // sda level, scl 0
+    i2c_master_setDC(level, 1);
+    i2c_master_wait(8); // sda level, scl 1
+    i2c_master_setDC(level, 0);
+    i2c_master_wait(5); // sda level, scl 0
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+    // ETS_INTR_UNLOCK();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_getAck
+ * Description  : confirm if peer send ack
+ * Parameters   : NONE
+ * Returns      : uint8_t - ack value, 0 or 1
+*******************************************************************************/
+uint8_t i2c_master_getAck(void)
+{
+    uint8_t retVal;
+    // ETS_INTR_UNLOCK();
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);
+
+    retVal = i2c_master_getDC();
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+    // ETS_INTR_UNLOCK();
+
+    return retVal;
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_checkAck
+* Description  : get dev response
+* Parameters   : NONE
+* Returns      : true : get ack ; false : get nack
+*******************************************************************************/
+bool i2c_master_checkAck(void)
+{
+    if(i2c_master_getAck()){
+        return false;
+    }else{
+        return true;
+    }
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_send_ack
+* Description  : response ack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void i2c_master_send_ack(void)
+{
+    i2c_master_setAck(0x0);
+}
+/******************************************************************************
+* FunctionName : i2c_master_send_nack
+* Description  : response nack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void i2c_master_send_nack(void)
+{
+    i2c_master_setAck(0x1);
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_readByte
+ * Description  : read Byte from i2c bus
+ * Parameters   : NONE
+ * Returns      : uint8_t - readed value
+*******************************************************************************/
+uint8_t i2c_master_readByte(void)
+{
+    uint8_t retVal = 0;
+    uint8_t k, i;
+    // ETS_INTR_UNLOCK();
+    i2c_master_wait(5);
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5); // sda 1, scl 0
+
+    for (i = 0; i < 8; i++) {
+        i2c_master_wait(5);
+        i2c_master_setDC(1, 0);
+        i2c_master_wait(5); // sda 1, scl 0
+        i2c_master_setDC(1, 1);
+        i2c_master_wait(5); // sda 1, scl 1
+
+        k = i2c_master_getDC();
+        i2c_master_wait(5);
+
+        if (i == 7) {
+            i2c_master_wait(3);   ////
+        }
+
+        k <<= (7 - i);
+        retVal |= k;
+    }
+
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5); // sda 1, scl 0
+   // ETS_INTR_UNLOCK();
+    return retVal;
+}
+#define DBG_TONY ets_printf
+/******************************************************************************
+ * FunctionName : i2c_master_writeByte
+ * Description  : write wrdata value(one byte) into i2c
+ * Parameters   : uint8_t wrdata - write value
+ * Returns      : NONE
+*******************************************************************************/
+void i2c_master_writeByte(uint8_t wrdata)
+{
+    uint8_t dat;
+    int8_t i;
+
+    i2c_master_wait(5);
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+
+	for (i = 7; i >= 0; i--) {
+        dat = wrdata >> i;
+        i2c_master_setDC(dat, 0);
+        i2c_master_wait(5);
+        i2c_master_setDC(dat, 1);
+        i2c_master_wait(5);
+
+        if (i == 0) {
+            i2c_master_wait(3);   ////
+        }
+
+        i2c_master_setDC(dat, 0);
+        i2c_master_wait(5);
+    }
+
+}

+ 615 - 0
examples/09_a2dp/components/MediaHal/Driver/i2s.c

@@ -0,0 +1,615 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "i2s.h"
+#include <string.h>
+#include "rom/ets_sys.h"
+#include "esp_intr.h"
+#include "soc/gpio_reg.h"
+#include "soc/gpio_sig_map.h"
+#include "soc/io_mux_reg.h"
+#include "soc/rtc_cntl_reg.h"
+#include "driver/gpio.h"
+#include "stdio.h"
+
+
+#define I2S_BASE_CLK (80000000L)
+#define ABS(x) (((x)>0)?(x):(-(x)))
+
+//*****************************************************************************
+//
+// Make sure all of the definitions in this header have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @brief Set the interrupt function.
+ *
+ */
+static void i2s_intr_func_set(void * isr, i2s_num_t i2sNum)
+{
+    if (I2S_NUM_I2S0 == i2sNum) {
+        intr_matrix_set(0, ETS_I2S0_INTR_SOURCE, ETS_I2S0_INUM);
+        ESP_I2S0_INTR_ATTACH(isr, NULL);
+        // enable intr in cpu
+        ESP_I2S0_INTR_ENABLE();
+    } else if (I2S_NUM_I2S1 == i2sNum) {
+        intr_matrix_set(0, ETS_I2S1_INTR_SOURCE, ETS_I2S1_INUM);
+        ESP_I2S1_INTR_ATTACH(isr, NULL);
+        // enable intr in cpu
+        ESP_I2S1_INTR_ENABLE();
+    } else {
+        // To do nothing
+    }
+}
+
+/**
+ * @brief Get I2S ping buffer address.
+ *
+ */
+uint32_t* i2s_dma_ping_buf_get(i2s_dma_attr_t *obj)
+{
+    if (NULL == obj) {
+        return NULL;
+    }
+    return obj->buf->ping->buffer_addr;
+}
+
+/**
+ * @brief Get I2S pong buffer address.
+ *
+ */
+uint32_t* i2s_dma_pong_buf_get(i2s_dma_attr_t *obj)
+{
+    if (NULL == obj) {
+        return NULL;
+    }
+    return obj->buf->pong->buffer_addr;
+}
+
+/**
+ * @brief Get not working ping-pong buffer address.
+ *
+ */
+uint32_t* i2s_dma_status_get(i2s_num_t i2sNum, i2s_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (i2sNum > I2S_NUM_MAX)) {
+        return NULL;
+    }
+    if ((I2S_MODE_MASTER_RX == obj->mode)
+        || (I2S_MODE_SLAVE_RX == obj->mode)) {
+        // Data stream receive
+        if (READ_PERI_REG(I2S_IN_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->ping->last_queue)) {
+            return obj->buf->ping->buffer_addr;
+        } else if (READ_PERI_REG(I2S_IN_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->pong->last_queue)) {
+            return obj->buf->pong->buffer_addr;
+        }
+    } else if ((I2S_MODE_MASTER_TX == obj->mode)
+               || (I2S_MODE_SLAVE_TX == obj->mode)) {
+        // Data stream send
+        if (READ_PERI_REG(I2S_OUT_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->ping->last_queue))  {
+            return obj->buf->ping->buffer_addr;
+        } else if (READ_PERI_REG(I2S_OUT_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->pong->last_queue)) {
+            return obj->buf->pong->buffer_addr;
+        }
+    }
+    return NULL;
+
+}
+
+/**
+ * @brief Set the Ping-Pong buffer to the destination
+ *
+ */
+void i2s_dma_dest_add_set(i2s_num_t i2sNum, i2s_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (i2sNum > I2S_NUM_MAX)) {
+        return;
+    }
+    if ((I2S_MODE_MASTER_RX == obj->mode)
+        || (I2S_MODE_SLAVE_RX == obj->mode)) {
+        SET_PERI_REG_BITS(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), I2S_INLINK_ADDR_S);
+    } else if ((I2S_MODE_MASTER_TX == obj->mode)
+               || (I2S_MODE_SLAVE_TX == obj->mode)) {
+        SET_PERI_REG_BITS(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), I2S_OUTLINK_ADDR_S);
+    }
+}
+
+/**
+ * @brief Initialize DMA and create a I2S DMA instance
+ *
+ */
+int i2s_dma_init(i2s_num_t i2sNum, i2s_dma_attr_t *obj, void *isr)
+{
+    if ((NULL == obj)
+        || (i2sNum > I2S_NUM_MAX)) {
+        return -1;
+    }
+    obj->buf = dma_buf_create(obj->buf_size);
+    if (NULL == obj->buf) {
+        return -2;
+    }
+    if ((I2S_MODE_MASTER_TX == obj->mode)
+        || (I2S_MODE_SLAVE_TX == obj->mode)) {
+        //Reset DMA
+        SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_OUT_RST);
+        CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_OUT_RST);
+        // enable send intr
+        i2s_int_enable(i2sNum, I2S_INT_SRC_ONE_BUF_SEND_DONE);
+    } else if ((I2S_MODE_MASTER_RX == obj->mode)
+               || (I2S_MODE_SLAVE_RX == obj->mode)) {
+        //Reset DMA
+        SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_IN_RST);
+        CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_IN_RST);
+        SET_PERI_REG_BITS(I2S_RXEOF_NUM_REG(i2sNum), I2S_RX_EOF_NUM, (obj->buf_size / 4), I2S_RX_EOF_NUM_S);
+        // enable receive intr
+        i2s_int_enable(i2sNum, I2S_INT_SRC_ONE_BUF_RECV_DONE /*| I2sIntSrc_RxHalfFull |I2sIntSrc_RxFull*/);
+    }
+
+    //Enable and configure DMA
+    SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_CHECK_OWNER | I2S_OUT_EOF_MODE |
+                      I2S_OUT_LOOP_TEST | I2S_IN_LOOP_TEST);
+    i2s_intr_func_set(isr, i2sNum);
+    return 0;
+}
+
+/**
+ * @brief Destroy the I2S DMA instance
+ *
+ */
+esp_err_t i2s_dma_uninit(i2s_dma_attr_t *obj)
+{
+    if (NULL == obj) {
+        return ESP_FAIL;
+    }
+    dma_buf_destroy(obj->buf);
+    return ESP_OK;
+}
+
+/**
+ * @brief Enable the I2S DMA work mode.
+ *
+ */
+void i2s_dma_enable(i2s_num_t i2sNum, i2s_mode_t mode)
+{
+    if (i2sNum > I2S_NUM_MAX) {
+        return;
+    }
+    if ((I2S_MODE_MASTER_RX == mode)
+        || (I2S_MODE_SLAVE_RX == mode)) {
+        SET_PERI_REG_MASK(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_START);
+    } else if ((I2S_MODE_MASTER_TX == mode)
+               || (I2S_MODE_SLAVE_TX == mode)) {
+        SET_PERI_REG_MASK(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_START);
+    }
+}
+
+/**
+ * @brief Disable the I2S DMA work mode.
+ *
+ */
+void i2s_dma_disable(i2s_num_t i2sNum, i2s_mode_t mode)
+{
+    if (i2sNum > I2S_NUM_MAX) {
+        return;
+    }
+    if ((I2S_MODE_MASTER_RX == mode)
+        || (I2S_MODE_SLAVE_RX == mode)) {
+        SET_PERI_REG_MASK(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_STOP);
+    } else if ((I2S_MODE_MASTER_TX == mode)
+               || (I2S_MODE_SLAVE_TX == mode)) {
+        SET_PERI_REG_MASK(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_STOP);
+    }
+}
+
+/**
+ * @brief Set the I2S sample rate, in HZ
+ *
+ */
+void i2s_clk_set(int rate, int bits)
+{
+    uint32_t i2sNum = 0 ;
+    int bckdiv, factor = 32;
+    int clkmInteger, clkmDecimals;
+    float denom = (float)1 / 16;
+    // BCLK = Fs * bits * 2;
+    // MCLK = factor * BCLK; m = 2;
+    // clkm = 160MHz / MCLK;
+    ets_printf("rate=%d, bits=%d \r\n", rate, bits);
+    float clkmdiv = (float)I2S_BASE_CLK / (rate * factor * bits * 2);
+    ets_printf("clkmdiv=%f\r\n", clkmdiv);
+    if (clkmdiv > 256) {
+        factor++;
+        clkmdiv = (float)I2S_BASE_CLK / (rate * factor * bits * 2);
+    }
+    ets_printf("clkmdiv=%f\r\n", clkmdiv);
+    clkmInteger = clkmdiv;
+    ets_printf("clkmInteger=%d\r\n", clkmInteger);
+    clkmDecimals = (clkmdiv - clkmInteger) / denom;
+    ets_printf("clkmDecimals=%d\r\n", clkmDecimals);
+    float mclk = clkmInteger + denom * clkmDecimals;
+    ets_printf("MCLK=%f\r\n", (float)I2S_BASE_CLK / mclk);
+    rtc_plla_ena(1,10,2);
+#if 0
+    CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
+                                            | I2S_CLKM_DIV_A_M
+                                            | I2S_CLKM_DIV_B_M));
+    SET_PERI_REG_MASK(I2S_CLKM_CONF_REG, I2S_CLK_EN | ((0 & I2S_CLKM_DIV_A_V) << I2S_CLKM_DIV_A_S)
+                      | ((0) << I2S_CLKM_DIV_B_S) | (20 & I2S_CLKM_DIV_NUM_V));
+
+    CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
+    SET_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, ((4 & I2S_RX_BCK_DIV_NUM_V) << I2S_RX_BCK_DIV_NUM_S)
+                      | ((4 & I2S_TX_BCK_DIV_NUM_V) << I2S_TX_BCK_DIV_NUM_S));
+
+#else
+#if 0 // Fs= 48kHz
+    CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
+                                            | I2S_CLKM_DIV_A_M
+                                            | I2S_CLKM_DIV_B_M));
+    I2S_SET_CLKA_ENA(1);
+    I2S_SET_CLKM_DIV_A(63);
+    I2S_SET_CLKM_DIV_B(32);
+    I2S_SET_CLKM_DIV_NUM(6);
+
+    CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
+    I2S_SET_RX_BCK_DIV_NUM(4);
+    I2S_SET_TX_BCK_DIV_NUM(2);
+    I2S_SET_TX_PDM_FS(480);
+#else
+    // Fs = 44.1kHz
+    CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), (I2S_CLKM_DIV_NUM_M | I2S_CLKM_DIV_A_M | I2S_CLKM_DIV_B_M));
+    SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_A_V, 64, I2S_CLKM_DIV_A_S);
+    SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_B_V,8, I2S_CLKM_DIV_B_S);
+    SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_NUM_V, 78, I2S_CLKM_DIV_NUM_S);
+    
+    CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
+    SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_V, 4, I2S_RX_BCK_DIV_NUM_S);
+    SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_TX_BCK_DIV_NUM_V, 2, I2S_TX_BCK_DIV_NUM_S);
+    SET_PERI_REG_BITS(I2S_PDM_FREQ_CONF_REG(i2sNum), I2S_TX_PDM_FS_V, 441, I2S_TX_PDM_FS_S);
+#endif
+
+#endif
+    CLEAR_PERI_REG_MASK(0x60009000, (0xf));
+    CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), 0x0f);
+
+
+#if 0 // Fs= 48kHz
+        CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
+                        |I2S_CLKM_DIV_A_M
+                        |I2S_CLKM_DIV_B_M));
+        I2S_SET_CLKA_ENA(1);
+        I2S_SET_CLKM_DIV_A(63);
+        I2S_SET_CLKM_DIV_B(32);
+        I2S_SET_CLKM_DIV_NUM(6);
+
+        CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M |I2S_TX_BCK_DIV_NUM_M);
+        I2S_SET_RX_BCK_DIV_NUM(4);
+        I2S_SET_TX_BCK_DIV_NUM(2);
+        I2S_SET_TX_PDM_FS(480);
+#else
+    // Fs = 44.1kHz
+        CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), (I2S_CLKM_DIV_NUM_M
+                    |I2S_CLKM_DIV_A_M
+                    |I2S_CLKM_DIV_B_M));
+        SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_A_V,64,I2S_CLKM_DIV_A_S);
+        SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_B_V,8,I2S_CLKM_DIV_B_S);
+        SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_NUM_V,78,I2S_CLKM_DIV_NUM_S);
+
+        CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_M |I2S_TX_BCK_DIV_NUM_M);
+        SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum),I2S_RX_BCK_DIV_NUM_V,4,I2S_RX_BCK_DIV_NUM_S);
+        SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum),I2S_TX_BCK_DIV_NUM_V,8,I2S_TX_BCK_DIV_NUM_S);
+        SET_PERI_REG_BITS(I2S_PDM_FREQ_CONF_REG(i2sNum),I2S_TX_PDM_FS_V,441,I2S_TX_PDM_FS_S);
+
+#endif
+        CLEAR_PERI_REG_MASK(0x60009000,(0xf));
+        CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum),0x0f);
+}
+
+/**
+ * @brief Reset I2s with a given module.
+ *
+ */
+void i2s_reset(i2s_num_t i2sNum)
+{
+    SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_RESET_M);
+    SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_RESET_M);
+    SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_FIFO_RESET_M);
+    SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_FIFO_RESET_M);
+
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_RESET_M);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_RESET_M);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_FIFO_RESET_M);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_FIFO_RESET_M);
+}
+
+/**
+ * @brief Initialize the I2S module
+ *
+ */
+void i2s_init(i2s_num_t i2sNum, i2s_attr_t *pAttr)
+{
+    if ((i2sNum > I2S_NUM_MAX)
+        || (NULL == pAttr)) {
+        return ;
+    }
+    if (i2sNum == I2S_NUM_I2S0) {
+        SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+        CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+    } else if (i2sNum == I2S_NUM_I2S1) {
+        SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
+        CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
+    }
+
+    // configure I2S data port interface.
+    CLEAR_PERI_REG_MASK(I2S_CONF2_REG(i2sNum), I2S_LCD_EN);
+    CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PCM2PDM_CONV_EN | I2S_PDM2PCM_CONV_EN);
+    SET_PERI_REG_BITS(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0x1, RTC_CNTL_SOC_CLK_SEL_S);
+
+    if (0 != pAttr->rx_mode.mode) {
+        if (I2S_IFACE_TYPE_DMA == pAttr->rx_mode.iface) {
+            SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
+        } else {
+            CLEAR_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
+        }
+        // Working mode
+        if (I2S_MODE_MASTER_RX == pAttr->rx_mode.mode) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_SLAVE_MOD);
+            // configure I2S communication standard format
+            i2s_clk_set(pAttr->rx_mode.rate, pAttr->rx_mode.bits);
+        } else if (I2S_MODE_SLAVE_RX == pAttr->rx_mode.mode) {
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_SLAVE_MOD);
+        } else {
+            // To do nothing.
+        }
+        // configure I2S communication standard format
+        if (I2S_STD_FORMAT_I2S == pAttr->rx_mode.std) {
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_MSB_SHIFT);
+            CLEAR_PERI_REG_MASK(I2S_CONF1_REG(i2sNum), I2S_RX_SHORT_SYNC);
+        } else if (I2S_STD_FORMAT_MSB == pAttr->rx_mode.std) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_MSB_SHIFT);
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
+        } else if (I2S_STD_FORMAT_LSB == pAttr->rx_mode.std) {
+
+        } else if (I2S_STD_FORMAT_PCM_SHORT == pAttr->rx_mode.std) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_MSB_SHIFT);
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_SHORT_SYNC);
+        } else if (I2S_STD_FORMAT_PCM_LONG == pAttr->rx_mode.std) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_MSB_SHIFT);
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_RX_SHORT_SYNC);
+        } else {
+            // To do nothing.
+        }
+        // configure bit width format.
+        SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BITS_MOD, pAttr->rx_mode.bits, I2S_RX_BITS_MOD_S);
+
+        SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_FORCE_EN);
+        // setting channel mode.
+        if (I2S_CHANNEL_FMT_RIGHT_LEFT == pAttr->rx_mode.channel) {
+            // set rx,tx channel mode, both are "two channel" here
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_RIGHT_LEFT, I2S_RX_CHAN_MOD_S);// 0-two channel;1-right;2-left
+        } else if (I2S_CHANNEL_FMT_ALL_RIGHT == pAttr->rx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_RIGHT, I2S_RX_CHAN_MOD_S);
+        } else if (I2S_CHANNEL_FMT_ALL_LEFT == pAttr->rx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_LEFT, I2S_RX_CHAN_MOD_S);
+        } else if (I2S_CHANNEL_FMT_ONLY_RIGHT == pAttr->rx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 1, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, 1, I2S_RX_CHAN_MOD_S);
+        } else if (I2S_CHANNEL_FMT_ONLY_LEFT == pAttr->rx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 1, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, 2, I2S_RX_CHAN_MOD_S);
+        } else {
+            // To do nothing.
+        }
+
+        if (I2S_MODULE_WORK_TYPE_PDM == pAttr->rx_mode.type) {
+            if (PDM_SAMPLE_RATE_RATIO_64 == pAttr->rx_mode.ratio) {
+                CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_SINC_DSR_16_EN); // Clear:64*fs;set:128*fs
+            } else if (PDM_SAMPLE_RATE_RATIO_128 == pAttr->rx_mode.ratio) {
+                SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_SINC_DSR_16_EN); // Clear:64*fs;set:128*fs
+            }
+            if (PDM_PCM_CONV_ENABLE == pAttr->rx_mode.conv) {
+                SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
+            } else if (PDM_PCM_CONV_DISABLE == pAttr->rx_mode.conv) {
+                CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
+            }
+        }
+    }
+
+    if (0 != pAttr->tx_mode.mode) {
+        if (I2S_IFACE_TYPE_DMA == pAttr->tx_mode.iface) {
+            SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
+        } else {
+            CLEAR_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
+        }
+
+        if (I2S_MODE_MASTER_TX == pAttr->tx_mode.mode) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SLAVE_MOD);
+            // configure I2S communication standard format
+            i2s_clk_set(pAttr->tx_mode.rate, pAttr->tx_mode.bits);
+          //  rtc_plla_ena(1, 621, 14);
+          //  SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKA_ENA);
+            printf("rtc_plla_ena is ok\r\n");
+        } else if (I2S_MODE_SLAVE_RX == pAttr->tx_mode.mode) {
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_SLAVE_MOD);
+        } else {
+            // To do nothing.
+        }
+        // configure I2S communication standard format
+        if (I2S_STD_FORMAT_I2S == pAttr->tx_mode.std) {
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_MSB_SHIFT);
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_SHORT_SYNC);
+        } else if (I2S_STD_FORMAT_MSB == pAttr->tx_mode.std) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_MSB_SHIFT);
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_SHORT_SYNC);
+        } else if (I2S_STD_FORMAT_LSB == pAttr->tx_mode.std) {
+
+        } else if (I2S_STD_FORMAT_PCM_SHORT == pAttr->tx_mode.std) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_MSB_SHIFT);
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_SHORT_SYNC);
+        } else if (I2S_STD_FORMAT_PCM_LONG == pAttr->tx_mode.std) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_MSB_SHIFT);
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum),  I2S_TX_SHORT_SYNC);
+        } else {
+            // To do nothing.
+        }
+        // configure bit width format.
+        SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_TX_BITS_MOD, pAttr->tx_mode.bits, I2S_TX_BITS_MOD_S);
+        SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_FORCE_EN);
+
+        if (I2S_CHANNEL_FMT_RIGHT_LEFT == pAttr->tx_mode.channel) {
+            // set rx,tx channel mode, both are "two channel" here
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_RIGHT_LEFT, I2S_TX_CHAN_MOD_S);// 0-two channel;1-right;2-left
+        } else if (I2S_CHANNEL_FMT_ALL_RIGHT == pAttr->tx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_RIGHT, I2S_TX_CHAN_MOD_S);
+        } else if (I2S_CHANNEL_FMT_ALL_LEFT == pAttr->tx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_LEFT, I2S_TX_CHAN_MOD_S);
+        } else if (I2S_CHANNEL_FMT_ONLY_RIGHT == pAttr->tx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 1, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, 1, I2S_TX_CHAN_MOD_S);
+        } else if (I2S_CHANNEL_FMT_ONLY_LEFT == pAttr->tx_mode.channel) {
+            SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 1, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
+            SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, 2, I2S_TX_CHAN_MOD_S);
+        } else {
+            // To do nothing.
+        }
+        if (I2S_MODULE_WORK_TYPE_PDM == pAttr->tx_mode.type) {
+            if (PDM_SAMPLE_RATE_RATIO_64 == pAttr->tx_mode.ratio) {
+                SET_PERI_REG_BITS(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_SINC_OSR2_M, 1, I2S_TX_PDM_SINC_OSR2_S); // TX: 2---128*fs;1---64*fs
+            } else if (PDM_SAMPLE_RATE_RATIO_128 == pAttr->tx_mode.ratio) {
+                SET_PERI_REG_BITS(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_SINC_OSR2_M, 2, I2S_TX_PDM_SINC_OSR2_S); // TX: 2---128*fs;1---64*fs
+            }
+            if (PDM_PCM_CONV_ENABLE == pAttr->rx_mode.conv) {
+                SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
+            } else if (PDM_PCM_CONV_DISABLE == pAttr->rx_mode.conv) {
+                CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
+            }
+        }
+    }
+    // Clear all of the interrupt sources.
+    WRITE_PERI_REG(I2S_INT_CLR_REG(i2sNum), 0xffffffff);
+}
+
+/**
+ * @brief Enable the interrupt source.
+ *
+ */
+void i2s_int_enable(i2s_num_t i2sNum, i2s_int_src_t intSrc)
+{
+    SET_PERI_REG_MASK(I2S_INT_ENA_REG(i2sNum), intSrc);
+}
+
+/**
+ * @brief Disable the interrupt source.
+ *
+ */
+void i2s_int_disable(i2s_num_t i2sNum, i2s_int_src_t intSrc)
+{
+    CLEAR_PERI_REG_MASK(I2S_INT_ENA_REG(i2sNum), intSrc);
+}
+
+/**
+ * @brief Clear the interrupt source.
+ *
+ */
+void i2s_int_clear(i2s_num_t i2sNum, i2s_int_src_t intSrc)
+{
+    SET_PERI_REG_MASK(I2S_INT_CLR_REG(i2sNum), intSrc);
+}
+
+/**
+ * @brief Get the I2S interrupt status
+ */
+uint32_t i2s_int_status_get(i2s_num_t i2sNum)
+{
+    return READ_PERI_REG(I2S_INT_ST_REG(i2sNum));
+}
+
+/**
+ * @brief Start I2S work
+ *
+ */
+void i2s_start(i2s_module_work_type_t type, i2s_num_t i2sNum, i2s_mode_t mode)
+{
+    if (i2sNum > I2S_NUM_MAX) {
+        return;
+    }
+    if (I2S_MODULE_WORK_TYPE_I2S == type) {
+        if ((I2S_MODE_MASTER_RX == mode)
+            || (I2S_MODE_SLAVE_RX == mode)) {
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
+            SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
+        } else if ((I2S_MODE_MASTER_TX == mode)
+                   || (I2S_MODE_SLAVE_TX == mode)) {
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
+            SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
+        }
+    } else if (I2S_MODULE_WORK_TYPE_PDM == type) {
+        if ((I2S_MODE_MASTER_RX == mode)
+            || (I2S_MODE_SLAVE_RX == mode)) {
+            SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_EN);
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
+        } else if ((I2S_MODE_MASTER_TX == mode)
+                   || (I2S_MODE_SLAVE_TX == mode)) {
+            SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_EN);
+            SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
+        }
+    }
+}
+
+/**
+ * @brief Stop I2S work
+ *
+ */
+void i2s_stop(i2s_module_work_type_t type, i2s_num_t i2sNum, i2s_mode_t mode)
+{
+    if (i2sNum > I2S_NUM_MAX) {
+        return;
+    }
+    if (I2S_MODULE_WORK_TYPE_I2S == type) {
+        if ((I2S_MODE_MASTER_RX == mode)
+            || (I2S_MODE_SLAVE_RX == mode)) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
+            SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
+        } else if ((I2S_MODE_MASTER_TX == mode)
+                   || (I2S_MODE_SLAVE_TX == mode)) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
+        }
+    } else if (I2S_MODULE_WORK_TYPE_PDM == type) {
+        if ((I2S_MODE_MASTER_RX == mode)
+            || (I2S_MODE_SLAVE_RX == mode)) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
+            CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_EN);
+        } else if ((I2S_MODE_MASTER_TX == mode)
+                   || (I2S_MODE_SLAVE_TX == mode)) {
+            CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
+            CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_EN);
+        }
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 1077 - 0
examples/09_a2dp/components/MediaHal/Driver/psram.c

@@ -0,0 +1,1077 @@
+#include "esp_types.h"
+#include "rom/ets_sys.h"
+#include "psram.h"
+//#include "spi.h"
+#include "soc/io_mux_reg.h"
+#include "soc/dport_reg.h"
+#include "rom/gpio.h"
+#include "soc/gpio_sig_map.h"
+#include "esp_attr.h"
+#include "rom/cache.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/timers.h"
+#include "freertos/task.h"
+#include "string.h"
+#include "rom/spi_flash.h"
+#include "esp_err.h"
+
+static psram_cache_mode_t g_PsramMode = PSRAM_CACHE_MAX;
+extern void Cache_Flush(int);
+
+//For now, we only use F40M + S40M, and we don't have to go through gpio matrix
+#define GPIO_MATRIX_FOR_40M   0
+static int extra_dummy = 0;
+
+typedef enum {
+    PSRAM_CMD_QPI,
+    PSRAM_CMD_SPI,
+} psram_cmd_mode_t;
+
+typedef struct {
+    uint16_t cmd;                /*!< Command value */
+    uint16_t cmdBitLen;          /*!< Command byte length*/
+    uint32_t *addr;              /*!< Point to address value*/
+    uint16_t addrBitLen;         /*!< Address byte length*/
+    uint32_t *txData;            /*!< Point to send data buffer*/
+    uint16_t txDataBitLen;       /*!< Send data byte length.*/
+    uint32_t *rxData;            /*!< Point to recevie data buffer*/
+    uint16_t rxDataBitLen;       /*!< Recevie Data byte length.*/
+    uint32_t dummyBitLen;
+} psram_cmd_t;
+
+static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode);
+
+
+
+static void psram_clear_spi_fifo(psram_spi_num_t spiNum)
+{
+	int i;
+	for(i=0;i<16;i++){
+		WRITE_PERI_REG(SPI_W0_REG(spiNum)+i*4,0);
+	}
+}
+
+static void disp_fifo(psram_spi_num_t spiNum)
+{
+    int i;
+    for(i=0;i<16;i++){
+        ets_printf(" FIFO[%d]: 0x%08x\n",i, READ_PERI_REG(SPI_W0_REG(spiNum)+i*4));
+    }
+}
+
+//set basic SPI write mode
+static void psram_set_basic_write_mode(psram_spi_num_t spiNum)
+{
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_QIO); //F WRITE QIO
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_DIO); //F WRITE DIO
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_QUAD); //F WRITE QUAD
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_DUAL); //F WRITE DUAL
+}
+//set QPI write mode
+static void psram_set_qio_write_mode(psram_spi_num_t spiNum)
+{
+    SET_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_QIO); //F WRITE QIO
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_DIO); //F WRITE DIO
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_QUAD); //F WRITE QUAD
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),SPI_FWRITE_DUAL); //F WRITE DUAL
+}
+//set QPI read mode
+static void psram_set_qio_read_mode(psram_spi_num_t spiNum)
+{
+    SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_QIO); //f read qio
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_QUAD); //f read quad
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_DUAL); //f read dual
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_DIO); //f read dio
+}
+//set SPI read mode
+static void psram_set_basic_read_mode(psram_spi_num_t spiNum)
+{
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_QIO); //f read qio
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_QUAD); //f read quad
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_DUAL); //f read dual
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum),SPI_FREAD_DIO); //f read dio
+}
+
+//start sending and wait for finishing
+static IRAM_ATTR void psram_cmd_start(psram_spi_num_t spiNum, psram_cmd_mode_t cmd_mode)
+{
+    //get cs1
+    CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS1_DIS_M);
+    SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS0_DIS_M);
+
+    uint32_t wr_mode_bkp = (READ_PERI_REG(SPI_USER_REG(spiNum)) >> SPI_FWRITE_DUAL_S) & 0xf;
+    uint32_t rd_mode_bkp = READ_PERI_REG(SPI_CTRL_REG(spiNum)) & (SPI_FREAD_DIO_M|SPI_FREAD_DUAL_M|SPI_FREAD_QUAD_M|SPI_FREAD_QIO_M);
+    if(cmd_mode == PSRAM_CMD_SPI) {
+        psram_set_basic_write_mode(spiNum);
+        psram_set_basic_read_mode(spiNum);
+    } else if (cmd_mode == PSRAM_CMD_QPI) {
+        psram_set_qio_write_mode(spiNum);
+        psram_set_qio_read_mode(spiNum);
+    }
+
+    //WAIT SPI0 IDLE
+    //READ THREE TIMES TO MAKE SURE?
+    while( READ_PERI_REG(SPI_EXT2_REG(0))!= 0);
+    while( READ_PERI_REG(SPI_EXT2_REG(0))!= 0);
+    while( READ_PERI_REG(SPI_EXT2_REG(0))!= 0);
+    SET_PERI_REG_MASK( DPORT_HOST_INF_SEL_REG, 1<<14);
+
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
+    while ((READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR));
+
+    CLEAR_PERI_REG_MASK( DPORT_HOST_INF_SEL_REG, 1<<14);
+
+    //recover spi mode
+    SET_PERI_REG_BITS(SPI_USER_REG(spiNum), 0xf, wr_mode_bkp, SPI_FWRITE_DUAL_S);
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), (SPI_FREAD_DIO_M|SPI_FREAD_DUAL_M|SPI_FREAD_QUAD_M|SPI_FREAD_QIO_M));
+    SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), rd_mode_bkp);
+
+    //return cs to cs0
+    SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1),SPI_CS1_DIS_M);
+    CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1),SPI_CS0_DIS_M);
+}
+
+//start sending cmd/addr and receving data
+static void IRAM_ATTR psram_recv_start(psram_spi_num_t spiNum,uint32_t* pRxData,uint16_t rxByteLen, psram_cmd_mode_t cmd_mode)
+{
+    //get cs1
+    CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS1_DIS_M);
+    SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS0_DIS_M);
+
+    uint32_t cmd_mode_bkp = (READ_PERI_REG(SPI_USER_REG(spiNum)) >> SPI_FWRITE_DUAL_S) & 0xf;
+    uint32_t rd_mode_bkp = READ_PERI_REG(SPI_CTRL_REG(spiNum)) & (SPI_FREAD_DIO_M|SPI_FREAD_DUAL_M|SPI_FREAD_QUAD_M|SPI_FREAD_QIO_M);
+    if(cmd_mode == PSRAM_CMD_SPI) {
+        psram_set_basic_write_mode(spiNum);
+        psram_set_basic_read_mode(spiNum);
+    } else if (cmd_mode == PSRAM_CMD_QPI) {
+        psram_set_qio_write_mode(spiNum);
+        psram_set_qio_read_mode(spiNum);
+    }
+
+    //WAIT SPI0 IDLE
+    //READ THREE TIMES TO MAKE SURE?
+    while( READ_PERI_REG(SPI_EXT2_REG(0))!= 0);
+    while( READ_PERI_REG(SPI_EXT2_REG(0))!= 0);
+    while( READ_PERI_REG(SPI_EXT2_REG(0))!= 0);
+    SET_PERI_REG_MASK( DPORT_HOST_INF_SEL_REG, 1<<14);
+
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
+    while ((READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR));
+
+    CLEAR_PERI_REG_MASK( DPORT_HOST_INF_SEL_REG, 1<<14);
+
+    //recover spi mode
+    SET_PERI_REG_BITS(SPI_USER_REG(spiNum), 0xf, cmd_mode_bkp, SPI_FWRITE_DUAL_S);
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), (SPI_FREAD_DIO_M|SPI_FREAD_DUAL_M|SPI_FREAD_QUAD_M|SPI_FREAD_QIO_M));
+    SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), rd_mode_bkp);
+
+    //return cs to cs0
+    SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1),SPI_CS1_DIS_M);
+    CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1),SPI_CS0_DIS_M);
+
+	int idx = 0;
+	// Read data out
+	do {
+		*pRxData++ =  READ_PERI_REG(SPI_W0_REG(spiNum) + (idx << 2));
+	} while (++idx < ((rxByteLen / 4) + ((rxByteLen % 4) ? 1 : 0)));
+}
+
+//setup spi command/addr/data/dummy in user mode
+static int psram_cmd_config(psram_spi_num_t spiNum, psram_cmd_t* pInData)
+{
+    uint8_t idx = 0;
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+
+    // Set command by user.
+    if (pInData->cmdBitLen != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,pInData->cmdBitLen-1, SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+        // Load command,bit15-0 is cmd value.
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_VALUE, pInData->cmd, SPI_USR_COMMAND_VALUE_S);
+    } else {
+    	CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+    	SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pInData->addrBitLen != 0) {
+        SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,(pInData->addrBitLen- 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
+        // Set address
+        SET_PERI_REG_BITS(SPI_ADDR_REG(spiNum), SPI_USR_ADDR_VALUE, *pInData->addr, SPI_USR_ADDR_VALUE_S);
+    } else{
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,0, SPI_USR_ADDR_BITLEN_S);
+    }
+    // Set data by user.
+    uint32_t* pTxVal = pInData->txData;
+    if (pInData->txDataBitLen != 0 ) {
+    	// Enable MOSI
+    	SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+    	// Load send buffer
+        int len = ((pInData->txDataBitLen / 32) + ((pInData->txDataBitLen % 32) ? 1 : 0));
+        if(pTxVal != NULL) {
+            do {
+                WRITE_PERI_REG((SPI_W0_REG(spiNum) + (idx << 2)), *pTxVal++);
+            } while(++idx < len);
+        }
+    	// Set data send buffer length.Max data length 64 bytes.
+    	SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN, (pInData->txDataBitLen - 1), SPI_USR_MOSI_DBITLEN_S);
+    } else {
+    	CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+    	SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,0, SPI_USR_MOSI_DBITLEN_S);
+    }
+    // Set rx data by user.
+    if (pInData->rxDataBitLen != 0  ) {
+        // Enable MOSI
+    	SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+    	// Set data send buffer length.Max data length 64 bytes.
+    	SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, (pInData->rxDataBitLen -1  ), SPI_USR_MISO_DBITLEN_S);
+    } else {
+    	CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+    	SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, 0, SPI_USR_MISO_DBITLEN_S);
+    }
+    if(pInData->dummyBitLen != 0){
+    	SET_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1),SPI_USR_DUMMY); // dummy en
+    	SET_PERI_REG_BITS(SPI_USER1_REG(PSRAM_SPI_1),SPI_USR_DUMMY_CYCLELEN_V,pInData->dummyBitLen-1,SPI_USR_DUMMY_CYCLELEN_S);  //DUMMY
+    }else{
+    	CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1),SPI_USR_DUMMY); // dummy en
+    	SET_PERI_REG_BITS(SPI_USER1_REG(PSRAM_SPI_1),SPI_USR_DUMMY_CYCLELEN_V,0,SPI_USR_DUMMY_CYCLELEN_S);  //DUMMY
+    }
+    return 0;
+}
+
+//read psram data in fast read mode
+static void psram_read_data(psram_spi_num_t spiNum,uint32_t* dst,uint32_t src,uint32_t len)
+{
+	uint32_t addr = 0;
+	uint32_t dummy_bits = 0;
+	psram_cmd_t pDat;
+	addr = (PSRAM_FAST_READ <<24) | src;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+			dummy_bits = 4+extra_dummy;
+			pDat.cmdBitLen = 0;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			dummy_bits = 4+extra_dummy;
+			pDat.cmdBitLen = 2;
+			break;
+	}
+	pDat.cmd = 0;
+	pDat.addr = &addr;
+	pDat.addrBitLen = 4*8;
+	pDat.txDataBitLen = 0;
+	pDat.txData = NULL;
+	pDat.rxDataBitLen = len*8 ;
+	pDat.rxData = dst;
+	pDat.dummyBitLen = dummy_bits;
+	psram_cmd_config(spiNum,&pDat);
+	psram_clear_spi_fifo(spiNum);
+	psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_QPI);
+}
+
+//read psram data in fast read quad mode
+static void psram_read_data_quad(psram_spi_num_t spiNum,uint32_t* dst,uint32_t src,uint32_t len)
+{
+	uint32_t addr = (PSRAM_FAST_READ_QUAD <<24) | src;
+	uint32_t dummy_bits = 0;
+	psram_cmd_t pDat;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+			dummy_bits = 6+extra_dummy;
+			pDat.cmdBitLen = 0;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			dummy_bits = 6+extra_dummy;
+			pDat.cmdBitLen = 2;
+			break;
+	}
+	pDat.cmd = 0;
+	pDat.addr = &addr;
+	pDat.addrBitLen = 4*8;
+	pDat.txDataBitLen = 0;
+	pDat.txData = NULL;
+	pDat.rxDataBitLen = len*8 ;
+	pDat.rxData = dst;
+	pDat.dummyBitLen = dummy_bits;
+	psram_cmd_config(spiNum,&pDat);
+	psram_clear_spi_fifo(spiNum);
+	psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_QPI);
+}
+
+//write data to psram
+static void psram_write_data(uint32_t dst,uint32_t* src,uint32_t len)
+{
+	uint32_t addr = (PSRAM_QUAD_WRITE <<24) | dst;
+	psram_cmd_t pDat;
+	int dummy_bits = 0;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+		    dummy_bits = 0 + 0;
+			pDat.cmdBitLen = 0;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+		    dummy_bits = 0 + 0;
+			pDat.cmdBitLen = 2;
+			break;
+	}
+	pDat.cmd = 0;
+	pDat.addr = &addr;
+	pDat.addrBitLen = 32;
+	pDat.txData = src;
+	pDat.txDataBitLen = len*8;
+	pDat.rxData = NULL;
+	pDat.rxDataBitLen = 0;
+	pDat.dummyBitLen = dummy_bits;
+	psram_cmd_config(PSRAM_SPI_1, &pDat);
+	psram_cmd_start(PSRAM_SPI_1, PSRAM_CMD_QPI);
+}
+
+static void psram_dma_cmd_write_config(uint32_t dst, uint32_t len, uint32_t dummy_bits)
+{
+    uint32_t addr = (PSRAM_QUAD_WRITE << 24) | dst;
+    psram_cmd_t pDat;
+    switch(g_PsramMode) {
+        case PSRAM_CACHE_F80M_S80M:
+            pDat.cmdBitLen = 0;
+            break;
+        case PSRAM_CACHE_F80M_S40M:
+        case PSRAM_CACHE_F40M_S40M:
+        default:
+            pDat.cmdBitLen = 2;
+            break;
+    }
+    pDat.cmd = 0;
+    pDat.addr = &addr;
+    pDat.addrBitLen = 32;
+    pDat.txData = NULL;
+    pDat.txDataBitLen = len * 8;
+    pDat.rxData = NULL;
+    pDat.rxDataBitLen = 0;
+    pDat.dummyBitLen = dummy_bits;
+    psram_cmd_config(PSRAM_SPI_1, &pDat);
+}
+
+static void psram_dma_qio_read_config(psram_spi_num_t spiNum, uint32_t src, uint32_t len)
+{
+    uint32_t addr = (PSRAM_FAST_READ_QUAD <<24) | src;
+    uint32_t dummy_bits = 0;
+    psram_cmd_t pDat;
+    switch(g_PsramMode){
+        case PSRAM_CACHE_F80M_S80M:
+            dummy_bits = 6+extra_dummy;
+            pDat.cmdBitLen = 0;
+            break;
+        case PSRAM_CACHE_F80M_S40M:
+        case PSRAM_CACHE_F40M_S40M:
+        default:
+            dummy_bits = 6+extra_dummy;
+            pDat.cmdBitLen = 2;
+            break;
+    }
+    pDat.cmd = 0;
+    pDat.addr = &addr;
+    pDat.addrBitLen = 4*8;
+    pDat.txDataBitLen = 0;
+    pDat.txData = NULL;
+    pDat.rxDataBitLen = len*8 ;
+    pDat.rxData = NULL;
+    pDat.dummyBitLen = dummy_bits;
+    psram_cmd_config(spiNum,&pDat);
+//    psram_clear_spi_fifo(spiNum);
+}
+
+//read psram id
+static void psram_read_id(uint32_t* dev_id)
+{
+	psram_spi_num_t spiNum = PSRAM_SPI_1;
+//	psram_set_basic_write_mode(spiNum);
+//	psram_set_basic_read_mode(spiNum);
+	uint32_t addr = (PSRAM_DEVICE_ID <<24) | 0;
+	uint32_t dummy_bits = 0;
+	psram_cmd_t pDat;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+			dummy_bits = 0+extra_dummy;
+			pDat.cmdBitLen = 0;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			dummy_bits = 0+extra_dummy;
+			pDat.cmdBitLen = 2;   //this two bits is used for delay one byte in qio mode
+			break;
+	}
+	pDat.cmd = 0;
+	pDat.addr = &addr;
+	pDat.addrBitLen = 4*8;
+	pDat.txDataBitLen = 0;
+	pDat.txData = NULL;
+	pDat.rxDataBitLen = 4*8 ;
+	pDat.rxData = dev_id;
+	pDat.dummyBitLen = dummy_bits;
+	psram_cmd_config(spiNum,&pDat);
+	psram_clear_spi_fifo(spiNum);
+	psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_SPI);
+}
+
+//switch psram burst length(32 bytes or 1024 bytes)
+//datasheet says it should be 1024 bytes by default
+//but they sent us a correction doc and told us it is 32 bytes for these samples
+static void psram_set_burst_length(psram_spi_num_t spiNum)
+{
+	psram_cmd_t pDat;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+			pDat.cmd = 0xC0;
+			pDat.cmdBitLen = 8;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			pDat.cmd = 0x0030;
+			pDat.cmdBitLen = 10;
+			break;
+	}
+	pDat.addr = 0;
+	pDat.addrBitLen = 0;
+	pDat.txData = NULL;
+	pDat.txDataBitLen = 0;
+	pDat.rxData = NULL;
+	pDat.rxDataBitLen = 0;
+	pDat.dummyBitLen = 0;
+	psram_cmd_config(spiNum, &pDat);
+	psram_cmd_start(spiNum, PSRAM_CMD_QPI);
+}
+
+//send reset command to psram(right now,we only send this command in QPI mode)
+//seems not working
+static void psram_reset_mode(psram_spi_num_t spiNum)
+{
+	psram_cmd_t pDat;
+	uint32_t cmd_rst = 0x99066;
+	pDat.txData = &cmd_rst;
+	pDat.txDataBitLen = 20;
+	pDat.addr = NULL;
+	pDat.addrBitLen = 0;
+	pDat.cmd = 0;
+	pDat.cmdBitLen = 0;
+	pDat.rxData = NULL;
+	pDat.rxDataBitLen = 0;
+	pDat.dummyBitLen = 0;
+	psram_cmd_config(spiNum, &pDat);
+	psram_cmd_start(spiNum, PSRAM_CMD_QPI);
+}
+//exit QPI mode(set back to SPI mode)
+static void psram_disable_qio_mode(psram_spi_num_t spiNum)
+{
+	psram_cmd_t pDat;
+	uint32_t cmd_exit_qpi;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+			cmd_exit_qpi = PSRAM_EXIT_QMODE;
+			pDat.txDataBitLen = 8;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			cmd_exit_qpi = PSRAM_EXIT_QMODE<<8;
+			pDat.txDataBitLen = 16;
+			break;
+	}
+	pDat.txData = &cmd_exit_qpi;
+	pDat.cmd = 0;
+	pDat.cmdBitLen = 0;
+	pDat.addr = 0;
+	pDat.addrBitLen = 0;
+	pDat.rxData = NULL;
+	pDat.rxDataBitLen = 0;
+	pDat.dummyBitLen = 0;
+	psram_cmd_config(spiNum, &pDat);
+	psram_cmd_start(spiNum, PSRAM_CMD_QPI);
+}
+//enter QPI mode
+static void IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spiNum)
+{
+	psram_cmd_t pDat;
+	switch(g_PsramMode){
+		case PSRAM_CACHE_F80M_S80M:
+			pDat.cmd = PSRAM_ENTER_QMODE;
+			pDat.cmdBitLen = 8;
+			break;
+		case PSRAM_CACHE_F80M_S40M:
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			pDat.cmd = 0x400d;
+			pDat.cmdBitLen = 10;
+			break;
+	}
+	pDat.addr = 0;
+	pDat.addrBitLen = 0;
+	pDat.txData = NULL;
+	pDat.txDataBitLen = 0;
+	pDat.rxData = NULL;
+	pDat.rxDataBitLen = 0;
+	pDat.dummyBitLen = 0;
+	psram_cmd_config(spiNum, &pDat);
+	psram_cmd_start(spiNum, PSRAM_CMD_SPI);
+}
+
+
+static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
+{
+    gpio_matrix_out(6, SPICLK_OUT_IDX, 0, 0);
+    gpio_matrix_out(11, SPICS0_OUT_IDX, 0, 0);
+
+	gpio_matrix_out(7, SPIQ_OUT_IDX, 0, 0);
+	gpio_matrix_in(7,SPIQ_IN_IDX, 0);
+	gpio_matrix_out(8, SPID_OUT_IDX, 0, 0);
+	gpio_matrix_in(8, SPID_IN_IDX, 0);
+	gpio_matrix_out(10, SPIWP_OUT_IDX, 0, 0);
+	gpio_matrix_in(10, SPIWP_IN_IDX, 0);
+	gpio_matrix_out(9, SPIHD_OUT_IDX, 0, 0);
+	gpio_matrix_in(9, SPIHD_IN_IDX, 0);
+
+	switch(mode){
+		case PSRAM_CACHE_F80M_S80M:
+		case PSRAM_CACHE_F80M_S40M:
+			SET_PERI_REG_MASK(SPI_USER_REG(0),SPI_USR_DUMMY); // dummy en
+			SET_PERI_REG_BITS(SPI_USER1_REG(0),SPI_USR_DUMMY_CYCLELEN_V,3+extra_dummy,SPI_USR_DUMMY_CYCLELEN_S);  //DUMMY
+			break;
+		case PSRAM_CACHE_F40M_S40M:
+		default:
+			SET_PERI_REG_MASK(SPI_USER_REG(0),SPI_USR_DUMMY); // dummy en
+			SET_PERI_REG_BITS(SPI_USER1_REG(0),SPI_USR_DUMMY_CYCLELEN_V,3+extra_dummy,SPI_USR_DUMMY_CYCLELEN_S);  //DUMMY
+			break;
+	}
+	//drive ability
+	SET_PERI_REG_BITS( PERIPHS_IO_MUX_SD_CLK_U,  FUN_DRV, 3 ,FUN_DRV_S);
+	SET_PERI_REG_BITS( PERIPHS_IO_MUX_SD_DATA0_U,FUN_DRV, 3 ,FUN_DRV_S);
+	SET_PERI_REG_BITS( PERIPHS_IO_MUX_SD_DATA1_U,FUN_DRV, 3 ,FUN_DRV_S);
+	SET_PERI_REG_BITS( PERIPHS_IO_MUX_SD_DATA2_U,FUN_DRV, 3 ,FUN_DRV_S);
+	SET_PERI_REG_BITS( PERIPHS_IO_MUX_SD_DATA3_U,FUN_DRV, 3 ,FUN_DRV_S);
+	SET_PERI_REG_BITS( PERIPHS_IO_MUX_SD_CMD_U,  FUN_DRV, 3 ,FUN_DRV_S);
+	//select pin function gpio
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U,2);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U,2);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U,2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U,2);
+
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U,2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U,2);
+}
+
+
+//spi param init for psram
+void IRAM_ATTR  psram_spi_init(psram_spi_num_t spiNum,psram_cache_mode_t mode)
+{
+	uint8_t i, k;
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE << 5);
+    SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);
+    // SPI_CPOL & SPI_CPHA
+    CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),  SPI_CK_OUT_EDGE);
+    // SPI bit order
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
+    CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
+    // SPI bit order
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
+    // May be not must to do.
+    WRITE_PERI_REG(SPI_USER1_REG(spiNum), 0);
+    // SPI mode type
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
+    switch(mode){
+    	case PSRAM_CACHE_F80M_S80M:
+    		WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
+    		break;
+    	case PSRAM_CACHE_F80M_S40M:
+    	case PSRAM_CACHE_F40M_S40M:
+    	default:
+    		i = (2 / 40) ? (2 / 40) : 1;
+    		k = 2 / i;
+    		CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK);
+    		WRITE_PERI_REG(SPI_CLOCK_REG(spiNum),
+    				(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
+    				(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
+    				((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
+    				(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
+    		break;
+    }
+    // Enable MOSI
+    SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI);
+    for (i = 0; i < 16; ++i) {
+        WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), 0);
+    }
+}
+
+
+//psram gpio init , different working frequency we have different solutions
+esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode)   //psram init
+{
+    WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG,BIT16|BIT17);//DISALBE OUPUT FOR IO16/17
+
+	g_PsramMode = mode;
+
+	SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,BIT16);//DPORT_SPI_CLK_EN
+	CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,BIT16);//DPORT_SPI_RST
+	SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,BIT1);//DPORT_SPI_CLK_EN_1
+	CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,BIT1);//DPORT_SPI_RST_1
+	SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,BIT6);//DPORT_SPI_CLK_EN_2
+	CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,BIT6);//DPORT_SPI_RST_2
+
+    WRITE_PERI_REG( SPI_EXT3_REG(0), 0x1);
+    CLEAR_PERI_REG_MASK( SPI_USER_REG(PSRAM_SPI_1), SPI_USR_PREP_HOLD_M);
+
+
+    switch(mode){
+    	case PSRAM_CACHE_F80M_S80M:
+    		psram_spi_init(PSRAM_SPI_1, mode);
+    		extra_dummy = 2;
+    		CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
+    		gpio_matrix_out(16, SPICS1_OUT_IDX, 0, 0);
+    		gpio_matrix_out(17, VSPICLK_OUT_MUX_IDX, 0, 0);
+    		//use spi3 clock,but use spi1 data/cs wires
+    		WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32<<24);
+    		WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3),SPI_CLK_EQU_SYSCLK_M);//SET 80M AND CLEAR OTHERS
+    		SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3),SPI_FLASH_READ_M);
+    		uint32_t spi_status;
+    		while(1){
+    			spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
+    			if(spi_status != 0 && spi_status != 1){
+    				CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,BIT16);//DPORT_SPI_CLK_EN
+    				break;
+    			}
+    		}
+    		break;
+    	case PSRAM_CACHE_F80M_S40M:
+    	case PSRAM_CACHE_F40M_S40M:
+    	default:
+#if GPIO_MATRIX_FOR_40M
+    	    extra_dummy = 1;
+#else
+    	    extra_dummy = 0;
+#endif
+    		psram_spi_init(PSRAM_SPI_1, mode);
+    		CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
+    		gpio_matrix_out(16, SPICS1_OUT_IDX, 0, 0);
+    		gpio_matrix_in(6,SIG_IN_FUNC224_IDX,0);
+    		gpio_matrix_out(20,SIG_IN_FUNC224_IDX,0,0);
+    		gpio_matrix_in(20,SIG_IN_FUNC225_IDX,0);
+    		gpio_matrix_out(17,SIG_IN_FUNC225_IDX,0,0);
+    		break;
+    }
+//    CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1),SPI_CS1_DIS_M);
+//    SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1),SPI_CS0_DIS_M);
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1),SPI_CS_SETUP_M);
+
+#if GPIO_MATRIX_FOR_40M
+    psram_gpio_config(mode);
+//    /* @param  uint32_t ishspi: 0 for spi, 1 for hspi, flash pad decided by strapping
+//    *              else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, bit[23:18] spics0, bit[29:24] spihd
+//    *
+//    * @return None
+//    */
+//    uint32_t ishspi = ( (6 & 0x3f) << 0)  //clk
+//                    | ( (7 & 0x3f) << 6)  //d0
+//                    | ( (8 & 0x3f) << 12)  //d1
+//                    | ( (11 & 0x3f) << 18) //cs
+//                    | ( (9 & 0x3f) << 24); //d2
+//    SelectSpiFunction(ishspi);
+//    spi_dummy_len_fix(1, 2);
+#endif
+
+
+    WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG,BIT16|BIT17);//GPIO_Pin_16 | GPIO_Pin_17
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U,2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U,2);
+
+    uint32_t id;
+    psram_read_id(&id);
+    if(((id >> 8) & 0xff )!= 0x5d) {
+        return ESP_FAIL;
+    }
+    psram_enable_qio_mode(PSRAM_SPI_1);
+    psram_cache_init(mode);
+    return ESP_OK;
+}
+
+//register initialization for sram cache params and r/w commands
+static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode)
+{
+    CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(0),SPI_CLK_EQU_SYSCLK_M);
+    SET_PERI_REG_BITS(SPI_CLOCK_REG(0),SPI_CLKDIV_PRE_V,0,SPI_CLKDIV_PRE_S);
+    SET_PERI_REG_BITS(SPI_CLOCK_REG(0),SPI_CLKCNT_N,1,SPI_CLKCNT_N_S);
+    SET_PERI_REG_BITS(SPI_CLOCK_REG(0),SPI_CLKCNT_H,0,SPI_CLKCNT_H_S);
+    SET_PERI_REG_BITS(SPI_CLOCK_REG(0),SPI_CLKCNT_L,1,SPI_CLKCNT_L_S);
+
+    switch(psram_cache_mode){
+    	case PSRAM_CACHE_F80M_S80M:
+    		CLEAR_PERI_REG_MASK(SPI_DATE_REG(0),BIT(31));//flash 1 div clk,80+40;
+    		CLEAR_PERI_REG_MASK(SPI_DATE_REG(0),BIT(30));//pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
+    	    WRITE_PERI_REG(SPI_CLOCK_REG(0),SPI_CLK_EQU_SYSCLK_M);//SET 1DIV CLOCK AND RESET OTHER PARAMS
+    	    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_USR_RD_SRAM_DUMMY_M);//enable cache read dummy
+    	    SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0),SPI_SRAM_DUMMY_CYCLELEN_V,3+extra_dummy,SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
+    	    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_CACHE_SRAM_USR_RCMD_M);//enable user mode for cache read command
+    	    break;
+    	case PSRAM_CACHE_F80M_S40M:
+    		SET_PERI_REG_MASK(SPI_DATE_REG(0),BIT(31));//flash 1 div clk
+    		CLEAR_PERI_REG_MASK(SPI_DATE_REG(0),BIT(30));//pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
+    	    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_USR_RD_SRAM_DUMMY_M);//enable cache read dummy
+    	    SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0),SPI_SRAM_DUMMY_CYCLELEN_V,3+extra_dummy,SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
+    	    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_CACHE_SRAM_USR_RCMD_M);//enable user mode for cache read command
+    		break;
+    	case PSRAM_CACHE_F40M_S40M:
+    	default:
+    		CLEAR_PERI_REG_MASK(SPI_DATE_REG(0),BIT(31));//flash 1 div clk
+    		CLEAR_PERI_REG_MASK(SPI_DATE_REG(0),BIT(30));//pre clk div
+    	    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_USR_RD_SRAM_DUMMY_M);//enable cache read dummy
+    	    SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0),SPI_SRAM_DUMMY_CYCLELEN_V,3+extra_dummy,SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
+    	    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_CACHE_SRAM_USR_RCMD_M);//enable user mode for cache read command
+    		break;
+    }
+    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_CACHE_SRAM_USR_WCMD_M);     // cache write command enable
+    SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0),SPI_SRAM_ADDR_BITLEN_V,23,SPI_SRAM_ADDR_BITLEN_S);//write address for cache command.
+    SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_USR_SRAM_QIO_M);//enable qio mode for cache command
+    CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0),SPI_USR_SRAM_DIO_M);//disable dio mode for cache command
+
+    //config sram cache r/w command
+    switch(psram_cache_mode) {
+        case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
+            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
+                SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
+            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, 0x38,
+                SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
+            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
+                SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
+            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, 0x0b,
+                SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
+            break;
+        case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
+        case PSRAM_CACHE_F40M_S40M:
+            default:
+            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
+                SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
+            SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, 0x0b00,
+                SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
+            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
+                SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
+            SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, 0x3800,
+                SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
+            break;
+    }
+    CLEAR_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL1_REG , DPORT_PRO_CACHE_MASK_DRAM1);//use Dram1 to visit ext sram.
+    SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CMMU_SRAM_PAGE_MODE, 0, DPORT_PRO_CMMU_SRAM_PAGE_MODE_S); //cache page mode : 1 -->16k  4 -->2k  0-->32k,(accord with the settings in cache_sram_mmu_set)
+    CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
+}
+
+typedef enum {
+    SPI_INT_SRC_TRANS_DONE = SPI_TRANS_DONE,
+    SPI_INT_SRC_WR_STA_DONE = SPI_SLV_WR_STA_DONE,
+    SPI_INT_SRC_RD_STA_DONE = SPI_SLV_RD_STA_DONE,
+    SPI_INT_SRC_WR_BUF_DONE = SPI_SLV_WR_BUF_DONE,
+    SPI_INT_SRC_RD_BUF_DONE = SPI_SLV_RD_BUF_DONE,
+    SPI_INT_SRC_ONE_BUF_RECV_DONE = SPI_IN_SUC_EOF_INT_ENA,
+    SPI_INT_SRC_ONE_BUF_SEND_DONE = SPI_OUT_EOF_INT_ENA,
+} spi_int_src_t;
+
+/**
+ * @brief DMA queue description.
+ */
+typedef struct {
+    uint32_t  block_size: 12;
+    uint32_t  data_length: 12;
+    uint32_t  unused: 5;
+    uint32_t  sub_sof: 1;
+    uint32_t  eof: 1;
+    uint32_t  owner: 1;
+    uint32_t  buf_ptr;
+    uint32_t  next_link_ptr;
+} dma_queue_t;
+
+/**
+ * @brief Initialize DMA and create a SPI DMA instance.
+ *
+ */
+//int spi_dma_init(spi_dma_attr_t *obj, void *isr)
+int psram_dma_tx(int dma_channel, uint32_t addr, uint32_t* buf, size_t data_len)
+{
+    int spi_num = 1;
+    // Reset DMA
+    SET_PERI_REG_MASK(SPI_DMA_CONF_REG(spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+    CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(spi_num), SPI_OUTLINK_START);
+    CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(spi_num), SPI_INLINK_START);
+    CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+
+    // Select DMA channel.
+    SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_channel, ((spi_num - 1) * 2));
+
+    SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_MOSI);//////add
+
+    // enable send intr
+    SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spi_num ), SPI_INT_SRC_ONE_BUF_SEND_DONE);
+    SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spi_num ), SPI_INT_SRC_ONE_BUF_RECV_DONE);
+
+    // Clear all of interrupt source
+    //spi_int_clear(obj->spi_num);
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spi_num), SPI_INT_SRC_TRANS_DONE
+                        | SPI_INT_SRC_WR_STA_DONE
+                        | SPI_INT_SRC_RD_STA_DONE
+                        | SPI_INT_SRC_WR_BUF_DONE
+                        | SPI_INT_SRC_RD_BUF_DONE);
+
+
+    dma_queue_t* dma_link = (dma_queue_t*) malloc( sizeof(dma_queue_t));
+    dma_link->block_size  = data_len;
+    dma_link->data_length = data_len;
+    dma_link->buf_ptr =  (uint32_t)buf;
+    dma_link->eof = 1;
+    dma_link->next_link_ptr = (uint32_t)NULL;
+    dma_link->owner = 1;//0: cpu  1: dma
+    dma_link->sub_sof = 0;
+    dma_link->unused = 0;
+
+    SET_PERI_REG_BITS(SPI_DMA_OUT_LINK_REG(spi_num), SPI_OUTLINK_ADDR, ((uint32_t )dma_link),
+        SPI_OUTLINK_ADDR_S);
+    SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(spi_num), SPI_OUTLINK_START);
+
+    // 1. Waiting DMA controller fill TX FIFO
+    while ((READ_PERI_REG(SPI_DMA_RSTATUS_REG(spi_num))&0x80000000));
+    psram_dma_cmd_write_config(addr, data_len, 0);
+    psram_cmd_start(spi_num, PSRAM_CMD_QPI);
+    free(dma_link);
+    return 0;
+}
+
+
+
+int psram_dma_rx(int dma_channel, uint32_t addr, uint32_t* buf, size_t data_len)
+{
+    int spi_num = 1;
+    // Reset DMA
+    SET_PERI_REG_MASK(SPI_DMA_CONF_REG(spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+    CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(spi_num), SPI_OUTLINK_START);
+    CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(spi_num), SPI_INLINK_START);
+    CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+
+    // Select DMA channel.
+    SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, DPORT_SPI3_DMA_CHAN_SEL_V, dma_channel, ((spi_num - 1) * 2));
+
+    SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_MISO);//////add
+
+    // enable send intr
+    SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spi_num ), SPI_INT_SRC_ONE_BUF_SEND_DONE);
+    SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spi_num ), SPI_INT_SRC_ONE_BUF_RECV_DONE);
+
+    // Clear all of interrupt source
+    //spi_int_clear(obj->spi_num);
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spi_num), SPI_INT_SRC_TRANS_DONE
+                        | SPI_INT_SRC_WR_STA_DONE
+                        | SPI_INT_SRC_RD_STA_DONE
+                        | SPI_INT_SRC_WR_BUF_DONE
+                        | SPI_INT_SRC_RD_BUF_DONE);
+
+
+    dma_queue_t* rx_dma_link = (dma_queue_t*) malloc( sizeof(dma_queue_t));
+    rx_dma_link->block_size  = data_len;
+    rx_dma_link->data_length = data_len;
+    rx_dma_link->buf_ptr =  (uint32_t)buf;
+    rx_dma_link->eof = 1;
+    rx_dma_link->next_link_ptr = (uint32_t)NULL;
+    rx_dma_link->owner = 1;//0: cpu  1: dma
+    rx_dma_link->sub_sof = 0;
+    rx_dma_link->unused = 0;
+
+    SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(spi_num), SPI_INLINK_ADDR, ((uint32_t )rx_dma_link),
+        SPI_INLINK_ADDR_S);
+    SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(spi_num), SPI_INLINK_START);
+
+    psram_dma_qio_read_config( spi_num, addr, data_len);
+    psram_cmd_start(spi_num, PSRAM_CMD_QPI);
+
+    //add semaphore to wait trans done, instead of while loop.
+    free(rx_dma_link);
+    return 0;
+}
+
+//---------------------------
+//--   below is test code  --
+//---------------------------
+#if 1
+void psram_write_once(uint32_t loop_num,uint32_t write_addr,uint32_t mode,uint32_t repeat)
+{
+//	psram_enable(PSRAM_CACHE_F80M_S40M);
+//	psram_enable_qio_mode(PSRAM_SPI_1);
+	uint32_t data_w[8];
+	int i;
+	for(i=0;i<8;i++) {
+		data_w[i]=  ((i+1)<<24)|((i+1)<<16)|((i+1)<<8)|(i+1);
+	}
+	ets_printf("WRITE DATA IN QMODE\n");
+	for(i = 0;i<loop_num;i++){
+		psram_write_data(write_addr+32*i,data_w,32);
+	}
+	vTaskDelay(500);
+}
+
+void psram_rw_loop_test(uint32_t loop_num,uint32_t write_addr,uint32_t mode,uint32_t repeat)
+{
+//	psram_enable(PSRAM_CACHE_F80M_S40M);
+//	psram_enable_qio_mode(PSRAM_SPI_1);
+	uint32_t data_w[8];
+	int i;
+	int test_num = 0;
+	do{
+		ets_printf("-----test num: %d------\n",test_num++);
+		ets_printf("---write----0x%08x\n",(test_num%2 == 0? 0x55555555:0xaaaaaaaa));
+		for(i=0;i<8;i++) {
+			data_w[i] = (test_num%2 == 0? 0x55555555:0xaaaaaaaa);
+		}
+		for(i = 0;i<loop_num;i++){
+			psram_write_data(write_addr+32*i,data_w,32);
+		}
+		ets_printf("----read----\n");
+		int fail_flg = 0;
+		uint32_t data_r[8]={0};
+		for(i = 0;i<loop_num;i++){
+			if((i%1000 == 0)){
+				ets_printf("addr [%d]: 0x%08x\n",i,write_addr+32*i);
+			}
+			memset(data_r,0,sizeof(data_r));
+			psram_clear_spi_fifo(PSRAM_SPI_1);
+			int dummy_num = 0;
+			psram_read_data_quad(PSRAM_SPI_1,data_r,write_addr+32*i,32);
+			int k = 0;
+			int ii = 0;
+			for(k=0;k<8;k++){
+				if(data_r[k] != (test_num%2 == 0? 0x55555555:0xaaaaaaaa)){
+					ets_printf("ERROR!!! @%d  [0x%08x]\n",k,write_addr+32*i);
+					ets_printf("data_r[%d] : 0x%08x\n",k,data_r[k]);
+					ets_printf("set val: 0x%08x\n",(test_num%2 == 0? 0x55555555:0xaaaaaaaa));
+					uint32_t vtmp = 0x9999;
+					psram_read_data(PSRAM_SPI_1,&vtmp,write_addr+32*i+k*4,4);
+					ets_printf("spi1 read again11 addr[0x%08x]: 0x%08x\n",write_addr+32*i+k*4,vtmp);
+					vtmp = 0x9999;
+					psram_read_data(PSRAM_SPI_1,&vtmp,write_addr+32*i+k*4,4);
+					ets_printf("spi1 read again22 addr[0x%08x]: 0x%08x\n",write_addr+32*i+k*4,vtmp);
+					for(ii = 0;ii<8;ii++){
+						//ets_printf("data[%d]: 0x%08x\n",ii,data_r[ii]);
+					}
+					fail_flg = 1;
+				}
+			}
+		}
+		if(fail_flg == 0){
+			ets_printf("TEST PASS!!!\n");
+			continue;
+		}
+		psram_clear_spi_fifo(PSRAM_SPI_1);
+		break;
+	}while(repeat == 0 ? 0 :1 );
+	ets_printf("TEST FAILED...\n");
+}
+
+void psram_read_test(uint32_t loop_num,uint32_t write_addr,uint32_t mode,uint32_t repeat)
+{
+	int i;
+	int test_num = 0;
+	do{
+		ets_printf("-----test num: %d------\n",test_num++);
+		int fail_flg = 0;
+		uint32_t data_r[8]={0};
+		for(i = 0;i<loop_num;i++){
+			if((i%100 == 0)){
+				ets_printf("addr [%d]: 0x%08x\n",i,write_addr+32*i);
+			}
+
+			memset(data_r,0,sizeof(data_r));
+			psram_clear_spi_fifo(PSRAM_SPI_1);
+			int dummy_num = 0;
+			psram_read_data(PSRAM_SPI_1,data_r,write_addr+32*i,32);
+			int k = 0;
+			int ii = 0;
+
+			for(k=0;k<8;k++){
+				if(data_r[k] != (((k+1)<<24)|((k+1)<<16)|((k+1)<<8)|(k+1))){
+					ets_printf("ERROR!!! @%d\n",k);
+					ets_printf("data_r[%d] : 0x%08x\n",k,data_r[k]);
+					ets_printf("set val: 0x%08x\n",(((k+1)<<24)|((k+1)<<16)|((k+1)<<8)|(k+1)));
+
+					for(ii = 0;ii<16;ii++){
+						ets_printf("data[%d]: 0x%08x\n",ii,data_r[ii]);
+					}
+					fail_flg = 1;
+					//return;
+				}
+			}
+		}
+		if(fail_flg == 0){
+			ets_printf("TEST PASS!!!\n");
+			continue;
+		}
+		psram_clear_spi_fifo(PSRAM_SPI_1);
+		break;
+	}while(repeat == 0 ? 0 :1 );
+}
+
+void psram_rw_test(uint32_t loop_num,uint32_t write_addr,uint32_t mode,uint32_t repeat)
+{
+//    psram_enable_qio_mode(PSRAM_SPI_1);
+    while(repeat--)
+    {
+        uint32_t data_w[16];
+        int i;
+        for(i = 0; i < 16; i++) {
+            data_w[i] = ((i + 1) << 24) | ((i + 1) << 16) | ((i + 1) << 8) | (i + 1);
+        }
+        ets_printf("WRITE DATA IN QMODE\n");
+        for(i = 0; i < loop_num; i++) {
+            psram_write_data(write_addr + 32 * i, data_w, 32);
+        }
+//        vTaskDelay(500);
+        int fail_flg = 0;
+        uint32_t data_r[16] = {0};
+        memset(data_r, 0, sizeof(data_r));
+        for(i = 0; i < loop_num; i++) {
+            if((i % 10 == 0)) {
+                ets_printf("addr i: %d\n", i);
+            }
+            memset(data_r, 0, sizeof(data_r));
+            psram_clear_spi_fifo(PSRAM_SPI_1);
+            int dummy_num = 0;
+            psram_read_data_quad(PSRAM_SPI_1, data_r, write_addr + 32 * i, 32);
+            int k = 0;
+            int ii = 0;
+            for(k = 0; k < 8; k++) {
+                if(data_r[k] != (((k + 1) << 24) | ((k + 1) << 16) | ((k + 1) << 8) | (k + 1))) {
+                    ets_printf("ERROR!!! @%d\n", k);
+                    ets_printf("data_r[%d] : 0x%08x\n", k, data_r[k]);
+                    ets_printf("set val: 0x%08x\n", (((k + 1) << 24) | ((k + 1) << 16) | ((k + 1) << 8) | (k + 1)));
+                    for(ii = 0; ii < 16; ii++) {
+                        ets_printf("data[%d]: 0x%08x\n", ii, data_r[ii]);
+                    }
+                    fail_flg = 1;
+                    return;
+                }
+            }
+        }
+        if(fail_flg == 0) {
+            ets_printf("TEST PASS!!!\n");
+        }
+        ets_printf("END OF TEST.\n");
+        psram_clear_spi_fifo(PSRAM_SPI_1);
+    }
+
+}
+#endif
+

+ 827 - 0
examples/09_a2dp/components/MediaHal/Driver/spi.c

@@ -0,0 +1,827 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+#include "spi.h"
+#include "soc/spi_reg.h"
+#include "soc/rtc_cntl_reg.h"
+#include "rom/ets_sys.h"
+#include "esp_intr.h"
+#include "soc/dport_reg.h"
+
+//*****************************************************************************
+//
+// Make sure all of the definitions in this header have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @brief Defines slave commands.Default value based on slave ESP8266 & ESP32.
+ */
+#define MASTER_WRITE_DATA_TO_SLAVE_CMD                      2
+#define MASTER_READ_DATA_FROM_SLAVE_CMD                     3
+#define MASTER_WRITE_STATUS_TO_SLAVE_CMD                    1
+#define MASTER_READ_STATUS_FROM_SLAVE_CMD                   4
+
+
+static void spi_intr_func_set(void * isr, spi_num_t spiNum)
+{
+    if (SPI_NUM_SPI1 == spiNum) {
+        intr_matrix_set(0, ETS_SPI1_DMA_INTR_SOURCE, ETS_SPI1_INUM);
+        ESP_SPI1_INTR_ATTACH(isr, NULL);
+        // enable intr in cpu
+        ESP_SPI1_INTR_ENABLE();
+    } else if (SPI_NUM_SPI2 == spiNum) {
+        intr_matrix_set(0, ETS_SPI2_DMA_INTR_SOURCE, ETS_SPI2_INUM);
+        ESP_SPI2_INTR_ATTACH(isr, NULL);
+        // enable intr in cpu
+        ESP_SPI2_INTR_ENABLE();
+    } else if (SPI_NUM_SPI3 == spiNum) {
+        intr_matrix_set(0, ETS_SPI3_DMA_INTR_SOURCE, ETS_SPI3_INUM);
+        ESP_SPI3_INTR_ATTACH(isr, NULL);
+        // enable intr in cpu
+        ESP_SPI3_INTR_ENABLE();
+    } else {
+        // To do nothing
+    }
+}
+#if 1
+
+/**
+ * @brief Get SPI ping buffer address.
+ *
+ */
+uint32_t* spi_dma_ping_buf_get(spi_dma_attr_t *obj)
+{
+    if (NULL == obj) {
+        return NULL;
+    }
+    return obj->buf->ping->buffer_addr;
+}
+
+/**
+ * @brief Get SPI ping buffer address.
+ *
+ */
+uint32_t* spi_dma_pong_buf_get(spi_dma_attr_t *obj)
+{
+    if (NULL == obj) {
+        return NULL;
+    }
+    return obj->buf->pong->buffer_addr;
+}
+
+/**
+ * @brief Get without work ping-pong buffer address.
+ *
+ */
+uint32_t* spi_dma_status_get(spi_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return NULL;
+    }
+    switch (obj->dir) {
+    case SPI_DMA_DIR_OUT:
+        if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue))  {
+            return obj->buf->ping->buffer_addr;
+        } else if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
+            return obj->buf->pong->buffer_addr;
+        }
+        break;
+    case SPI_DMA_DIR_IN:
+        if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
+            return obj->buf->ping->buffer_addr;
+        } else if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
+            return obj->buf->pong->buffer_addr;
+        }
+        break;
+    default:
+        break;
+    }
+    return NULL;
+}
+
+/**
+ * @brief Configrate the Ping-Pong buffer to the destination
+ *
+ */
+void spi_dma_dest_add_set(spi_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return;
+    }
+    if (SPI_DMA_DIR_IN == obj->dir) {
+        SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_INLINK_ADDR_S);
+    } else if (SPI_DMA_DIR_OUT == obj->dir) {
+        SET_PERI_REG_BITS(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_OUTLINK_ADDR_S);
+    }
+}
+
+/**
+ * @brief Reset SPI ping buffer address.
+ *
+ */
+void spi_dma_rest(spi_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return;
+    }
+    dma_buf_len_reset(obj->buf);
+}
+
+/**
+ * @brief Initialize DMA and create a SPI DMA instance.
+ *
+ */
+int spi_dma_init(spi_dma_attr_t *obj, void *isr)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return -1;
+    }
+    obj->buf = dma_buf_create(obj->buf_size);
+    if (NULL == obj->buf) {
+        return -2;
+    }
+    // Reset DMA
+    SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+    CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
+    CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
+    CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+
+    // Select DMA channel.
+    SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, obj->channel, ((obj->spi_num - 1) * 2));
+
+    SET_PERI_REG_MASK(SPI_USER_REG(obj->spi_num), SPI_USR_MOSI);//////add
+    if ((SPI_MODE_MASTER == obj->mode)) {
+        // enable send intr
+        SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_SEND_DONE);        
+        SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_RECV_DONE);
+        
+    } else if ((SPI_MODE_SLAVE == obj->mode)) {
+        SET_PERI_REG_MASK(SPI_SLV_RDBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
+        SET_PERI_REG_MASK(SPI_SLV_WRBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
+        // enable receive intr
+        SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num), SPI_INT_SRC_ONE_BUF_RECV_DONE);
+    }
+    // Clear all of interrupt source
+    spi_int_clear(obj->spi_num);
+
+    spi_intr_func_set(isr, obj->spi_num);
+    return 0;
+}
+
+/**
+ * @brief Destroy the SPI DMA instance
+ *
+ */
+int spi_dma_uninit(spi_dma_attr_t *obj)
+{
+    if (NULL == obj) {
+        return -1;
+    }
+    dma_buf_destroy(obj->buf);
+    return 0;
+}
+
+/**
+ * @brief Enable the SPI DMA work mode.
+ *
+ */
+static void spi_dma_enable(spi_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return;
+    }
+    
+    if (SPI_DMA_DIR_IN == obj->dir) {
+        WRITE_PERI_REG(0x3ff000c4,1<<22);
+        WRITE_PERI_REG(0x3ff000c4,0);
+        SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
+        SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
+       // LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
+       // while (((READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18)&0x3)!=0x3){
+       //LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
+       //  }
+    } else if (SPI_DMA_DIR_OUT == obj->dir) {
+        SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
+        SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
+        // Waiting DMA controller fill TX FIFO
+        while ((READ_PERI_REG(SPI_DMA_RSTATUS_REG(obj->spi_num))&0x80000000));
+    }
+}
+
+/**
+ * @brief Disable the SPI DMA work mode.
+ *
+ */
+static void spi_dma_disable(spi_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return;
+    }
+    if (SPI_DMA_DIR_IN == obj->dir) {
+        CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_STOP);
+    } else if (SPI_DMA_DIR_OUT == obj->dir) {
+        CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_STOP);
+    }
+}
+
+/**
+ * @brief Enable SPI DMA interrupt source.
+ *
+ */
+void  spi_dma_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
+}
+
+/**
+ * @brief Disable SPI DMA interrupt source.
+ *
+ */
+void  spi_dma_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
+}
+
+/**
+ * @brief Clear all of SPI DMA interrupt source.
+ *
+ */
+void  spi_dma_int_clear(spi_num_t spiNum)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    SET_PERI_REG_MASK(SPI_DMA_INT_CLR_REG(spiNum), 0x1FF);
+}
+
+/**
+ * @brief Get the SPI DMA interrupt status.
+ *
+ */
+int32_t spi_dma_int_status_get(spi_num_t spiNum)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return -1;
+    }
+    return READ_PERI_REG(SPI_DMA_INT_ST_REG(spiNum));
+}
+
+/**
+ * @brief Start SPI work by DMA
+ *
+ */
+void spi_dma_start(spi_dma_attr_t *obj, uint32_t len)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return;
+    }
+    // Reset DMA controller
+
+    SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+    CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
+    
+    if (SPI_MODE_MASTER == obj->mode) {
+        CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
+        if (obj->dir == SPI_DMA_DIR_IN) {
+            SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
+            SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S); 
+        }else{
+            SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
+            SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);  
+        }
+    } else if (SPI_MODE_SLAVE == obj->mode) {
+        if (0 == len) {
+            SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
+        } else {
+            CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
+        }
+    }
+    // 1.Enable DMA
+
+
+    spi_dma_enable(obj);
+    //LOGD("recv start before:%08x\n",obj->buf->ping->first_queue->data_length);
+
+    // LOGD("SPI_DMA_STATUS_REG=%x",READ_PERI_REG(SPI_DMA_STATUS_REG(obj->spi_num)));
+
+    // 2.Start SPI
+    SET_PERI_REG_MASK(SPI_CMD_REG(obj->spi_num), SPI_USR);
+    //LOGD("recv start after:%08x\n",obj->buf->ping->first_queue->data_length);    
+
+    
+}
+
+/**
+ * @brief Stop SPI work by DMA
+ *
+ */
+void spi_dma_stop(spi_dma_attr_t *obj)
+{
+    if ((NULL == obj)
+        || (obj->spi_num > SPI_NUM_MAX)) {
+        return;
+    }
+    if (SPI_MODE_MASTER == obj->mode) {
+        SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_TX_STOP);
+    } else if (SPI_MODE_SLAVE == obj->mode) {
+        SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_RX_STOP);
+    }
+    spi_dma_disable(obj);
+}
+#endif
+
+/**
+ * @brief Based on pAttr initialize SPI module.
+ *
+ */
+void spi_init(spi_num_t spiNum, spi_attr_t* pAttr)
+{
+    if ((spiNum > SPI_NUM_MAX)
+        || (NULL == pAttr)) {
+        return;
+    }
+
+    SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
+    CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
+    SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
+    CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
+    SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
+    CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
+
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE << 5);
+    SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);
+    // By default clear command
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+
+    // SPI_CPOL & SPI_CPHA
+    switch (pAttr->sub_mode) {
+    case SPI_SUBMODE_1:
+        CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum),  SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
+        break;
+    case SPI_SUBMODE_2:
+        SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum),  SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
+        break;
+    case SPI_SUBMODE_3:
+        SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),  SPI_CK_OUT_EDGE);
+        break;
+    case SPI_SUBMODE_0:
+    default:
+        CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum),  SPI_CK_OUT_EDGE);
+        // To do nothing
+        break;
+    }
+
+    // SPI bit order
+    if (SPI_BIT_ORDER_MSB_FIRST == pAttr->bit_order) {
+        CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
+        CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
+    } else if (SPI_BIT_ORDER_LSB_FIRST == pAttr->bit_order) {
+        SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
+        SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
+    } else {
+        // To do nothing
+    }
+
+    // SPI bit order
+    if (SPI_WORK_MODE_HALF == pAttr->half_mode) {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
+    } else if (SPI_WORK_MODE_FULL == pAttr->half_mode) {
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
+    }
+    // May be not must to do.
+    WRITE_PERI_REG(SPI_USER1_REG(spiNum), 0);
+    // SPI mode type
+    if (SPI_MODE_MASTER == pAttr->mode) {
+        // SPI mode type
+        SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_MODE, 0, SPI_MISO_DELAY_MODE_S); ////??????
+        // SPI_SET_MISO_DELAY_NUM(spiNum,0);////???????
+        //SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_NUM,0,SPI_MISO_DELAY_NUM_S);////??????
+
+        CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
+        // SPI Send buffer
+        // CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7
+        // SPI Speed
+        if (1 < (pAttr->speed)) {
+            uint8_t i, k;
+            i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1;
+
+            k = pAttr->speed / i;
+            CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK);
+            WRITE_PERI_REG(SPI_CLOCK_REG(spiNum),
+                           (((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
+                           (((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
+                           ((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
+                           (((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
+        } else {
+            WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
+        }
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI);
+
+        // CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_HOLD);/////////////add
+        SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x4 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S)); //delay num
+
+    } else if (SPI_MODE_SLAVE == pAttr->mode) {
+
+        // SPI mode type
+        SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
+        // SPI mode type
+        SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLV_WR_RD_BUF_EN);
+        // SPI Send buffer
+        // SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15
+
+        // If do not set delay cycles, slave not working,master cann't get the data.
+        SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x2 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num
+        // SPI Speed
+        WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), 0);
+
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);/////////////add
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+
+        // By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes)
+        // set pAttr->cmd_len bit slave recieve command length
+        // set 1 bytes status buffer length
+        // set pAttr->addr_len bit slave recieve read address length
+        // set pAttr->addr_len bit slave recieve write address length
+        // set 32 bytes slave recieve buffer length
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
+                          (7), SPI_USR_COMMAND_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_STATUS_BITLEN,
+                          (7), SPI_SLV_STATUS_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_WR_ADDR_BITLEN,
+                          (7), SPI_SLV_WR_ADDR_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_RD_ADDR_BITLEN,
+                          (7), SPI_SLV_RD_ADDR_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLV_WRBUF_DLEN_REG(spiNum), SPI_SLV_WRBUF_DBITLEN,
+                          (32 * 8 - 1), SPI_SLV_WRBUF_DBITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLV_RDBUF_DLEN_REG(spiNum), SPI_SLV_RDBUF_DBITLEN,
+                          (32 * 8 - 1), SPI_SLV_RDBUF_DBITLEN_S);
+    } else {
+        // To do nothing
+    }
+
+    char i;
+    for (i = 0; i < 16; ++i) {
+        WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), 0);
+    }
+}
+
+/**
+ * @brief Set address value by master mode.
+ *
+ */
+void spi_master_cfg_addr(spi_num_t spiNum, uint32_t addr)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    // Set address
+    SET_PERI_REG_BITS(SPI_ADDR_REG(spiNum), SPI_USR_ADDR_VALUE, addr, SPI_USR_ADDR_VALUE_S);
+}
+
+/**
+ * @brief Set command value by master mode.
+ *
+ */
+void  spi_master_cfg_cmd(spi_num_t spiNum, uint32_t cmd)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    // SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+    // bit15-0 is cmd value.
+    SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S);
+}
+
+/**
+ * @brief Send data to slave.
+ *
+ */
+int  spi_master_send_data(spi_num_t spiNum, spi_data_t* pInData)
+{
+    char idx = 0;
+    if ((spiNum > SPI_NUM_MAX)
+        || (NULL == pInData)
+        || (64 < pInData->tx_data_len)) {
+        return -1;
+    }
+    uint32_t *value = pInData->tx_data;
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+    // Set command by user.
+    if (pInData->cmd_len != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
+                          ((pInData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+        // Load command
+        spi_master_cfg_cmd(spiNum, pInData->cmd);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
+                          0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pInData->addr_len == 0) {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
+                          0, SPI_USR_ADDR_BITLEN_S);
+    } else {
+        if (NULL == pInData->addr) {
+            return -1;
+        }
+        SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
+                          ((pInData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
+        // Load address
+        spi_master_cfg_addr(spiNum, *pInData->addr);
+    }
+    // Set data by user.
+    if (pInData->tx_data_len != 0) {
+        if (NULL == value) {
+            return -1;
+        }
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+        // Load send buffer
+        do {
+            WRITE_PERI_REG((SPI_W0_REG(spiNum) + (idx << 2)), *value++);
+        } while (++idx < ((pInData->tx_data_len / 4) + ((pInData->tx_data_len % 4) ? 1 : 0)));
+
+        // Set data send buffer length.Max data length 64 bytes.
+        SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN, ((pInData->tx_data_len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
+
+        SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pInData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+        SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
+                          0, SPI_USR_MOSI_DBITLEN_S);
+
+    }
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
+    while (!(READ_PERI_REG(SPI_SLAVE_REG(spiNum))&SPI_TRANS_DONE));
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE);
+    return 0;
+}
+
+/**
+ * @brief Receive data from slave.
+ *
+ */
+int  spi_master_recv_data(spi_num_t spiNum, spi_data_t* pData)
+{
+    char idx = 0;
+    if ((spiNum > SPI_NUM_MAX)
+        || (NULL == pData)) {
+        return -1;
+    }
+    uint32_t *value = pData->rx_data;
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+    // Set command by user.
+    if (pData->cmd_len != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
+                          ((pData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+        // Load command
+        spi_master_cfg_cmd(spiNum, pData->cmd);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
+        SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
+                          0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pData->addr_len == 0) {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
+                          0, SPI_USR_ADDR_BITLEN_S);
+    } else {
+        if (NULL == pData->addr) {
+            return -1;
+        }
+        SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
+                          ((pData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
+        // Load address
+        spi_master_cfg_addr(spiNum, *pData->addr);
+    }
+    // Set data by user.
+    if (pData->rx_data_len != 0) {
+        if (NULL == value) {
+            return -1;
+        }
+        // Clear MOSI enable
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+        // Set data send buffer length.Max data length 64 bytes.
+        SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+        CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+        SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, 0, SPI_USR_MISO_DBITLEN_S);
+    }
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
+
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+    // Read data out
+    do {
+        *value++ =  READ_PERI_REG(SPI_W0_REG(spiNum) + (idx << 2));
+    } while (++idx < ((pData->rx_data_len / 4) + ((pData->rx_data_len % 4) ? 1 : 0)));
+
+    return 0;
+}
+
+/**
+ * @brief Load data to send buffer by slave mode.
+
+ *
+ */
+int  spi_slave_send_data(spi_num_t spiNum, uint32_t *pOutData, uint8_t outLen)
+{
+    if (NULL == pOutData) {
+        return -1;
+    }
+    char i;
+    uint32_t *value  = pOutData;
+    for (i = 0; i < outLen; ++i) {
+        WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), *value++);
+    }
+    return 0;
+}
+
+/**
+ * @brief Configurate slave prepare for receive data.
+ *
+ */
+int  spi_slave_recv_data(spi_num_t spiNum, void(*isrFunc)(void*))
+{
+    char idx = 0;
+    if (spiNum > SPI_NUM_MAX) {
+        return -1;
+    }
+
+    spi_int_enable(spiNum, SPI_INT_SRC_WR_STA_DONE
+                   | SPI_INT_SRC_RD_STA_DONE | SPI_INT_SRC_WR_BUF_DONE | SPI_INT_SRC_RD_BUF_DONE);
+    spi_int_disable(spiNum, SPI_INT_SRC_TRANS_DONE);
+
+    spi_intr_func_set(isrFunc, spiNum);
+    return 0;
+}
+
+/**
+ * @brief Send data to slave(ESP32,RD_STATUS or WR_STATUS).
+ *
+ */
+void  spi_master_send_status(spi_num_t spiNum, uint8_t data)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+    // enable MOSI
+    SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR);
+
+    // 8bits cmd, 0x04 is eps32 slave write cmd value
+    WRITE_PERI_REG(SPI_USER2_REG(spiNum),
+                   ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
+                   | MASTER_WRITE_STATUS_TO_SLAVE_CMD);
+    // Set data send buffer length.
+    SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
+                      ((sizeof(data) << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
+
+    WRITE_PERI_REG(SPI_W0_REG(spiNum), (uint32_t)(data));
+    // start SPI
+    SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
+}
+
+/**
+ * @brief Receive data from slave(ESP32).
+ *
+ */
+int  spi_master_recv_status(spi_num_t spiNum)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return -1;
+    }
+
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+    // enable MISO
+    SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
+    CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR);
+
+    // 8bits cmd, 0x06 is eps32 slave read cmd value
+    WRITE_PERI_REG(SPI_USER2_REG(spiNum),
+                   ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
+                   | MASTER_READ_STATUS_FROM_SLAVE_CMD);
+    // Set revcive buffer length.
+    SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN,
+                      7, SPI_USR_MISO_DBITLEN_S);
+
+    // start spi module.
+    SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
+
+    while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
+
+    uint8_t data = (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
+    return (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
+}
+
+
+/**
+ * @brief Enable SPI interrupt source.
+ *
+ */
+void  spi_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc << 4);
+}
+
+/**
+ * @brief Disable SPI interrupt source.
+ *
+ */
+void  spi_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc);
+}
+
+/**
+ * @brief Clear all of SPI interrupt source.
+ *
+ */
+void  spi_int_clear(spi_num_t spiNum)
+{
+    if (spiNum > SPI_NUM_MAX) {
+        return;
+    }
+    CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_INT_SRC_TRANS_DONE
+                        | SPI_INT_SRC_WR_STA_DONE
+                        | SPI_INT_SRC_RD_STA_DONE
+                        | SPI_INT_SRC_WR_BUF_DONE
+                        | SPI_INT_SRC_RD_BUF_DONE);
+}
+
+/**
+ * @brief Get the SPI interrupt status.
+ *
+ */
+int32_t spi_int_status_get(spi_num_t i2sNum)
+{
+    if (i2sNum > SPI_NUM_MAX) {
+        return -1;
+    }
+    return READ_PERI_REG(SPI_SLAVE_REG(i2sNum));
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 469 - 0
examples/09_a2dp/components/MediaHal/ES8388/ES7242.c

@@ -0,0 +1,469 @@
+#include "driver/i2c.h"
+#include "esp_types.h"
+#include <stdio.h>
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/xtensa_api.h"
+#include "esp_err.h"
+#include "driver/i2c_soft.h"
+#include "ES7242.h"
+#include "driver/gpio.h"
+//#include "driver/gpio_sig_map.h"
+#include "rom/ets_sys.h"
+
+
+
+#define I2C_FREQ    100000   //HZ
+#define I2C_SLAVE_DEV_ADDR 0x60
+
+#define I2C_SDA_OUT_IO_NUM   21
+#define I2C_SDA_OUT_IO_SIG   I2CEXT0_SDA_OUT_IDX
+#define I2C_SDA_OUT_IO_PIN   GPIO_SEL_21
+
+#define I2C_SCL_OUT_IO_NUM   19
+#define I2C_SCL_OUT_IO_SIG   I2CEXT0_SCL_OUT_IDX
+#define I2C_SCL_OUT_IO_PIN   GPIO_SEL_19
+
+#define I2C_SDA_IN_IO_SIG    I2CEXT0_SDA_IN_IDX
+#define I2C_SCL_IN_IO_SIG    I2CEXT0_SCL_IN_IDX
+
+#define ES8388_ADDR 0x20
+
+#if 0
+
+
+void I2C_GpioInit()
+{
+#if 1
+    ets_printf("Configuring GPIO...........\n");
+    gpio_config_t gpio_conf;
+    gpio_conf.gpio_pin_sel = I2C_SDA_OUT_IO_PIN | I2C_SCL_OUT_IO_PIN ;
+    gpio_conf.gpio_mode_sel = GPIO_MODE_INPUT_OUTPUT_OD;
+    gpio_conf.gpio_pulldown_sel = GPIO_PULLDOWN_DISABLE;
+    gpio_conf.gpio_pullup_sel = GPIO_PULLUP_ENABLE;
+    gpio_conf.gpio_intry_type_sel = GPIO_PIN_INTR_DISABLE;
+    gpio_config(&gpio_conf);
+#if 0
+    SET_PERI_REG_BITS(GPIO_PIN_REG_19, FUN_DRV, 3, FUN_DRV_S);
+    SET_PERI_REG_BITS(GPIO_PIN_REG_23, FUN_DRV, 3, FUN_DRV_S);
+    CLEAR_PERI_REG_MASK(GPIO_PIN_REG_19, FUN_PD);
+    CLEAR_PERI_REG_MASK(GPIO_PIN_REG_23, FUN_PD);
+#endif
+
+    gpio_matrix_out(I2C_SDA_OUT_IO_NUM, I2C_SDA_OUT_IO_SIG, 0, 0);
+    gpio_matrix_out(I2C_SCL_OUT_IO_NUM, I2C_SCL_OUT_IO_SIG, 0, 0);
+    gpio_matrix_in(I2C_SDA_OUT_IO_NUM, I2C_SDA_IN_IO_SIG, 0);
+    gpio_matrix_in(I2C_SCL_OUT_IO_NUM, I2C_SCL_IN_IO_SIG, 0);
+#else
+    // SDA OUT
+    gpio_matrix_out(19, I2C_SDA_OUT_IO_SIG, 0, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_GPIO19);
+    SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO19_U, FUN_IE | FUN_PU);
+    CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO19_U, FUN_PD);
+
+    SET_PERI_REG_MASK(GPIO_PIN19_REG, GPIO_PIN19_PAD_DRIVER);
+    //====debug====
+    gpio_matrix_out(23, I2C_SCL_OUT_IO_SIG, 0, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO23_U, FUNC_GPIO23_GPIO23);
+    SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO23_U, FUN_IE | FUN_PU);
+    CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO23_U, FUN_PD);
+    SET_PERI_REG_MASK(GPIO_PIN23_REG, GPIO_PIN23_PAD_DRIVER);
+    //============================
+    //SDA IN
+    gpio_matrix_in(19, I2C_SDA_IN_IO_SIG, 0);
+    //SCL IN
+    gpio_matrix_in(23, I2C_SCL_IN_IO_SIG, 0);
+
+#endif
+
+    ets_printf("GPIO Configured! ! ! ! ! ! ! ! ! !\n");
+}
+
+
+void disp_cmd(uint8_t i2c_no, uint8_t idx)
+{
+//  ets_printf("---cmd %d ---\n",idx);
+
+//  ets_printf("opcode: %d \n",I2C_GET_COMMAND_OP_CODE(i2c_no,idx));
+//  ets_printf("acken: %d \n",I2C_GET_COMMAND_ACK_EN(i2c_no,idx));
+//  ets_printf("ackexp: %d \n",I2C_GET_COMMAND_ACK_EXP(i2c_no,idx));
+//  ets_printf("ack val: %d \n",I2C_GET_COMMAND_ACK_VALUE(i2c_no,idx));
+//  ets_printf("byte num: %d \n",I2C_GET_COMMAND_BYTE_NUM(i2c_no,idx));
+//  ets_printf("done: %d \n",I2C_GET_COMMAND_DONE(i2c_no,idx));
+
+}
+
+
+void i2c_master_read_test()
+
+{
+    uint8_t i2c_no = 0;
+    uint8_t idx = 0;
+
+    uint8_t data_buf[] = {I2C_SLAVE_DEV_ADDR, //addr
+                          0x10,
+                          0x01,
+                          0x12,
+                          0x13,
+                          0x14,
+                         };
+    uint8_t byte_num = 3;//sizeof(data_buf);
+
+    I2C_SET_TX_FIFO_RST(0, 1);
+    I2C_SET_TX_FIFO_RST(0, 0);
+
+    //command0 : sending restart signal
+    idx = 0;
+    I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 0);
+    I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0);
+    I2C_SET_COMMAND_BYTE_NUM(i2c_no, 0, 1);
+    disp_cmd( i2c_no, 0);
+
+    //command1 : picking slave and sending data
+    idx = 1;
+    I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0);
+    I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 1); //WRITE COMMAND
+    I2C_SET_COMMAND_BYTE_NUM(i2c_no, idx, byte_num); //BYTE NUMBER
+    disp_cmd( i2c_no, 1);
+
+    //command2 : master generating stop
+    idx = 2;
+    I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 0x3); //STOP
+    I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0); //NO ACK
+    disp_cmd( i2c_no, 2);
+
+    int i = 0;
+    for (i = 0; i < byte_num; i++) {
+        WRITE_PERI_REG(I2C_DATA_REG(i2c_no), data_buf[i]);
+    }
+
+    //start sending
+    I2C_SET_TRANS_START(i2c_no, 1);
+}
+
+
+
+void I2C_MasterInit(uint8_t init_num)
+{
+
+    //step 1: gpio init
+    I2C_GpioInit();
+#if 1
+    ets_delay_us(500000);
+    //step 2: i2c init
+    ets_printf("Initializing I2C Master.............\r\n");
+    I2C_InitTypeDef i2c_master;
+    i2c_master.mode = I2C_MASTER_MODE;  //master mode
+    i2c_master.addr_10bit_en = 0;       //not used
+    i2c_master.clk_speed = 100000;      //clk set
+    i2c_master.slave_addr = 0x0;        //no slave addr for master mode
+    I2C_Init(init_num, &i2c_master);
+#else
+    uint8_t i2c_no = init_num;
+    if (i2c_no > 1) {
+        ets_printf("invalid i2c number...\r\n");
+        return;
+    }
+
+    //set master mode
+    //I2C_SET_RX_LSB_FIRST(i2c_no,0); //MSB FIRST
+    //I2C_SET_TX_LSB_FIRST(i2c_no,0); //MSB FIRST
+    I2C_SET_MS_MODE(i2c_no, 1); //MASTER MODE
+    //I2C_SET_SCL_FORCE_OUT(i2c_no,1); //out put practical level
+    //I2C_SET_SDA_FORCE_OUT(i2c_no,1); //out put practical level
+
+    //SET FREQ/DUTY
+    I2C_SET_SCL_LOW_PERIOD(i2c_no, (APB_CLK_FREQ / I2C_FREQ) / 2);
+    I2C_SET_SCL_HIGH_PERIOD(i2c_no, (APB_CLK_FREQ / I2C_FREQ) / 2);
+
+    //SET CLK RE/START HOLD/SETUP
+    I2C_SET_SCL_START_HOLD_TIME(i2c_no, 50); //400);
+    I2C_SET_SCL_RSTART_SETUP_TIME(i2c_no, 50); //400);
+
+    //SET CLK STOP HOLD/SETUP
+    I2C_SET_SCL_STOP_HOLD_TIME(i2c_no, 50); //400);
+    I2C_SET_SCL_STOP_SETUP_TIME(i2c_no, 50); //400);
+
+    //SET DATA I/O HOLD/SAMPLE
+    I2C_SET_SDA_HOLD_TIME(i2c_no, 40);
+    I2C_SET_SDA_SAMPLE_TIME(i2c_no, 40);
+
+    //SET CLK TIME OUT
+    //I2C_SET_TIME_OUT_THRSH(i2c_no,2000);
+    I2C_SET_TIME_OUT_REG(i2c_no, 2000);
+
+    //SET FIFO MODE
+    //I2C_SET_NONFIFO_EN(i2c_no,0);
+    //SET SCL FILTER
+    //I2C_SET_SCL_FILTER_EN(i2c_no,1);
+    //SET SDA FILTER
+    //I2C_SET_SDA_FILTER_EN(i2c_no,0);
+
+    //i2c_intr_config();
+
+#endif
+
+}
+
+
+
+
+
+void i2c_send_data_test(uint8_t i2c_num, uint8_t slave_addr, uint8_t reg_addr, uint8_t data)
+{
+
+
+    //struct I2C_DEV * I2Cx = I2C(i2c_num);
+    uint8_t data_buf[] = {
+        slave_addr,
+        reg_addr,
+        data
+    };
+
+    uint8_t byte_num = sizeof(data_buf);
+    struct I2C_CmdDef cmd;
+    memset(&cmd, 0, sizeof(cmd));
+
+    //reset tx fifo
+    I2C_ResetTxFifo(i2c_num);
+
+    //setup command 0
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.ack_en = 0;
+    cmd.ack_exp = 0;
+    cmd.ack_val = 0;
+    cmd.byte_num = 0;
+    cmd.op_code = I2C_CMD_RESTART;
+
+    I2C_ConfigCmd(i2c_num, 0, &cmd);
+
+    disp_cmd( i2c_num, 0);
+
+    //setup command 1
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.ack_en = 0;
+    cmd.ack_exp = 0;
+    cmd.ack_val = 0;
+    cmd.byte_num = byte_num;
+    cmd.op_code = I2C_CMD_WRITE;
+    I2C_ConfigCmd(i2c_num, 1, &cmd);
+    disp_cmd( i2c_num, 1);
+
+    //setup command 2
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.byte_num = 0;
+    cmd.op_code = I2C_CMD_STOP;
+    I2C_ConfigCmd(i2c_num, 2, &cmd);
+    disp_cmd( i2c_num, 2);
+
+    //push the sending data to tx fifo
+    I2C_TxFifoPush(i2c_num, data_buf , byte_num);
+
+    //I2C start sending
+    I2C_Start(i2c_num);
+
+    I2C_WaitTxDone(i2c_num, 2);
+
+
+}
+#endif
+
+void ES8388_PowerOn_Init1(void)
+{
+    ES7242_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE -
+
+    ES7242_WriteReg(ES8388_ADDR, 0x00, 0x07);   //PLAY BACK,ENREFR=0 //changed
+    ES7242_WriteReg(ES8388_ADDR, 0x2d, 0x00);   //vroi=0
+
+    ets_delay_us(10000);
+
+    ES7242_WriteReg(ES8388_ADDR, 0x01, 0x40);   //pdn_ana=1,ibiasgen_pdn=0,lpvrefbuf=1
+
+    ets_delay_us(10000);
+
+    ES7242_WriteReg(ES8388_ADDR, 0x02, 0xf3);   //Reset STM and DLL
+    ES7242_WriteReg(ES8388_ADDR, 0x03, 0xFF);   //Reset STM and DLL
+    ES7242_WriteReg(ES8388_ADDR, 0x04, 0xC0);   //power up L/R DAC,Enable LO1/RO1,LO2/RO2,OUT3/MONO
+
+    ES7242_WriteReg(ES8388_ADDR, 0x0A, 0x00);  //LIN1/RIN1 as ADC Input
+    ES7242_WriteReg(ES8388_ADDR, 0x0C, 0x0C);  //I2S-16BIT,LADC=Left data,RADC=right data W
+    ES7242_WriteReg(ES8388_ADDR, 0x0d, 0x02);  //SINGLE SPEED,RATIO=256
+    ES7242_WriteReg(ES8388_ADDR, 0x10, 0x00);  //ADC Left Volume=0db
+    ES7242_WriteReg(ES8388_ADDR, 0x11, 0x00);  //ADC Right Volume=0db
+
+    ES7242_WriteReg(ES8388_ADDR, 0x17, 0x18);  //I2S-16BIT 0x18 //PCM 16BIT 0x5E
+    ES7242_WriteReg(ES8388_ADDR, 0x18, 0x02);  //SINGLE SPEED,RATIO=256
+    ES7242_WriteReg(ES8388_ADDR, 0x19, 0x36);  //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
+    ES7242_WriteReg(ES8388_ADDR, 0x1A, 0x00);  //LDAC volume=0db,RDAC Volume=0db
+    ES7242_WriteReg(ES8388_ADDR, 0x1B, 0x00);
+    ES7242_WriteReg(ES8388_ADDR, 0x19, 0x32);  //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
+    ES7242_WriteReg(ES8388_ADDR, 0x27, 0xB8);  //Left DAC TO Left MIXER
+    ES7242_WriteReg(ES8388_ADDR, 0x28, 0x38);
+    ES7242_WriteReg(ES8388_ADDR, 0x29, 0x38);
+    ES7242_WriteReg(ES8388_ADDR, 0x2A, 0xB8);  //RIGHT DAC TO RIGHT MIXER
+    ES7242_WriteReg(ES8388_ADDR, 0x04, 0x30);  //Enable DAC and Enable Lout/Rout
+    ES7242_WriteReg(ES8388_ADDR, 0x2e, 0X10);  //LOUT/ROUT volume
+    ES7242_WriteReg(ES8388_ADDR, 0x2f, 0X10);
+
+    ets_delay_us(50000);
+
+
+    ES7242_WriteReg(ES8388_ADDR, 0x2e, 0x1A);  //LOUT/ROUT volume
+    ES7242_WriteReg(ES8388_ADDR, 0x2f, 0x1A);
+
+    ES7242_WriteReg(ES8388_ADDR, 0x04, 0xc0);  //Disable DAC and  Lout/Rout
+}
+
+void ES8388_DAC_Play1(void)
+{
+    int Vol = 0x1f;
+    ES7242_WriteReg(ES8388_ADDR, 0x02, 0xAA);  //START DAC DLL and State Machine
+    ES7242_WriteReg(ES8388_ADDR, 0x2d, 0X00);  //vroi=0   DelayT0(10);          //Delay 10mS
+    ES7242_WriteReg(ES8388_ADDR, 0x04, 0x3C);  //Enable DAC and Enable Lout/Rout
+
+    ets_delay_us(10000);
+
+
+    ES7242_WriteReg(ES8388_ADDR, 0x2e, Vol);  //LOUT2/ROUT2
+    ES7242_WriteReg(ES8388_ADDR, 0x2f, Vol);
+    ES7242_WriteReg(ES8388_ADDR, 0x30, Vol);  //LOUT1/ROUT1
+    ES7242_WriteReg(ES8388_ADDR, 0x31, Vol);
+
+    ES7242_WriteReg(ES8388_ADDR, 0x19, 0xF2);   //DAC un-Mute
+    ES7242_WriteReg(ES8388_ADDR, 0x01, 0x40);  //LPVrefBuf=0,Pdn_ana=0
+    ES7242_WriteReg(ES8388_ADDR, 0x00, 0x07);  //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
+}
+
+
+void ES7242_Poweron_Init(void)
+{
+    ets_printf("Writing Data to Registers\n");
+#if 0
+    ES7242_WriteReg(ES7242_Address1, 0x00, 0x01);
+    ets_delay_us(10000);
+    ES7242_WriteReg(ES7242_Address1, 0x01, 0x00);
+    ets_delay_us(10000);
+    ES7242_WriteReg(ES7242_Address2, 0x00, 0x01);
+    ets_delay_us(10000);
+    ES7242_WriteReg(ES7242_Address2, 0x01, 0x00);
+    ets_delay_us(10000);
+#endif
+#if 1
+    ES7242_WriteReg(ES7242_Address3, 0x00, 0x01);
+    ets_delay_us(10000);
+    ES7242_WriteReg(ES7242_Address3, 0x01, 0x00);
+    ets_delay_us(10000);
+    ES7242_WriteReg(ES7242_Address4, 0x00, 0x01);
+    ets_delay_us(10000);
+    ES7242_WriteReg(ES7242_Address4, 0x01, 0x00);
+    ets_delay_us(10000);
+#endif
+}
+
+void ES7242_ADC_Record()
+{
+
+#if 0
+    ES7242_WriteReg(ES7242_Address1, 0x01, 0x0F);
+    ES7242_WriteReg(ES7242_Address1, 0x07, 0x00);
+    ES7242_WriteReg(ES7242_Address1, 0x08, 0x11);
+    ES7242_WriteReg(ES7242_Address1, 0x09, 0x00);
+
+    ES7242_WriteReg(ES7242_Address2, 0x01, 0x8F);
+    ES7242_WriteReg(ES7242_Address2, 0x07, 0x00);
+    ES7242_WriteReg(ES7242_Address2, 0x08, 0x11);
+    ES7242_WriteReg(ES7242_Address2, 0x09, 0x00);
+#endif
+#if 1
+    ES7242_WriteReg(ES7242_Address3, 0x01, 0x0F);
+    ES7242_WriteReg(ES7242_Address3, 0x07, 0x00);
+    ES7242_WriteReg(ES7242_Address3, 0x08, 0x11);
+    ES7242_WriteReg(ES7242_Address3, 0x09, 0x00);
+#endif
+#if 1
+    ES7242_WriteReg(ES7242_Address4, 0x01, 0x8F);
+    ES7242_WriteReg(ES7242_Address4, 0x07, 0x00);
+    ES7242_WriteReg(ES7242_Address4, 0x08, 0x11);
+    ES7242_WriteReg(ES7242_Address4, 0x09, 0x00);
+#endif
+}
+
+void ES7242_ADC_StandBy()
+{
+
+
+}
+void ES7242_init(void)
+{
+    //I2C_MasterInit(0x0);
+    i2c_master_gpio_init();
+    ES8388_PowerOn_Init1();
+    ES8388_DAC_Play1();
+    //ES7242_Poweron_Init();
+   // ES7242_ADC_Record();
+
+}
+
+
+
+static bool I2C_Write_Byte(uint8_t data, uint8_t iter)
+{
+    if (iter == 0) {
+        iter = 1;
+    }
+
+    while (iter--) {
+        i2c_master_writeByte(data);
+
+        if (i2c_master_getAck()) {
+            i2c_master_stop();
+            i2c_master_wait(500);  // Wait 500us and retry.
+            i2c_master_start();
+        } else {
+            return true;
+        }
+    }
+    i2c_master_stop();
+    return false;
+}
+#if 1
+void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
+{
+    i2c_master_start();
+    if (false == I2C_Write_Byte(slave_add, 10)) {
+        ets_printf("Slave is busy, TIME OUT");
+    }
+    if (false == I2C_Write_Byte(reg_add, 10)) {
+        ets_printf("Slave is busy, TIME OUT");
+    }
+    if (false == I2C_Write_Byte(data, 10)) {
+        ets_printf("Slave is busy, TIME OUT");
+    }
+    i2c_master_stop();
+}
+#endif
+#if 0
+void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
+{
+    i2c_send_data_test(0x0, slave_add, reg_add, data);
+//ets_delay_us(10000);
+}
+#endif
+uint8_t ES7242_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat)
+{
+    i2c_master_start();
+    if (false == I2C_Write_Byte(slave_add, 0)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    if (false == I2C_Write_Byte(reg_add, 0)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    i2c_master_start();
+    i2c_master_writeByte(0x21);
+    uint8_t ack = i2c_master_getAck();
+    uint8_t Reve = i2c_master_readByte();
+    i2c_master_setAck(1);
+    i2c_master_stop();
+    return Reve;
+}

+ 273 - 0
examples/09_a2dp/components/MediaHal/ES8388/ES8388.c

@@ -0,0 +1,273 @@
+#include "i2c_soft.h"
+#include "rom/ets_sys.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include <stdio.h>
+#include "ES8388.h"
+
+#define ES8388_ADDR 0x22  // 0x22:CE=1;0x20:CE=0
+
+static bool I2C_Write_Byte(uint8_t data, uint8_t iter);
+void ES8388_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data);
+uint8_t ES8388_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat);
+
+
+void ES8388_Init(uint32_t mode, uint32_t channel, uint32_t bits, uint32_t rate)
+{
+
+}
+
+void ES8388_Start()
+{
+
+}
+
+void ES8388_Stop()
+{
+
+}
+
+void ES8388_Pause()
+{
+
+}
+
+void ES8388_Resume()
+{
+
+}
+
+void ES8388_SetVolume()
+{
+
+}
+
+void ES8388_SetDacChannel(int32_t channel, int32_t value)
+{
+
+}
+
+void ES8388_SetMute(int32_t channel)
+{
+
+}
+
+void ES8388_SetMicGain()
+{
+
+}
+
+
+void ES8388_PowerOn_Init(void)
+{
+    ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE -
+
+    ES8388_WriteReg(ES8388_ADDR, 0x00, 0x07);   //PLAY BACK,ENREFR=0 //changed
+    ES8388_WriteReg(ES8388_ADDR, 0x2d, 0x00);   //vroi=0
+
+    vTaskDelay(1);
+
+    ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40);   //pdn_ana=1,ibiasgen_pdn=0,lpvrefbuf=1
+
+    vTaskDelay(1);
+
+    ES8388_WriteReg(ES8388_ADDR, 0x02, 0xf3);   //Reset STM and DLL
+    ES8388_WriteReg(ES8388_ADDR, 0x03, 0xFF);   //Reset STM and DLL
+    ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0);   //power up L/R DAC,Enable LO1/RO1,LO2/RO2,OUT3/MONO
+
+    ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00);  //LIN1/RIN1 as ADC Input
+    ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C);  //I2S-16BIT,LADC=Left data,RADC=right data W
+    ES8388_WriteReg(ES8388_ADDR, 0x0d, 0x02);  //SINGLE SPEED,RATIO=256
+    ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00);  //ADC Left Volume=0db
+    ES8388_WriteReg(ES8388_ADDR, 0x11, 0x00);  //ADC Right Volume=0db
+
+    ES8388_WriteReg(ES8388_ADDR, 0x17, 0x18);  //I2S-16BIT
+    ES8388_WriteReg(ES8388_ADDR, 0x18, 0x02);  //SINGLE SPEED,RATIO=256
+    ES8388_WriteReg(ES8388_ADDR, 0x19, 0x36);  //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
+    ES8388_WriteReg(ES8388_ADDR, 0x1A, 0x00);  //LDAC volume=0db,RDAC Volume=0db
+    ES8388_WriteReg(ES8388_ADDR, 0x1B, 0x00);
+    ES8388_WriteReg(ES8388_ADDR, 0x19, 0x32);  //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
+    ES8388_WriteReg(ES8388_ADDR, 0x27, 0xB8);  //Left DAC TO Left MIXER
+    ES8388_WriteReg(ES8388_ADDR, 0x28, 0x38);
+    ES8388_WriteReg(ES8388_ADDR, 0x29, 0x38);
+    ES8388_WriteReg(ES8388_ADDR, 0x2A, 0xB8);  //RIGHT DAC TO RIGHT MIXER
+    ES8388_WriteReg(ES8388_ADDR, 0x04, 0x30);  //Enable DAC and Enable Lout/Rout
+    ES8388_WriteReg(ES8388_ADDR, 0x2e, 0X10);  //LOUT/ROUT volume
+    ES8388_WriteReg(ES8388_ADDR, 0x2f, 0X10);
+
+    vTaskDelay(5);
+
+    ES8388_WriteReg(ES8388_ADDR, 0x2e, 0x1A);  //LOUT/ROUT volume
+    ES8388_WriteReg(ES8388_ADDR, 0x2f, 0x1A);
+
+    ES8388_WriteReg(ES8388_ADDR, 0x04, 0xc0);  //Disable DAC and  Lout/Rout
+}
+
+
+
+void ES8388_DAC_Play()
+{
+    ES8388_WriteReg(ES8388_ADDR, 0x02, 0x00);  //START DAC DLL and State Machine
+    ES8388_WriteReg(ES8388_ADDR, 0x2d, 0X00);  //vroi=0   DelayT0(10);          //Delay 10mS
+    ES8388_WriteReg(ES8388_ADDR, 0x04, 0x3C);  //Enable DAC and Enable Lout/Rout
+
+    vTaskDelay(1);
+
+    ES8388_WriteReg(ES8388_ADDR, 0x2e, Vol);  //LOUT2/ROUT2
+    ES8388_WriteReg(ES8388_ADDR, 0x2f, Vol);
+    ES8388_WriteReg(ES8388_ADDR, 0x30, Vol);  //LOUT1/ROUT1
+    ES8388_WriteReg(ES8388_ADDR, 0x31, Vol);
+
+    ES8388_WriteReg(ES8388_ADDR, 0x19, 0xF2);   //DAC un-Mute
+    ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40);  //LPVrefBuf=0,Pdn_ana=0
+    ES8388_WriteReg(ES8388_ADDR, 0x00, 0x07);  //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
+}
+void ES8388_ALC()
+{
+
+    ES8388_WriteReg(ES8388_ADDR, 0x12, 0xf2);  //ALC for Microphone
+    ES8388_WriteReg(ES8388_ADDR, 0x13, 0xb0);
+    ES8388_WriteReg(ES8388_ADDR, 0x14, 0x05);
+    ES8388_WriteReg(ES8388_ADDR, 0x15, 0x06);
+    ES8388_WriteReg(ES8388_ADDR, 0x16, 0x7b);
+
+}
+void ES8388_ADC_Record()
+{
+
+    /*
+        ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //Codec in I2S slave mode
+        ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //ADC Power-up
+
+        ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //DAC Power-DN,LOUT/ROUT disable
+        ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //DAC Power-DN,LOUT/ROUT disable
+
+        ES8388_WriteReg(ES8388_ADDR, 0x03, 0x00); //ADC Power-up
+        ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //DAC Power-DN,LOUT/ROUT disable
+
+        ES8388_WriteReg(ES8388_ADDR, 0x09, 0x77); //Analog In PGA=24db
+
+        ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //MIC INPUT FROM LIN1/RIN1
+        // ES8388_WriteReg(0x0A,0x50); //MIC INPUT FROM LIN2/RIN2
+
+        ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT, leftADC-Left Channel, RightADC-Right Channel
+        ES8388_WriteReg(ES8388_ADDR, 0x0D, 0x02); //MCLK/LRCK=256
+
+        ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0dB
+        ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0dB
+
+        ES8388_WriteReg(ES8388_ADDR, 0x02, 0x55);
+
+        vTaskDelay(1);          //Delay 10mS
+        ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=0,ibiasgen_pdn=0
+        ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //置ES8350于PLAYBACK & RECORD 模式,且EnRefr=1
+                 ES8388_ALC();
+                 ES8388_ADC_StandBy();
+    */
+    //unsigned int i;
+    ES8388_WriteReg(ES8388_ADDR, 0x01, 0x36); //Power down whole chip analog
+    ES8388_WriteReg(ES8388_ADDR, 0x01, 0x72); //power up whole chip analog
+    //ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //stop STM and DLL, power down DAC&ADC vref
+    //ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF0); //power up DAC&ADC vref
+    ES8388_WriteReg(ES8388_ADDR, 0x2B, 0x80); //set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK
+    ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //ADC clock is same as DAC. Use ADC MCLK as internal MCLK
+    ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE-0x00;master-0x80
+    ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power down DAC, Disable LOUT&ROUT
+    ES8388_WriteReg(ES8388_ADDR, 0x05, 0x00); //low power setting
+    ES8388_WriteReg(ES8388_ADDR, 0x06, 0xC3);
+    ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //select LIN1&RIN1 as Microphone
+    ES8388_WriteReg(ES8388_ADDR, 0x0B, 0x00);
+//  ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x6F); //ADC 16BIT PCM & right=left
+
+    ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //ADC I2S-16BIT
+    ES8388_WriteReg(ES8388_ADDR, 0x0D, 0x02); //ADCLRCK = MCLK/256
+    ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0DB
+    ES8388_WriteReg(ES8388_ADDR, 0x11, 0x00);
+    ES8388_WriteReg(ES8388_ADDR, 0x09, 0x88); //MIC PGA =24DB
+    ES8388_WriteReg(ES8388_ADDR, 0x12, 0xE2); //MIC ALC SETTING
+    ES8388_WriteReg(ES8388_ADDR, 0x13, 0xC0);
+    ES8388_WriteReg(ES8388_ADDR, 0x14, 0x12);
+    ES8388_WriteReg(ES8388_ADDR, 0x15, 0x06);
+    ES8388_WriteReg(ES8388_ADDR, 0x16, 0xC3);
+    ES8388_WriteReg(ES8388_ADDR, 0x02, 0x00); //startup FSM and DLL
+    ES8388_WriteReg(ES8388_ADDR, 0x03, 0x00); //Power up ADC, Enable LIN&RIN, Power down MICBIAS, set int1lp to low power mode
+    vTaskDelay(1);
+    //ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=0,ibiasgen_pdn=0
+    //ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //置ES8350于PLAYBACK & RECORD 模式,且EnRefr=1
+
+}
+void ES8388_ADC_StandBy()
+{
+
+
+    ES8388_WriteReg(ES8388_ADDR, 0x00, 0x01); //置ES8350于PLAYBACK & RECORD 模式,且EnRefr=1
+    ES8388_WriteReg(ES8388_ADDR, 0x01, 0x58); //pdn_ana=0,ibiasgen_pdn=0
+    vTaskDelay(1);        //Delay 10mS
+    ES8388_WriteReg(ES8388_ADDR, 0x03, 0xFF); //ADC Power-Down
+    ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //DAC Power-DN,LOUT/ROUT disable
+    ES8388_WriteReg(ES8388_ADDR, 0x02, 0xf3);  //关闭录音
+
+}
+void ES8388_init(void)
+{
+    i2c_master_gpio_init();
+    ES8388_PowerOn_Init();
+// ES8388_ADC_Record();
+    //ES8388_DAC_Play();
+
+}
+
+static bool I2C_Write_Byte(uint8_t data, uint8_t iter)
+{
+    if (iter == 0) {
+        iter = 1;
+    }
+
+    while (iter--) {
+        i2c_master_writeByte(data);
+
+        if (i2c_master_getAck()) {
+            i2c_master_stop();
+            ets_delay_us(500);  // Wait 500us and retry.
+            i2c_master_start();
+        } else {
+            return true;
+        }
+    }
+    i2c_master_stop();
+    return false;
+}
+
+void ES8388_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
+{
+    i2c_master_start();
+    if (false == I2C_Write_Byte(slave_add, 30)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    if (false == I2C_Write_Byte(reg_add, 30)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    if (false == I2C_Write_Byte(data, 30)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    i2c_master_stop();
+}
+
+uint8_t ES8388_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat)
+{
+    i2c_master_start();
+    if (false == I2C_Write_Byte(slave_add, 10)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    if (false == I2C_Write_Byte(reg_add, 10)) {
+        printf("Slave is busy, TIME OUT");
+    }
+    i2c_master_start();
+    i2c_master_writeByte(0x21);
+    uint8_t ack = i2c_master_getAck();
+    uint8_t Reve = i2c_master_readByte();
+    i2c_master_setAck(1);
+    i2c_master_stop();
+    return Reve;
+}

+ 388 - 0
examples/09_a2dp/components/MediaHal/MediaHal.c

@@ -0,0 +1,388 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "MediaHal.h"
+#include "audio_log.h"
+#include "driver/gpio.h"
+#include "esp_types.h"
+//#include "inc/Vs10xx.h"
+#include "AP80/Ap80xx.h"
+#include "EspAudioCom.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "MyString.h"
+#include "ES8388.h"
+
+// 2---ES8388
+// 1---AP8048
+// 0---VS1053
+
+#define PA_POINT_PWR    25      // GPIO25
+#define AP_POINT_PWR    26      // GPIO26
+
+#define CODECTYPE  1
+static char* LOGPRE = "[mediaHal Err]";
+static char* LOGPRD = "[mediaHal Info]";
+
+
+static MediaState mediaStatus = 0;
+static uint32_t mediaVol = 50;
+
+void mediaHalInit(void)
+{
+#if CODECTYPE==0
+    VS_Init();
+    VS_Sine_Test();
+    VS_HD_Reset();
+    VS_Soft_Reset();
+    VS_Set_All();
+#elif CODECTYPE==1
+    // AP8048 PWRKEY
+    gpio_config_t  io_conf;
+    memset(&io_conf, 0, sizeof(io_conf));
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_GPIO26);
+    SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO26_U, FUN_PU);
+
+    io_conf.pin_bit_mask     = GPIO_SEL_26;
+    io_conf.mode             = GPIO_MODE_OUTPUT;
+    io_conf.intr_type        = GPIO_PIN_INTR_DISABLE ;
+    gpio_config(&io_conf);
+    gpio_set_level(AP_POINT_PWR, 0x01);  // Enable the AP80 powerkey
+    
+    // PA PWR
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_GPIO25);
+    SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO25_U, FUN_PU);
+    gpio_set_level(PA_POINT_PWR, 0x01);
+
+    apInit();
+#elif CODECTYPE==2
+    ES8388_init();
+
+#endif
+    mediaStatus = MediaState_Initialized;
+    LOGI("mediaHalInit ok");
+}
+
+MediaErr mediaHalDataRead(uint8_t *dat, int *len)
+{
+    if ((NULL == dat)
+        /*|| (MediaState_Playing != mediaStatus)*/) {
+        printf("%s,[func]%s,MediaState is not playing[%x]\r\n", LOGPRE, __func__, mediaStatus);
+        return MediaErr_ParaError;
+    }
+    uint32_t ret = 0;
+#if CODECTYPE==0
+    ret = VS_Send_MusicData(dat);
+#elif CODECTYPE==1
+    ret = apMicReadData(dat, (uint16_t*)len);
+#endif
+    if (ret != MediaErr_NoError) {
+        printf("%s,[func]%s,Send data to codec failed,ret=%d\r\n", LOGPRE, __func__, ret);
+        return MediaErr_CodecError;
+    } else {
+        return MediaErr_NoError;
+    }
+}
+
+MediaErr mediaHalDataWrite(uint8_t *dat, int len)
+{
+    if ((NULL == dat)
+        || (MediaState_Playing != mediaStatus)) {
+        printf("%s,[func]%s,MediaState is not playing[%x]\r\n", LOGPRE, __func__, mediaStatus);
+        return MediaErr_ParaError;
+    }
+    uint32_t ret = 0;
+#if CODECTYPE==0
+    ret = VS_Send_MusicData(dat);
+#elif CODECTYPE==1
+    ret = apSendData(dat, len);
+#endif
+    if (ret != MediaErr_NoError) {
+        printf("%s,[func]%s,Send data to codec failed,ret=%d\r\n", LOGPRE, __func__, ret);
+        return MediaErr_CodecError;
+    } else {
+        return MediaErr_NoError;
+    }
+}
+
+void mediaHalReset(void)
+{
+  //  VS_HD_Reset();
+    //VS_Soft_Reset();
+}
+
+MediaErr mediaHalPlay(EspAudioMeidaType type)
+{
+    uint32_t ret = 0;
+#if CODECTYPE==0
+    VS_Restart_Play();                      //
+    VS_Reset_DecodeTime();                  //
+    VS_SPI_SpeedHigh();
+#else
+    if ((MediaState_Initialized == mediaStatus)
+        || (MediaState_Stoped == mediaStatus)) {
+        if (EspAudioMeidaType_Aac == type) {
+            ret = apPlayStart("radio", sizeof("radio"), AAC_DECODER);
+        } else if (EspAudioMeidaType_Mp3 == type) {
+            ret = apPlayStart("radio", sizeof("radio"), MP3_DECODER);
+        } else if (EspAudioMeidaType_Wav == type) {
+            ret = apPlayStart("radio", sizeof("radio"), WAV_DECODER);
+        } else if (EspAudioMeidaType_Flac == type) {
+            ret = apPlayStart("radio", sizeof("radio"), FLAC_DECODER);
+        } else if (EspAudioMeidaType_Opus == type) {
+            ret = apPlayStart("radio", sizeof("radio"), OPUS_DECODER);
+        } else if (EspAudioMeidaType_Pcm == type) {          
+            ret = apPlayStart("radio", sizeof("radio"), PCM_DECODER);
+        }
+        else {
+            printf("%s,[func]%s,Music type[%d] does not support\r\n", LOGPRE, __func__, type);
+        }
+    } else {
+        apPlayResume();
+    }
+
+    printf("%s,[func]%s, mediaStatus=%d\r\n", LOGPRD, __func__, mediaStatus);
+#endif
+    mediaStatus = MediaState_Playing;
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+
+}
+
+MediaErr mediaHalPause(void)
+{
+    uint32_t ret = 0;
+    if (MediaState_Playing == mediaStatus) {
+        apPlayPause();
+        mediaStatus = MediaState_Paused;
+    }
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    printf("%s,[func]%s,mediaStatus=%d\r\n", LOGPRD, __func__, mediaStatus);
+    return ret;
+}
+
+MediaErr mediaHalStop(void)
+{
+
+    uint32_t ret = 0;
+#if CODECTYPE==0
+    VS_Cancel();
+#elif CODECTYPE==1
+
+    apPlayStop();
+#endif
+    mediaStatus = MediaState_Stoped;
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+}
+
+MediaErr mediaHalVolumeSet(uint8_t value)
+{
+    uint32_t ret = 0;
+    uint32_t tmp = value;
+    LOGD("volmue=%d", tmp);
+
+#if CODECTYPE==0
+    vsset.mvol = value;
+    mediaVol = vsset.mvol;
+    tmp = (value * 200) / 100 + 50;
+    mediaVol = tmp;
+    VS_Set_Vol(tmp); // when vs1053 does not init,this call will be hang.
+#elif CODECTYPE==1
+
+    ret = apVolSet(tmp);
+#endif
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+}
+
+MediaErr mediaHalMute(void)
+{
+    uint32_t ret = 0;
+#if CODECTYPE==0
+    VS_Set_Vol(0);
+#elif CODECTYPE==1
+
+    ret = apVolMuteEnable();
+#endif
+    mediaVol = 0;
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+}
+
+MediaErr mediaHalStatusGet(MediaState *staus)
+{
+    if (NULL == staus) {
+        return MediaErr_ParaError;
+    }
+    *staus = mediaStatus;
+    return MediaErr_NoError;
+}
+
+void mediaHalSleep(void)
+{
+  //  GPIO_OUTPUT_SET(PA_POINT_PWR, 0);
+  //  GPIO_OUTPUT_SET(AP_POINT_PWR, 0);
+    printf("%s mediaHal sleep\r\n", LOGPRE);
+}
+
+void mediaHalWakeup(void)
+{
+  //  GPIO_OUTPUT_SET(PA_POINT_PWR, 1);
+  //  GPIO_OUTPUT_SET(AP_POINT_PWR, 1);
+    printf("%s Codec wakeup\r\n", LOGPRE);
+}
+
+MediaErr mediaHalDecodeTimeRest()
+{
+    uint32_t ret = apRestDecodeTime();
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+}
+
+MediaErr mediaHalDecodeTimeGet(uint32_t *time)
+{
+    if (NULL == time) {
+        return MediaErr_ParaError;
+    }
+    uint32_t ret = apGetDecodeTime((DecodeTime*)time);
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+}
+
+MediaErr mediaHalMusicInfoGet(MusicInfo *info)
+{
+    if (NULL == info) {
+        return MediaErr_ParaError;
+    }
+    uint32_t ret = apGetInfo((SongInformation*)info);
+    if (ret != OK_RESPONSE) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        ret = MediaErr_CodecError;
+    }
+    return ret;
+}
+
+MediaErr mediaHalModeSet(MediaMode mode, MusicInfo* info)
+{
+    MediaErr err = MediaErr_NoError;
+    uint8_t ret = OK_RESPONSE;
+   
+
+    switch (mode) {
+    case MediaMode_Encode:
+    {
+         setEnccodeInfo tmpInfo;
+        memset(&tmpInfo, 0, sizeof(tmpInfo));
+        ret = apSetEncodeMode();
+        tmpInfo.streamDirection    = 1;
+        tmpInfo.numChannels        = info->num_channels;
+        tmpInfo.sampleRate         = info->sampling_rate;
+        tmpInfo.encoderType        = info->stream_type; //OPUS_ENCODER;
+        ret = apEncodeStart();
+        ret += apSetEncodeInfo(&tmpInfo);
+        LOGD("apSetEncodeInfo ret = %d %d\n", ret, tmpInfo.encoderType, 
+            tmpInfo.sampleRate, tmpInfo.numChannels);
+        break;
+    }
+    case MediaMode_Decode:
+    {
+        setDecodeInfo tmpInfo;
+        memset(&tmpInfo, 0, sizeof(tmpInfo));
+        ret = apSetDecodeMode();
+        tmpInfo.streamDirection = 0;
+        tmpInfo.numChannels    = info->num_channels;
+        tmpInfo.sampleRate     = info->sampling_rate;
+        
+        ret += apSetDecodeInfo(&tmpInfo);
+        LOGD("apSetDecodeInfo ret=%d\n", ret);
+
+        break;
+    }
+    case MediaMode_AuxIn:
+        ret = apSetDecodeMode();
+        break;
+    default:
+        err = MediaErr_NotSuport;
+        break;
+    }
+    if ((ret != OK_RESPONSE) && (ERROR_OTHER!= ret)) {
+        printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
+        err = MediaErr_CodecError;
+    }
+    return err;
+}
+
+EspAudioMeidaType checkMediaType(const char* targetUri)
+{
+    EspAudioMeidaType type;
+    if (EndsWith(targetUri, ".wav", 1) != 0) {
+        type = EspAudioMeidaType_Wav;
+    } else if (EndsWith(targetUri, ".aac", 1) != 0) {
+        type = EspAudioMeidaType_Aac;
+    } else if (EndsWith(targetUri, ".mp3", 1) != 0) {
+        type = EspAudioMeidaType_Mp3;
+    } else if (EndsWith(targetUri, ".amr", 1) != 0) {
+        type = EspAudioMeidaType_Amr;
+    } else if (EndsWith(targetUri, ".alac", 1) != 0) {
+        type = EspAudioMeidaType_Alac;
+    } else if (EndsWith(targetUri, ".flac", 1) != 0) {
+        type = EspAudioMeidaType_Flac;
+    } else if (EndsWith(targetUri, ".ape", 1) != 0) {
+        type = EspAudioMeidaType_Ape;
+    } else if (EndsWith(targetUri, ".m3u8", 1) != 0) {
+        type = EspAudioMeidaType_M3u;
+    } else if (EndsWith(targetUri, ".opu", 1) != 0) {
+        type = EspAudioMeidaType_Opus;
+    } else if (EndsWith(targetUri, ".pcm", 1) != 0) {
+        type = EspAudioMeidaType_Pcm;
+    } else {
+        type = EspAudioMeidaType_Unknown;
+    }
+    return type;
+}
+
+// end

+ 15 - 0
examples/09_a2dp/components/MediaHal/component.mk

@@ -0,0 +1,15 @@
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, 
+# this will take the sources in the src/ directory, compile them and link them into 
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_ADD_INCLUDEDIRS := include include/AP80 include/ES8388 include/driver \
+                             ../misc/include
+
+COMPONENT_SRCDIRS :=  AP80 ES8388 Driver test .
+
+include $(IDF_PATH)/make/component_common.mk

+ 253 - 0
examples/09_a2dp/components/MediaHal/include/AP80/Ap80xx.h

@@ -0,0 +1,253 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __AP80XX_H__
+#define __AP80XX_H__
+#include <stdint.h>
+#pragma pack (1)
+
+#define CHIPTYPE 32
+
+#if CHIPTYPE == 32
+#include "soc/gpio_sig_map.h"
+
+#define SPIMasterSendData           spi_master_send_data
+
+#define HSPICLK_OUT_MUX_IDX         HSPICLK_OUT_IDX
+#define SpiNum_HSPI                 SPI_NUM_SPI2
+
+#define AP80XXENABLEDMA             1
+#define AP80XXENABLEINT             1
+#define CALLPLAYOBJ_EN              1
+
+#define SPIM_STREAM_CONTROL_GET_STATUS() (gpio_get_level(GPIO_NUM_22))
+
+#elif CHIPTYPE == 31
+#define SPIM_STREAM_CONTROL_GET_STATUS() (GPIO_INPUT_GET(22))
+#endif
+
+#define EAU_SYNC_BYTE               'S'
+
+#define EAU_COMMAND_LENGTH          (1)
+#define EAU_SYNC_WORD_LENGTH        (1)
+#define EAU_CRC_VALUE_LENGTH        (2)
+#define EAU_RESEND_IF_CRC_ERROR     (1)
+
+#define EAU_SEND_DATA_LENGTH        (32 * 48)
+#define EAU_SEND_FARMA_LENGTH       (32)
+#define EAU_RECV_FARMA_LENGTH       (32)
+
+#define OK_RESPONSE                 (0x00)
+//Òì³£¶¨Òå
+#define ERROR_TIME_OUT              (0x01)
+#define ERROR_STREAM_FULL           (0x02)
+#define ERROR_CRC                   (0x03)
+#define ERROR_RESPONSE              (0x04)
+#define ERROR_CMD                   (0x05)
+#define ERROR_PARAMETER             (0x06)
+#define ERROR_INIT                  (0x07)
+#define ERROR_OTHER                 (0x08)
+#define ERROR_PROMODE               (0x09)
+#define ERROR_DEVICE_TIME_OUT       (0x0A)
+#define ERROR_START                 (0x0B)
+#define ERROR_DMABUSY               (0x0C)
+
+#define SPIDATABUFMAXLEN            (64)
+
+typedef uint32_t DecodeTime;
+
+typedef enum _SSPP_CMD
+{
+    EAU_CMD_UNKOWN = 0,
+    EAU_CMD_START,
+    EAU_CMD_PAUSE,
+    EAU_CMD_RESUME,
+    EAU_CMD_STOP,
+    EAU_CMD_MUTE,
+    EAU_CMD_UNMUTE,
+    EAU_CMD_DATA,
+    EAU_CMD_WRITE_DATA = EAU_CMD_DATA,
+    EAU_CMD_VOL_SET,
+    EAU_CMD_VOL_ADD,
+    EAU_CMD_VOL_SUB,
+    EAU_CMD_INFO_GET,
+    EAU_CMD_INFO_SET,
+    EAU_CMD_TIME_REST,
+    EAU_CMD_TIME_GET,
+    EAU_CMD_VERSION_GET,
+    EAU_CMD_ENCODE_MODE,
+    EAU_CMD_DECODE_MODE,
+    EAU_CMD_READ_DATA,
+    EAU_CMD_LIN_SWITCH,
+    EAU_CMD_MIC_SWITCH,
+    EAU_CMD_ENCODE_START,
+}SSPP_CMD;
+
+typedef struct _MASTERCmdContext
+{
+    uint8_t  SyncWord;
+    uint8_t  Command;
+    uint16_t Content;
+    uint16_t CrcValue;
+}MASTERCmdContext,EAUCmdContext;
+
+typedef struct _EAUCmdResponseContext
+{
+    uint8_t  SyncWord;
+    uint8_t  Command;
+    uint16_t Response;
+    uint16_t CrcValue;
+}EAUCmdResponseContext;
+
+
+typedef struct _DataContext
+{
+    uint8_t  SyncWord;
+    uint8_t  data[EAU_SEND_DATA_LENGTH+EAU_CRC_VALUE_LENGTH];
+}EAUDataContext;
+
+typedef enum __EAU_CMD_RESPONSE
+{
+    EAU_CMD_RESP_UNKOWN = 0,
+    EAU_CMD_RESP_OKCMD,
+    EAU_CMD_RESP_ERCMD,
+    EAU_CMD_RESP_OKSEND,
+    EAU_CMD_RESP_RESEND,
+    EAU_CMD_RESP_NEXTSEND,
+    EAU_CMD_RESP_INITERROR,
+    EAU_CMD_RESP_STATEERROR,
+}EAU_CMD_RESPONSE;
+
+/**
+ * @ly Audio encoder type Ex
+ */
+typedef enum _EncoderTypeEx
+{
+    OPUS_ENCODER_EX = 1,        /**<   OPUS encoder */
+    PCM_ENCODER_EX,             /**<   PCM  encoder */
+} EncoderTypeEx;
+
+/**
+ * @ly Audio Decoder Type Set
+ */
+typedef enum _DecoderType
+{
+    UNKOWN_DECODER               = 0,       /**< Unknown decoder                     */
+    PURE_SOFTWARE_DECODERS       = 1,       /**< Pure software decoders as follows   */
+    WAV_DECODER,                            /**< WAV  decoder */
+    FLAC_DECODER,                           /**< FLAC decoder */
+    AAC_DECODER,                            /**< AAC  decoder */
+    AIF_DECODER,                            /**< AIFF and AIFC decoder */
+    ALAC_DECODER,                           /**< ALAC and AIFC decoder */
+    OPUS_DECODER,                           /**< OPUS decoder */
+    PCM_DECODER,                            /**< PCM  decoder */
+    WITH_HARDWARE_DECODERS       = 128,     /**< Decoders with hardware as follows   */
+    MP3_DECODER,                            /**< MP3  decoder */
+    WMA_DECODER,                            /**< WAM  decoder */
+    SBC_DECODER,                            /**< SBC  decoder */
+} DecoderType;
+
+/**
+ * @ly Song Information
+ */
+typedef struct _SongInformation
+{
+    int32_t     stream_type;            /**< Stream type, must be in @code StreamTypeSet    */
+    uint32_t    num_channels;           /**< Number of channels                             */
+    uint32_t    sampling_rate;          /**< Sampling rate, unit: Hz                        */
+    uint32_t    bitrate;                /**< Bit rate, unit:bps                             */
+    uint32_t    duration;               /**< Total play time, unit:ms                       */
+    uint32_t    file_size;              /**< Song file size in bytes .                      */
+    uint16_t    firmware_ver;           /**< AP80xx firmware version .                      */
+    uint16_t    firmware_num;           /**< AP80xx firmware number  .                      */
+    uint8_t     Stream_buf_is_Empty;    /**< Stream_buf_is_Empty                     .      */
+    uint8_t     RFU;                    /**< RFU                     .                      */
+} SongInformation;
+
+/**
+ * @ly code Information
+ */
+typedef struct _setdeccodeInfo
+{
+    int32_t     streamDirection;        /**< Stream direction                               */
+    uint32_t    numChannels;            /**< Number of channels                             */    
+    uint32_t    sampleRate;             /**< Bit rate, unit:bps                             */
+    uint32_t    decoderType;            /**< Decoder Type:OPUS,PCM                          */
+    uint32_t    frameSize;              /**< opus and pcm                                   */
+    uint32_t    RFU2;                   /**< RFU                                            */
+    uint32_t    RFU3;                   /**< RFU                                            */
+    uint32_t    RFU4;                   /**< RFU                                            */
+    uint32_t    RFU5;                   /**< RFU                                            */
+    uint32_t    RFU6;                   /**< RFU                                            */
+    uint32_t    RFU7;                   /**< RFU                                            */
+} setDecodeInfo;
+
+/**
+ * @ly encode Information
+ */
+typedef struct _set_enccode_info
+{
+    int32_t         streamDirection;        /**< Stream direction                               */
+    uint32_t        numChannels;            /**< Number of channels                             */
+    uint32_t        sampleRate;             /**< Sample rate, unit:bps                          */
+    uint32_t        encoderType;            /**< Encoder Type:OPUS,PCM                          */
+    uint32_t        frameSize;              /**< RFU                                            */
+    uint32_t        RFU2;                   /**< RFU                                            */
+    uint32_t        RFU3;                   /**< RFU                                            */
+    uint32_t        RFU4;                   /**< RFU                                            */
+    uint32_t        RFU5;                   /**< RFU                                            */
+    uint32_t        RFU6;                   /**< RFU                                            */
+    uint32_t        RFU7;                   /**< RFU                                            */
+}setEnccodeInfo;
+
+//public function
+void apInit();
+uint8_t apPlayStop(void);
+uint8_t apPlayPause(void);
+uint8_t apLinSwitch(void);
+uint8_t apMicSwitch(void);
+uint8_t apPlayResume(void);
+uint8_t apEncodeStart(void);
+uint8_t apVolSet(uint16_t vol);
+uint8_t apSetEncodeMode(void);
+uint8_t apSetDecodeMode(void);
+uint8_t apVolMuteEnable(void);
+uint8_t apVolMuteDisable(void);
+uint8_t apRestDecodeTime(void);
+uint8_t apSetWaitTime(uint32_t waitTime);
+uint8_t apGetDecodeTime(DecodeTime *time);
+uint8_t apGetInfo(SongInformation *songInfo);
+uint8_t apSetDecodeInfo(setDecodeInfo *decodeInfo);
+uint8_t apSetEncodeInfo(setEnccodeInfo *encodeInfo);
+uint8_t apSendData(uint8_t *sendData, uint16_t  sendLen);
+uint8_t apMicReadData(uint8_t *readData, uint16_t  *readLen);
+uint8_t apPlayStart(const char *songFileName, uint8_t len, DecoderType decType);
+
+//private function
+void audio_test_main();
+void mic_test();
+void audio_test_main();
+void apSetResponse(bool responseEnable);
+void printfByteS(uint8_t *indata, uint16_t len);
+
+#endif //  __AP80XX_H__

+ 28 - 0
examples/09_a2dp/components/MediaHal/include/AP80/crc.h

@@ -0,0 +1,28 @@
+/**
+ **************************************************************************************
+ * @file    crc.h
+ * @brief   Calculate CRC Value
+ * 
+ * @author  Aissen Li
+ * @version V1.0.0
+ *
+ * &copy; Shanghai Mountain View Silicon Technology Co.,Ltd. All rights reserved.
+ **************************************************************************************
+ */
+
+#ifndef __CRC_H__
+#define __CRC_H__
+
+#ifdef  __cplusplus
+extern "C" {
+#endif//__cplusplus
+
+#include <stdint.h>
+
+uint16_t GetCRC16NBS(uint8_t* data, uint32_t length);
+
+#ifdef  __cplusplus
+}
+#endif//__cplusplus
+
+#endif//__CRC_H__

+ 27 - 0
examples/09_a2dp/components/MediaHal/include/ES8388/ES7242.h

@@ -0,0 +1,27 @@
+#ifndef __ES8388_H
+#define __ES8388_H
+
+#include "esp_types.h"
+#include "rom/ets_sys.h"
+
+#define ES7154_Address 0x00
+#define ES7242_Address1 0x20
+#define ES7242_Address2 0x22
+#define ES7242_Address3 0x24
+#define ES7242_Address4 0x26
+
+void ES7242_init(void);
+void ES7242_Poweron_Init(void);
+//void ES8388_DAC_Play(void);
+//void ES8388_ALC(void);
+void ES7242_ADC_Record(void);
+void ES7242_ADC_StandBy(void);
+static bool I2C_Write_Byte(uint8_t data, uint8_t iter);
+void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data);
+uint8_t ES7242_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat);
+void I2C_MasterInit(uint8_t init_num);
+void i2c_master_read_test();
+
+
+#endif
+

+ 78 - 0
examples/09_a2dp/components/MediaHal/include/ES8388/ES8388.h

@@ -0,0 +1,78 @@
+#ifndef __ES8388_H
+#define __ES8388_H
+#include "esp_types.h"
+
+#define ES8388_CONTROL1         0x00
+#define ES8388_CONTROL2         0x01
+
+#define ES8388_CHIPPOWER        0x02
+
+#define ES8388_ADCPOWER         0x03
+#define ES8388_DACPOWER         0x04
+
+#define ES8388_CHIPLOPOW1       0x05
+#define ES8388_CHIPLOPOW2       0x06
+
+#define ES8388_ANAVOLMANAG      0x07
+
+#define ES8388_MASTERMODE       0x08
+
+#define ES8388_ADCCONTROL1      0x09
+#define ES8388_ADCCONTROL2      0x0a
+#define ES8388_ADCCONTROL3      0x0b
+#define ES8388_ADCCONTROL4      0x0c
+#define ES8388_ADCCONTROL5      0x0d
+#define ES8388_ADCCONTROL6      0x0e
+#define ES8388_ADCCONTROL7      0x0f
+#define ES8388_ADCCONTROL8      0x10
+#define ES8388_ADCCONTROL9      0x11
+#define ES8388_ADCCONTROL10     0x12
+#define ES8388_ADCCONTROL11     0x13
+#define ES8388_ADCCONTROL12     0x14
+#define ES8388_ADCCONTROL13     0x15
+#define ES8388_ADCCONTROL14     0x16
+
+#define ES8388_DACCONTROL1      0x17
+#define ES8388_DACCONTROL2      0x18
+#define ES8388_DACCONTROL3      0x19
+#define ES8388_DACCONTROL4      0x1a
+#define ES8388_DACCONTROL5      0x1b
+#define ES8388_DACCONTROL6      0x1c
+#define ES8388_DACCONTROL7      0x1d
+#define ES8388_DACCONTROL8      0x1e
+#define ES8388_DACCONTROL9      0x1f
+#define ES8388_DACCONTROL10     0x20
+#define ES8388_DACCONTROL11     0x21
+#define ES8388_DACCONTROL12     0x22
+#define ES8388_DACCONTROL13     0x23
+#define ES8388_DACCONTROL14     0x24
+#define ES8388_DACCONTROL15     0x25
+#define ES8388_DACCONTROL16     0x26
+#define ES8388_DACCONTROL17     0x27
+#define ES8388_DACCONTROL18     0x28
+#define ES8388_DACCONTROL19     0x29
+#define ES8388_DACCONTROL20     0x2a
+#define ES8388_DACCONTROL21     0x2b
+#define ES8388_DACCONTROL22     0x2c
+#define ES8388_DACCONTROL23     0x2d
+#define ES8388_DACCONTROL24     0x2e
+#define ES8388_DACCONTROL25     0x2f
+#define ES8388_DACCONTROL26     0x30
+#define ES8388_DACCONTROL27     0x31
+#define ES8388_DACCONTROL28     0x32
+#define ES8388_DACCONTROL29     0x33
+#define ES8388_DACCONTROL30     0x34
+
+#define Vol 0x0F
+
+
+void ES8388_init(void);
+void ES8388_PowerOn_Init(void);
+void ES8388_DAC_Play(void);
+void ES8388_ALC(void);
+void ES8388_ADC_Record(void);
+void ES8388_ADC_StandBy(void);
+
+
+#endif
+

+ 130 - 0
examples/09_a2dp/components/MediaHal/include/MediaHal.h

@@ -0,0 +1,130 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __MEDIAHAL_H__
+#define __MEDIAHAL_H__
+#include <stdint.h>
+
+
+//*****************************************************************************
+//
+// Make sure all of the definitions in this header have a C binding.
+//
+//*****************************************************************************
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+    
+#define AP_POINT_PWR    26      // GPIO26 AP8048
+#define PA_POINT_PWR    25      // GPIO25
+
+typedef enum {
+    MediaState_Initialized = 0,        /* codec is initialized */
+    MediaState_Stoped,                  /* codec is stoped */
+    MediaState_Transit,                  /* codec is busy in a transition */
+    MediaState_Playing,                 /* codec is currently playing */
+    MediaState_Paused,                 /* codec is in the paused state for playback */
+    MediaState_Ended,                   /* codec finished decoding media, media has stopped without user request. */
+    MediaState_Error,                     /* codec was given a URI that could not be played */
+
+    MediaState_Unknow                 /* unknown playstate */
+}MediaState;
+
+
+typedef enum
+{
+    EspAudioMeidaType_Unknown = 0,
+    EspAudioMeidaType_Wav,
+    EspAudioMeidaType_Aac,
+    EspAudioMeidaType_Mp3,
+    EspAudioMeidaType_Amr,
+    EspAudioMeidaType_Alac,
+    EspAudioMeidaType_Flac,
+    EspAudioMeidaType_Ape,
+    EspAudioMeidaType_M3u,
+    EspAudioMeidaType_Opus,
+    EspAudioMeidaType_Pcm,
+    EspAudioMeidaType_Max,
+}EspAudioMeidaType;
+
+
+typedef enum {
+    MediaErr_NoError    = 0,
+    MediaErr_ParaError,
+    MediaErr_CodecInitFailed,
+    MediaErr_CodecError,
+    MediaErr_NotSuport,
+} MediaErr;
+
+typedef enum {
+    MediaMode_Decode    = 0,
+    MediaMode_Encode    = 1,
+    MediaMode_AuxIn     = 2,
+    MediaMode_Max       = 3,
+} MediaMode;
+
+typedef struct
+{
+    int32_t     stream_type;            /**< Stream type, must be in @code StreamTypeSet    */
+    uint32_t    num_channels;           /**< Number of channels                             */
+    uint32_t    sampling_rate;          /**< Sampling rate, unit: Hz                        */
+    uint32_t    bitrate;                /**< Bit rate, unit:bps                             */
+    uint32_t    duration;               /**< Total play time, unit:ms                       */
+    uint32_t    file_size;              /**< Song file size in bytes .                      */
+    uint16_t    firmware_ver;           /**< AP80xx firmware version .                      */
+    uint16_t    firmware_num;           /**< AP80xx firmware number  .                      */
+    uint8_t     bufEmpty;               /**< Stream_buf_is_Empty                     .      */
+    uint8_t     RFU;                    /**< RFU                     .                      */
+
+} MusicInfo;
+
+void mediaHalInit();
+MediaErr mediaHalDataWrite(uint8_t *dat, int len);
+MediaErr mediaHalDataRead(uint8_t *dat, int *len);
+
+MediaErr mediaHalPlay(EspAudioMeidaType type);
+MediaErr mediaHalPause(void);
+MediaErr mediaHalStop(void);
+void     mediaHalReset(void);
+MediaErr mediaHalVolumeSet(uint8_t value);
+MediaErr mediaHalMute(void);
+MediaErr mediaHalStatusGet(MediaState *staus);
+void mediaHalSleep(void);
+void mediaHalWakeup(void);
+MediaErr mediaHalModeSet(MediaMode mode, MusicInfo* info);
+
+
+MediaErr mediaHalDecodeTimeRest(void);
+MediaErr mediaHalDecodeTimeGet(uint32_t *time);
+MediaErr mediaHalMusicInfoGet(MusicInfo *info);
+
+EspAudioMeidaType checkMediaType(const char* targetUri);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //  __MEDIAHAL_H__

+ 127 - 0
examples/09_a2dp/components/MediaHal/include/driver/dma.h

@@ -0,0 +1,127 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _DRIVER_DMA_H_
+#define _DRIVER_DMA_H__
+#include <esp_types.h>
+
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup Driver_APIs Driver APIs
+  * @brief Driver APIs
+  */
+
+/** @addtogroup Driver_APIs
+  * @{
+  */
+
+/**
+ * @brief DMA queue description.
+ */
+typedef struct {
+    uint32_t  block_size: 12;
+    uint32_t  data_length: 12;
+    uint32_t  unused: 5;
+    uint32_t  sub_sof: 1;
+    uint32_t  eof: 1;
+    uint32_t  owner: 1;
+    uint32_t  buf_ptr;
+    uint32_t  next_link_ptr;
+} dma_queue_t;
+
+/**
+ * @brief DMA element description
+ */
+typedef struct {
+    uint32_t        *buffer_addr;
+    dma_queue_t     *first_queue;
+    dma_queue_t     *last_queue;
+    dma_queue_t     backup_queue;
+} dma_element_t;
+
+/**
+ * @brief DMA ping-pong buffer object description
+ */
+typedef struct {
+    dma_element_t   *ping;
+    dma_element_t   *pong;
+    uint32_t        len;
+    uint32_t        queue_cnt;
+} ping_pong_buf_t;
+
+
+/**
+ * @brief Create a ping-pong buffer object used by DMA.
+ *
+ * @param [in] bufLen
+ *             Set the buffer length.
+ *             --------------------
+ *             | ping   | Pong    |
+ *             --------------------
+ *             | bufLen | bufLen  |
+ *             --------------------
+ *
+ * @return uint32*, NULL:indicates parameter error, others indicates ping-pong buffer address.
+ */
+ping_pong_buf_t* dma_buf_create(uint32_t bufLen);
+
+/**
+ * @brief Reset the dma buffer length.
+ *
+ * @param [in] obj
+ *             Pointer to a struct ping_pong_buf_t that indicates the object length to be reset to bufLen.
+ *
+ * @return uint32*, ESP_FAIL:indicates parameter error, ESP_OK :indicates success.
+ */
+esp_err_t dma_buf_len_reset(ping_pong_buf_t *obj);
+
+/**
+ * @brief Set the buffer length before the start.
+ *
+ * @param [in] obj
+ *             Pointer to a struct spi_dma_attr_t.
+ * @param [in] len
+ *             Set the transmit length .
+ *
+ * @return uint32*, ESP_FAIL:indicates parameter error, ESP_OK: indicates success.
+ */
+esp_err_t dma_buf_len_set(ping_pong_buf_t *obj, dma_element_t *element, uint32_t len);
+
+/**
+ * @brief Destroy the ping-pong buffer instance.
+ *
+ * @param [in] obj
+ *             Pointer to a struct ping_pong_buf_t that indicates the object to be destroy.
+ *
+ * @return NULL
+ */
+void dma_buf_destroy(ping_pong_buf_t *obj);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DMA_H__

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików