赞
踩
主要实现及功能:
1,播放,暂停及继续,上一页下一页,上一首下一首和退出
2,歌曲结束根据播放模式来自动下一首
3,可根据不同格式导入歌曲
4,ANSI控制码实现简单的界面制作
5, 通过管道来向mplayer播放器发送指令
6, 在播歌曲滑动显示
主要技术点:
父进程捕捉SIGCHLD信号通过信号处理函数wait收尸来获得mplayer的退出状态,当mplayer正常结束时,信号处理函数创建一个分离的线程重新打开mplayer播放器根据播放模式来自动播放下一首,main线程通过temp标志位来获取mplayer的控制权
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <glob.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <termios.h>
- #include <fcntl.h>
- #include <sys/wait.h>
- #include <pthread.h>
- #include "mplayer.h"
- #include "double_link.h"
-
- #define PATTERN "/home/ll/Music/*.mp3"
- #define FIFOPATH "music.fifo"
- #define MUSICSIZE 256
- #define OPTSIZE 512
- #define NAMEBUFSIZE 256
- #define ROW 15
- #define LINE 10
-
- /* 音乐名字数组*/
- char musicBuff[MUSICSIZE] = {0};
- /* 链表头结点 */
- LList_st *head = NULL;
- /* 链表当前位置 */
- llist *cur = NULL;
- /* 进程号 */
- pid_t pid;
- /* golb参数 */
- glob_t buff;
- /* 播放模式 */
- int playWay = ORDER;
- /* 播放器状态 */
- int tmp = 0;
-
- /* 主界面 */
- void interface()
- {
- int i, j, k;
-
- printf("\033[2J\033[5;25H\033[44m--====================--------------------\033[0m\n");
- printf("%c[6;25H",'\033');
-
- for (i = 0; i < ROW; i++)
- {
- printf("\033[44m||\033[0m");
- for (j = 0; j < LINE; j++)
- {
- printf(" ");
- }
- printf("\033[44m||\t\t||\033[0m\n\033[24C");
-
- }
-
- printf("\033[6;35H%s\n","歌单");
- printf("\033[6;53H\033[42m%s\033[0m\n","按键说明");
- printf("\033[8;52H%s\n","播放 'b'");
- printf("\033[9;52H%s\n","暂停 'p'");
- printf("\033[10;52H%s\n","退出 'q'");
- printf("\033[12;52H%s\n","上一首 'a'");
- printf("\033[13;52H%s\n","下一首 'd'");
- printf("\033[15;52H%s\n","上一页 'w'");
- printf("\033[16;52H%s\n","下一页 's'");
- printf("\033[18;52H\033[42m%s\033[0m\n"," 播放模式 ");
- printf("\033[21;25H\033[44m--====================--------------------\033[0m\n");
- }
-
- /* 歌曲路径和名字导入链表 */
- LList_st *loading()
- {
- int i, ret;
- musicNode name;
- LList_st *head = NULL;
-
- head = llist_create(sizeof(name));
- if (head == NULL)
- {
- fprintf(stderr,"llist_create() faild\n");
- exit(1);
- }
-
- glob(PATTERN,0,NULL,&buff);
- for (i = 0; i < buff.gl_pathc; i++)
- {
- strncpy(name.musicName,buff.gl_pathv[i],NAMESIZE);
- ret = llist_insert(head,&name,BEHIND);
- if (ret < 0)
- {
- fprintf(stderr,"llist_insert() fail\n");
- exit(1);
- }
- }
- return head;
- }
-
- /* 从链表中获取歌曲名字 */
- char *getNameFromLink(void *record)
- {
- musicNode *dest = record;
- return dest->musicName;
- }
-
- /* 获取不包含路径的名字 */
- char *getRealName(char *name)
- {
- char *pos = NULL;
-
- pos = strrchr(name,'/');
- if (pos == NULL)
- return name;
- return pos+1;
- }
-
- /* 模式显示 */
- void showPatten()
- {
- if (playWay == ORDER)
- printf("\033[19;52H%s\n"," 顺序播放 ");
- else if (playWay == SIGLOOP)
- printf("\033[19;52H%s\n"," 循环播放 ");
- else
- printf("\033[19;52H%s\n"," 随机播放 ");
- }
-
- /* 歌曲页数 */
- int songPage()
- {
- int i;
- int firstPage = 0;
-
- for (i = 0; i < buff.gl_pathc; i++)
- {
- if (strcmp(buff.gl_pathv[i],getNameFromLink(cur->data)) == 0)
- {
- firstPage = i;
- break;
- }
- }
- return firstPage;
- }
-
- /* 歌单的滑动显示,因为ansi控制码不好控制,根据需求自行添加 */
- /*
- void *curSongNameList(void *argc)
- {
- int i, j, len;
- int count;
- char *buf = (char *)argc;
-
- len = strlen(buf);
- while (1)
- {
- for (j = 0; j < len; j += 3)
- {
- count = SIZE;
- printf("\033[10;40H");
- for (i = j; i < len && (i - j) < 3*N; i++)
- {
- printf("%c",buf[i]);
- }
- fflush(stdout);
- usleep(700000);
- printf("\033[10;40H");
- while (count--)
- printf(" ");
- pthread_testcancel();
- }
- }
- }
- */
-
- /* 歌单展示
- *当当前链表歌曲和播放歌曲一样时,以红色背景色显示
- *
- */
- void showList(llist *cur,enum song_way pageTmp)
- {
- char *name = NULL;
- char nameBuf[NAMEBUFSIZE] = {0};
- int i = 0;
- int n = 0;
- int firstPage;
-
- firstPage = songPage(cur);
-
- i = 12 * (firstPage / 12);
- if (i % 12 == 0)
- {
- interface();
- }
-
- printf("\033[8;31H");
- if (pageTmp == NEXT)
- {
- if (i + 12 < buff.gl_pathc)
- i += 12;
- }
- else if (pageTmp == LAST)
- {
- if (i - 12 >= 0)
- i -= 12;
- }
- for (; i < buff.gl_pathc && n < 12; i++, n++)
- {
- name = getRealName(buff.gl_pathv[i]);
- if (strlen(name) < 18)
- {
- if (i == firstPage)
- printf("\033[41m%s\033[0m\n\033[30C",name);
- else
- printf("%s\n\033[30C",name);
- }
- else
- {
- if (i == firstPage)
- printf("\033[41m%s\033[0m\n\033[30C",strncpy(nameBuf,name,9));
- else
- printf("%s\n\033[30C",strncpy(nameBuf,name,18));
- }
- }
- showPatten();
-
- }
-
- /* 线程函数,根据播放模式不同来播放下一首 */
- void *playPat(void *args)
- {
- int n;
-
- if (playWay == ORDER)
- {
- cur = cur->next;
- if (cur == &head->head)
- cur = cur->next;
- strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE);
- showList(cur,0);
- fflush(stdout);
- pid = fork();
- createProgress(pid, musicBuff);
-
- }
- else if (playWay == SIGLOOP)
- {
- fflush(stdout);
- pid = fork();
- createProgress(pid, musicBuff);
- }
- else
- {
- srand((unsigned int)time(NULL));
- n = (1 + rand() % 10);
- while (n--)
- {
- cur = cur->next;
- }
- if (cur == &head->head)
- cur = cur->next;
- strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE);
- showList(cur,0);
- fflush(stdout);
- pid = fork();
- createProgress(pid,musicBuff);
- }
- tmp = 1;
- }
-
- /* 信号函数,接到信号时判断子进程是否正常结束,如果正常结束就根据播放模式播放下一首 */
- void actionHandler(int s)
- {
- int status;
- pthread_t tid;
-
- wait(&status);
- if (WIFEXITED(status))
- {
- pthread_create(&tid, NULL, playPat, NULL);
- pthread_detach(tid);
- tmp = 0;
- }
-
- }
-
- /* 创建子进程播放歌曲并将3个标准流置null */
- void createProgress(pid_t pid,char *musicBuff)
- {
- int fd;
- if (pid < 0)
- {
- perror("fork()");
- exit(1);
- }
- if (pid == 0)
- {
- fd = open("/dev/null",O_RDWR);
- if (fd < 0)
- {
- perror("open()");
- exit(1);
- }
- dup2(fd,0);
- dup2(fd,1);
- dup2(fd,2);
- if (fd > 2)
- close(fd);
-
- execlp("mplayer", "mplayer", "-slave", "-quiet", "-input", "file=music.fifo", musicBuff, NULL);
- perror("execlp()");
- exit(1);
- }
- }
-
- /* 导入歌曲 */
- void loadfile()
- {
- int fd;
- char optName[OPTSIZE] = {0};
-
- fd = open(FIFOPATH, O_WRONLY);
- if (fd < 0)
- {
- perror("open()");
- exit(1);
- }
-
- sprintf(optName, "%s %s\n", "loadfile", musicBuff);
- write(fd, optName, strlen(optName));
- close(fd);
- }
-
- /* 歌曲暂停 */
- void songPause()
- {
- int fd;
-
- fd = open(FIFOPATH, O_WRONLY);
- if (fd < 0)
- {
- perror("open()");
- exit(1);
- }
-
- write(fd, "pause\n", strlen("pause\n"));
- close(fd);
-
- }
-
- /* 歌曲退出 */
- void songStop()
- {
- int fd;
-
- fd = open(FIFOPATH, O_WRONLY);
- if (fd < 0)
- {
- perror("open()");
- exit(1);
- }
-
- write(fd, "quit\n", strlen("quit\n"));
- close(fd);
- }
-
- /* 运行函数
- * 关闭系统回显和getchar()以\n结尾的设置
- *
- * flag播放状态 0:未播放 1:正在播放 2:暂停
- * tmp检测第一次是否创建了子进程,防止意外杀死主进程 0:未创建子进程 1:已创建子进程
- *
- */
- void operationFunction()
- {
- struct termios new,old;
- struct sigaction sa;
- char ch;
-
- tcgetattr(0,&old);
- tcgetattr(0,&new);
-
- new.c_lflag = new.c_lflag & ~(ICANON | ECHO);
- new.c_cc[VMIN] = 1;
- new.c_cc[VTIME] = 0;
-
- tcsetattr(0,TCSANOW,&new);
- printf("\033[?25l"); //隐藏光标
- interface();
-
-
- unlink(FIFOPATH);
- if (mkfifo(FIFOPATH, 0666) < 0)
- {
- perror("mkfifo()");
- exit(1);
- }
-
- sa.sa_handler = actionHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction(SIGCHLD, &sa, NULL);
-
- head = loading();
- cur = head->head.next;
- showList(cur,0);
- while(1)
- {
- ch = getchar();
- switch (ch)
- {
- /* 播放 */
- case 'b':
- if (tmp == 0)
- {
- if (cur == NULL)
- cur = cur->next;
- strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE);
- showList(cur,0);
- fflush(stdout);
- pid = fork();
- tmp = 1;
- createProgress(pid,musicBuff);
- }
- break;
- /* 上一页 */
- case 'w':
- interface();
- showList(cur,LAST);
- break;
- /* 下一页 */
- case 's':
- interface();
- showList(cur,NEXT);
- break;
- /* 上一首 */
- case 'a':
- cur = cur->prev;
- if (cur == &head->head)
- cur = cur->prev;
- strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE);
- showList(cur,0);
- if (tmp == 1)
- loadfile();
- break;
- /* 下一首 */
- case 'd':
- cur = cur->next;
- if (cur == &head->head)
- cur = cur->next;
- strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE);
- showList(cur, 0);
- if (tmp == 1)
- loadfile();
- break;
- /* 暂停 | 恢复播放 */
- case 'p':
- if (tmp == 1)
- songPause();
- break;
- case 't':
- playWay++;
- if (playWay > 3)
- playWay = 1;
- showPatten();
- break;
- default:
- break;
- }
- /* 退出 */
- if (ch == 'q')
- {
- if (tmp)
- {
- songStop();
- kill(pid, SIGKILL);
- }
- break;
- }
- }
- tcsetattr(0,TCSANOW,&old); //还原终端原始设置
- printf("\033[?25h\033[2J");
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。