通过madplay命令进行歌曲播放,功能有: 1、实现音乐的开始播放、结束播放、继续播放、暂停播放; 2、实现歌曲上一首、下一首切换; 3、实现歌曲播放模式的选择(顺序播放、随机播放、单曲循环); 4、实现音量调节(有上限和下限);
通过两个程序控制这个音乐播放器 客户端用来发一些请求就可以了。 服务器端:至少创建三个进程,父进程,子进程阻塞,等待回收孙进程,孙进程负责播放音乐。 父进程:用于监听按键和socket请求,与孙进程进行通信(通过共享内存),告诉孙进程需要播放的歌曲名,以及发送信号给孙进程。 子进程:一直不停的创建孙进程,然后wait等待孙进程结束,再创建新的孙进程。 孙进程:读共享内存中的歌曲名,execl执行madplay,接收父进程发来的信号(暂停,杀死等信号)。 共享内存:三个进程之间的通信用共享内存实现,歌曲列表通过系统调用的函数写道链表中,再fork父子孙三进程。 音量调节:https://blog.csdn.net/zqixiao_09/article/details/50859302
用到的系统调用函数: pid_t fork(void); pid_t waitpid(pid_t pid,int *status, int options); int execl(const char *pathname, const char *arg, ..., (char *)NULL); shmid = shmget(SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL); //创建共享内存 shmaddr = shmat(shmid, NULL, 0); //映射到虚拟地址空间 int ioctl(int handle, int cmd,[int *argdx, int argcx]); //控制I/O设备
源码:
main.c #include "server.h" struct info* shareInfo; int total = 0; Node *first = NULL; pid_t pid; //extern OnMusic[20]; int main() { int shmid; int ret; int status; //初始化链表 ret = LinkInit(&first); if(ret == SUCCESS) { printf("init success \n"); } else { printf("init failure \n"); } //获取歌曲名,顺便把歌曲名插入到链表中 GetName(); printf("total is %d \n",total); //显示链表 ret = LinkShow(first); if(ret == SUCCESS) { printf("show success \n"); } else { printf("show failure \n"); } //开辟共享内存 shmid = shmget(SHMKEY, sizeof(struct info), IPC_CREAT | IPC_EXCL); if(-1 == shmid) { perror("shmget"); exit(1); } //映射到进程的虚拟内存 shareInfo = (struct info*)shmat(shmid, NULL, 0); if(NULL == shareInfo) { perror("shmat"); exit(1); } //初始化共享内存的一些参数 strcpy(shareInfo->order, "off"); strcpy(shareInfo->mode, "order"); shareInfo->num = 1; //创建进程 先创建父子两个进程,再在子进程里面再次调用fork就有了孙进程 pid = fork(); if(pid < 0) { perror("fork"); } else if(pid == 0) { //子进程代码段 printf("clid process id: %d \n", getpid()); //不停的创建孙进程 while(1) { pid = fork(); if(pid < 0) { perror("fork"); } else if(pid == 0) { //孙进程代码段 printf("grandson process id: %d \n", getpid() ); shareInfo->ppid = getpid(); //音乐播放函数 MusicPlay(); } else { printf("clild process id: %d \n", getpid() ); printf("child in wait \n"); //等待孙进程结束 waitpid(pid, &status, 0); //判断孙进程结束状态 //正常退出状态 if(WIFEXITED(status)) { printf("child exit \n"); //查看循环模式,如果是顺序播放就把下一首音乐的歌名存到共享内存中 ret = CheckMode(); if(ret == SUCCESS) { printf("on music is %s\n",shareInfo->name); } else { printf("on music is %s\n",shareInfo->name); } } //被信号杀死而退出,什么都不做,因为再父进程那接收到socket请求的同时以及把歌曲写到共享内存中了 else if(WIFSIGNALED(status)) { printf("siganl kill \n"); } else { printf("......\n"); } } } } else { //父进程代码段 printf("parent process id: %d \n", getpid() ); //父进程的主函数,一直阻塞接收来自客户端socket的请求 Parent_Recv(); } } server.c #include "server.h" int ret; int sound = 1; //音量参数 //int number = 1; extern struct info* shareInfo; //共享内存地址 extern Node *first; //链表首地址 //char OnMusic[20] = "../music/111.mp3"; int devmask, stereodevs; //调节音量的 const char *sound_device_names[] = SOUND_DEVICE_NAMES; //存放可用的音频设备 int devfd; //打开的音频设备的文件描述符 extern int total; //总共的歌曲数目 extern pid; //音频设备的初始化 int DeviceInit(char *dev) { int i; int status; devfd = open("/dev/mixer", O_RDONLY); if (devfd == -1) { perror("unable to open /dev/mixer"); return FAILURE; } status = ioctl(devfd, SOUND_MIXER_READ_DEVMASK, &devmask); if (status == -1) { perror("SOUND_MIXER_READ_DEVMASK ioctl failed"); return FAILURE; } status = ioctl(devfd, SOUND_MIXER_READ_STEREODEVS, &stereodevs); if (status == -1) { perror("SOUND_MIXER_READ_STEREODEVS ioctl failed"); return FAILURE; } for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) { if (((1 << i) & devmask) && !strcmp(dev, sound_device_names[i])) { break; } } if(i == SOUND_MIXER_NRDEVICES) { fprintf(stderr, "%s is not a valid mixer device\n", dev); return FAILURE; } return i; } //父进程的函数 void Parent_Recv() { int fd, sockfd; int length = sizeof(client_addr); int ppid; int device; char choise[10]; Info1 RecvInfo; char vol[10] = "vol"; sockfd = SocketInit(); fd = accept(sockfd, (struct sockaddr *)&client_addr, &length); if(fd == -1) { perror("accept"); } else { printf("client connect success \n"); printf("port is %d fd is %d \n", client_addr.sin_port, fd); } ret = MusicCopy(first, 1); if(ret == SUCCESS) { printf("init music copy success \n"); printf("success on music is %s \n",shareInfo->name); } else { printf("init music copy fialure \n"); printf("failure on music is %s \n",shareInfo->name); } device = DeviceInit(vol); if(device == FAILURE) { printf("device init failure \n"); } else { printf("device init success \n"); } while(1) { printf("in parent while\n"); ret = recv(fd ,&RecvInfo, sizeof(RecvInfo), 0); if(ret == -1) { perror("recv"); } if(strcmp(RecvInfo.flag, "on") == 0) { printf("recv flag : %s \n", RecvInfo.flag); strcpy(shareInfo->order, "on"); printf("chareinfo order : %s \n", shareInfo->order); kill(shareInfo->ppid, SIGCONT); } else if(strcmp(RecvInfo.flag, "off") == 0) { printf("recv flag : %s \n", RecvInfo.flag); strcpy(shareInfo->order, "off"); printf("chareinfo order : %s \n", shareInfo->order); kill(shareInfo->ppid, SIGKILL); } else if(strcmp(RecvInfo.flag, "stop") == 0) { printf("recv flag : %s \n", RecvInfo.flag); strcpy(shareInfo->order, "stop"); printf("chareinfo order : %s \n", shareInfo->order); kill(shareInfo->ppid, SIGSTOP); } else if(strcmp(RecvInfo.flag, "next") == 0) { printf("recv flag : %s \n", RecvInfo.flag); kill(shareInfo->ppid, SIGKILL); strcpy(shareInfo->order, "next"); printf("chareinfo order : %s \n", shareInfo->order); (shareInfo->num)++; if((shareInfo->num) > total) { shareInfo->num = 1; } printf("num is %d \n", shareInfo->num); ret = MusicCopy(first, shareInfo->num); if(ret == SUCCESS) { printf("music copy success \n"); printf("success on music is %s \n",shareInfo->name); } else { printf("music copy fialure \n"); printf(" fial on music is %s \n",shareInfo->name); } } else if(strcmp(RecvInfo.flag, "front") == 0) { printf("recv flag : %s \n", RecvInfo.flag); kill(shareInfo->ppid, SIGKILL); strcpy(shareInfo->order, "front"); printf("chareinfo order : %s \n", shareInfo->order); (shareInfo->num)--; if((shareInfo->num) <= 0) { shareInfo->num = total; } printf("num is %d \n", shareInfo->num); ret = MusicCopy(first, shareInfo->num); if(ret == SUCCESS) { printf("music copy success \n"); printf("success on music is %s \n",shareInfo->name); } else { printf("music copy fialure \n"); printf("failure on music is %s \n",shareInfo->name); } } else if(strcmp(RecvInfo.flag, "poweron") == 0) { printf("recv flag : %s \n", RecvInfo.flag); sound++; printf("soud is %d \n", sound); ret = Sound(device, sound); if(ret == SUCCESS) { printf("soud is %d\n", sound); } else { printf("sound failure \n"); } } else if(strcmp(RecvInfo.flag, "poweroff") == 0) { printf("recv flag : %s \n", RecvInfo.flag); sound--; printf("soud is %d \n", sound); ret = Sound(device, sound); if(ret == SUCCESS) { printf("soud is %d\n", sound); } else { printf("sound failure \n"); } } else if(strcmp(RecvInfo.flag, "sigal") == 0) { printf("recv flag : %s \n", RecvInfo.flag); strcpy(shareInfo->mode, "sigal"); } else if(strcmp(RecvInfo.flag, "order") == 0) { printf("recv flag : %s \n", RecvInfo.flag); strcpy(shareInfo->mode, "order"); } else if(strcmp(RecvInfo.flag, "random") == 0) { printf("recv flag : %s \n", RecvInfo.flag); strcpy(shareInfo->mode, "random"); } else if(strcmp(RecvInfo.flag, "quit") == 0) { printf("recv flag : %s \n", RecvInfo.flag); kill(shareInfo->ppid, SIGKILL); kill(pid,SIGKILL); exit(1); } else { sleep(3); printf("wait client \n"); } } } //调节音量 dev:设备名 num:音量参数 int Sound(int dev, int num) { int left, right, level; int status; if(num > 5 || num < 0) { return FAILURE; } switch(num) { case 1: left = 50; right = 50; level = (right << 8) + left; status = ioctl(devfd, MIXER_WRITE(dev), &level); if (status == -1) { perror("MIXER_WRITE ioctl failed"); return FAILURE; } left = level & 0xff; right = (level & 0xff00) >> 8; fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right); break; case 2: left = 60; right = 60; level = (right << 8) + left; status = ioctl(devfd, MIXER_WRITE(dev), &level); if (status == -1) { perror("MIXER_WRITE ioctl failed"); return FAILURE; } left = level & 0xff; right = (level & 0xff00) >> 8; fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right); break; case 3: left = 70; right = 70; level = (right << 8) + left; status = ioctl(devfd, MIXER_WRITE(dev), &level); if (status == -1) { perror("MIXER_WRITE ioctl failed"); return FAILURE; } left = level & 0xff; right = (level & 0xff00) >> 8; fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right); break; case 4: left = 80; right = 80; level = (right << 8) + left; status = ioctl(devfd, MIXER_WRITE(dev), &level); if (status == -1) { perror("MIXER_WRITE ioctl failed"); return FAILURE; } left = level & 0xff; right = (level & 0xff00) >> 8; fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right); break; case 5: left = 90; right = 90; level = (right << 8) + left; status = ioctl(devfd, MIXER_WRITE(dev), &level); if (status == -1) { perror("MIXER_WRITE ioctl failed"); return FAILURE; } left = level & 0xff; right = (level & 0xff00) >> 8; fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right); break; case 6: left = 100; right = 100; level = (right << 8) + left; status = ioctl(devfd, MIXER_WRITE(dev), &level); if (status == -1) { perror("MIXER_WRITE ioctl failed"); return FAILURE; } left = level & 0xff; right = (level & 0xff00) >> 8; fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right); break; } return SUCCESS; } //把链表中的第num首歌写道共享内存中 int MusicCopy(Node *l, int num) { int k = 1; printf("node is %s \n", l); if(NULL == l) { printf("l is null\n"); return FAILURE; } Node *p = l; while(k <= num && p != NULL) { printf("k < num failure \n"); p = p->next; k++; } if((k > (num + 1)) || p == NULL) { printf("k > num failure \n"); return FAILURE; } strcpy(shareInfo->name, p->music_name); printf("share music name is:%s \n",shareInfo->name); return SUCCESS; } //socket初始化 int SocketInit() { int sockfd; sockfd = socket(PF_INET, SOCK_STREAM, 0); if(-1 == sockfd) { perror("socket"); //exit(1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = PF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr("192.168.162.128"); ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if(ret < 0) { perror("bind"); // exit(1); } ret = listen(sockfd, 5); if(ret < 0) { perror("listen"); // exit(1); } return sockfd; } //获取歌曲的名字 void GetName() { char name[20]; char flag[10]; DIR *dirp; struct dirent *dp; const char *dirpath = "./music"; dirp = opendir(dirpath); if (dirp == NULL) { printf("opendir failed on '%s'", dirpath); return; } while(1) { dp = readdir(dirp); if (dp == NULL) { break; } else if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) { continue; } else { strcpy(name, dirpath); strcat(name, "/"); strcat(name, dp->d_name); } ret = LinkInsert(first, name); if(ret == SUCCESS) { total++; printf("insert success \n"); } else { printf("insert failure \n"); } printf("total is %d \n",total); } } //链表初始化 int LinkInit(Node **l) { *l = (Node *)malloc(sizeof(Node)); if(NULL == *l) { return FAILURE; } (*l)->next = NULL; return SUCCESS; } int LinkInsert(Node *l, char *name) { if(l == NULL) { return FAILURE; } if(name == NULL) { return FAILURE; } Node *p = l; while(p->next != NULL) { p = p->next; } Node *n = (Node *)malloc(sizeof(Node)); p->next = n; strcpy(n->music_name, name); n->next = NULL; return SUCCESS; } int LinkShow(Node *l) { if(NULL == l) { return FAILURE; } Node *p = l; while(p->next != NULL) { p = p->next; printf("link info :%s \n", p->music_name); } return SUCCESS; } /* char* GetLink(Node *l, int num) { char buf[10] = "false"; char *name; name = (char *)malloc(10); int k = 1; if(NULL == l) { return buf; } Node *p = l; while(k <= num && p != NULL) { p = p->next; k++; } if(k > num || p == NULL) { return buf; } strcpy(name, p->music_name); return name; } */ //********************************** //检查播放模式 int CheckMode() { printf("this mode is %s \n", shareInfo->mode); if(strcmp(shareInfo->mode, "sigal") == 0) { ret = MusicCopy(first, shareInfo->num); if(ret == SUCCESS) { printf("music copy success \n"); printf("success on music is %s \n",shareInfo->name); } else { printf("music copy fialure \n"); printf("fail on music is %s \n",shareInfo->name); } } else if(strcmp(shareInfo->mode, "order") == 0) { (shareInfo->num)++; if((shareInfo->num) > total) { shareInfo->num = 1; } printf("set mode num is %d \n", shareInfo->num); ret = MusicCopy(first, shareInfo->num); if(ret == SUCCESS) { printf("music copy success \n"); printf("success on music is %s \n",shareInfo->name); } else { printf("music copy fialure \n"); printf("fail on music is %s \n",shareInfo->name); } } else if(strcmp(shareInfo->mode, "random") == 0) { shareInfo->num = rand()%total; ret = MusicCopy(first, shareInfo->num); if(ret == SUCCESS) { printf("music copy success \n"); printf("success on music is %s \n",shareInfo->name); } else { printf("music copy fialure \n"); printf("fail on music is %s \n",shareInfo->name); } } else { return FAILURE; } return SUCCESS; } void KillPro() { printf("kill signal \n"); } void StopPro() { // printf("stop signal \n"); } void ContPro() { // printf("cont signal \n"); } //孙进程的音乐播放函数 void MusicPlay() { char opt[10] = " "; signal(SIGKILL, KillPro); signal(SIGSTOP, StopPro); signal(SIGCONT, ContPro); /* ret = CheckMode(); if(ret == SUCCESS) { printf("on music is %s\n",shareInfo->name); } else { printf("on music is %s\n",shareInfo->name); } */ while(1) { printf("madplay share info music is : %s \n", shareInfo->name); printf("madplay share info order is : %s \n", shareInfo->order); printf("madplay No%d \n",shareInfo->num); if(strcmp(shareInfo->order, "off") != 0) { execl("/usr/local/bin/madplay" , opt , shareInfo->name , NULL); } { sleep(3); printf("wait client \n"); } } } server.h #ifndef MUSIC_H #define MUSIC_H #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/socket.h> #include <dirent.h> #include <sys/ioctl.h> #include <linux/soundcard.h> #define SHMKEY 1234 #define PORT 7777 #define FAILURE 10000 #define SUCCESS 10001 #define TRUE 10002 #define FALSE 10003 struct sockaddr_in server_addr; struct sockaddr_in client_addr; struct info { int ppid; int num; char name[20]; char order[10]; char mode[10]; }; typedef struct info Info; struct info1 { char flag[10]; char music[20]; }; typedef struct info1 Info1; struct node { char music_name[20]; struct node *next; }; typedef struct node Node; int LinkShow(Node *l); void Parent_Recv(); int SocketInit(); void Child_Pro(); void GetName(); int LinkInit(Node **l); int LinkInsert(Node *l, char *name); void MusicPlay(); #endif