Лучшая практика: где ресемплировать PCM и какой инструмент?

Я разработал модуль ядра (Android), который предоставляет мне:

PCM
16-bit
48000 Hz
2 channel

и я хочу передать его в Apple's Airport Express (AEX) в java.

Для AEX требуется PCM с частотой 44,1 кГц, поэтому мне нужно передискретизировать поток PCM.

У меня есть следующие возможности, но какой из них лучше?

1. Используйте программу C "raop_play" (часть 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. Ресемплинг и потоковая передача в Java (с помощью 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. Пересэмплировать уже в модуле ядра

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?!

person Martin L.    schedule 27.06.2012    source источник


Ответы (1)


В душе я сторонник Java, но эта задача (особенно на устройствах с ограниченным процессором, таких как карманные компьютеры) требует C. Я бы предложил просто использовать libsamplerate. У него простой API, и даже если вы новичок в C, вы найдете множество примеров, просто погуглив.

конечно, решение на основе Java могло бы и будет работать, просто пользователям кажется невежливым тратить свои батареи только потому, что вы новичок в C :)

РЕДАКТИРОВАТЬ: я могу немного противоречить себе, но даже несмотря на то, что производительность является серьезной проблемой, я бы не стал делать что-либо в пространстве ядра, если только я не знаю ядро ​​и аппаратное обеспечение действительно хорошо. В свете этого я бы выбрал программу пользовательского пространства, связанную с libsamplerate. Немного погуглив, я нашел этот пример (обратите внимание, что вывод — это интерфейс jack, очевидно, для вас он должен быть другим)

#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);
}

из http://old.nabble.com/Example-of-using-libresample-with-jack-td8795847.html

Этот пример кажется довольно простым, надеюсь, вы сможете его использовать.

person Gergely Szilagyi    schedule 27.06.2012
comment
Наконец, я смешал решение № 1 и № 2: я реализовал понижение частоты дискретизации с помощью libresample в программе в пользовательском пространстве. Высокопроизводительный. У меня была головная боль с 2 каналами, но я решил ее :). Благодарю вас! - person Martin L.; 03.07.2012