capture-send-play

本文介绍了一种使用 UDP 和 ALAW 编码进行流媒体传输的方法,包括创建 UDP 套接字、配置 ALSA PCM 设备、设置硬件参数、发送 ALAW 编码的音频数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <errno.h>
  #include <string.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <netdb.h>
  #include <fcntl.h>
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <netinet/in.h>
  #include <alsa/asoundlib.h>
   
  #define UDP_TARGET_HOST "127.0.0.1"
  #define UDP_TARGET_PORT "4001"
  #define UDP_PACKET_SIZE 64
  #define ALSA_SAMPLE_RATE 8000
  #define ALSA_CHANNELS 1
   
  main (int argc, char *argv[]) {
   
  int err;
  int buffer_frames = 128;
   
  struct addrinfo hints;
  memset(&hints,0,sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = 0;
  hints.ai_flags = AI_ADDRCONFIG;
   
  struct addrinfo* res=0;
  getaddrinfo(UDP_TARGET_HOST, UDP_TARGET_PORT, &hints, &res);
   
  int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
  if (sock==-1) {
  fprintf(stderr, "cannot create udp socket (%s)\n", strerror(errno));
  return -1;
  }
   
  snd_pcm_t *capture_handle;
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_format_t format = SND_PCM_FORMAT_A_LAW;
   
  if ((err = snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 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);
  }
   
  snd_pcm_hw_params_any(capture_handle, hw_params);
  snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  snd_pcm_hw_params_set_format(capture_handle, hw_params, format);
  snd_pcm_hw_params_set_rate(capture_handle, hw_params, ALSA_SAMPLE_RATE, 0);
  snd_pcm_hw_params_set_channels(capture_handle, hw_params, ALSA_CHANNELS);
  snd_pcm_hw_params_set_period_size(capture_handle, hw_params, 32, 0);
  snd_pcm_hw_params(capture_handle, hw_params);
  snd_pcm_hw_params_free(hw_params);
   
  if ((err = snd_pcm_prepare(capture_handle)) < 0) {
  fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err));
  exit (1);
  }
   
   
  uint8_t buffer[UDP_PACKET_SIZE];
  while (1) {
  if ((err = snd_pcm_readi(capture_handle, buffer, sizeof(buffer))) != sizeof(buffer)) {
  fprintf(stderr, "read from audio interface failed (%s)\n", snd_strerror(err));
  break;
  }
   
  if (sendto(sock, buffer, sizeof(buffer), 0, res->ai_addr,res->ai_addrlen)==-1) {
  fprintf(stderr, "udp sendto failed(%s)\n", strerror(errno));
  break;
  }
  }
   
  snd_pcm_close(capture_handle);
  exit(0);
  }



#include <errno.h>
  #include <string.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <netdb.h>
  #include <fcntl.h>
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <netinet/in.h>
  #include <time.h>
   
  #define UDP_TARGET_HOST "127.0.0.1"
  #define UDP_TARGET_PORT "4001"
  #define UDP_PACKET_SIZE 64
  #define FILE_SAMPLE_RATE 8000
   
  int8_t alaw_encode(int16_t number)
  {
  /*
  * Taken from:
  * http://dystopiancode.blogspot.de/2012/02/pcm-law-and-u-law-companding-algorithms.html
  */
   
  const uint16_t ALAW_MAX = 0xFFF;
  uint16_t mask = 0x800;
  uint8_t sign = 0;
  uint8_t position = 11;
  uint8_t lsb = 0;
  if (number < 0) {
  number = -number;
  sign = 0x80;
  }
  if (number > ALAW_MAX) {
  number = ALAW_MAX;
  }
  for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--);
  lsb = (number >> ((position == 4) ? (1) : (position - 4))) & 0x0f;
   
  return (sign | ((position - 4) << 4) | lsb) ^ 0x55;
  }
   
  int main(int argc, char **argv) {
   
  struct addrinfo hints;
  memset(&hints,0,sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = 0;
  hints.ai_flags = AI_ADDRCONFIG;
   
  struct addrinfo* res=0;
  getaddrinfo(UDP_TARGET_HOST, UDP_TARGET_PORT, &hints, &res);
   
  int fd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
  if (fd==-1) {
  puts(strerror(errno));
  return -1;
  }
   
  int readfd = open(argv[1], O_RDONLY);
  if (!readfd) { perror("could not open file"); }
   
  struct timespec t_next_send;
  clock_gettime(CLOCK_MONOTONIC, &t_next_send);
   
  int frame_inteval_us = 1000000 / FILE_SAMPLE_RATE;
  int frames_per_packet = UDP_PACKET_SIZE;
  int packet_interval_us = frames_per_packet * frame_inteval_us;
   
   
  int16_t readbuf[UDP_PACKET_SIZE];
  int8_t sendbuf[UDP_PACKET_SIZE];
   
  while (1) {
  int bytes_read = read(readfd, readbuf, sizeof(readbuf));
  if (bytes_read<=0) { break; }
   
  int i;
  for (i=0; i<UDP_PACKET_SIZE; i++) {
  sendbuf[i] = alaw_encode(readbuf[i]/8);
  }
   
  if (sendto(fd, sendbuf, bytes_read/2, 0, res->ai_addr,res->ai_addrlen)==-1) {
  puts(strerror(errno));
  break;
  }
   
  t_next_send.tv_nsec += 1000*packet_interval_us;
  while (t_next_send.tv_nsec>1000000000UL) {
  t_next_send.tv_nsec -= 1000000000UL;
  t_next_send.tv_sec += 1;
  }
   
  clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next_send, NULL);
  }
   
  close(readfd);
   
  return 0;
   
  }




/*
  * udp-alaw-sink.c
  *
  * Created on: 14.03.2015
  * Author: hd
  */
   
   
  #define ALSA_PCM_NEW_HW_PARAMS_API
   
  #include <alsa/asoundlib.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
   
  #define ALSA_SAMPLE_RATE 8000
  #define ALSA_CHANNELS 1
  #define UDP_ALAW_PORT 4001
  #define UDP_MAX_PACKET_SIZE 1024
   
  int main() {
   
  /* create UDP socket */
  int sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
  perror("Opening datagram socket");
  exit(1);
  }
   
  struct sockaddr_in server_addr;
  bzero((char *) &server_addr, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(UDP_ALAW_PORT);
   
  if (bind(sock, (struct sockaddr *) &server_addr, sizeof(server_addr))) {
  perror("binding datagram socket");
  exit(1);
  }
   
  /* open PCM device */
  snd_pcm_t *pcm_handle;
  int rc = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
  if (rc < 0) {
  fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
  exit(1);
  }
   
  /* set hardware paramters */
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_hw_params_alloca(&hw_params);
  snd_pcm_hw_params_any(pcm_handle, hw_params);
  snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_A_LAW);
  snd_pcm_hw_params_set_channels(pcm_handle, hw_params, ALSA_CHANNELS);
  snd_pcm_hw_params_set_rate(pcm_handle, hw_params, ALSA_SAMPLE_RATE, 0);
  snd_pcm_hw_params_set_period_size(pcm_handle, hw_params, 32, 0);
  rc = snd_pcm_hw_params(pcm_handle, hw_params);
  if (rc < 0) {
  fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
  exit(1);
  }
   
  /* set software paramters */
  snd_pcm_sw_params_t *sw_params;
  snd_pcm_sw_params_malloc(&sw_params);
  snd_pcm_sw_params_current(pcm_handle, sw_params);
  snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, 64);
  rc = snd_pcm_sw_params(pcm_handle, sw_params);
  if (rc < 0) {
  fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
  exit(1);
  }
  snd_pcm_sw_params_free(sw_params);
   
   
  uint8_t buffer[UDP_MAX_PACKET_SIZE];
  struct sockaddr_in client_addr;
   
  while (1) {
  socklen_t client_addr_len = sizeof(client_addr);
  int send_bytes_avail = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_addr_len);
  int send_pos = 0;
  while (send_bytes_avail>0) {
  int rc = snd_pcm_writei(pcm_handle, &buffer[send_pos], send_bytes_avail);
  if (rc>0) {
  send_bytes_avail -= rc;
  send_pos += rc;
  } else if (rc == -EPIPE) {
  /* EPIPE means underrun */
  snd_pcm_prepare(pcm_handle);
  } else { // other error
  break;
  }
  }
  }
   
  close(sock);
  snd_pcm_drain(pcm_handle);
  snd_pcm_close(pcm_handle);
   
  return 0;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值