ALSA 接口编程实例——语音聊天
2017-10-01 11:00
495 查看
本文转自博客:http://blog.csdn.net/u014338577/article/details/49096397
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
本程序维护一个 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);
}
[cpp] view
plaincopy
/*
本程序维护一个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);
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
本程序维护一个 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);
}
[cpp] view
plaincopy
/*
本程序维护一个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);
}
相关文章推荐
- ALSA 接口编程实例——语音聊天
- ALSA 接口编程实例——语音聊天
- 【Socket编程二】利用Socket实现聊天通信的编程实例
- iPhone蓝牙编程之实现语音聊天
- C语言与MATLAB接口 编程与实例 李传军编着
- 百度文字转语音免费接口使用实例
- iPhone蓝牙编程之实现语音聊天 .
- 移动端接口编程之服务器配置与简单API接口实例
- Mybatis 接口编程中dao 层接口没有注解和<bean> 为什么能被实例化为bean??
- VC++之网络编程五 聊天编程实例(UDP)
- 百度文字转语音免费接口使用实例
- 通过生活中例子模拟java面向接口编程实例
- 编程实例------打造武装部队(实战接口)
- 【分析】Ceph编程实例 接口Librbd(C++) -- 映像创建与数据读写
- 接口编程 -实例
- Visual C#事件与接口编程实例
- Visual C#事件与接口编程实例.
- C#接口编程实例解析[转]
- socket编程技巧(1)tcp接收接口(变长数据定长数据)的编写实例
- 百度文字转语音免费接口使用实例