我正在解决在语音通话中录制音频的问题。我正在使用AudioRecord来获取录制的缓冲区。现在问题是我想要一个始终运行的后台服务,每当PHONE_STATE为OFFHOOK时,它应该记录来自用户定义的AudioSource(MIC或VOICE_DOWNLINK)的缓冲区。
当我在活动按钮中录制语音时,AudioRecord正在录制缓冲区并将其保存为可在Audacity中播放的PCM格式。它的录制文件大小约为100KB,录制时间为2秒。
但是当我尝试在后台服务中启动AudioRecord时,它是录制无法在Audacity中播放的缓冲区。录制的文件大小约为25MB,录制的2秒钟也无法播放。
我进行了广泛的搜索,但还没有找到任何解决方案。我做错了什么?
以下是我的代码
这是我的CallRecordingService.java
public class CallRecordingService extends Service {
private final IBinder mBinder = new CallRecordingBinder();
private AudioRecorder mAudioRecorder;
private boolean mRecording = false;
public ByteBuffer buffer;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter callRecordingFilter = new IntentFilter();
callRecordingFilter.addAction("android.intent.action.PHONE_STATE");
registerReceiver(phoneStateListener, callRecordingFilter);
return Service.START_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
BroadcastReceiver phoneStateListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Incoming", Toast.LENGTH_SHORT).show();
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)) {
Toast.makeText(context, state + "- Recording Started ", Toast.LENGTH_SHORT).show();
mAudioRecorder = new AudioRecorder(getApplicationContext());
mAudioRecorder.recordAudio(null);
mRecording = true;
}
if (TelephonyManager.EXTRA_STATE_IDLE.equals(state) && mRecording == true) {
Toast.makeText(context, state + "- Recording Stopped", Toast.LENGTH_SHORT).show();
mAudioRecorder.stopRecording();
mRecording = false;
}
if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
String fname = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
//Toast.makeText(context, state + " : " + fname, Toast.LENGTH_SHORT).show();
}
}
};
public class CallRecordingBinder extends Binder {
CallRecordingService getService() {
return CallRecordingService.this;
}
}
}
public class CallRecordingService extends Service {
private final IBinder mBinder = new CallRecordingBinder();
private AudioRecorder mAudioRecorder;
private boolean mRecording = false;
public ByteBuffer buffer;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter callRecordingFilter = new IntentFilter();
callRecordingFilter.addAction("android.intent.action.PHONE_STATE");
registerReceiver(phoneStateListener, callRecordingFilter);
return Service.START_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
BroadcastReceiver phoneStateListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Incoming", Toast.LENGTH_SHORT).show();
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)) {
Toast.makeText(context, state + "- Recording Started ", Toast.LENGTH_SHORT).show();
mAudioRecorder = new AudioRecorder(getApplicationContext());
mAudioRecorder.recordAudio(null);
mRecording = true;
}
if (TelephonyManager.EXTRA_STATE_IDLE.equals(state) && mRecording == true) {
Toast.makeText(context, state + "- Recording Stopped", Toast.LENGTH_SHORT).show();
mAudioRecorder.stopRecording();
mRecording = false;
}
if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
String fname = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
//Toast.makeText(context, state + " : " + fname, Toast.LENGTH_SHORT).show();
}
}
};
public class CallRecordingBinder extends Binder {
CallRecordingService getService() {
return CallRecordingService.this;
}
}
}
在AudioRecorder.java中(自定义类作为android AudioRecord.java的包装器)。我在recordAudio()方法中启动一个线程,读取缓冲区并将其保存在文件中,如下所示。
private void writeAudioDataToFile() {
// Write the output audio in byte
String filePath = "/sdcard/voice16K16bitmono.pcm";
short sData[] = new short[BufferElements2Rec];
FileOutputStream os = null;
try {
os = new FileOutputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (isRecording) {
audioRecord.read(sData, 0, BufferElements2Rec);
System.out.println("Short writing to file" + sData.toString());
try {
// // writes the data to file from buffer
// // stores the voice buffer
byte bData[] = short2byte(sData);
Log.i("Size", "bData Size : " + bData.length);
os.write(bData, 0, BufferElements2Rec * BytesPerElement);
} catch (IOException e) {
e.printStackTrace();
}
}
Log.i(TAG, "Message - Recording done.");
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
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;
}
这是我开始服务的主要活动课程。
private void writeAudioDataToFile() {
// Write the output audio in byte
String filePath = "/sdcard/voice16K16bitmono.pcm";
short sData[] = new short[BufferElements2Rec];
FileOutputStream os = null;
try {
os = new FileOutputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (isRecording) {
audioRecord.read(sData, 0, BufferElements2Rec);
System.out.println("Short writing to file" + sData.toString());
try {
// // writes the data to file from buffer
// // stores the voice buffer
byte bData[] = short2byte(sData);
Log.i("Size", "bData Size : " + bData.length);
os.write(bData, 0, BufferElements2Rec * BytesPerElement);
} catch (IOException e) {
e.printStackTrace();
}
}
Log.i(TAG, "Message - Recording done.");
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
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;
}
这是我的AndroidManifest.xml文件
public class MainActivity extends Activity {
private CallRecordingService mService = null;
private Button startRecordingService, stopRecordingService;
private static MainActivity activityInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityInstance = this;
setContentView(R.layout.activity_main);
startRecordingService = (Button) findViewById(R.id.btnStartRecording);
stopRecordingService = (Button) findViewById(R.id.btnStopRecording);
startRecordingService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), CallRecordingService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
startService(intent);
}
});
stopRecordingService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(mConnection);
}
});
}
@Override
public void onResume() {
super.onResume();
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
CallRecordingService.CallRecordingBinder b = (CallRecordingService.CallRecordingBinder) service;
mService = b.getService();
}
};
public static MainActivity getInstance() {
return activityInstance;
}
}
public class MainActivity extends Activity {
private CallRecordingService mService = null;
private Button startRecordingService, stopRecordingService;
private static MainActivity activityInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityInstance = this;
setContentView(R.layout.activity_main);
startRecordingService = (Button) findViewById(R.id.btnStartRecording);
stopRecordingService = (Button) findViewById(R.id.btnStopRecording);
startRecordingService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), CallRecordingService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
startService(intent);
}
});
stopRecordingService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(mConnection);
}
});
}
@Override
public void onResume() {
super.onResume();
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
CallRecordingService.CallRecordingBinder b = (CallRecordingService.CallRecordingBinder) service;
mService = b.getService();
}
};
public static MainActivity getInstance() {
return activityInstance;
}
}
答案 0 :(得分:0)
我终于解决了这个问题。我必须在Android代码中进行一些框架更改才能启用此功能。由于法律问题,一些OEM禁用了通话记录功能。