/* *miniplayer--a simple mp3 player based on libmad and alsa. *author: zheng.wenwei *date: 2009.4.17 *version: 0.8(network file supported) */
/* * refix * 1.sigwait will action unlike the sigsuspend, when it return, it won't * trigger the signal handle, it just discards the signal. howerver, since t * the thread directed signal syscalls don't include mounting the signal * handle(p*kill, sigmask, sigwait), and the mount action in fack is about * the process, so it maybe understant here. * * 2.before creating the thread which will send a USR1 to the play thread, * you should make sure the USR1 is masked in it. this is the sequence * should be obeyed. * * 3.assume the MP3 is CBR, 128kps, 2 channels(in coming days, we shouldn't * use this assumption any longer. * * 4.BUG1:(refixed) * at the begining, it's silent, why? * silly!!! that's because I start playing at one part of the mem finished * filling, but not at the time all the mem(index == FREAMMEM); * * 5.BUG2:(refixed) * frequencily the music on lap, why? * NOTICE THIS: * the writei in fact count by frames!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * so I use bytes is wrong. maybe the alsa find the mem is not so long and * do something? * */
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <pthread.h> #include <error.h> #include <signal.h> #include <string.h> #include <sys/stat.h> #include <sys/mman.h> #include "miniplayer_decode.h" #include "miniplayer_play.h"
//#define _DEBUG
typedef enum{LOCAL_FILE, NETWORK_FILE} work_modeT;
//mem_to_fill is the mem to fill decoded data
char *mem1, *mem2, *mem_to_fill; //mem include the MP3 data
char *mem_to_input; //if the last_mem is not zero, that means it's the end of music
int last_mem_len = 0; //the tid of play thread(also the main thread)
pthread_t play_tid; //just for calling sigwait
int signo; //working mode
work_modeT work_mode; sigset_t usr2_set; sigset_t usr1_set; snd_pcm_t *playback_handle;
//the test and exit function
static void test_null(void *p, const char *errstr) { if(p == NULL) { fputs(errstr, stderr); exit(-1); } }
static void test_LT0(int no, int flag, const char *errstr) { if(no < 0) { if(flag ==0) { perror(errstr); } else { fputs(errstr, stderr); } exit(-1); } }
static void play(char *mem, unsigned int length); void *decode_routin(void *arg);
int main() { int mem_num = 0; pthread_t decode_tid; #ifdef _DEBUG //rediret the stdin and stdout
int stdin_fd; int stdout_fd; stdin_fd = open("travel.mp3", O_RDONLY, 0); test_LT0(stdin_fd, 0, "open"); test_LT0(dup2(stdin_fd, STDIN_FILENO), 0, "dup2"); stdout_fd = open("temp", O_WRONLY|O_CREAT, 0); test_LT0(stdout_fd, 0, "open"); test_LT0(dup2(stdout_fd, STDOUT_FILENO), 0, "dup2"); #endif mem1 = (char *)malloc(sizeof(char) * MEMLEN); test_null(mem1, "malloc"); mem2 = (char *)malloc(sizeof(char) * MEMLEN); test_null(mem2, "malloc"); memset(mem1, 0, MEMLEN); memset(mem2, 0, MEMLEN); //the first mem to fill decoded data is mem1
mem_to_fill = mem1;
//do all prepare for playback handle
all_prepare();
//mask signal SIGUSR1 for waiting
sigemptyset(&usr1_set); sigaddset(&usr1_set, SIGUSR1); pthread_sigmask(SIG_BLOCK, &usr1_set, NULL);
//get play thread id
play_tid = pthread_self();
//create decode thread
test_LT0(pthread_create(&decode_tid, NULL, decode_routin, NULL), 0, "pthread create");
//wait for SIGUSR1 to start playing
sigwait(&usr1_set, &signo); fputs("begin playing\n", stderr);
//loop for playing music
while(1) { //tell decodr to start filling mem1 or mem2
mem_to_fill = mem_num?mem1:mem2; pthread_kill(decode_tid, SIGUSR2); if(mem_num = !mem_num) { if(last_mem_len) { play(mem1, last_mem_len); break; } else { play(mem1, MEMLEN); } } else { if(last_mem_len) { play(mem2, last_mem_len); } else { play(mem2, MEMLEN); } } } //finish playing
fputs("finish playing\n", stderr); //wait for decode thread exit
pthread_join(decode_tid, NULL);
close_playback_handle(playback_handle); free(mem1); mem1 = NULL; free(mem2); mem2 = NULL; #ifdef _DEBUG close(stdin_fd); close(stdout_fd); #endif return(0); }
static void play(char *mem, unsigned int length) { write_to_audio(mem, length); }
void *decode_routin(void *arg) { int retval; size_t mem_size; struct stat stat; void *fdm; int stdin_mode;
//mask the USR2 for waiting
sigemptyset(&usr2_set); sigaddset(&usr2_set, SIGUSR2); pthread_sigmask(SIG_BLOCK, &usr2_set, NULL);
//mmap the STDIN_FILE
test_LT0(fstat(STDIN_FILENO, &stat), 0, "fstat"); stdin_mode = stat.st_mode & S_IFMT;
//if the stdin is not a regular file
if(stdin_mode != S_IFREG) { work_mode = NETWORK_FILE; } else { work_mode = LOCAL_FILE; if(stat.st_size == 0) { fputs("file size error\n", stderr); exit(-1); } fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0); if(fdm == MAP_FAILED) { perror("map"); exit(-1); } mem_to_input = (char *)fdm; mem_size = stat.st_size; }
//decode the STD_FILE
decode((const unsigned char *)mem_to_input, mem_size); //wait for the last USR2
sigwait(&usr2_set, &signo);
test_LT0(munmap(fdm ,stat.st_size), 0, "munmap");
pthread_exit(&retval); }
|