Best practice: Where to resample PCM and which tool?
c, java, java-native-interface, kernel-module, resampling
Solution
I'm a java-guy in heart, but this task (especially on a cpu constrained device, like a handheld) is crying for C. I would suggest simply using the libsamplerate. It has a simple API, and even if you're new to C you'll find plenty of examples by just googling around.
of course the java based solution could and would work, it just doesn't seem polite to the users to eat up their batteries just because your new to C :)
EDIT: I might contradict myself a bit, but even though performance is a serious issue, I would avoid doing anything in kernel-space, unless I know the kernel and the hardware really well. In light of this I would go with a user-space program linked to libsamplerate. After a bit of googling around I've found this example (note that the output is the jack interface, obviously it has to be different for you)
#include <jack/jack.h>
#include <samplerate.h>
int channels;
float data_samplerate;
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
void getDasData(float **dst,int num_frames){
/* Provide sound data here, and only here. */
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
long getDasResampledData_callback(void *cb_data, float **data){
static float ret[1024];
static float ret3[1024];
static float *ret2[2]={&ret[0],&ret[512]};
getDasData(ret2,512);
for(int i=0;i<512;i++){
ret3[i*2]=ret2[0][i];
ret3[i*2+1]=ret2[1][i];
}
*data=&ret3[0];
return 512;
}
void getDasResampledData(float **dst,int num_frames){
double ratio=samplerate/getSourceRate();
float outsound[num_frames*2];
long read=src_callback_read(dassrc_state,ratio,num_frames,outsound);
//fprintf(stderr,"read: %d, num_frames: %d\n",read,num_frames);
for(int i=0;i<read;i++){
dst[0][i]=outsound[i*2];
dst[1][i]=outsound[i*2+1];
}
if(read<num_frames){
float *newdst[2]={dst[0]+read,dst[1]+read};
getDasResampledData(newdst,num_frames-read);
}
}
static int process (jack_nframes_t nframes, void *arg){
int ch;
sample_t *out[channels];
for(ch=0;ch<channels;ch++){
out[ch]=(sample_t*)jack_port_get_buffer(ports[ch],nframes);
}
if( (fabs(data_samplerate - jack_samplerate)) > 0.1)
getDasResampledData(out,numSamples);
else
getDasData(outputChannelData,numSamples);
return;
audioCallback(NULL,0,out,channels,nframes);
}
int main(){
dassrc_state=src_callback_new(getDasResampledData_callback,SRC_QUALITY,2,NULL,NULL);
jack_set_process_callback(client, process,NULL);
}
from http://old.nabble.com/Example-of-using-libresample-with-jack-td8795847.html
This example seems pretty straightforward, I hope you can use it.
Problem
I have developed a kernel module (Android) which provides me: ``` PCM 16-bit 48000 Hz 2 channel ``` and I want to stream it to an Apple's Airport Express (AEX) in java. The AEX needs 44.1 kHz PCM so I have to resample the PCM-stream. I have following possibilities, but which is the best? 1. Use the C-program "raop_play" (part of raop-play) ``` advantages: high-performant due to native C already uses libsamplerate to resample wav, mp3, ogg, flac, aac, pls openssl as static library usable via command-line from my java-program via Runtime.exec() disadvantages: I am relative new to C overloaded: I don't need wav, mp3.. only PCM many dependencies with GPL-libraries which I have to compile for Android only supports PCM already with 44.1 kHz, no resampling for PCM implemented yet -> have to implement resampling for PCM ``` 2. Resample & stream in java (with libresample JNI-bridge) ``` advantages: I CAN java :) middle-performant due to resamling in C , but streaming in java just one dependency to LGPL-library no Runtime.exec() needed disadvantages: needs [bouncycastle][3] for AES which is a bit larger than openssl less performant than solution #1 (but maybe fast enough) ``` 3. Resample already in kernel module ``` advantages: most performant no resampling at higher level disadvantages: I am relative new to C Is it possible to use libsamplerate or libresample in kernel-space?! ```