使用 ChannelAPI 的 Android Wear 录音机

标签 android audio wear-os audiorecord channel-api

我正在尝试为 Android Wear 构建录音机应用。现在,我能够在 watch 上捕捉音频,将其传输到手机并保存在文件中。但是,音频文件存在间隙或裁剪部分。

我发现这回答了与我的问题相关的问题 link1 , link2 ,但他们帮不了我。


这是我的代码:

首先,在 watch 端,我使用 channelAPI 创建 channel ,并成功地将 watch 上捕获的音频发送到智能手机。

//here are the variables values that I used

//44100Hz is currently the only rate that is guaranteed to work on all devices
//but other rates such as 22050, 16000, and 11025 may work on some devices.

private static final int RECORDER_SAMPLE_RATE = 44100; 
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
int BufferElements2Rec = 1024; 
int BytesPerElement = 2; 

//start the process of recording audio
private void startRecording() {

    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
            RECORDER_SAMPLE_RATE, RECORDER_CHANNELS,
            RECORDER_AUDIO_ENCODING, BufferElements2Rec * BytesPerElement);

    recorder.startRecording();
    isRecording = true;
    recordingThread = new Thread(new Runnable() {
        public void run() {
            writeAudioDataToPhone();
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}

private void writeAudioDataToPhone(){

    short sData[] = new short[BufferElements2Rec];
    ChannelApi.OpenChannelResult result = Wearable.ChannelApi.openChannel(googleClient, nodeId, "/mypath").await();
    channel = result.getChannel();

    Channel.GetOutputStreamResult getOutputStreamResult = channel.getOutputStream(googleClient).await();
    OutputStream outputStream = getOutputStreamResult.getOutputStream();

    while (isRecording) {
        // gets the voice output from microphone to byte format

        recorder.read(sData, 0, BufferElements2Rec);
        try {
            byte bData[] = short2byte(sData);
            outputStream.write(bData);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

然后,在智能手机端,我从 channel 接收音频数据并将其写入 PCM 文件。

public void onChannelOpened(Channel channel) {
    if (channel.getPath().equals("/mypath")) {
        Channel.GetInputStreamResult getInputStreamResult = channel.getInputStream(mGoogleApiClient).await();
        inputStream = getInputStreamResult.getInputStream();

        writePCMToFile(inputStream);

        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(MainActivity.this, "Audio file received!", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

public void writePCMToFile(InputStream inputStream) {
    OutputStream outputStream = null;

    try {
        // write the inputStream to a FileOutputStream
        outputStream = new FileOutputStream(new File("/sdcard/wearRecord.pcm"));

        int read = 0;
        byte[] bytes = new byte[1024];

        while ((read = inputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, read);
        }

        System.out.println("Done writing PCM to file!");

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (outputStream != null) {
            try {
                // outputStream.flush();
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}

我做错了什么或者您有什么建议可以在智能手机上实现完美的无缝音频文件?提前致谢。

最佳答案

我注意到在您的代码中,您正在将所有内容读入一个 short[] 数组,然后将其转换为一个 byte[] 数组以供 Channel API 发送。您的代码还通过循环的每次迭代创建一个新的 byte[] 数组,这将为垃圾收集器创建大量工作。通常,您希望避免在循环内进行分配。

我会在顶部分配一个 byte[] 数组,让 AudioRecord 类将它直接存储到 byte[] 数组中(只要确保分配的字节数是 shorts 的两倍),代码如下:

mAudioTemp = new byte[bufferSize];

int result;
while ((result = mAudioRecord.read(mAudioTemp, 0, mAudioTemp.length)) > 0) {
  try {
    mAudioStream.write(mAudioTemp, 0, result);
  } catch (IOException e) {
    Log.e(Const.TAG, "Write to audio channel failed: " + e);
  }
}

我还用 1 秒的音频缓冲区测试了这个,使用这样的代码,它运行良好。在开始出现问题之前,我不确定最小缓冲区大小是多少:

int bufferSize = Math.max(
  AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT),
  44100 * 2);

关于使用 ChannelAPI 的 Android Wear 录音机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31838129/

相关文章:

vb.net - 某些音频文件会播放,但其他音频文件不会播放

android - 如何从 Android Marshmallow 中的服务请求权限

安卓穿戴音频

android - 如何在使用 MapBox 加载 map 之前防止黑屏闪烁?

android - 小部件服务在尝试填充集合之前不会等待数据

java - 如何使用 Java 从 url 流式传输音乐 - Android

android - 无法通过蓝牙调试 android wear - 无法连接到 localhost

java - 如何停止/等待线程,然后稍后恢复/重新启动它

android - onDataChange 陷入无限循环

android - Android-在循环中播放条件匹配的声音