如何用手机录制手机内部电脑播放声音怎么录制

Android录制声音文件(音频),并播放
readme:1、这个demo中没有对多次点击同一个声音文件做详细处理,偶尔会有崩溃,用的时候需要注意。2、按住录音按钮录音过程中,只对竖直方向处理了一下,水平方向没写;3、没有做删除某个声音文件的操作,但是测试的时候实现了功能,需要用到的话,在MainActivity&&onItemClick中的TODO中有详细说明;4、这只是个demo,如果要在项目中使用,先写出demo,没问题了,再引入项目,在写成demo后,在真机上运行的时候,如果出现获取录音权限,最好选择&允许&,如果拒绝,可能会崩溃。
记得打开手机运行录音的权限
先来效果图:
目录结构:
1、添加权限:vcD4NCjxwcmUgY2xhc3M9"brush:">
2、新建MediaRecorderUtils,复制以下:
package com.chen.
import android.media.MediaR
import android.os.H
import android.util.L
import android.widget.ImageV
import java.io.F
* 录音工具类
public class MediaRecorderUtils {
private static MediaR
static MediaRecorderUtils mediaRecorderU
static ImageView mimageV
* 获得单例对象,传入一个显示音量大小的imageview对象,如不需要显示可以传null
public static MediaRecorderUtils getInstence(ImageView imageView) {
if (mediaRecorderUtils == null) {
mediaRecorderUtils = new MediaRecorderUtils();
mimageView = imageV
return mediaRecorderU
* 获得音频路径
public String getPath() {
private void init() {
recorder = new MediaRecorder();// new出MediaRecorder对象
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置MediaRecorder的音频源为麦克风
recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
// 设置MediaRecorder录制的音频格式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// 设置MediaRecorder录制音频的编码为amr.
File file = new File(Utils.IMAGE_SDCARD_MADER);
if (!file.exists()) {
file.mkdirs();
path = Utils.IMAGE_SDCARD_MADER + Utils.getVoiceFileName() + &stock.amr&;
recorder.setOutputFile(path);
// 设置录制好的音频文件保存路径
recorder.prepare();// 准备录制
} catch (Exception e) {
e.printStackTrace();
* 开始录音
public void MediaRecorderStart() {
recorder.start();
if (mimageView != null) {
updateMicStatus();
} catch (Exception e) {
e.printStackTrace();
Log.e(&chen&, &录制失败&);
* 停止录音
public void MediaRecorderStop() {
recorder.stop();
recorder.release(); //释放资源
mimageView =
recorder =
} catch (Exception e) {
e.toString();
* 删除已录制的音频
public void MediaRecorderDelete() {
File file = new File(path);
if (file.isFile()) {
file.delete();
file.exists();
private final Handler mHandler = new Handler();
private Runnable mUpdateMicStatusTimer = new Runnable() {
public void run() {
updateMicStatus();
private int BASE = 1;
private int SPACE = 1000;// 间隔取样时间
private boolean flag =
* 更新话筒状态
private void updateMicStatus() {
if (recorder != null) {
double ratio = (double) recorder.getMaxAmplitude() / BASE;
double db = 0;// 分贝
if (ratio & 1) {
db = 20 * Math.log10(ratio);
int i = (int) db / 10;
switch (i) {
mimageView.setImageResource(R.drawable.rc_ic_volume_1);
mimageView.setImageResource(R.drawable.rc_ic_volume_2);
mimageView.setImageResource(R.drawable.rc_ic_volume_3);
mimageView.setImageResource(R.drawable.rc_ic_volume_4);
mimageView.setImageResource(R.drawable.rc_ic_volume_5);
mimageView.setImageResource(R.drawable.rc_ic_volume_6);
mimageView.setImageResource(R.drawable.rc_ic_volume_7);
mimageView.setImageResource(R.drawable.rc_ic_volume_8);
if (flag) {
mHandler.postDelayed(mUpdateMicStatusTimer, SPACE);
3、创建MyChronometer,复制以下代码
package com.chen.
import android.annotation.SuppressL
import android.content.C
import android.os.H
import android.os.M
import android.os.SystemC
import android.util.AttributeS
import android.view.accessibility.AccessibilityE
import android.view.accessibility.AccessibilityNodeI
import android.widget.TextV
public class MyChronometer extends TextView {
private static final String TAG = &MyChronometer&;
* A callback that notifies when the MyChronometer has incremented on its
public interface OnMyChronometerTickListener {
* Notification that the MyChronometer has changed.
void onMyChronometerTick(int time);
public interface OnMyChronometerTimeListener {
* Notification that the MyChronometer has changed.
void OnMyChronometerTimeListener(int time);
private OnMyChronometerTimeListener OnMyChronometerTimeL
private long mB
private boolean mV
private boolean mS
private boolean mR
private OnMyChronometerTickListener mOnMyChronometerTickL
private long now_
private static final int TICK_WHAT = 2;
* Initialize this MyChronometer object. Sets the base to the current time.
public MyChronometer(Context context) {
this(context, null, 0);
* Initialize with standard view layout information. Sets the base to the
* current time.
public MyChronometer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
* Initialize with standard view layout information and style. Sets the base
* to the current time.
public MyChronometer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
private void init() {
mBase = SystemClock.elapsedRealtime();
updateText(mBase);
* Set the time that the count-up timer is in reference to.
* @param base Use the {@link SystemClock#elapsedRealtime} time base.
public void setBase(long base) {
updateText(SystemClock.elapsedRealtime());
* Sets the listener to be called when the MyChronometer changes.
* @param listener The listener.
public void setOnMyChronometerTickListener(OnMyChronometerTickListener listener) {
mOnMyChronometerTickListener =
public void setOnMyChronometerTimeListener(OnMyChronometerTimeListener listener) {
OnMyChronometerTimeListener =
* Start counting up. This does not affect the base as set from
* {@link #setBase}, just the view display.
* MyChronometer works by regularly scheduling messages to the handler, even * when the Widget is not visible. To make sure resource leaks do not occur, * the user should make sure that each start() call has a reciprocal call to * {@link #stop}. */ public void start() { mStarted = updateRunning(); } /** * Stop counting up. This does not affect the base as set from * {@link #setBase}, just the view display. *
* This stops the messages to the handler, effectively releasing resources * that would be held as the MyChronometer is running, via {@link #start}. */ public void stop() { mStarted = updateRunning(); now_time /= 10; if (OnMyChronometerTimeListener != null) { OnMyChronometerTimeListener.OnMyChronometerTimeListener((int) now_time); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mVisible = updateRunning(); } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); mVisible = visibility == VISIBLE; updateRunning(); } private synchronized void updateText(long now) { long seconds = now - mB seconds /= 10; now_time = int time_m = (int) (seconds / 100); if (mOnMyChronometerTickListener != null) { mOnMyChronometerTickListener.onMyChronometerTick(time_m); } int time_s = (int) (seconds % 100); setText(time_m + &&); } private void updateRunning() { boolean running = mVisible && mS if (running != mRunning) { if (running) { updateText(SystemClock.elapsedRealtime()); mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000); } else { mHandler.removeMessages(TICK_WHAT); } mRunning = } } private Handler mHandler = new Handler() { public void handleMessage(Message m) { if (mRunning) { updateText(SystemClock.elapsedRealtime()); sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000); } } }; @SuppressLint(&NewApi&) @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setClassName(MyChronometer.class.getName()); } @SuppressLint(&NewApi&) @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(MyChronometer.class.getName()); } }
4、创建工具类
package com.chen.
import android.M
import android.content.C
import android.content.pm.PackageM
import android.os.E
import android.support.v4.content.ContextC
import android.widget.T
import java.io.F
import java.text.SimpleDateF
import java.util.ArrayL
public class Utils {
* SD卡下语音目录
public static final String IMAGE_SDCARD_MADER = Environment
.getExternalStorageDirectory()
+ &/chen/voice/&;
* 检查录音权限6.0
public static boolean checkVoice(Context context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
} catch (Exception e) {
private static T
* 单例吐司
public static void showToast(Context context, String msg) {
if (toast == null) {
toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
toast.setText(msg);
toast.show();
* 获取指定文件夹下的所有文件路径
* @param root 指定文件夹路径
* @return 指定文件夹下的所有文件
public static ArrayList getVideoFiles(String root) {
if (root == null || root == &&)
ArrayList list = new ArrayList&&();
File file = new File(root);
File[] fileList = file.listFiles();
for (File f : fileList) {
list.add(f.getPath());
* 获取声音文件名字
* @return 假如当前录制声音时间是号14点30分30秒。得到的文件名字就是30.这样保证文件名的唯一性
public static String getVoiceFileName() {
long getNowTimeLong = System.currentTimeMillis();
SimpleDateFormat time = new SimpleDateFormat(&yyyyMMddHHmmss&);
String result = time.format(getNowTimeLong);
5、MainActivity
package com.chen.
import android.app.A
import android.graphics.drawable.AnimationD
import android.graphics.drawable.ColorD
import android.media.MediaP
import android.os.B
import android.os.SystemC
import android.util.L
import android.view.LayoutI
import android.view.MotionE
import android.view.V
import android.view.ViewG
import android.view.W
import android.view.WindowM
import android.widget.AdapterV
import android.widget.BaseA
import android.widget.ImageV
import android.widget.ListV
import android.widget.PopupW
import android.widget.TextV
import java.io.F
import java.util.ArrayL
import java.util.L
public class MainActivity extends Activity implements View.OnTouchListener, AdapterView.OnItemClickListener {
* 开始录音按钮
private TextV
* 用于定位。使录音时展示的popupwindow,展示在该控件 的下面
private TextView voice_
* 展示指定文件夹下所有录制的声音文件
private TextView show_voice_
* 展示目标文件夹下,所有已录制的声音路径
private ListView show_voices_
private List voiceL
* 停止播放声音
private TextView stop_show_
* 播放声音时,动的图片
private ImageView voice_
private MediaPlayer mediaP
private Boolean flag =
private float int_x = 0;
private float int_y = 0;
* 用于限制最大录音时常。单位是秒。意义是:最大录60秒的音频,到了60秒的是,自动停止
private int maxRecordTime = 60;
* 用于显示频繁操作时间间隔。单位是毫秒。意义是:500毫秒内再次操作,就算是频频操作,做相应处理
private int oftenOperationTime = 500;
private MyAdapter myA
private AnimationD
* 录音popup
private PopupWindow voice_popupW
* 录音时声音变化
private ImageView voice_
* 录音计时器
private MyChron
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
voiceList = new ArrayList();
voice = (TextView) findViewById(R.id.voice);
voice_popup = (TextView) findViewById(R.id.voice_popup);
voice_anim = (ImageView) findViewById(R.id.voice_anim);
voice_anim.setImageResource(R.drawable.lcs_voice_receive);
show_voice_list = (TextView) findViewById(R.id.show_voice_list);
show_voice_list.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
voiceList = Utils.getVideoFiles(Utils.IMAGE_SDCARD_MADER);
if (voiceList.size()&0){
myAdapter.notifyDataSetChanged();
Utils.showToast(MainActivity.this, &没有文件&);
show_voices_listview = (ListView) findViewById(R.id.show_voices);
show_voices_listview.setOnItemClickListener(this);
myAdapter = new MyAdapter();
stop_show_voice = (TextView) findViewById(R.id.stop_show_voice);
* 停止播放的监听器
stop_show_voice.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.e(&chen&, &点击了停止播放按钮&);
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.release();// 释放资源
mediaPlayer =
if (animation != null && animation.isRunning()) {
animation.stop();
voice_anim.setImageResource(R.drawable.lcs_voice_receive);
show_voices_listview.setAdapter(myAdapter);
voice.setOnTouchListener(this);
* 声音文件列表的item点击事件,播放对应声音文件
* @param parent
* @param view
* @param position
* @param id
public void onItemClick(AdapterView parent, View view, int position, long id) {
//TODO 以下4行,是用来做测试,点击item,手机SD卡上对应路径下的声音文件就会被删除。如果录制声音失败,或者不满足条件,可以把以下4行写成一个工具方法调用,删除不满意的文件。这里不做详细演示
//File f_delete=new File(voiceList.get(position));
//f_delete.delete();
//voiceList.remove(voiceList.get(position));
//myAdapter.notifyDataSetChanged();
//TODO 以上4行,是用来做测试,点击item,手机SD卡上对应路径下的声音文件就会被删除。
mediaPlayer = new MediaPlayer();
* 播放过程中展示的动画
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
if (mp != null) {
mp.start();
voice_anim.setImageResource(R.drawable.voice_anim);
播放完成监听
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
if (mp.isPlaying()) {
mp.release();// 释放资源
animation = (AnimationDrawable) voice_anim.getDrawable();
if (animation != null && animation.isRunning()) {
animation.stop();
voice_anim.setImageResource(R.drawable.lcs_voice_receive);
mediaPlayer.setDataSource(voiceList.get(position));
mediaPlayer.prepare();
} catch (Exception e) {
Utils.showToast(MainActivity.this, &语音异常,加载失败&);
* 展示声音列表的adapter
class MyAdapter extends BaseAdapter {
public int getCount() {
return voiceList.size() == 0 ? 0 : voiceList.size();
public Object getItem(int position) {
public long getItemId(int position) {
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = new TextView(MainActivity.this);
tv.setText(voiceList.get(position));
tv.setTextSize(20);
* 开始录制按钮的onTouch事件
* @param v
* @param event
public boolean onTouch(View v, MotionEvent event) {
if (v.getId() == R.id.voice) {
//检查权限
if (!Utils.checkVoice(this)) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Utils.showToast(this, &录音权限未打开,请打开录音权限!&);
//避免短时间里频繁操作
if (!getTimeTF(SystemClock.elapsedRealtime()) && event.getAction() == MotionEvent.ACTION_DOWN) {
Utils.showToast(this, &操作过于频繁&);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
setTime(SystemClock.elapsedRealtime());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int_x = event.getRawX();
int_y = event.getRawY();
VoicePopupWindow();
mychronometer.setBase(SystemClock.elapsedRealtime());
mychronometer.start();
MediaRecorderUtils.getInstence(voice_shengyin).MediaRecorderStart();
mychronometer.setOnMyChronometerTickListener(new MyChronometer.OnMyChronometerTickListener() {
public void onMyChronometerTick(int time) {
if (time == maxRecordTime || time & maxRecordTime) {
mychronometer.setText(&60&);
setVoiceToUp();
case MotionEvent.ACTION_MOVE:
if (flag) {
if (Math.abs(int_y) - Math.abs(event.getRawY()) & 100.0 && flag) {
voice_popupWindow.dismiss();
mychronometer.stop();
MediaRecorderUtils.getInstence(voice_shengyin).MediaRecorderStop();
MediaRecorderUtils.getInstence(voice_shengyin).MediaRecorderDelete();
case MotionEvent.ACTION_CANCEL:
if (flag) {
voice_popupWindow.dismiss();
mychronometer.stop();
MediaRecorderUtils.getInstence(voice_shengyin).MediaRecorderStop();
case MotionEvent.ACTION_UP:
if (flag) {
setVoiceToUp();
private long base_time = 0;
private void setTime(long time) {
base_time =
private boolean getTimeTF(long time) {
int data = (int) (time - base_time) / oftenOperationT
if (data & 1) {
* 声音popupwindow
public void VoicePopupWindow() {
View view = LayoutInflater.from(this).inflate(R.layout.voice_popupwindow, null);
voice_popupWindow = new PopupWindow(this);
voice_popupWindow.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
voice_popupWindow.setHeight(WindowManager.LayoutParams.MATCH_PARENT);
voice_shengyin = (ImageView) view.findViewById(R.id.voice_shengyin);
mychronometer = (MyChronometer) view.findViewById(R.id.mychronometer);
voice_popupWindow.setContentView(view);
voice_popupWindow.setFocusable(true);
ColorDrawable dw = new ColorDrawable(0x);
voice_popupWindow.setBackgroundDrawable(dw);
voice_popupWindow.showAsDropDown(voice_popup);
private void setVoiceToUp() {
voice_popupWindow.dismiss();
mychronometer.stop();
MediaRecorderUtils.getInstence(voice_shengyin).MediaRecorderStop();
int time = Integer.parseInt(mychronometer.getText().toString());
if (time != 0) {
File file = new File(MediaRecorderUtils.getInstence(voice_shengyin).getPath());
if (file.length() & 0) {
voiceList = Utils.getVideoFiles(Utils.IMAGE_SDCARD_MADER);
myAdapter.notifyDataSetChanged();
Utils.showToast(this, &录音失败,请检查权限&);
Utils.showToast(this, &录音时间太短&);
6、activity_main布局
7、voice_popupwindow布局代码:录音的时候,会出现以下图片中的popupwindow
8、还有一个动画布局,播放声音的时候,有个动画效果
附录:用到的图片资源说明:如果手上没有这样的图片,可以随便用其他图片代替,有效果,就算成功如何通过电脑录手机内部的声音? - 知乎39被浏览<strong class="NumberBoard-itemValue" title="分享邀请回答2913 条评论分享收藏感谢收起1添加评论分享收藏感谢收起写回答1 个回答被折叠()如何通过手机单独录制屏幕及声音
1. 电脑端安装小萝贝,启动小萝贝2. 点击小萝贝手机窗口右上角的设置按钮,显示 手机设置 窗口3. 插件页面,点击 安装4. 点击手机端的 录屏 按钮5. 点击一个应用程序进行录制6. 可以竖屏录制或者横屏录制屏幕,录制时可以解说,声音会被录制下来7. 下拉通知栏可以看到 小萝贝正在录制按钮,点击按钮可以停止录制,或者回到小萝贝手机端应用程序内点击停止录制8. 点击手机端小萝贝的 文件按钮,点击录像9. 可以查看录制的文件平板/笔记本
HiLink生态产品
终端云服务专区
屏幕录制功能,不能录手机内部的声音?
&渐入佳境&
来自:浏览器
我今天用录屏录了下手机游戏,戴了耳机玩的,游戏内的声音一点儿也没录到,外界的噪音倒是全录进去了。
后来试了试,一定要声音外放,还要很大声盖过外界的杂音效果才会好,但这样很妨碍他人啊!
所以程序猿同志们,能不能弄个选项,自主选择录屏是录外放声音或内放声音呢?
还是说这个功能并不能实现?
width:100%">
&炉火纯青&
来自:浏览器
是怎么样的呢
width:100%">
&渐入佳境&
来自:浏览器
选自己顶一下
width:100%">
&渐入佳境&
来自:浏览器
width:100%">
&新学乍练&
来自:HUAWEI P10 VTR-AL00
欸&&我也巨想录制手机内部的声音
width:100%">
雨后 海边……缤纷芳华高原美最瞬间(1)『走走拍拍』【风光】青岛世纪公园
花粉客户端
Make it Possible
Make your device special
华为云空间
Huawei cloud services
音乐播放器
Huawei Music
Huawei Vmall
关注花粉俱乐部
举报邮箱:
|关注花粉俱乐部:
增值电信业务经营许可证:苏B2-号|
Copyright (C)
华为软件技术有限公司 版权所有 保留一切权利

我要回帖

更多关于 录制播放声音 的文章

 

随机推荐