从 MIC 录制并流式传输到 TCP 服务器; MediaRecorder:启动失败:-38
Posted
技术标签:
【中文标题】从 MIC 录制并流式传输到 TCP 服务器; MediaRecorder:启动失败:-38【英文标题】:Record from MIC and stream to TCP server; MediaRecorder: start failed: -38 【发布时间】:2018-04-18 11:18:12 【问题描述】:我正在尝试通过 TCP 将音频从 android 设备的麦克风流式传输到服务器。问题是我在控制台上收到错误。已建立 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();
);
我运行的设备是搭载 Android 7.0 的三星 Galaxy A5。我在 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]);
然后将流内容发送到服务器。 我不知道这是否存在一些时间问题,或者它是否会导致某些声音文件格式损坏,因为我猜头中的字节可能会随时根据格式发生变化。
【问题讨论】:
【参考方案1】:根据这个答案,这是因为麦克风正在被另一个应用程序使用,包括语音助手https://***.com/a/47290248/3938238
【讨论】:
所以我需要关闭语音助手才能录音?我尝试使用内置录音机进行录音,效果很好。有什么办法可以让这项工作更顺利吗? 好像不是语音助手。在设置中设置为关闭位置。【参考方案2】:可能是因为有其他应用正在使用手机的麦克风,请参阅:
https://***.com/a/23975085/5479863
【讨论】:
也许,但哪个应用程序?这是一部全新的手机,没有安装任何特定的东西。我现在也尝试过 Galaxy S5 Neo。同样的问题以上是关于从 MIC 录制并流式传输到 TCP 服务器; MediaRecorder:启动失败:-38的主要内容,如果未能解决你的问题,请参考以下文章