从麦克风录制并流式传输到TCP服务器;MediaRecorder:启动失败:-38

7
我正在尝试从Android设备的麦克风流式传输音频到服务器上的TCP。问题在于我在控制台上收到一个错误。TCP连接已经建立,但没有发送任何音频数据。
我意识到这可能是因为编解码器选错了,因为有些需要在流中寻找,这是不可能的。实际上,我可以使用任何有效的编解码器,但我读到MediaRecorder.OutputFormat.RAW_AMR和 MediaRecorder.AudioEncoder.AMR_NB 是用于流媒体的最佳组合。如果有更好的替代方案,请建议。
以下是我在日志中看到的内容:
11-06 11:09:27.276 22983-22983/se.jensolsson.test.test D/ViewRootImpl@5ed8717[MainActivity]: ViewPostImeInputStage processPointer 0
11-06 11:09:27.355 22983-22983/se.jensolsson.test.test D/ViewRootImpl@5ed8717[MainActivity]: ViewPostImeInputStage processPointer 1
11-06 11:09:27.387 22983-25466/se.jensolsson.test.test I/MediaRecorderJNI: setup
11-06 11:09:27.394 22983-25466/se.jensolsson.test.test I/MediaRecorderJNI: setAudioSource(1)
11-06 11:09:27.397 22983-25466/se.jensolsson.test.test I/MediaRecorderJNI: setAudioEncoder(1)
11-06 11:09:27.400 22983-25466/se.jensolsson.test.test I/MediaRecorderJNI: setOutputFile
11-06 11:09:27.400 22983-25466/se.jensolsson.test.test I/MediaRecorderJNI: prepare
11-06 11:09:27.407 22983-25466/se.jensolsson.test.test I/MediaRecorderJNI: start
11-06 11:09:27.408 22983-25466/se.jensolsson.test.test E/MediaRecorder: start failed: -38
11-06 11:09:27.408 22983-25466/se.jensolsson.test.test W/System.err: java.lang.IllegalStateException
11-06 11:09:27.411 22983-25466/se.jensolsson.test.test W/System.err:     at android.media.MediaRecorder._start(Native Method)
11-06 11:09:27.411 22983-25466/se.jensolsson.test.test W/System.err:     at android.media.MediaRecorder.start(MediaRecorder.java:1170)
11-06 11:09:27.411 22983-25466/se.jensolsson.test.test W/System.err:     at se.jensolsson.test.test.MainActivity$1$1.run(MainActivity.java:78)
11-06 11:09:27.411 22983-25466/se.jensolsson.test.test W/System.err:     at java.lang.Thread.run(Thread.java:762)

以下是AndroidManifest.xml文件中相关部分:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

以下是源代码:

public class MainActivity extends AppCompatActivity {

    private MediaRecorder mediaRecorder;
    private boolean permissionToRecordAccepted;
    private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;

    private ParcelFileDescriptor pfd;

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case REQUEST_RECORD_AUDIO_PERMISSION:
                permissionToRecordAccepted  = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                if (!permissionToRecordAccepted ) finish();
                break;
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);

        Button buttonStartRecording = (Button)findViewById(R.id.button_start_recording);
        buttonStartRecording.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            Socket s = new Socket("10.0.83.8", 8888);
                            ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(s);

                            MediaRecorder recorder = new MediaRecorder();
                            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                            recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
                            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                            recorder.setOutputFile(pfd.getFileDescriptor());

                            try {
                                recorder.prepare();
                            } catch (IllegalStateException e) {
                                e.printStackTrace();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                            recorder.start();

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

            }
        });   
    }
}

我所使用的设备是三星Galaxy A5,并搭载Android 7.0操作系统。在gradle文件中,我使用了minSdkVersion为22,targetSdkVersion为26。
编辑:预装的语音记录应用程序可以正常工作。因此,我不认为麦克风正忙导致问题。
编辑2:如果我更改以下内容并保存到文件而不是流,则似乎可以正常工作。因此,我仍然认为声音格式存在问题,而流式传输作为网络流不支持查找。如果是这种情况,我应该使用哪种格式?
//recorder.setOutputFile(pfd.getFileDescriptor());
File outputFile = File.createTempFile("test", "mp4", getApplicationContext().getCacheDir());
recorder.setOutputFile(outputFile.getPath());

编辑3 所有答案都不正确。我现在发现主要问题是我无法将声音数据保存到由ParcelFileDescriptor.fromSocket创建的流中。

然而,如果我这样做,它可以工作。

ParcelFileDescriptor[] mParcelFileDescriptors = ParcelFileDescriptor.createPipe();
final ParcelFileDescriptor mParcelRead = new ParcelFileDescriptor(mParcelFileDescriptors[0]);
ParcelFileDescriptor mParcelWrite = new ParcelFileDescriptor(mParcelFileDescriptors[1]);

然后将流内容发送到服务器。 我不知道这是否存在时间问题,或者是否会导致某些声音文件格式的损坏,因为我猜测头部中的字节可能随时根据格式而改变。

2个回答

0

也许,但是是哪一个应用程序?这是一部全新的手机,没有安装任何特定的内容。我现在还尝试了Galaxy S5 Neo。同样的问题。 - www.jensolsson.se

0

所以我需要关闭语音助手才能录制吗?我尝试使用内置的录音机进行录制,效果还不错。有没有什么方法可以让这个过程更加流畅? - www.jensolsson.se
似乎不是语音助手。在设置中它被设为关闭状态。 - www.jensolsson.se

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接