android服务(service)初步——通话录音

本文介绍了使用Android开发手机通话录音服务的过程,并详细说明了如何处理在点击多次停止服务时出现的bug。通过分析Log日志,我们发现了不支持参数导致的错误,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

启动服务之后,监听手机TelephonyManager状态,根据不同情况做出选择,源码以及截图如下:

生成的录音文件:

Log日志:


这个不知道为什么,点击多次停止服务的时候,总是会出现下面的BUG:

图片看不清楚,我把日志复制了出来如下:

09-21 19:56:31.850: ERROR/audio_input(34): unsupported parameter: x-pvmf/media-input-node/cap-config-interface;valtype=key_specific_value
09-21 19:56:31.850: ERROR/audio_input(34): VerifyAndSetParameter failed

知道原因的,麻烦告诉我,灰常感激。。。俺百度了好久不知道为啥。




源码:

MainActivity:

package com.song;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class PhoneListenerActivity extends Activity
{

	protected static final String ACTION = "recordingFlag";
	protected static final String TAG = "TAG";
	Button btnStart;
	Button btnStop;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		btnStart = (Button) findViewById(R.id.btnstart);
		btnStop = (Button) findViewById(R.id.btnstop);

		btnStart.setOnClickListener(new Button.OnClickListener()
		{

			@Override
			public void onClick(View v)
			{
				Log.v(TAG, "startService");
				startService(new Intent(ACTION));
			}
		});

		btnStop.setOnClickListener(new Button.OnClickListener()
		{

			@Override
			public void onClick(View v)
			{
				Log.v(TAG, "stopService");
				stopService(new Intent(ACTION));		
			}

		});

	}
}

服务类:

package com.song;

import java.io.IOException;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

public class PhoneListenerService extends Service
{

	private MediaRecorder recorder;
	private boolean recording = false;

	@Override
	public IBinder onBind(Intent intent)
	{
		return null;
	}

	@Override
	public void onCreate()
	{
		TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		manager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
		super.onCreate();
	}

	private PhoneStateListener listener = new PhoneStateListener()
	{

		@Override
		public void onCallStateChanged(int state, String incomingNumber)
		{
			super.onCallStateChanged(state, incomingNumber);
			switch (state)
			{
			case TelephonyManager.CALL_STATE_IDLE:// 空闲或者挂断
				// 挂断就停止录音
				stopRecord();
				break;
			case TelephonyManager.CALL_STATE_RINGING:// 响铃
				// 响铃什么都不做
				break;
			case TelephonyManager.CALL_STATE_OFFHOOK:// 接起电话
				// 接起电话开始录音
				recordCalling();
				break;
			default:
				break;
			}
		}
	};

	private void stopRecord()
	{
		if (recording)
		{
			Log.v("TAG", "stopRecord");
			recorder.stop();
			recorder.release();// 释放资源
		}
	}

	private void recordCalling()
	{

		try
		{
			Log.v("TAG", "recordCalling");
			recorder = new MediaRecorder();
			recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
			recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
			recorder.setOutputFile(Environment.getExternalStorageDirectory()
					.getAbsolutePath()+"/" + System.currentTimeMillis() + ".3gp");
			recorder.prepare();
			recorder.start();
			recording = true;
		}catch (Exception e)
		{
			e.printStackTrace();
		}

	}
}

配置文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.song"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".PhoneListenerActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

	<service android:name=".PhoneListenerService">
		<intent-filter>
			<action android:name="recordingFlag"/>
		</intent-filter>
	</service>
	
    </application>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!-- 向sdcard中写数据的权限 -->
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>


### 处理或设置Android设备通话背景音的方法 在Android设备上处理或设置通话背景音涉及多个方面,包括权限管理、音频流控制以及可能的自定义UI组件。 #### 权限管理 对于现代版本的Android操作系统而言,在尝试修改任何与麦克风或者电话状态有关的功能之前,应用程序必须获得相应的运行时权限。特别是当涉及到录音或是调整通话期间播放的内容时,这变得尤为重要。由于这类操作可能会引起隐私问题,因此开发者应当遵循官方文档中的指导来正确申请必要的权限[^2]。 #### 使用AudioManager类 为了能够在通话过程中加入背景音乐或其他形式的声音效果,可以利用`AudioManager`对象来进行音频路由的选择和模式切换。具体来说: - 设置音频焦点:通过调用`requestAudioFocus()`方法获取当前应用对特定类型的音频资源(如媒体播放器使用的那种)拥有优先使用权; - 更改音频路径:如果希望让背景声仅影响耳麦而不是扬声器,则可以通过改变默认输出设备的方式达成目的;例如,使用`setMode(int mode)`函数指定为`MODE_IN_CALL`表示处于呼叫状态下。 需要注意的是,直接向正在进行中的语音通信注入额外的数据并不是一件简单的事情,因为这样做不仅违反了大多数国家和地区关于窃听法律的规定,而且也可能被运营商网络视为非法行为而遭到阻止。所以通常情况下不会建议这么做除非是在受控环境中测试某些特殊应用场景下的可行性[^1]。 #### 自定义通话界面 假设确实存在合法合理的理由想要实现这一特性的话,那么还可以考虑构建一个完全由自己掌控的VoIP服务端架构,并基于此开发一套完整的移动客户端解决方案。此时就可以更加灵活地设计出满足需求的功能模块了——比如允许用户上传一段MP3文件作为彩铃使用,或者是提供几种预设好的环境噪音选项供选择等等。不过这样一来就需要投入更多的人力物力成本去维护整个系统的稳定性和安全性[^5]。 ```java // 获取 AudioManager 实例 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); // 请求音频焦点 audioManager.requestAudioFocus( null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值