/* *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); }
|