Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/225.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 实时编码音频会导致音频跳过 高级别:_Android_Audio_Audio Recording - Fatal编程技术网

Android 实时编码音频会导致音频跳过 高级别:

Android 实时编码音频会导致音频跳过 高级别:,android,audio,audio-recording,Android,Audio,Audio Recording,我用两种不同的方式使用相同的编码器 方法#1:录制原始音频并保存到整个文件中,完成后压缩文件结果完美的音频 方法2:记录原始音频,逐帧编码结果可听到跳跃声 为什么路径2会导致跳过 低级别 路径#1的代码(写入FileOutputStream fos,并在所有写入完成后压缩) 道路代码#2 近乎完美: 通道2中的短buf长度为15360。由于这是一个奇数大小的数字,我采用了这种技术:但仍然有轻微的声音跳跃: ByteArrayInputStream bais = new ByteArr

我用两种不同的方式使用相同的编码器

方法#1:录制原始音频并保存到整个文件中,完成后压缩文件结果完美的音频

方法2:记录原始音频,逐帧编码结果可听到跳跃声

为什么路径2会导致跳过

低级别 路径#1的代码(写入FileOutputStream fos,并在所有写入完成后压缩)

道路代码#2

近乎完美: 通道2中的短buf长度为15360。由于这是一个奇数大小的数字,我采用了这种技术:但仍然有轻微的声音跳跃:

      ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
      byte[] readme = new byte[4096];
      int count = bais.read(readme);
      while ( count != -1 ) {
        System.out.println("READING :"+count+ " bytes");
        if(bais.available() < 4096) {
          System.out.println ("LESS THAN 4096 available: "+bais.available());
          byte[] remain = new byte[bais.available()];
          bais.read(remain);
          aacEncoder.encode(remain);
          break;
        }
        aacEncoder.encode(readme);
        count = bais.read(readme);
      }
ByteArrayInputStream bais=新的ByteArrayInputStream(byteArray);
字节[]自述文件=新字节[4096];
int count=bais.read(自述文件);
而(计数!=-1){
System.out.println(“读取:“+count+”字节”);
如果(BAI.available()<4096){
System.out.println(“小于4096可用:+bais.available());
字节[]剩余=新字节[bais.available()];
读(留);
aacEncoder.encode(保留);
打破
}
aacEncoder.encode(自述文件);
count=bais.read(自述文件);
}

问题是:编码器编码时,并不总是花费相同的时间。有时它只是把一些数据隐藏起来,以备日后使用,有时它实际上做了大量的数字运算。它必须等待足够的音频来编码整个MP3“帧”,否则它只会隐藏数据

每次有新数据需要进行数字运算时,如果所需时间超过音频所代表的时间,就有可能出现辍学的情况

解决方案是让您的记录线程填充一个缓冲区,让第二个线程完成所有可能会减慢速度或花费不可预测时间的工作。这包括编码和写入文件

对于缓冲区,如果您的目标是android 2.3或更高版本,则可以使用piped/。从技术上讲,这不是一个环形缓冲区,因为它会阻塞,但根据我的经验,它工作得足够好。(此api在早期版本的android中可用,但无法设置缓冲区大小。Grrr!)


您可能会发现此链接有助于理解音频IO在概念上的实际工作方式:

为什么way#2会导致跳过。逻辑上会有什么不同?也许吧。然而,我质疑你的假设。在AAC中录制时,会发生跳过。但是,当我在OGG中录制时,不会发生跳过。这是苹果和桔子:不同的编解码器、不同的算法、不同的CPU要求和块大小,所有这些都会导致不同的计时要求。最终,你不应该把任何时间要求未知的东西(包括文件写入、互斥和一堆其他东西)与播放I/O放在同一个线程中。如果它碰巧起作用,那是因为你很幸运,你侥幸成功,并不是因为其他条件有问题。我现在实现了一个生产/消费线程模型,我仍然听到点击声。所以我真的不认为这是一个线程问题。IDK的任何代码样本-我总是这样做的工作/封闭源代码。这是PortAudio邮件列表中的一个常见问题,因此您可能会在那里找到一些搜索内容(尽管这是C)。在这种情况下,生产者-消费者比看起来更复杂。你必须确保你的制作人线程(录音机)永远不会等待消费者。还要确保缓冲区大小足够大。IIRC,你需要一个巨大的MP3缓冲区,像5秒这样荒谬的东西才能真正可靠地播放/录制。您还可以增加android AudioTrack的延迟/缓冲区大小设置,这将有所帮助。
public void writeSample(short[] buf) throws IOException {
            byte[] byteArray = Util.toByteArray(buf,false);
            bytesWritten += byteArray.length;
            encoder.encode(byteArray);
        }
      ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
      byte[] readme = new byte[4096];
      int count = bais.read(readme);
      while ( count != -1 ) {
        System.out.println("READING :"+count+ " bytes");
        if(bais.available() < 4096) {
          System.out.println ("LESS THAN 4096 available: "+bais.available());
          byte[] remain = new byte[bais.available()];
          bais.read(remain);
          aacEncoder.encode(remain);
          break;
        }
        aacEncoder.encode(readme);
        count = bais.read(readme);
      }