用链表、信号,实现简易MP3项目
链表实现MP3
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
typedef struct MP3Node
{
char *filename;//数据域,存储指针,里面存储歌曲名
struct MP3Node *next;//指针域
}MP3Node;
void mp3_dvd();
void mp3_caidanname(char * dir1);
void kill_kill(MP3Node *head);
MP3Node *upup(MP3Node *head,MP3Node *nowmusic, char *dir1);
MP3Node *nextnext(MP3Node *head,MP3Node *nowmusic, char *dir1);
void free_head(MP3Node *head);
pid_t pid;//全局变量
int main(int argc, char *argv[])
{
char *dir1 = argv[1];//输入要播放的目录
mp3_caidanname(dir1);
return 0;
}
void mp3_dvd(char *dir1, char *filename)
{
raise(19);//子进程近来先暂停播放
char path[100];
snprintf(path, sizeof(path), "%s/%s", dir1,filename);
execlp("mpg123","mpg123",path,NULL);
exit(EXIT_FAILURE);// 确保子进程退出
}
void mp3_caidanname(char * dir1)
{
int count = 0;//记录歌曲数量
MP3Node *head = NULL;//头指针
MP3Node *tail = NULL;//尾指针
MP3Node *nowmusic = NULL;//现在播放的歌曲
DIR *dirp = NULL;
dirp = opendir(dir1);//打开目录
if(dirp == NULL)
{
perror("opendir");
}
struct dirent *dent = NULL;
while((dent = readdir(dirp)))
{
if(dent->d_type == 8)//DT_REG,普通文件
{
char *filename = dent->d_name;//歌曲名字全存到数据域中
//if(strstr(filename, ".mp3")) ,,char *strstr(const char *haystack, const char *needle);
//strstr()函数返回一个指向haystack中第一次出现needle的指针。如果未找到子字符串,则返回NULL。
if(strstr(filename, ".mp3"))
{
count++;
MP3Node *newfile = (MP3Node *)malloc(sizeof(MP3Node));//重新定义一个newfile保存刚的filename
newfile->filename = strdup(filename);//strdup从堆上分配一块内存,并将传入的字符串复制到这块内存中,然后返回这块内存的指针
newfile->next = NULL;
if(head == NULL)//第一次运行为空
{
head = newfile;//头指针不动
tail = newfile;
}
else//第二次往后链接
{
tail->next = newfile;//尾指针往后连接
tail = newfile;
}
}
}
}
closedir(dirp); // 关闭目录
if(count == 0)
{
printf("此文件夹无歌曲!\n");
free_head(head);
return ;
}
/*glob_t fn = {0};//显示歌单
glob("./mp3file/*.mp3", 0, NULL, &fn);
for(int i = 0; i < fn.gl_pathc; i++)
{
printf("%d.%s\n", i+1,fn.gl_pathv[i]);//glob函数打印歌单
}
globfree(&fn);*/
printf("歌单如下:\n");
MP3Node *menu = head;
int i = 1;
while(menu != NULL)
{
printf("%d.%s\n", i++, menu->filename);
menu = menu->next;
}
int nummusic = 0;//选择要播放的音乐
printf("请选择要播放的音乐:\n");
scanf("%d", &nummusic);
nowmusic = head;//nowmusic指向第一个歌曲
for(int i = 1; i < nummusic; i++)//遍历找到选中的歌曲,例如num = 2,执行一次循环
{
nowmusic = nowmusic->next;//找到第2个数据
}
pid = fork();
if(pid == -1)
{
perror("fork");
free_head(head);
return ;
}
else if(pid == 0)
{
mp3_dvd(dir1,nowmusic->filename);
}
else
{
int val = 0;
while(1)
{
waitpid(pid, NULL, WNOHANG);//检测子进程是否结束
if(waitpid(pid, NULL, WNOHANG) > 0)//子进程结束返回pid号
{
nowmusic = nowmusic->next;
if(nowmusic == NULL)
{
printf("所有歌曲播放完毕!\n");//循环播放
break;
}
}
printf("1,播放 2,暂停 3,上一首 4,下一首 0,退出\n");
system("stty echo");//开回显
printf("\033[?25h");//显示光标
scanf("%d",&val);
switch(val)
{
case 0: kill_kill(head); return ;
case 1: kill(pid, 18); break;//继续
case 2: kill(pid, 19); break;//暂停
case 3: nowmusic = upup(head, nowmusic, dir1); break;//上一首
case 4: nowmusic = nextnext(head, nowmusic, dir1); break; //下一首
}
}
}
}
void kill_kill(MP3Node *head)
{
kill(pid, 9); //杀死子进程
free_head(head);
printf("退出播放器。\n");
}
MP3Node *upup(MP3Node *head,MP3Node *nowmusic, char *dir1)
{
if(nowmusic == head)
{
printf("已经是第一首歌\n");
system("stty echo");//开回显
printf("\033[?25h");//显示光标
}
else
{
MP3Node *up_name = head;//定义上一首指向头指针
while(up_name->next != nowmusic)//上一首!=当前歌曲
{
up_name = up_name->next;//找到上一首歌曲
}
nowmusic = up_name;//把当前歌曲更新为上一首
kill(pid, 9); // 杀掉当前子进程
pid = fork();//重新创建紫禁城
if(pid == -1)
{
perror("fork");
}
else if(pid == 0)
{
mp3_dvd(dir1, nowmusic->filename);
}
}
return nowmusic;
}
MP3Node *nextnext(MP3Node *head,MP3Node *nowmusic, char *dir1)
{
if(nowmusic->next == NULL)
{
printf("已经是最后一首了!\n");
system("stty echo");//开回显
printf("\033[?25h");//显示光标
}
else
{
nowmusic = nowmusic->next;
kill(pid, 9); // 杀掉当前子进程
pid = fork();//重新创建子进程
if(pid == -1)
{
perror("fork");
}
else if(pid == 0)
{
mp3_dvd(dir1, nowmusic->filename);
}
}
return nowmusic;
}
void free_head(MP3Node *head)
{
while(head != NULL)//释放连表
{
MP3Node *temp = head;//临时变量存储头指针
head = head->next;
free(temp->filename);//释放strdup返回的歌曲名指针
free(temp);//保存一次head释放一次temp
}
}
用链表,改造成信号实现MP3
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
typedef struct MP3Node
{
char *filename;//数据域,存储指针,里面存储歌曲名
struct MP3Node *next;//指针域
}MP3Node;
void mp3_dvd();
void mp3_caidanname(char * dir1);
void kill_kill(MP3Node *head);
MP3Node *upup(MP3Node *head,MP3Node *nowmusic);
MP3Node *nextnext(MP3Node *nowmusic);
void signal_up_next(int signum);
void free_head(MP3Node *head);
void cleanFun(void);
pid_t pid;//全局变量
MP3Node *nowmusic = NULL;//现在播放的歌曲
MP3Node *head1 = NULL;
int again = 0;
char *dir1;
int main(int argc, char *argv[])
{
dir1 = argv[1];//输入要播放的目录
mp3_caidanname(dir1);
return 0;
}
void mp3_dvd(char *dir1, char *filename)
{
raise(19);//子进程近来先暂停播放
char path[100];
//printf("即将播放\n");"-q"
snprintf(path, sizeof(path), "%s/%s", dir1,filename);
execlp("mpg123","mpg123", "-k 9000",path,NULL);
exit(EXIT_FAILURE);// 确保子进程退出
}
void mp3_caidanname(char * dir1)
{
int count = 0;//记录歌曲数量
MP3Node *head = NULL;//头指针
MP3Node *tail = NULL;//尾指针
DIR *dirp = NULL;
dirp = opendir(dir1);//打开目录
if(dirp == NULL)
{
perror("opendir");
}
struct dirent *dent = NULL;
while((dent = readdir(dirp)))
{
if(dent->d_type == 8)//DT_REG,普通文件
{
char *filename = dent->d_name;//歌曲名字全存到数据域中
//if(strstr(filename, ".mp3")) ,,char *strstr(const char *haystack, const char *needle);
//strstr()函数返回一个指向haystack中第一次出现needle的指针。如果未找到子字符串,则返回NULL。
if(strstr(filename, ".mp3"))
{
count++;
MP3Node *newfile = (MP3Node *)malloc(sizeof(MP3Node));//重新定义一个newfile保存刚的filename
newfile->filename = strdup(filename);//strdup从堆上分配一块内存,并将传入的字符串复制到这块内存中,然后返回这块内存的指针
newfile->next = NULL;
if(head == NULL)//第一次运行为空
{
head = newfile;//头指针不动
head1 = head;//为了循环播放释放
tail = newfile;
}
else//第二次往后链接
{
tail->next = newfile;//尾指针往后连接
tail = newfile;
}
}
}
}
closedir(dirp); // 关闭目录
if(count == 0)
{
printf("此文件夹无歌曲!\n");
free_head(head);
return ;
}
/*glob_t fn = {0};//显示歌单
glob("./mp3file/*.mp3", 0, NULL, &fn);
for(int i = 0; i < fn.gl_pathc; i++)
{
printf("%d.%s\n", i+1,fn.gl_pathv[i]);//glob函数打印歌单
}
globfree(&fn);*/
printf("歌单如下:\n");
MP3Node *menu = head;
int i = 1;
while(menu != NULL)
{
printf("%d.%s\n", i++, menu->filename);
menu = menu->next;
}
int nummusic = 0;//选择要播放的音乐
printf("请选择要播放的音乐:\n");
scanf("%d", &nummusic);
nowmusic = head;//nowmusic指向第一个歌曲
for(int i = 1; i < nummusic; i++)//遍历找到选中的歌曲,例如num = 2,执行一次循环
{
nowmusic = nowmusic->next;//找到第2个数据
}
pid = fork();
if(pid == -1)
{
perror("fork");
free_head(head);
return ;
}
else if(pid == 0)
{
//mp3_dvd(dir1,nowmusic->filename);
}
else
{
signal(17, signal_up_next); // 注册信号处理函数,子进程稍有改变就会发信号
atexit(cleanFun);
int val = 0;
while(1)
{
system("stty echo");//开回显
printf("\033[?25h");//显示光标
printf("-----------------------------------------------\n");
printf("---1,播放 2,暂停 3,上一首 4,下一首 0,退出------\n");
printf("-----------------------------------------------\n");
scanf("%d",&val);
while(getchar() != '\n');//清空缓冲区
switch(val)
{
case 0: kill_kill(head); return ;
case 1: kill(pid, 18); break;//继续
case 2: kill(pid, 19); break;//暂停
case 3:
nowmusic = upup(head, nowmusic);
kill(pid, 9); break;//上一首
case 4:
nowmusic = nextnext(nowmusic);
kill(pid, 9); break; //下一首
default: printf("无效输入,请重新选择。\n");
}
}
}
}
void kill_kill(MP3Node *head)
{
kill(pid, 9); //杀死子进程
free_head(head);
printf("退出播放器。\n");
}
MP3Node *upup(MP3Node *head,MP3Node *nowmusic)
{
MP3Node *head2 = head;
MP3Node *nowmusic1 = nowmusic;
if(nowmusic == head)
{
system("clear");
printf("--------------\n");
printf("已经是第一首歌\n");
printf("--------------\n");
return nowmusic;
}
else
{
MP3Node *up_name = head2;//定义上一首指向头指针
MP3Node *pre = NULL;//定义临时变量指向当前节点
while(up_name != NULL && up_name->next != nowmusic1)//上一首!=当前歌曲
{
pre = up_name;
up_name = up_name->next;//找到上一首歌曲
}
if(pre != NULL)
{
return pre; // 如果没有上一首歌,则返回当前歌
}
else
{
return nowmusic;
}
}
}
MP3Node *nextnext(MP3Node *nowmusic)
{
MP3Node *nowmusic1 = nowmusic;
if(nowmusic1->next == NULL)
{
system("clear");
printf("--------------\n");
printf("已经是最后一首了!\n");
printf("--------------\n");
return nowmusic1;
}
else
{
nowmusic1 = nowmusic->next;
}
return nowmusic1;
}
void signal_up_next(int signum)// 信号处理函数
{
pid_t tmp=0;
printf("--进入改造函数--\n");
if(signum == 17)
{
int wstatus=0;
tmp = waitpid(pid, &wstatus, WNOHANG);
printf("p = %d, pid = %d\n", tmp,pid);
if(tmp == pid && again == 0)
{
printf("子进程死亡\n");
if(WIFEXITED(wstatus))
{
nowmusic = nowmusic->next;
if(nowmusic == NULL)
{
printf("所有歌曲播放完毕!\n");//循环播放
kill_kill(head1);
}
}
pid = fork();//父进程回到主函数while,子进程放歌
if(pid == 0)
{
mp3_dvd(dir1, nowmusic->filename);
}
}
}
if(signum == 18)
{
pid = fork();
if(pid == 0)
{
mp3_dvd(dir1,nowmusic->filename);
}
}
}
void free_head(MP3Node *head)
{
while(head != NULL)//释放连表
{
MP3Node *temp = head;//临时变量存储头指针
head = head->next;
free(temp->filename);//释放strdup返回的歌曲名指针
free(temp);//保存一次head释放一次temp
}
}
void cleanFun(void)
{
again = 1;
kill(pid, 9);
system("stty echo");//开回显
printf("\033[?25h");//显示光标
}
信号实现MP3
#include <stdio.h>
#include <glob.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
void sigFun(int num);
void cleanFun(void);
glob_t pglob;
pid_t pid;
int con;
int again;
int main()
{
glob("./mp3file/*.mp3", 0, NULL, &pglob);
for(int i = 0; i < pglob.gl_pathc; i++)
{
printf("%d.%s\n", i+1, pglob.gl_pathv[i]+10);
}
pid = fork();
if(pid < 0)
{
perror("fork");
return -1;
}
else if(pid == 0)
{
raise(19);
execlp("mpg123", "mpg123", pglob.gl_pathv[con],NULL);
exit(0);
}
signal(17, sigFun);
atexit(cleanFun);
while(1)
{
int val = 0;
system("stty echo");
printf("\033[?25h\n");
printf("0.退出 1.播放 2.暂停 3.上一曲 4.下一曲\n");
scanf("%d", &val);
while(getchar() != '\n');
switch(val)
{
case 0: return 0;
case 1: kill(pid, 18); break;
case 2: kill(pid, 19); break;
case 3:
con--;
if(con == -1)
{
con = (int)pglob.gl_pathc-1;
}
kill(pid, 9);
break;
case 4:
con++;
if(con == (int)pglob.gl_pathc)
{
con = 0;
}
kill(pid, 9);
break;
default: break;
}
}
return 0;
}
void sigFun(int num)
{
printf("signai == num:%d\n", num);
int wstatus = 0;
pid_t ret = 0;
ret = waitpid(pid, &wstatus, WNOHANG);
if(ret == pid && again == 0)
{
if(WIFEXITED(wstatus))
{
con++;
}
pid = fork();
if(pid == 0)
{
execlp("mpg123","mpg123",pglob.gl_pathv[con],NULL);
exit(0);
}
}
}
void cleanFun(void)
{
again = 1;
kill(pid, 9);
system("stty echo");
printf("\033[?25h\n");
}