Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 录音及;AudioTrack似乎不适用于32位编码_Android_Encoding_32 Bit_Pcm - Fatal编程技术网

Android 录音及;AudioTrack似乎不适用于32位编码

Android 录音及;AudioTrack似乎不适用于32位编码,android,encoding,32-bit,pcm,Android,Encoding,32 Bit,Pcm,我目前正在进行一个项目,尝试使用WebSocket将音频从一个设备实时传输到另一个设备。为此,我正在尝试实现一个“跨平台”的实现,它可以与浏览器、android和ios一起使用。我的目标是录制和播放各种格式的PCM音频。浏览器(chrome和firefox)生产的PCM采用32位编码,我尝试在android手机上播放。该项目仅供参考 在安卓系统上,我使用原始pcm进行录制,并通过websocket将原始pcm传输到另一台设备。同样地,我也会使用。如果我使用16位编码,采样率为44100Hz和2个

我目前正在进行一个项目,尝试使用WebSocket将音频从一个设备实时传输到另一个设备。为此,我正在尝试实现一个“跨平台”的实现,它可以与浏览器、android和ios一起使用。我的目标是录制和播放各种格式的PCM音频。浏览器(chrome和firefox)生产的PCM采用32位编码,我尝试在android手机上播放。该项目仅供参考

在安卓系统上,我使用原始pcm进行录制,并通过websocket将原始pcm传输到另一台设备。同样地,我也会使用。如果我使用16位编码,采样率为44100Hz和2个通道,一切正常。但是,它似乎不适用于32位编码。来自浏览器的录制(32位)不会播放,即使我确实交错了频道等。同样,当我尝试使用32位编码在android上录制时,它不会产生任何声音,因为它不会在浏览器上播放任何内容

我试着在android上播放一个32位编码的wav文件,效果很好。但是,我不知道系统是否在后台进行下采样

我的目标是尽可能避免向下/向上采样,因为我希望实现低延迟

我在网上找不到任何解决方案,这是一个常见问题吗?我是不是遗漏了什么

对于32位编码,
write
方法的结果返回
AudioTrack.ERROR\u INVALID\u操作

int result = audioTrack.write(buffer, 0, buffer.length, AudioTrack.WRITE_BLOCKING);

if(result == AudioTrack.ERROR_BAD_VALUE){
    System.out.println("ERROR: bad value");
}else if (result == AudioTrack.ERROR_DEAD_OBJECT){
    System.out.println("ERROR: dead object");
}else if (result == AudioTrack.ERROR_INVALID_OPERATION){
    System.out.println("ERROR: invalid operation");
}else if (result == AudioTrack.ERROR){   
    System.out.println("ERROR: ??");
}else{
    System.out.println("Successfully written to buffer!");
}
录制音频的实现:

public class AudioStream {
    private AudioStreamMetadata metadata = AudioStreamMetadata.getDefault();
    ...

    public void start() {
        ...
        new Thread(() -> {
            socket.send("started");
            socket.send(metadata.toString());

            while (!hasStopped) {
                float[] data = new float[metadata.getBufferSize()];
                recorder.read(data, 0, data.length, AudioRecord.READ_BLOCKING);
                byte[] output = new byte[data.length * metadata.getBytesPerSample()];
                ByteBuffer.wrap(output).order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer().put(data);
                socket.send(ByteString.of(output));
            }
        }).start();
    }

    private void initRecorder() {
        int min = AudioRecord.getMinBufferSize(metadata.getSampleRate(), metadata.getChannels(true), metadata.getEncoding());
        recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, metadata.getSampleRate(),
                metadata.getChannels(true), metadata.getEncoding(), min);
    }
}
AudioStreamMetadata类:

public class AudioStreamMetadata {

    public static final int DEFAULT_SAMPLE_RATE = 44100;
    public static final int DEFAULT_CHANNELS = 2;
    public static final int DEFAULT_ENCODING = 32;
    public static final int DEFAULT_BUFFER_SIZE = 6144*4;
    ...

    public AudioStreamMetadata(int sampleRate, int bufferSize, int channels, int encoding) {
        this.sampleRate = sampleRate;
        this.bufferSize = bufferSize;
        this.channels = channels;
        this.encoding = encoding;
        this.bytesPerSample = encoding / 8;
        this.bufferSizeInBytes = bufferSize * bytesPerSample;
    }

    //getters

    public int getChannels(boolean in) {
        if(channels == 1){
            return in? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_OUT_MONO;
        }else if(channels == 2){
            return in? AudioFormat.CHANNEL_IN_STEREO : AudioFormat.CHANNEL_OUT_STEREO;
        }else{
            return 0;
        }
    }

    public int getEncoding() {
        if(encoding == 8){
            return AudioFormat.ENCODING_PCM_8BIT;
        }else if(encoding == 16){
            return AudioFormat.ENCODING_PCM_16BIT;
        }else if(encoding == 32){
            return AudioFormat.ENCODING_PCM_FLOAT;
        }else{
            return 0;
        }
    }

    public static AudioStreamMetadata getDefault(){
        return new AudioStreamMetadata(DEFAULT_SAMPLE_RATE, DEFAULT_BUFFER_SIZE, DEFAULT_CHANNELS, DEFAULT_ENCODING);
    }
}

要设置缓冲区大小,请使用以下代码:

bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate, channels, encoding);

我假设
AudioTrack
能够在
write()
中处理不同的数据类型,因为我用正确的配置初始化了它。但是,初始化为8位编码的
音轨
仅接受
字节
,作为16位编码的
字节
,而作为32位浮点编码的
音轨
仅接受
浮点
。 我正在以
字节[]
的形式从套接字接收数据,我需要将其转换为
浮点[]

@Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {
        super.onMessage(webSocket, bytes);

        byte[] buffer = bytes.toByteArray();
        FloatBuffer fb = ByteBuffer.wrap(buffer).asFloatBuffer();
        float[] out = new float[fb.capacity()];
        fb.get(out);

        int result = audioTrack.write(out, 0, out.length, AudioTrack.WRITE_BLOCKING);

    }

在某些情况下,我们应该在播放32位浮点PCM时首先更改字节顺序

FloatBuffer fb = buffer.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();

你使用哪种API级别?最低API级别是23,两款android手机都满足32位编码的最低API级别。你能将你的录音机代码粘贴到这里吗?@Squti我添加了代码谢谢,这很有效@梅尔维萨欣