- /*
- 本程序维护一个 256bytes*4 缓冲区,两个信号量保护(读和写)。创建两
- 个线程,一个用于采集声卡数据并写到缓冲区,数据采集线程使用ALSA接口
- 编程,设置采样率 22333,周期帧数 128,帧格式 U8,声道数 2,每个周期
- 大约 5.73ms,每个周期 256bytes。另外一个将缓冲区数据广播到网络,每
- 次发送 256bytes。
- */
- #define ALSA_PCM_NEW_HW_PARAMS_API
- #include <alsa/asoundlib.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <stdlib.h>
- #include <semaphore.h>
- #include <sys/types.h> /* basic system data types */
- #include <sys/socket.h> /* basic socket definitions */
- #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
- #include <arpa/inet.h> /* inet(3) functions */
- #define RATE 22333
- #define CHANNEL 2
- #define FORMAT SND_PCM_FORMAT_U8
- #define FRAMES 128
- #define SIZE CHANNEL*FRAMES*1
- #define NBUFF 4
- // 套接字端口
- #define PORT 10000
- #define SA struct sockaddr
- // 数据缓冲区及信号量
- struct {
- char buffer[1024];
- sem_t mutex, nempty, nstored;
- } shared;
- char* pRead = shared.buffer; //读指针
- char* pWrite = shared.buffer; //写指针
- void* sendData(void *arg); //线程函数,广播数据
- void* generateData(void *arg); //线程函数,读声卡
- // 计数变量
- long produce=0;
- long consume=0;
- long totalTime = 0;
- int main()
- {
- pthread_t tid_generateData, tid_sendData;
- // 初始化信号量
- sem_init(&shared.mutex, 0, 1); //未用到
- sem_init(&shared.nempty, 0, NBUFF);
- sem_init(&shared.nstored, 0, 0);
- // 创建读声卡线程,将数据保存到缓冲区
- pthread_create(&tid_generateData, NULL, generateData, NULL);
- // 创建广播线程,将缓冲区数据发送到网络
- pthread_create(&tid_sendData, NULL, sendData, NULL);
- pthread_join(tid_sendData, NULL);
- pthread_join(tid_generateData, NULL);
- sem_destroy(&shared.mutex);
- sem_destroy(&shared.nempty);
- sem_destroy(&shared.nstored);
- exit(0);
- }
- void* sendData(void *arg)
- {
- int sockfd;
- struct sockaddr_in servaddr;
- /* socket 初始化 */
- const int on = 1;
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(PORT);
- inet_pton(AF_INET, "192.168.1.255", &servaddr.sin_addr);
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- int n;
- const SA *pservaddr = (SA*)(&servaddr);
- socklen_t servlen = sizeof(SA);
- printf("\n\n\n\n\nData generating starts, Broadcasting ...\n\n\n\n\n\n\n\n\n\n");
- printf("|------------------------------------------------------------|\t0\tmin |\n\033[1A|");
- while(1)
- {
- // 获取nstored信号量
- sem_wait(&shared.nstored);
- // 发送数据
- n = sendto(sockfd, pRead, 256, 0, pservaddr, servlen);
- if(n!=256) //printf("send short: send %d\n",n)
- {
- sem_post(&shared.nstored);
- continue;
- }
- // 更新缓冲区读指针
- pRead += 256;
- if(pRead-1024 == shared.buffer)
- pRead = shared.buffer;
- // 释放nempty信号量
- sem_post(&shared.nempty);
- // 计数器
- if(0 == ++consume % 175)
- {
- ++totalTime;
- printf("-");
- fflush(stdout);
- if(0 == totalTime %60)
- printf("|\t%ld\tmin |\n\033[1A|", totalTime/60),fflush(stdout);
- }
- }
- }
- void* generateData(void *arg)
- {
- // 设备打开初始化配置
- int rc;
- snd_pcm_t *handle;
- snd_pcm_hw_params_t *params;
- unsigned int val = RATE; // 采样率 22333
- int dir;
- snd_pcm_uframes_t frames;
- rc = snd_pcm_open(&handle, "default",SND_PCM_STREAM_CAPTURE, 0); // 打开方式为“抓取数据”
- if (rc < 0)
- {
- fprintf(stdout, "unable to open pcm device: %s\n",snd_strerror(rc));
- exit(1);
- }
- snd_pcm_hw_params_alloca(¶ms);
- snd_pcm_hw_params_any(handle, params);
- snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);
- snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_U8); //帧数据格式,每帧1byte
- snd_pcm_hw_params_set_channels(handle, params, 2); // 声道数 2
- snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); // 获取真实采样率 22333
- snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); // 获取每周期帧数 64
- rc = snd_pcm_hw_params(handle, params);
- if (rc < 0)
- {
- fprintf(stdout,"unable to set hw parameters: %s\n", snd_strerror(rc));
- exit(1);
- }
- snd_pcm_hw_params_get_period_size(params, &frames, &dir);
- snd_pcm_hw_params_get_period_time(params, &val, &dir);
- while (1)
- {
- frames = FRAMES; // 更改每周期的帧数,设置为128
- sem_wait(&shared.nempty);
- rc = snd_pcm_readi(handle, pWrite, frames); // 获取256 Bytes 数据
- if (rc != (int)frames)
- {
- usleep(1000);
- snd_pcm_prepare(handle);
- sem_post(&shared.nempty);
- continue;
- }
- // 更新缓冲区写指针
- pWrite += 256;
- if(pWrite-1024 == shared.buffer)
- pWrite = shared.buffer;
- sem_post(&shared.nstored);
- // 计数器
- ++produce;
- }
- snd_pcm_drain(handle);
- snd_pcm_close(handle);
- }
- /*
- 本程序维护一个256bytes*4缓冲区,两个信号量保护(读和写)。创建两
- 个线程,一个监听广播消息并将获取的数据写到缓冲区,另外一个线程将
- 缓冲区数据写到声卡。写声卡编程使用ALSA接口编程,采样率 22333,周
- 期帧数128,帧格式U8,声道数2,计算下来,每个周期大约 5.73ms,每个
- 周期256bytes。
- */
- #define ALSA_PCM_NEW_HW_PARAMS_API
- #include <alsa/asoundlib.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <stdlib.h>
- #include <semaphore.h>
- #include <sys/types.h> /* basic system data types */
- #include <sys/socket.h> /* basic socket definitions */
- #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
- #include <arpa/inet.h> /* inet(3) functions */
- // 声卡配置参数
- #define RATE 22333
- #define CHANNEL 2
- #define FORMAT SND_PCM_FORMAT_U8
- #define FRAMES 128
- #define SIZE CHANNEL*FRAMES*1
- #define NBUFF 4
- #define SEM_MUTEX "mutex"
- #define SEM_NEMPTY "nempty"
- #define SEM_NSTORED "nstored"
- #define PORT 10000
- #define SA struct sockaddr
- // 缓冲区及信号量
- struct {
- char buffer[1024];
- sem_t mutex, nempty, nstored;
- } shared;
- // 缓冲区读写指针
- char* pRead = shared.buffer;
- char* pWrite = shared.buffer;
- void* recvData(void *arg);
- void* generateSnd(void *arg);
- // 计数变量
- long produce=0;
- long consume=0;
- long totalTime = 0;
- int main()
- {
- pthread_t tid_generateSnd, tid_recvData;
- // 信号量初始化
- sem_init(&shared.mutex, 0, 1); //未使用
- sem_init(&shared.nempty, 0, NBUFF);
- sem_init(&shared.nstored, 0, 0);
- // 创建发声线程
- pthread_create(&tid_generateSnd, NULL, generateSnd, NULL);
- // 创建数据接收线程
- pthread_create(&tid_recvData, NULL, recvData, NULL);
- pthread_join(tid_recvData, NULL);
- pthread_join(tid_generateSnd, NULL);
- sem_destroy(&shared.mutex);
- sem_destroy(&shared.nempty);
- sem_destroy(&shared.nstored);
- exit(0);
- }
- void* recvData(void *arg)
- {
- // 配置socket
- int sockfd;
- struct sockaddr_in servaddr;
- /* initialization for socket */
- const int on = 1;
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(PORT);
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
- setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- int n;
- SA *preply_addr = (SA*)malloc(sizeof(SA));
- socklen_t len = sizeof(SA);
- // 计时器
- printf("\n\n\n\n\nData receiving starts, voice generating ...\n\n\n\n\n\n\n\n\n\n");
- printf("|------------------------------------------------------------|\t0\tmin |\n\033[1A|");
- for (;;)
- {
- // 获取写信号量
- sem_wait(&shared.nempty);
- // 监听网络,并将数据写到缓冲区
- n = recvfrom(sockfd, pWrite, 256, 0, preply_addr, &len);
- if (n < 0) {
- if (errno == EINTR)
- break; /* waited long enough for replies */
- }
- else if(n != 256)
- {
- sem_post(&shared.nempty);
- continue;
- }
- else
- {
- // 更新写指针
- pWrite += 256;
- if(pWrite-1024 == shared.buffer)
- pWrite = shared.buffer;
- // 释放读信号量
- sem_post(&shared.nstored);
- if(0 == ++produce % 175)
- {
- ++totalTime;
- printf("-");
- fflush(stdout);
- if(0 == totalTime %60)
- printf("|\t%ld\tmin |\n\033[1A|", totalTime/60),fflush(stdout);
- }
- }
- }
- free(preply_addr);
- }
- void* generateSnd(void *arg)
- {
- // 声卡配置变量
- int rc;
- snd_pcm_t *handle;
- snd_pcm_hw_params_t *params;
- unsigned int val = RATE;
- int dir;
- snd_pcm_uframes_t frames;
- rc = snd_pcm_open(&handle, "default",SND_PCM_STREAM_PLAYBACK, 0); // 播放模式打开
- if (rc < 0)
- {
- fprintf(stderr, "unable to open pcm device: %s\n",snd_strerror(rc));
- exit(1);
- }
- // 配置声卡,和发送进程的声卡配置一致
- snd_pcm_hw_params_alloca(¶ms);
- snd_pcm_hw_params_any(handle, params);
- snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);
- snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_U8);
- snd_pcm_hw_params_set_channels(handle, params, 2);
- snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
- snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
- rc = snd_pcm_hw_params(handle, params);
- if (rc < 0)
- {
- fprintf(stderr,"unable to set hw parameters: %s\n", snd_strerror(rc));
- exit(1);
- }
- snd_pcm_hw_params_get_period_size(params, &frames, &dir);
- snd_pcm_hw_params_get_period_time(params, &val, &dir);
- while (1)
- {
- frames = FRAMES;
- // 获取读信号量
- sem_wait(&shared.nstored);
- // 向声卡写数据
- rc = snd_pcm_writei(handle, pRead, frames);
- if (rc != (int)frames)
- {
- usleep(1000);
- snd_pcm_prepare(handle);
- sem_post(&shared.nstored);
- continue;
- }
- // 更新读指针
- pRead += 256;
- if(pRead-1024 == shared.buffer)
- pRead = shared.buffer;
- // 释放写信号量
- sem_post(&shared.nempty);
- ++consume;
- }
- snd_pcm_drain(handle);
- snd_pcm_close(handle);
- }