录制/保存来自语音识别意图的音频



我想保存/录制Google识别服务用于语音到文本操作的音频(使用RecognizerIntent或SpeechRecognizer(。

我经历了很多想法:

  1. onBufferReceived from RecognitionListener:我知道,这是行不通的,只需测试它看看会发生什么,并且永远不会调用 onBufferReceived(使用 JB 4.3 在 Galaxy nexus 上测试(

  2. 使用媒体录像机:不工作。它正在打破语音识别。麦克风只允许一个操作

  3. 尝试在执行语音到文本API之前查找识别服务保存临时音频文件的位置以进行复制,但没有成功

我几乎绝望了,但我只是注意到谷歌保持应用程序正在做我需要做的事情!我使用 logcat 调试了一些 keep 应用程序,该应用程序还调用"RecognizerIntent.ACTION_RECOGNIZE_SPEECH"(就像我们开发人员一样(来触发语音到文本。但是,如何保存音频?它可以是隐藏 API 吗?谷歌在"作弊"吗?

@Kaarel的答案几乎是完整的 - 生成的音频是intent.getData()的,可以使用ContentResolver

读取

不幸的是,返回的 AMR 文件质量低下 - 我无法找到获得高质量录音的方法。我尝试除"音频/AMR"以外的任何值在 intent.getData() 中返回 null .

如果您找到获得高质量录音的方法 - 请发表评论或添加答案!

public void startSpeechRecognition() {
   // Fire an intent to start the speech recognition activity.
   Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
   // secret parameters that when added provide audio url in the result
   intent.putExtra("android.speech.extra.GET_AUDIO_FORMAT", "audio/AMR");
   intent.putExtra("android.speech.extra.GET_AUDIO", true);
   startActivityForResult(intent, "<some code you choose>");
}
// handle result of speech recognition
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // the resulting text is in the getExtras:
    Bundle bundle = data.getExtras();
    ArrayList<String> matches = bundle.getStringArrayList(RecognizerIntent.EXTRA_RESULTS)
    // the recording url is in getData:
    Uri audioUri = data.getData();
    ContentResolver contentResolver = getContentResolver();
    InputStream filestream = contentResolver.openInputStream(audioUri);
    // TODO: read audio file from inputstream
}

上次我检查时,Google Keep 设置了这些附加功能:

  • android.speech.extra.GET_AUDIO_FORMAT:音频/AMR
  • android.speech.extra.GET_AUDIO:真

这些未作为 Android 文档的一部分进行记录,因此它们不构成 Android API。此外,Google Keep 不依赖于识别器的意图来考虑这些额外功能。如果谷歌推广和记录这些附加功能,那当然会很好。

要了解Google Keep在调用RecognizerIntent时设置了哪些附加功能,请实现一个响应RecognizerIntent的应用程序并打印出它收到的所有附加功能。您还可以安装 Kõnele (http://kaljurand.github.io/K6nele/(,它是 RecognizerIntent 的实现。当 Kõnele 由 Google Keep 启动时,长按扳手形状的设置图标。这显示了有关呼叫者的一些技术详细信息,还包括传入的附加内容。

@Iftah的答案解释了Google Keep如何将录音返回给RecognizerIntent的呼叫者。

我从这里得到了这个答案,我检查了日期,看到它是在您发布几天后发布的,所以我认为您错过了它。安卓语音识别和录音同时进行

那里的一个家伙说:

我得到了一个运行良好的解决方案,可以进行语音识别和 录音。这里 (https://github.com/katchsvartanian/voiceRecognition ( 是指向的链接 我创建的一个简单的Android项目来展示解决方案的工作原理。 此外,我在项目中放置了一些打印屏幕来说明 .app。

我将尝试简要解释我使用的方法。我合并了两个 该项目的功能:Google Speech API和Flac录音。

Google Speech API 通过 HTTP 连接调用。迈克·普尔茨给出 有关 API 的更多详细信息:

"(...新的 [Google] API 是一个全双工流媒体 API。这是什么 意味着,它实际上使用两个HTTP连接 - 一个POST请求 将内容作为"实时"分块流上传,然后第二个 GET 请求访问结果,这在更长时间内更有意义 音频样本,或用于流式传输音频。

但是,此 API 需要接收 FLAC 声音文件才能正常工作。 这让我们进入第二部分:Flac录音

我在该项目中通过提取和 从开源应用程序中改编一些代码和库 称为音频嘘声。AudioBoo使用本机代码来录制和播放FLAC 格式。

因此,可以录制一个flac声音,将其发送到谷歌语音 API,获取文本,然后播放刚刚录制的声音。

我创建的项目具有使其工作的基本原则,并且可以 针对特定情况进行改进。为了使它在一个 不同的场景,需要获取谷歌语音API密钥, 这是通过成为Google Chromium-dev组的一部分获得的。我离开了 该项目中的一个键只是为了表明它正在工作,但我会删除它 最终。如果有人需要更多信息,请告诉我 因为我无法在这篇文章中放置超过 2 个链接。

我们可以通过使用音频录制类来保存该音频。我已经成功地做到了这一点。

public class MainActivity extends AppCompatActivity {
TextView textView;
ImageView imageView;
static int request = 1;
private static final int RECORDER_SAMPLERATE = 8000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord recorder = null;
private Thread recordingThread = null;
private boolean isRecording = false;
private int[] mSampleRates = new int[]{8000, 11025, 22050, 44100};
int bufferSize;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView = findViewById(R.id.textView);
    imageView = findViewById(R.id.mic);

    int bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
            RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);

    recorder = findAudioRecord();
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.RECORD_AUDIO)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},
                1234);
    }
    
    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent speech = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            speech.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
            speech.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak to Text");
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.RECORD_AUDIO)
                    == PackageManager.PERMISSION_GRANTED) {
                startRecording();
                startActivityForResult(speech, request);
            }
        }
    });
    textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            stopRecording();
        }
    });
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == request && resultCode == RESULT_OK) {
        stopRecording();
        ArrayList<String> dataa = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
        textView.setText(dataa.get(0).toString());
    }
}
int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
int BytesPerElement = 2; // 2 bytes in 16bit format
private void startRecording() {
    recorder.startRecording();
    isRecording = true;
    recordingThread = new Thread(new Runnable() {
        public void run() {
            writeAudioDataToFile();
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}
@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1234: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            } else {
                Log.d("TAG", "permission denied by user");
            }
            return;
        }
    }
}
private byte[] short2byte(short[] sData) {
    int shortArrsize = sData.length;
    byte[] bytes = new byte[shortArrsize * 2];
    for (int i = 0; i < shortArrsize; i++) {
        bytes[i * 2] = (byte) (sData[i] & 0x00FF);
        bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
        sData[i] = 0;
    }
    return bytes;
}
public AudioRecord findAudioRecord() {
    for (int rate : mSampleRates) {
        for (short audioFormat : new short[]{
                AudioFormat.ENCODING_PCM_8BIT,
                AudioFormat.ENCODING_PCM_16BIT}) {
            for (short channelConfig : new short[]{
                    AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.CHANNEL_IN_STEREO}) {
                try {
                    Log.d("Mic2", "Attempting rate " + rate
                            + "Hz, bits: " + audioFormat
                            + ", channel: " + channelConfig);
                    bufferSize = AudioRecord.getMinBufferSize(rate,
                            channelConfig, audioFormat);
                        AudioRecord recorder = new AudioRecord(
                                MediaRecorder.AudioSource.DEFAULT, rate,
                                channelConfig, audioFormat, bufferSize);
                        if (recorder.getState() == AudioRecord.STATE_INITIALIZED)
                            rate = rate;
                        return recorder;
                } catch (Exception e) {
                    Log.e("TAG", rate + "Exception, keep trying.", e);
                }
            }
        }
    }
    return null;
}
private void writeAudioDataToFile() {
    String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/file.pcm";
    short sData[] = new short[BufferElements2Rec];
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(filePath);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    while (isRecording) {
        recorder.read(sData, 0, BufferElements2Rec);
        System.out.println("Short writing to file" + sData.toString());
        try {
            byte bData[] = short2byte(sData);
            os.write(bData, 0, BufferElements2Rec * BytesPerElement);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
private void stopRecording() {
    if (null != recorder) {
        isRecording = false;
        recorder.stop();
        recorder.release();
        recorder = null;
        recordingThread = null;
    }
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        finish();
    }
    return super.onKeyDown(keyCode, event);
}

相关内容

  • 没有找到相关文章

最新更新