1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 */
4 #ifdef HAAS_AUDIO_DEMO
5 #include <posix/pthread.h>
6 #else
7 #include <pthread.h>
8 #endif
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include "sound_pcm.h"
14 #include "sound_mixer.h"
15 #include "audio_drv.h"
16 #include "ulog/ulog.h"
17
18 #define LOG_TAG "[sound_example_wav]"
19
20 #define ID_RIFF 0x46464952
21 #define ID_WAVE 0x45564157
22 #define ID_FMT 0x20746d66
23 #define ID_DATA 0x61746164
24
25 #define AUDIO_PLAYER_HIGH_STACKSIZE 8192
26 #define AUDIO_PLAYER_DEFAULT_PRIORITY 33
27
28 struct riff_wave_header {
29 uint32_t riff_id;
30 uint32_t riff_sz;
31 uint32_t wave_id;
32 };
33
34 struct chunk_header {
35 uint32_t id;
36 uint32_t sz;
37 };
38
39 struct chunk_fmt {
40 uint16_t audio_format;
41 uint16_t num_channels;
42 uint32_t sample_rate;
43 uint32_t byte_rate;
44 uint16_t block_align;
45 uint16_t bits_per_sample;
46 };
47
48 static pthread_cond_t g_play_cond;
49 static pthread_mutex_t g_play_mutex;
50 static pthread_t g_play_thread;
51 static bool bCreateAudioThreadFlag = false;
52
53 static struct chunk_fmt chunk_fmt;
54 static unsigned int period_size = 3200;
55 static unsigned int period_count = 1;
56 static unsigned int total_cnt = 0;
57 static char *filename;
58
play_sample(FILE * file,unsigned int channels,unsigned int rate,unsigned int bits,unsigned int period_size,unsigned int period_count)59 static int play_sample(FILE *file, unsigned int channels, unsigned int rate, unsigned int bits, unsigned int period_size,
60 unsigned int period_count)
61 {
62 char *buffer;
63 int size;
64 int num_read, frame_size;
65 int ret = -1;
66 aos_pcm_t *pcm;
67 aos_pcm_format_t format;
68
69 LOGD(LOG_TAG, "%s:%d: channels %d, sample_rate %d, sample_bits %d, period_size %d, period_count %d", __func__, __LINE__,
70 channels, rate, bits, period_size, period_count);
71
72 ret = aos_pcm_open(&pcm, "default", AOS_PCM_STREAM_PLAYBACK, 0);
73 if (ret < 0) {
74 LOGE(LOG_TAG, "%s:%d, could NOT open audio device", __func__, __LINE__);
75 return -1;
76 }
77 switch(bits) {
78 case 16:
79 format = AOSRV_PCM_FORMAT_S16_LE;
80 break;
81 case 24:
82 format = AOSRV_PCM_FORMAT_S24_LE;
83 break;
84 case 32:
85 format = AOSRV_PCM_FORMAT_S32_LE;
86 break;
87 default:
88 format = AOSRV_PCM_FORMAT_S16_LE;
89 break;
90 }
91
92 aos_pcm_set_params(pcm, format, AOS_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 0, 0);
93 aos_pcm_prepare(pcm);
94
95 frame_size = channels * bits / 8;
96 //size = period_size * period_count * frame_size;
97 size = rate /10 * frame_size;
98 LOGD(LOG_TAG, "%s:%d, size = %d", __func__, __LINE__, size);
99 buffer = malloc(size);
100 if (!buffer) {
101 LOGE(LOG_TAG, "%s:%d: failed to malloc %d bytes", __func__, __LINE__, size);
102 free(buffer);
103 aos_pcm_close(pcm);
104 return -1;
105 }
106
107 aos_pcm_start(pcm);
108 do {
109 num_read = fread(buffer, 1, size, file);
110 if (num_read > 0) {
111 if (aos_pcm_writei(pcm, buffer, num_read/frame_size) < 0) {
112 LOGE(LOG_TAG, "%s:%d: aos_pcm_writei error. ", __func__, __LINE__);
113 break;
114 }
115 }
116 } while (num_read > 0);
117
118 //aos_pcm_drain(pcm);
119 aos_pcm_stop(pcm);
120 aos_pcm_close(pcm);
121 free(buffer);
122 return 0;
123 }
124
sound_wav_thread(void * arg)125 static void sound_wav_thread(void *arg)
126 {
127 FILE *file;
128 struct riff_wave_header riff_wave_header;
129 struct chunk_header chunk_header;
130 int more_chunks = 1;
131
132 while(1) {
133 if(total_cnt <= 0) {
134 LOGD(LOG_TAG, "%s:%d, wav player end !!!", __func__, __LINE__);
135 pthread_cond_wait(&g_play_cond, &g_play_mutex);
136 }
137 total_cnt --;
138
139 if(!filename) {
140 total_cnt = 0;
141 continue;
142 }
143 file = fopen(filename, "rb");
144 if (!file) {
145 LOGE(LOG_TAG, "%s:%d, failed to open file '%s'", __func__, __LINE__, filename);
146 total_cnt = 0;
147 continue;
148 }
149 LOGD(LOG_TAG, "%s:%d, open '%s' successfully", __func__, __LINE__, filename);
150
151 fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
152 if ((riff_wave_header.riff_id != ID_RIFF) ||
153 (riff_wave_header.wave_id != ID_WAVE)) {
154 LOGE(LOG_TAG, "%s:%d, Error: '%s' is not a riff/wave file", __func__, __LINE__, filename);
155 total_cnt = 0;
156 fclose(file);
157 continue;
158 }
159
160 do {
161 fread(&chunk_header, sizeof(chunk_header), 1, file);
162
163 switch (chunk_header.id) {
164 case ID_FMT:
165 fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
166 /* If the format header is larger, skip the rest */
167 if (chunk_header.sz > sizeof(chunk_fmt))
168 fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
169 break;
170 case ID_DATA:
171 /* Stop looking for chunks */
172 more_chunks = 0;
173 break;
174 default:
175 /* Unknown chunk, skip bytes */
176 fseek(file, chunk_header.sz, SEEK_CUR);
177 }
178 } while (more_chunks);
179
180 if(play_sample(file, chunk_fmt.num_channels, chunk_fmt.sample_rate, chunk_fmt.bits_per_sample, period_size, period_count) < 0) {
181 total_cnt = 0;
182 }
183
184 fclose(file);
185 }
186
187 return 0;
188 }
189
sound_wav_init(void)190 static void sound_wav_init(void)
191 {
192 if(bCreateAudioThreadFlag) {
193 return;
194 }
195 LOGD(LOG_TAG, "%s:%d, -->>", __func__, __LINE__);
196
197 pthread_attr_t attr;
198 struct sched_param sched;
199
200 pthread_cond_init(&g_play_cond, NULL);
201 pthread_mutex_init(&g_play_mutex, NULL);
202
203 pthread_attr_init(&attr);
204 pthread_attr_setstacksize(&attr, AUDIO_PLAYER_HIGH_STACKSIZE);
205 sched.sched_priority = AUDIO_PLAYER_DEFAULT_PRIORITY;
206 pthread_attr_setschedparam(&attr, &sched);
207
208 pthread_create(&g_play_thread, &attr, sound_wav_thread, NULL);
209 pthread_setname_np(g_play_thread, "wav_player_thread");
210
211 pthread_attr_destroy(&attr);
212 bCreateAudioThreadFlag = true;
213 }
214
sound_example_wav_entry(int argc,char ** argv)215 void sound_example_wav_entry(int argc, char **argv)
216 {
217 if (argc < 3) {
218 LOGD(LOG_TAG, "%s:%d: Usage: %s file.wav cnt ", __func__, __LINE__, argv[0]);
219 return;
220 }
221 filename = strdup(argv[1]);
222 total_cnt = atoi(argv[2]);
223 sound_wav_init();
224 pthread_cond_signal(&g_play_cond);
225 }
226
227