通过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