Воспроизвести поток PCM на Android

Я получаю потоки PCM через порт Ethernet. Пока что я могу захватывать пакеты и извлекать из них данные pcm_payload.

Как воспроизвести эти необработанные данные PCM в Android? Данные PCM - это 16-битный 2-канальный поток со скоростью 44,1 кГц.

Я новичок в программировании приложений для Android и программировании звука. Извините, если это банальный вопрос.


person mk..    schedule 09.01.2017    source источник


Ответы (2)


Вы можете использовать AudioTrack для воспроизведения данных PCM!

Может быть так:

int bufsize = AudioTrack.getMinBufferSize(44100,
           AudioFormat.CHANNEL_OUT_STEREO,
           AudioFormat.ENCODING_PCM_16BIT);

AudioTrack audio = new AudioTrack(AudioManager.STREAM_MUSIC, 
                       44100, //sample rate
                       AudioFormat.CHANNEL_OUT_STEREO, //2 channel
                       AudioFormat.ENCODING_PCM_16BIT, // 16-bit
                       bufsize, 
                       AudioTrack.MODE_STREAM );
audio.play()

затем вызовите audio.write(), чтобы записать данные PCM.

person 木大白易    schedule 09.01.2017
comment
CHANNEL_CONFIGURATION_STEREO кажется устаревшим. Вместо этого я использовал CHANNEL_OUT_STEREO. Оно работает. Это нормально? - person mk..; 12.01.2017
comment
Да, CHANNEL_CONFIGURATION_STEREO и CHANNEL_OUT_STEREO являются двухканальными! - person 木大白易; 12.01.2017
comment
Ok. Я просто соответствующим образом отредактировал ответ. Кроме того, перед записью нужно было вызвать play () ... и только одного play () было достаточно для нескольких вызовов write (). Однако мне пришлось преобразовать данные с прямым порядком байтов в прямой порядок байтов перед записью в audioTrack (). После моих правок, если вы чувствуете, что есть необходимость отредактировать ответ, сделайте это. Спасибо. - person mk..; 12.01.2017
comment
Прошу прощения за свою невнимательность, возможно, я не ясно выразился, то, что вы отредактировали и прокомментировали, кажется более ясным и правильным! - person 木大白易; 12.01.2017
comment
Есть ли способ передать поток PCM с удаленного сервера? Я имею в виду, для audio.write()? - person cantona_7; 18.07.2019

это мое решение. записать поток в файл и воспроизвести его

public class AudioTrackPlayer {
private String pathAudio;
private AudioTrack audioPlayer;
private Thread mThread;
private int bytesread = 0, ret = 0;
private int size;
private FileInputStream in = null;
private byte[] byteData = null;
private int count = 512 * 1024; // 512 kb
private boolean isPlay = true;
private boolean isLooping = false;
private static Handler mHandler;

public AudioTrackPlayer() {

}

public void prepare(String pathAudio){
    this.pathAudio = pathAudio;
    mHandler = new Handler();
}

public void play(){
    stop();

    isPlay = true;
    bytesread = 0;
    ret = 0;
    if (pathAudio == null)
        return;

    audioPlayer = createAudioPlayer();
    if (audioPlayer == null) return;
    audioPlayer.play();

    mThread = new Thread(new PlayerProcess());
    mThread.start();
}

private final Runnable mLopingRunnable = new Runnable() {
    @Override
    public void run() {
        play();
    }
};

private AudioTrack createAudioPlayer(){
    int intSize = android.media.AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT);
    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT, intSize, AudioTrack.MODE_STREAM);
    if (audioTrack == null) {
        Log.d("TCAudio", "audio track is not initialised ");
        return null;
    }

    File file = null;
    file = new File(pathAudio);

    byteData = new byte[(int) count];
    try {
        in = new FileInputStream(file);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    size = (int) file.length();
    return  audioTrack;
}

private class PlayerProcess implements Runnable{

    @Override
    public void run() {
        while (bytesread < size && isPlay) {
            if (Thread.currentThread().isInterrupted()) {
                break;
            }
            try {
                ret = in.read(byteData, 0, count);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (ret != -1) { // Write the byte array to the track
                audioPlayer.write(byteData,0, ret);
                bytesread += ret;
            } else break;
        }
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (audioPlayer!=null){
            if (audioPlayer.getState()!=AudioTrack.PLAYSTATE_STOPPED){
                audioPlayer.stop();
                audioPlayer.release();
                mThread = null;
            }
        }
        if (isLooping && isPlay ) mHandler.postDelayed(mLopingRunnable,100);
    }
}

public void setLooping(){
    isLooping = !isLooping;
}

public void pause(){

}

public void stop(){
    isPlay = false;
    if (mThread != null) {
        mThread.interrupt();
        mThread = null;
    }
    if (audioPlayer != null) {
        audioPlayer.stop();
        audioPlayer.release();
        audioPlayer = null;
    }
}

public void reset(){

}

}

person Ar Rik    schedule 19.11.2017