0%

ubuntu下C代码播放音频文件

播放音频文件分两种情况:

一、单纯播放音频文件推荐操作简单使用方便(sox软件、madplay库)。
sox软件播放音频

1、ubuntu安装命令

1
2
sudo apt-get install sox                       // 工具。
sudo apt-get install libsox-fmt-all // 包含MP3的解码器和其他格式的解码器。

2、代码通过系统 system 播放(play是sox软件播放的命令)

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <stdlib.h>
int main() {
system("play 1.mp3");
printf("播放结束了 \n");
exit:
printf("按任意键退出 ...\n");
getchar();
return 0;
}

常用命令和说明推荐文档:
sox常用命令
sox-音频处理工具

madplay库(自己没有测试需要编译就搁置了,推荐网上现成的)

madplay安装及使用

二、想要控制采样率、通道等(alsa库)

安装alsa

1
#sudo apt-get install alsa-base, alsa-utils, alsa-source,libasound2-dev

如果上述安装不成功或者因为墙的问题可以自己去官网下载源文件编译。

alsa简单使用只能播放wav:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <sys/stat.h>
#include <sys/mman.h>

struct RIFF_HEADER
{
char szRiffID[4]; // 'R','I','F','F'
unsigned int dwRiffSize;
char szRiffFormat[4]; // 'W','A','V','E'
};

struct WAVE_FORMAT
{
unsigned short wFormatTag;
unsigned short wChannels;
unsigned int dwSamplesPerSec;
unsigned int dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
};

struct FMT_BLOCK
{
char szFmtID[4]; // 'f','m','t',' '
unsigned int dwFmtSize;
struct WAVE_FORMAT wavFormat;
};

struct DATA_BLOCK
{
char szDataID[4]; // 'd','a','t','a'
unsigned int dwDataSize;
};

// 获取音频文件的采样率、通道、采样格式、文件大小等。
void read_wav(unsigned char *wav_buf, unsigned int *fs, int *channels, int *bits_per_sample, int *wav_size, int *file_size)
{
struct RIFF_HEADER *headblk;
struct FMT_BLOCK *fmtblk;
struct DATA_BLOCK *datblk;

headblk = (struct RIFF_HEADER *)wav_buf;
fmtblk = (struct FMT_BLOCK *)&headblk[1];
datblk = (struct DATA_BLOCK *)&fmtblk[1];

*file_size = headblk->dwRiffSize;

//采样频率
*fs = fmtblk->wavFormat.dwSamplesPerSec;

//通道数
*channels = fmtblk->wavFormat.wChannels;

*wav_size = datblk->dwDataSize;
//采样bit数 16 24
*bits_per_sample = fmtblk->wavFormat.wBitsPerSample;
}

main(int argc, char *argv[])
{
int err;
snd_pcm_t *playback_handle;
snd_pcm_hw_params_t *hw_params;

// 打开文件
FILE *fp = fopen("1.wav", "rb");
if (fp == NULL)
{
exit(0);
}

unsigned int dir = 0;
unsigned int rate;
int channels, bits_per_sample, wav_size, file_size;
unsigned char *wav_buf;
struct stat stat;

fstat(fp->_fileno, &stat);
wav_buf = (unsigned char *)mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0);
read_wav(wav_buf, &rate, &channels, &bits_per_sample, &wav_size, &file_size);

// 打开PCM
if ((err = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf(stderr, "cannot open audio device %s (%s)\n",
argv[1],
snd_strerror(err));
exit(1);
}

// 分配空间
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}

// 初始化
if ((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0)
{
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}

// 初始化访问权限
if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf(stderr, "cannot set access type (%s)\n",
snd_strerror(err));
exit(1);
}

// 初始化采样格式
snd_pcm_format_t format;
if (bits_per_sample == 8)
{
format = SND_PCM_FORMAT_U8;
}
if (bits_per_sample == 16)
{
format = SND_PCM_FORMAT_S16_LE;
}
if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, format)) < 0)
{
fprintf(stderr, "cannot set sample format (%s)\n",
snd_strerror(err));
exit(1);
}

// 设置采样率
if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, &dir)) < 0)
{
fprintf(stderr, "cannot set sample rate (%s)\n",
snd_strerror(err));
exit(1);
}

// 设置通道数量(1 单声道 2 双声道)
if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, channels)) < 0)
{
fprintf(stderr, "cannot set channel count (%s)\n",
snd_strerror(err));
exit(1);
}

// 设置参数
if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0)
{
fprintf(stderr, "cannot set parameters (%s)\n",
snd_strerror(err));
exit(1);
}

/* Use a buffer large enough to hold one period */
snd_pcm_uframes_t frames;
snd_pcm_hw_params_get_period_size(hw_params, &frames, &dir);

snd_pcm_hw_params_free(hw_params);

if ((err = snd_pcm_prepare(playback_handle)) < 0)
{
fprintf(stderr, "cannot prepare audio interface for use (%s)\n",
snd_strerror(err));
exit(1);
}

fseek(fp, 100, SEEK_SET);

char *buffer;
int size = frames * 2 * channels;
buffer = (char *)malloc(size);

while (1)
{
int ret = fread(buffer, 1, size, fp);
if (ret == 0)
{
fprintf(stderr, "end of file on input\n");
break;
}
// 写入音频数据
if ((err = snd_pcm_writei(playback_handle, buffer, frames)) != frames)
{
fprintf(stderr, "write to audio interface failed (%s)\n",
snd_strerror(err));
exit(1);
}
}

free(buffer);
/* Stop PCM device after pending frames have been played */
snd_pcm_drain(playback_handle);
snd_pcm_close(playback_handle);
exit(0);
}
也可以自己读取数据写入到硬件,但是太麻烦了就不研究了。

作者:伯莎boy
链接:https://www.jianshu.com/p/67c63df551d9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。