Code: Select all
#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdebug.h>
#include <pspaudio.h>
#include <pspaudiolib.h>
#include <psppower.h>
#include <pspdisplay.h>
#include <string.h>
#include <stdio.h>
//#include <tremor/ivorbiscodec.h>
//#include <tremor/ivorbisfile.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include <FLAC/stream_decoder.h>
#define printf pspDebugScreenPrintf
#define OUTPUT_BUFFER 32768
PSP_MODULE_INFO("Cueplayer", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER|PSP_THREAD_ATTR_VFPU);
//PSP_HEAP_SIZE_MAX();
PSP_HEAP_SIZE_KB(-256);
//Semaphores
static SceUID buffer_empty_sema;
static SceUID buffer_full_sema;
//global flags
static int running_flag = 0;
static int eos_flag = 0;
//global parameters and data
static int audio_vol = 0x4000; // 1/2 max volume
static FLAC__uint64 total_samples = 0;
static unsigned int sample_rate = 0;
static unsigned int bps = 0;
static unsigned int channels = 0;
static int buffer_flip = 0;
static char pcmout1[OUTPUT_BUFFER];
static char pcmout2[OUTPUT_BUFFER];
static long pcmlen1;
static long pcmlen2;
static FILE* fileptr;
static int audio_channel = 0;
FLAC__StreamDecoder* decoder = NULL;
FLAC__StreamDecoderInitStatus init_status;
//Common Routines
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common) {
sceKernelExitGame();
return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp) {
int cbid;
cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void) {
int thid = 0;
thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, PSP_THREAD_ATTR_USER, 0);
if(thid >= 0) {
sceKernelStartThread(thid, 0, 0);
}
return thid;
}
//FLAC decoding callbacks
//required by
//FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
// FLAC__StreamDecoder * decoder,
// const char * filename,
// FLAC__StreamDecoderWriteCallback write_callback,
// FLAC__StreamDecoderMetadataCallback metadata_callback,
// FLAC__StreamDecoderErrorCallback error_callback,
// void * client_data
// )
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* client_data)
{
const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps / 8));
FLAC__int16* fillbuf;
int i;
(void)decoder, (void)client_data;
if(total_samples == 0){
printf("Error total samples is 0??\n");
return -1;
}
if(channels != 2 || bps != 16){
printf("Error Only support 16bit and 2 channel\n");
return -1;
}
sceKernelWaitSema(buffer_empty_sema, 1, 0);
printf("B");
fillbuf = buffer_flip ? (FLAC__int16*)pcmout2 : (FLAC__int16*)pcmout1;
for(i = 0; i < frame -> header.blocksize; i++){
// fill 2 channel into odd and even continuous fillbuf
fillbuf[i << 1] = (FLAC__int16)buffer[0][i];
fillbuf[(i << 1) + 1] = (FLAC__int16)buffer[1][i];
}
if(buffer_flip){
pcmlen2 = frame -> header.blocksize << 2;
}
else{
pcmlen1 = frame -> header.blocksize << 2;
}
sceKernelSignalSema(buffer_full_sema, 1);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void metadata_callback(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data)
{
(void)decoder, (void)client_data;
if(metadata -> type == FLAC__METADATA_TYPE_STREAMINFO){
total_samples = metadata -> data.stream_info.total_samples;
sample_rate = metadata -> data.stream_info.sample_rate;
channels = metadata -> data.stream_info.channels;
bps = metadata -> data.stream_info.bits_per_sample;
}
}
void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data)
{
(void)decoder, (void)client_data;
printf("Error callback invoked: %s!\n", FLAC__StreamDecoderErrorStatusString[status]);
}
//Output audio thread
int audio_output(SceSize args, void* argp)
{
int playlen;
char* playbuf;
while(running_flag){
sceKernelWaitSema(buffer_full_sema, 1, 0);
printf("A");
if(eos_flag || !running_flag){
break;
}
playlen = buffer_flip ? pcmlen1 : pcmlen2;
playbuf = buffer_flip ? pcmout1 : pcmout2;
buffer_flip ^= 1;
sceKernelSignalSema(buffer_empty_sema, 1);
sceAudioSetChannelDataLen(audio_channel, playlen / 4);
sceAudioOutputBlocking(audio_channel, audio_vol, playbuf);
}
sceKernelExitDeleteThread(0);
return 0;
}
//FLAC playing Main function
int playflac(char* filename)
{
//SceUID sceKernelCreateSema ( const char * name,
// SceUInt attr,
// int initVal,
// int maxVal,
// SceKernelSemaOptParam * option
// )
SceUID audio_thid;
fileptr = fopen(filename, "rb");
buffer_empty_sema = sceKernelCreateSema("buffer_empty_sema", 0, 1, 1, 0);
buffer_full_sema = sceKernelCreateSema("buffer_full_sema", 0, 0, 1, 0);
if((decoder = FLAC__stream_decoder_new()) == NULL){
printf("cannot create flac stream decoder!\n");
sceKernelDelayThread(2*1000*1000);
return -1;
}
init_status = FLAC__stream_decoder_init_file(decoder, filename, write_callback, metadata_callback, error_callback, fileptr);
if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK){
printf("Init decoder error\n");
fclose(fileptr);
return -1;
}
memset(pcmout1, 0, OUTPUT_BUFFER);
memset(pcmout2, 0, OUTPUT_BUFFER);
pcmlen1 = 0;
pcmlen2 = 0;
eos_flag = 0;
running_flag = 1;
sceKernelSignalSema(buffer_empty_sema, 1);
sceKernelSignalSema(buffer_full_sema, 0);
audio_channel = sceAudioChReserve(audio_channel, OUTPUT_BUFFER / 4, PSP_AUDIO_FORMAT_STEREO);
audio_thid = sceKernelCreateThread("audio_output", audio_output, 0x16, 0x1800, PSP_THREAD_ATTR_USER, NULL);
if(audio_thid < 0){
printf("audio thread creation error!\n");
return -1;
}
sceKernelStartThread(audio_thid, 0, NULL);
if(FLAC__stream_decoder_process_until_end_of_stream(decoder)){
printf("SUCCESS END OF STREAM.\n");
FLAC__stream_decoder_delete(decoder);
fclose(fileptr);
running_flag = 0;
sceKernelSignalSema(buffer_empty_sema, 1);
sceKernelSignalSema(buffer_full_sema, 1);
sceKernelDelayThread(1000 * 1000);
sceAudioChRelease(audio_channel);
sceKernelDelayThread(1000 * 1000);
return 0;
}
else{
printf("Failed!\n");
return -1;
}
}
int player_control(SceSize args, void* argp)
{
SceCtrlData pad;
while(1){
sceKernelDelayThread(1000*500);
sceCtrlReadBufferPositive(&pad, 1);
if(pad.Buttons & PSP_CTRL_CROSS){
printf("hihi\n");
sceKernelDelayThread(1000*20);
FLAC__stream_decoder_seek_absolute(decoder, 44100*30);
FLAC__stream_decoder_reset(decoder);
sceKernelDelayThread(1000*20);
}
}
return 0;
}
int main()
{
char* filename = "ms0:/psp/music/b.flac";
pspDebugScreenInit();
SceUID pc_thid;
SetupCallbacks();
pc_thid = sceKernelCreateThread("player_control", player_control, 0x11, 0x1800, PSP_THREAD_ATTR_USER, NULL);
if(pc_thid > 0){
sceKernelStartThread(pc_thid, 0, 0);
}
else{
printf("player_control thread error\n");
}
printf("playing!........");
playflac(filename);
sceKernelExitGame();
return 0;
}
player_control().
using this function.
FLAC__stream_decoder_seek_absolute(decoder, 44100 * 30);
The music is more than 3 minutes that is more than 8000000 samples.
The player can play music correctly but when it invoke "FLAC__stream_decoder_seek_absolute", the whole system halts.
No matter where I add the FLAC__stream_decoder_seek_absolute function, the system will halt when invoking this function.
Forget to mention, I am using the latest SVN SDK in Linux and libflac 1.2.1. And I have found the lightmp3 can do the seeking using the same function correctly.
Anyone know how to solve this problem? Thank you very much!