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