blob: 899faf635400d2ff48371bec276818f4f523d876 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ADK_INTERNAL
#include "fwk.h"
#include "simpleOgg.h"
#include "Audio.h"
#include "coop.h"
#include "f_ff.h"
#include "v_ivorbiscodec.h"
#include "v_ivorbisfile.h"
static size_t oggRead2(void *ptr, size_t size, size_t nmemb, void *data){
FIL *f = data;
FRESULT r;
UINT read = 0;
read = size * nmemb;
if(read + f->fptr > f->fsize) read = f->fsize - f->fptr;
if(!read) return 0;
r = f_read(f, ptr, size * nmemb, &read);
if(r) return 0;
return read / size;
}
static int oggSeek2(void *data, ogg_int64_t offset, int whence){
return -1;
}
static int oggClose2(void *data){
FIL *f = data;
f_close(f);
return 0;
}
static long oggTell2(void *data){
FIL *f = data;
return f->fptr;
}
static char _playOgg(const char *name, char *abort){
const static ov_callbacks cbks ={ oggRead2, oggSeek2, oggClose2, oggTell2 };
const uint32_t bufSz = 2048;
const uint32_t numBufs = 3;
uint16_t** bufs;
uint32_t bufIdx = 0;
int vorbis_state = 0;
OggVorbis_File F;
long i, t;
char ret = SIMPLE_OGG_MEM_ERR;
FRESULT r;
FIL f;
ret = SIMPLE_OGG_OK;
r = f_open(&f, name, FA_READ);
if(r) return SIMPLE_OGG_OPEN_ERR;
i = ov_open_callbacks(&f, &F, NULL, 0, cbks);
if(i != 0) return SIMPLE_OFF_OGG_OPEN_ERR;
bufs = malloc(sizeof(uint16_t*[numBufs]));
if(!bufs) goto errout;
for(i = 0; i < numBufs; i++) bufs[i] = NULL;
for(i = 0; i < numBufs; i++) if(!(bufs[i] = malloc(sizeof(uint16_t[bufSz])))) break;
if(i != numBufs) goto errout;
vorbis_info *info = ov_info(&F, 0);
//dbgPrintf("vorbis info: version %d channels %d rate %d\n", info->version, info->channels, info->rate);
audioOn(AUDIO_ALARM, ov_info(&F, 0)->rate);
while(!(*abort)){
uint8_t volume = getVolume();
i = ov_read(&F, bufs[bufIdx], bufSz * 2, &vorbis_state);
if(i == 0){
break;
} else if(i == OV_HOLE || i == OV_EBADLINK){
ret = SIMPLE_OGG_FILE_ERR;
break;
} else {
i >>= 1;
if (info->channels == 1) {
for (t = 0; t < i; t++){
bufs[bufIdx][t] =
((signed long)(((((int16_t) bufs[bufIdx][t]) >> 4) * (signed long)((unsigned long)volume) + 1)) >> 8) + 2048;
}
} else {
// 2 channels, pick the left channel
i >>= 1;
for (t = 0; t < i; t++){
bufs[bufIdx][t] =
((signed long)(((((int16_t) bufs[bufIdx][t*2]) >> 4) * (signed long)((unsigned long)volume) + 1)) >> 8) + 2048;
}
}
}
audioAddBuffer(AUDIO_ALARM, bufs[bufIdx], i);
if(++bufIdx == numBufs) bufIdx = 0;
}
bufs[bufIdx][0] = 2048;
audioAddBuffer(AUDIO_ALARM, bufs[bufIdx], 1);
ov_clear(&F);
f_close(&f);
audioOff(AUDIO_ALARM);
errout:
for(i = 0; i < numBufs; i++) if(bufs[i]) free(bufs[i]);
free(bufs);
return ret;
}
char playOgg(const char *name){
char abort = 0;
return _playOgg(name, &abort);
}
struct oggWorkerArgs {
const char *name;
char *complete;
char *abort;
};
static void oggBackgroundWorker(void *_arg)
{
struct oggWorkerArgs *args = _arg;
char ret = _playOgg(args->name, args->abort);
*args->complete = 1;
free(args);
}
char playOggBackground(const char *name, char *complete, char *abort){
struct oggWorkerArgs *args = malloc(sizeof(struct oggWorkerArgs));
if (!args)
return -1;
args->name = name;
args->complete = complete;
args->abort = abort;
coopSpawn(&oggBackgroundWorker, args, 12*1024);
return 0;
}