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!