Linux应用程序--WAV与AMR


AMR,全称是:Adaptive Multi-Rate,自适应多速率,是一种音频编码文件格式,专用于有效地压缩语音频率,用于移动设备的音频压缩,压缩比非常高,但是音质比较差,主要用于语音类的音频压缩,不适合对音质要求较高的音乐类音频的压缩。


WAV头文解析:

typedef struct
{
  char id[4];
  uint32_t size;
} chunk_t;

typedef struct
{
  uint16_t format;   // 格式类别
  uint16_t channels; // 声道数
  uint32_t sample;   // 采样速率
  uint32_t bytes;    // 数据传输速度(每秒数据量字节数)
  uint16_t align;    // 数据块对齐
  uint16_t bits;     // 采样位数
} fmt_t;

void show_wave_info(void *buff, int len)
{
  fmt_t *pfmt = (fmt_t *)buff;
  printf("格式类别:%d(1:PCM)\r\n", pfmt->format);
  printf("声 道 数:%d\r\n", pfmt->channels);
  printf("采样频率:%d\r\n", pfmt->sample);
  printf("采样位数:%d\r\n", pfmt->bits);
  printf("每秒数据量:%d\r\n", pfmt->bytes);
  printf("数据块对齐单位:%d\r\n", pfmt->align);      
}

void show_chunk(chunk_t *p)
{
  printf("%c%c%c%c %d\r\n",
         p->id[0],
         p->id[1],
         p->id[2],
         p->id[3],
         p->size);
}

int read_wave_head(int fd, fmt_t *fmt)
{
  int ret;
  char buff[1024];
  chunk_t chunk;

  // 读RIFF及WAVE
  ret = read(fd, buff, 12);

  // 读fmt字段
  ret = read(fd, &chunk, 8);
  if (ret == 8)
  {
    read(fd, fmt, chunk.size);
    show_wave_info(fmt, chunk.size);
  }

  // 读下一字段(LIST或data)
  ret = read(fd, &chunk, 8);
  if (ret == 8)
  {
    show_chunk(&chunk);
  }
  if (!strncmp(chunk.id, "data", 4))
  {
    return chunk.size;
  }
  // 读取LIST的内容字节
  read(fd, buff, chunk.size); 

  // 这里应该是data段了
  ret = read(fd, &chunk, 8);
  show_chunk(&chunk);

  return chunk.size;
}

AMR编解码:

安装开发库: libopencore-amrnb
编译选项: -lopencore-amrnb
头文件相关:

#include <opencore-amrnb/interf_dec.h>
// 通过帧头编码格式,转换帧长
const char amr_f_sizes[] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0 };
AmrInterface = Decoder_Interface_init();
// 读取6个字节的文件头
ret = read(fd, inbuff, 6);
while (1)
{
  // 先读取1字节的帧头
  read(fd, inbuff, 1);
  // 剔除坏帧
  if(inbuff[0] & 0x04)
  {
    continue;
  }
  // 通过帧头计算帧长
  n = (inbuff[0] >> 3) & 0x07;
  ret = read(fd, &inbuff[1], amr_f_sizes[n]);
  // 音频解码
  Decoder_Interface_Decode(AmrInterface, inbuff, (int16_t *)(outbuff), 0);
  // 播放解码数据
  ret = snd_pcm_writei(snd_pcm, outbuff, frames);
}

- 阅读全文 -

Linux应用程序--ALSA编程


文章摘要:
本文主要描述了采用alsa接口播放wav格式声音方法,稍后抄一些关于alsa的介绍补充。

运行环境:debian8


安装alsa应用程序接口库:

编译选项: -lasound


打开并初始化设备:

#include <alsa/asoundlib.h>

snd_pcm_t *snd_pcm;      
snd_pcm_hw_params_t *params;    
unsigned int sample     = 44100;    // 采样率(重要)
unsigned int channels   = 1;        // 通道数量
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; 

/*
 * 初始化ALSA设备
 */
int alsa_init(void)
{
  int ret;     
  snd_pcm_uframes_t frames = 1024;
   
  // 打开音频设备
  ret = snd_pcm_open(&snd_pcm, "default",SND_PCM_STREAM_PLAYBACK, 0);
  if (ret)
  {
    printf("can not open pcm device: %s\r\n", snd_strerror(ret));
    return -1;
  }
  // 分配参数内存(将指针地址传入)
  snd_pcm_hw_params_alloca(&params);
  // 填充默认参数
  snd_pcm_hw_params_any(snd_pcm, params);
  // 初始化访问权限
  ret = snd_pcm_hw_params_set_access(snd_pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (ret < 0) 
  {
    printf("set_access error: %s\r\n", snd_strerror(ret));
    return -2;
  }
  // 设置数据格式: SND_PCM_FORMAT_S16_LE/S24_LE/U8
  snd_pcm_hw_params_set_format(snd_pcm, params, format);
  // 设置通道数量(重要)
  snd_pcm_hw_params_set_channels(snd_pcm, params, channels);
  // 设置采样率(重要)
  snd_pcm_hw_params_set_rate_near(snd_pcm, params, &sample, 0);
  
#if 0
  // 设置每个周期有多少帧(可采用默认值)  
  ret = snd_pcm_hw_params_set_period_size_near(snd_pcm, params,&frames, 0);
  if(ret < 0)
  {
    printf("set_period_size error: %s\r\n", snd_strerror(ret));    
  }
  printf("frames = %d\r\n", frames);
#endif
  
  // 将参数写入设备
  ret = snd_pcm_hw_params(snd_pcm, params);
  if(ret < 0)
  {
    printf("write params failed: %s\r\n", snd_strerror(ret));    
    return -3;
  }   
  
  // 读取每周期帧数
  snd_pcm_hw_params_get_period_size(params, &frames, 0);
  
  return 0;
}

播放WAV格式:

int main(int argc, char** argv)
{
  int fd;
  int ret;
  int count;
  char *pdata;                  // 数据指针
  char buff[2048];
  snd_pcm_uframes_t frames;
  
  // 打开声音文件
  fd = open(argv[1], O_RDONLY);
  if (fd < 0)
  {
    perror("can not open snd file ");
  }
     
  // 读取文件头并解析相关参数,此处先跳过文件头,再WAV章节再做解析
  ret = read(fd, buff, 44); 
    
  // 初始化声卡
  alsa_init(); 
  // 获取每周期的帧数
  snd_pcm_hw_params_get_period_size(params, &frames, 0);
  // 计算单次数据长度 = 每周期帧数*通道号*样本数据位数/8
  count = frames * channels * 2;
  
  printf("size = %d\r\n", count);
  
  pdata = malloc(count);
  if(pdata == NULL)
  {
    printf("malloc failed\r\n");    
  }

  while (1)
  {
    // 从文件读入声音数据
    ret = read(fd, pdata, count);
    if (ret <= 0)
    {
      break;
    }
     
    // 将数据写入alsa播放(写入的帧数是前边读出来的值)
    ret = snd_pcm_writei(snd_pcm, pdata, frames);
    if (ret == -EPIPE)
    {
      snd_pcm_prepare(snd_pcm);
    }
  }

  // 等待缓冲区数据播放结束
  while(snd_pcm_avail_update(snd_pcm) > 0)
  {
    usleep(20 * 1000);
  }

  snd_pcm_drop(snd_pcm);
  snd_pcm_drain(snd_pcm);
  snd_pcm_close(snd_pcm); // 关闭ALSA
  
  close(fd); // 关闭文件
}

移植alsa库至ARM平台:
下载地址:https://www.alsa-project.org/files/pub/lib/
软件版本:alsa-lib-1.2.1.tar.bz2

# ./configure --host=arm-linux --prefix=/opt/rootfs CC=arm-linux-gnueabihf-gcc
# make
# make install

注意事项:
V1.2.2版本有问题,交叉编译报错。

- 阅读全文 -

samba配置及应用


通过命令man smb.conf来查看配置说明

samba定义的变量:

%S = 当前服务名(如果有的话) 
%P = 当前服务的根目录(如果有的话) 
%u = 当前服务的用户名(如果有的话) 
%g = 当前用户所在的主工作组 
%U = 当前对话的用户名 
%G = 当前对话的用户的主工作组 
%H = 当前服务的用户的Home目录 
%v = Samba服务的版本号。 
%h = 运行Samba服务机器的主机名 
%m = 客户机的NETBIOS名称 
%L = 服务器的NETBIOS名称 
%M = 客户机的主机名 
%N = NIS服务器名 
%p = NIS服务的Home目录 
%R = 说采用的协议等级(值可以是CORE, COREPLUS, LANMAN1, LANMAN2,NT1) 
%d = 当前服务进程的ID 
%a = 客户机的结构(只能识别几项:Samba,WfWg,WinNT,Win95) 
%I = 客户机的IP 
%T = 当前日期和时间 

设置匿名用户的用户名: 不设置的话默认为nobody不能上传文件。

[global]
guest account = user

运行日志:
貌似只有操作失败时的日志

 # 设置日志路径(每个连接单独生成一个文件)
 log file = /var/log/samba/log.%I

 # 设置单个日志文件的大小,单位KB,0表示无限制
 max log size = 1000

示例:

[usbdisk]
   comment = Users profiles
   path = /media/usbdisk
   guest ok = yes
   browseable = yes
   create mask = 0600
   directory mask = 0700
   writable = yes
   vaild users = user

browseable 表示是否可以显示列表,不显示时需要可直接输入路径访问; //10.0.10.1/usbdisk
guest ok 表示是否允许匿名用户访问

- 阅读全文 -

Linux文件系统(四)--其他


修改/dev/pty数量(虚拟终端)
重新配置内核,设置数量:

Device Drivers  --->
    Character devices  --->
        [*]   Legacy (BSD) PTY support
        (3)     Maximum number of legacy PTY in use

修改/dev/tty的数量(终端):

修改include/linux/vt.h(kernel代码,不同版本的位置有所不同)
#define MIN_NR_CONSOLES 1       /* must be at least 1 */
#define MAX_NR_CONSOLES 63      /* serial lines start at 64 */
#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */

修改/dev/ram的数量(ramdisk):

Device Drivers  --->
    [*] Block devices  --->
        <*>   RAM block device support    
        (16)    Default number of RAM disks

如果不需要用到ramdisk,可以直接取消对其的支持;


回环设备loop

/dev/loop应用说明:主要用于挂载iso等文件

# losetup /dev/loop0 abc.iso
# mount /dev/loop0 /media  

# umount /media
#losetup -d /dev/loop0

实际使用中一般直接用-o参数来挂载

# mount -o loop abc.iso /media  

修改/dev/loop数量:

# 修改 /etc/modprob.conf文件
options loop max_loop=64

重新加载loop模块

# rmmod loop
# modprobe loop

- 阅读全文 -

Linux文件系统(三)--高级应用


文章摘要:本文描述了在Linux文件系统中常用的一些应用。


新建用户的home目录文件
/etc/skel
此目录中的文件是创建用户时在其家目录中自动生成的默认文件

.profile 用户配置,登录时自动运行
.bashrc 由.profile脚本显式调用
.bash_logout


开启/取消自动登陆
修改/etc/inittab

# 自动登陆
::respawn:-/bin/sh

# 非自动登陆
::respawn:-/sbin/getty 115200 /dev/ttyO0
::respawn:-/bin/login

执行su命令时提示:

su: must be suid to work properly

将busybox权限修改为4755即可。


last命令: 建立var/log/wtmp文件,以保存最近用户登陆。

- 阅读全文 -


Copyright©2025 春天花会开, All Rights Reserved. Email: webmaster@oroct.com