当前位置: 首页 > 知识库问答 >
问题:

使用VOICE_UPLINK和VOICE_DOWNLINK的呼叫记录

邢浩邈
2023-03-14

使用AudioSource VOICE_UPLINK和Voice_Downlink成功录制的任何一个呼叫。

还有一个问题:-当音频源VOICE_CALL不工作时,它有什么用?

谢谢你。

共有1个答案

贲高寒
2023-03-14

实际上,VOICE_CALL是有效的,至少对我来说在索尼Xperia Z1上是这样。我使用AudioRecord在某个临时文件中保存字节,然后将临时文件转换为WAV文件。

我也有同样的问题,声音拉长。问题是输出文件中的sampleRates参数小于记录期间的参数。以下是完整的代码。

public class Recorder {
    private static Recorder mInstance;
    private AudioRecord mRecorder = null;

    private Recorder() {}

    public static Recorder getInstance() {
        if (mInstance == null) {
            mInstance = new Recorder();
        }
        return mInstance;
    }

    private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_CALL;
    private static final int SAMPLE_RATE = 44100;
    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
    private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    private AudioRecord createAudioRecorder() {
        Log.d(MainActivity.TAG, "Initialize AudioRecord object");
        int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
        mRecorder = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize);

        Log.d(MainActivity.TAG, String.format("SampleRate: %d", mRecorder.getSampleRate()));

        return mRecorder;
    }

    public void startRecording() {
        Log.d(MainActivity.TAG, "Start recording the conversation...");

        mRecorder = createAudioRecorder();

        byte[] buffer = new byte[1024];
        mRecorder.startRecording();

        String tempFileName = UUID.randomUUID().toString() + ".raw";
        String wavFileName = UUID.randomUUID().toString() + ".wav";
        File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
        File tempFile = new File(path, tempFileName);
        File wavFile = new File(path, wavFileName);

        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(tempFile));
            while (mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                int num = mRecorder.read(buffer, 0, buffer.length);
                bos.write(buffer, 0, num);
            }
            mRecorder.release();
            mRecorder = null;
            bos.flush();
        } catch (IOException e) {
            Log.e(MainActivity.TAG, "IOException", e);
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {}
        }
        properWAV(tempFile, wavFile);
        tempFile.delete();
        Log.d(MainActivity.TAG, String.format("Successfully recorded the conversation to %s", wavFile.getPath()));
    }

    public void stopRecording() {
        Log.d(MainActivity.TAG, "Stop recording");
        if (mRecorder == null) {
            Log.d(MainActivity.TAG, "Recorder.stopRecording() mRecorder is NULL");
            return;
        }

        if (mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING)
            mRecorder.stop();
    }

    private void properWAV(File sourceFile, File destinationFile){
        try {
            long mySubChunk1Size = 16;
            int myBitsPerSample= 16;
            int myFormat = 1;
            long myChannels = 1;
            long mySampleRate = SAMPLE_RATE;    //22100;
            long myByteRate = mySampleRate * myChannels * myBitsPerSample/8;
            int myBlockAlign = (int) (myChannels * myBitsPerSample/8);

            byte[] clipData = getBytesFromFile(sourceFile);

            long myDataSize = clipData.length;
            long myChunk2Size =  myDataSize * myChannels * myBitsPerSample/8;
            long myChunkSize = 36 + myChunk2Size;

            OutputStream os;
            os = new FileOutputStream(destinationFile);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            DataOutputStream outFile = new DataOutputStream(bos);

            outFile.writeBytes("RIFF");                                     // 00 - RIFF
            outFile.write(intToByteArray((int)myChunkSize), 0, 4);          // 04 - how big is the rest of this file?
            outFile.writeBytes("WAVE");                                     // 08 - WAVE
            outFile.writeBytes("fmt ");                                     // 12 - fmt
            outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4);      // 16 - size of this chunk
            outFile.write(shortToByteArray((short)myFormat), 0, 2);         // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
            outFile.write(shortToByteArray((short)myChannels), 0, 2);       // 22 - mono or stereo? 1 or 2?  (or 5 or ???)
            outFile.write(intToByteArray((int)mySampleRate), 0, 4);         // 24 - samples per second (numbers per second)
            outFile.write(intToByteArray((int)myByteRate), 0, 4);           // 28 - bytes per second
            outFile.write(shortToByteArray((short)myBlockAlign), 0, 2);     // 32 - # of bytes in one sample, for all channels
            outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2);  // 34 - how many bits in a sample(number)?  usually 16 or 24
            outFile.writeBytes("data");                                     // 36 - data
            outFile.write(intToByteArray((int)myDataSize), 0, 4);           // 40 - how big is this data chunk
            outFile.write(clipData);                                        // 44 - the actual data itself - just a long string of numbers

            outFile.flush();
            outFile.close();
            bos.close();
            os.close();
        } catch (IOException e) {
            Log.e(MainActivity.TAG, "IOException", e);
        }

    }

    private byte[] getBytesFromFile(File file) {
        int size = (int) file.length();
        byte[] bytes = new byte[size];
        try {
            BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
            buf.read(bytes, 0, bytes.length);
            buf.close();
        } catch (FileNotFoundException e) {
            Log.e(MainActivity.TAG, "FileNotFoundException", e);
        } catch (IOException e) {
            Log.e(MainActivity.TAG, "IOException", e);
        }
        return bytes;
    }


    private static byte[] intToByteArray(int i)
    {
        byte[] b = new byte[4];
        b[0] = (byte) (i & 0x00FF);
        b[1] = (byte) ((i >> 8) & 0x000000FF);
        b[2] = (byte) ((i >> 16) & 0x000000FF);
        b[3] = (byte) ((i >> 24) & 0x000000FF);
        return b;
    }

    // convert a short to a byte array
    public static byte[] shortToByteArray(short data)
    {
        /*
         * NB have also tried:
         * return new byte[]{(byte)(data & 0xff),(byte)((data >> 8) & 0xff)};
         *
         */

        return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)};
    }
}
 类似资料:
  • 我已经开发了一个用于WebRTC视频呼叫的android应用程序,运行良好。现在的要求是记录通话音频并将其存储在外部存储器中。我尝试过MedieRecorder,它正在录制音频并存储,但这里面临一个问题。当我开始录制音频时,声音在接收器一侧停止。Media Recorder不允许webrtc使用麦克风。 我尝试了以下代码。 我也尝试过“录音机”音频源(媒体记录器,音频源.MIC);录音机音频源(M

  • 问题内容: 我正在重新整理用golang编写的小型Web应用程序的日志记录。由于外部需求,日志记录已被隔离在一个地方,因此我们以后可能会切换到 日志记录服务器 。(不是我的主意- 我保证…。)尽管如此,我们现在基本上可以使用标准库的一部分以及我们正在传递的用户/会话结构来记录日期/时间,行号,用户和消息等常见信息周围。 但是-随之而来的问题是- 在较低级别的方法中,仅为了获取日志而仅为了获取用户名

  • 如何获得呼叫的位置?不是全部地点,只是一个地区?也许android有一些API?未找到内容解析程序和Calllog.calls.content_uri

  • 但是上行和下行都不起作用 当我使用上行链路或下行链路时,我的应用程序行为不端,而当我使用其他来源时,我的应用程序工作正常

  • 问题内容: 如果用户查看我的JavaScript文件,复制函数的内容并使用AJAX向我的服务器发送请求,会发生什么情况?有没有办法适当地防止这种情况的发生? 问题答案: 防止这种情况发生的方法与针对 任何 Web请求采取的保护方法没有什么不同。您这样做是为了使您的站点需要某种形式的身份验证(即用户必须登录),并且如果请求未正确身份验证,则不要执行任何操作。 通常,当您发出AJAX请求时,cooki

  • 更新:任何人都知道如何强迫另一个流到麦克风音频源。这需要原生android代码。请在这方面帮助我,请参考这个问题,以获得更多关于路由音频的详细信息