1. 程式人生 > >Android 語音播放和錄製以及轉換mp3,上傳伺服器,ios親測可用

Android 語音播放和錄製以及轉換mp3,上傳伺服器,ios親測可用

最近在做一個類似微信,QQ語音錄製,上傳資料庫,並進行播放,根據錄製的時間長短,顯示出來的語音條長短也會發生變化,以及在錄製時動畫等,以及適應iOS,對錄製的音訊,進行格式轉換.

下面就讓我們看一下具體的實現吧

先看需要新增的許可權,

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- 用於訪問wifi網路資訊,wifi資訊會用於進行網路定位 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!-- 用於獲取wifi的獲取許可權,wifi資訊會用來進行網路定位 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <!-- 用於訪問網路,網路定位需要上網 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 在SD卡中建立與刪除檔案許可權 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <!-- 用於寫入快取資料到擴充套件儲存卡 -->
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

有些許可權需要動態申請的

 /**
     * 動態新增許可權
     */
    public void getPression() {
        int checkSelfPermission = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (checkSelfPermission == PackageManager.PERMISSION_DENIED) {
            //沒有許可權,申請許可權
            ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.CAMERA,
                    Manifest.permission.WRITE_SETTINGS,
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.CALL_PHONE}, 100);
        } else if (checkSelfPermission == PackageManager.PERMISSION_GRANTED) {
            //已經有了許可權 ,不需要申請
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 100:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(getContext(), "已經授權成功了", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

下面就是正式的來寫程式碼

先在頁面上定義個按鈕,用來錄音

這有一個工具類

public class RecordUtil {
    public static final String AUDIO_DIR = Environment
            .getExternalStorageDirectory().getAbsolutePath() + "/Horusch/audio";
    private String mName;
    private String mAudioPath; // 要播放的聲音的路�?
    private boolean recording = false;// 是否正在錄音
    private boolean playing = false;// 是否正在播放
    public MediaRecorder mRecorder;
    public MediaPlayer mPlay;

    public boolean isRecording() {
        return recording;
    }

    public void setRecording(boolean recording) {
        this.recording = recording;
    }

    public boolean isPlaying() {
        return playing;
    }

    public void setPlaying(boolean playing) {
        this.playing = playing;
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public String getmAudioPath() {
        return mAudioPath;
    }

    public void setmAudioPath(String mAudioPath) {
        this.mAudioPath = mAudioPath;
    }

    // 初始�?錄音�?
    private void initRecorder() {

    }

    // �?��錄音
    public void startRecord() {
        if (mRecorder != null)
            return;
        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        mName = "audio_" + 1;
        mAudioPath = AUDIO_DIR + "/" + mName + ".mp3";

        // 判斷是否存在檔案�?
        File folder = new File(AUDIO_DIR);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        // 判斷檔案是否存在
        File file = new File(mAudioPath);
        if (file.exists()) {
            int count = 2;
            while (true) {
                mName = "audio_" + count;
                mAudioPath = AUDIO_DIR + "/" + mName + ".mp3";
                file = new File(mAudioPath);
                if (file.exists()) {
                    count++;
                } else {
                    break;
                }
            }
        }
        mRecorder.setOutputFile(file.getAbsolutePath());
        recording = true;
        try {
            mRecorder.prepare();
            mRecorder.start();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // 停止錄音
    public void stopRecord() {
        try {
            if (mRecorder != null && recording) {
                //設定異常時不崩潰
                mRecorder.setOnErrorListener(null);
                mRecorder.setOnInfoListener(null);
                mRecorder.setPreviewDisplay(null);
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;
                recording = false;
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // 獲取音量值,只是針對錄音音量
    public int getVolume() {
        int volume = 0;
        // 錄音
        if (mRecorder != null && recording) {
            volume = mRecorder.getMaxAmplitude() / 650;
            Log.d("sdfgasd", volume + "");
            if (volume != 0)
                // volume = (int) (10 * Math.log(volume) / Math.log(10)) / 7;
                volume = (int) (10 * Math.log10(volume)) / 3;
            Log.d("db", volume + "");
        }
        return volume;
    }

    // �?��播放
    public void startPlay(String path, boolean isLooping) {
        if (!path.equals("")) {
            mPlay = new MediaPlayer();
            try {
                mPlay.setDataSource(path);
                mPlay.prepare();
                mPlay.start();
                mPlay.setLooping(isLooping);
                playing = true;
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    // 停止播放
    public void stopPlay() {
        if (mPlay != null && mPlay.isPlaying()) {
            mPlay.stop();
            mPlay.release();
            mPlay = null;
            playing = false;
        }
    }

}


下面是按鈕的觸控事件,我們需要計算錄音的時間,所以需要重寫這個按鈕的觸控事件,,這裡還牽扯到當你手移動出去這個按鈕,錄製錄音就會被中斷,而不是都是在up的時候停止,所以我們重新複寫觸控事件的,應該多重寫一個狀態MotionEvent.ACTION_CANCEL,下面就這個按鈕的觸控事件

/**
     * 錄音的觸控事件
     */
    private void initEvent() {
        btnEventRecording.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                int action = event.getAction();
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        currentTime = System.currentTimeMillis();
                        tvTack.setText("請開始說話");
                        mRecorduUtil.startRecord();
                        if (mRecorduUtil.isRecording()) {
                            //將step2中的linearlayout設為可視
                            ll_record.setVisibility(View.VISIBLE);
                            /**
                             *啟動執行緒<注意!這裡不能用handler.post啟動Runnable,否則無法removeCallBack>
                             */
                            Thread t = new Thread(mPollTask);
                            t.start();
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                        myRecording(currentTime);
                        break;

                    case MotionEvent.ACTION_CANCEL:
                        myRecording(currentTime);
                        break;
                }
                return true;
            }
        });
    }

當你在Dwon時,防止阻塞主執行緒,需要開啟一個執行緒更改語音圖片,在錄製的時候會有錄製的動畫,根據聲音的變化,而改變,下面是這個執行緒

/**
     * 開啟一個執行緒更改語音圖片
     */
    private Runnable mPollTask = new Runnable() {
        public void run() {
            int mVolume = mRecorduUtil.getVolume();
            Log.d("volume", mVolume + "");
            updateVolume(mVolume);
            mHandler.postDelayed(mPollTask, 100);
        }
    };

這個是語音的圖片

// 更新音量圖
    private void updateVolume(int volume) {
        switch (volume) {
            case 1:
                iv_volume.setImageResource(R.drawable.volume_icon1);
                break;
            case 2:
                iv_volume.setImageResource(R.drawable.volume_icon2);
                break;
            case 3:
                iv_volume.setImageResource(R.drawable.volume_icon3);
                break;
            case 4:
                iv_volume.setImageResource(R.drawable.volume_icon4);
                break;
            case 5:
                iv_volume.setImageResource(R.drawable.volume_icon5);
                break;
            case 6:
                iv_volume.setImageResource(R.drawable.volume_icon6);
                break;
            case 7:
                iv_volume.setImageResource(R.drawable.volume_icon7);
                break;
            default:
                break;
        }
    }

下面就是開始錄音的程式碼


/**
     * 開始錄音
     *
     * @param DownTime
     */
    private void myRecording(long DownTime) {
        long thisTime = System.currentTimeMillis();
        long recordingTime = thisTime - DownTime;
        time = (int) (recordingTime / 1000);
        ll_record.setVisibility(View.GONE);
        if (recordingTime < 1000) {
            tvTack.setText("說話時間太短");
            ShowToast.show(EventReportActivity.this, "錄音時間太短");
            mRecorduUtil.stopRecord();
            return;
        } else {
            if(time<=1){
                ViewGroup.LayoutParams layoutParams = startRecding.getLayoutParams();
                layoutParams.width = 160;
                startRecding.setLayoutParams(layoutParams);
            }else if (time>1){
                int s = time - 1;
                ViewGroup.LayoutParams pp = startRecding.getLayoutParams();
                if (160 + s * 9 < 500) {
                    pp.width = 160 + s * 9;
                    startRecding.setLayoutParams(pp);

                } else if (160 + s * 9 >= 500) {
                    pp.width = 500;
                    startRecding.setLayoutParams(pp);

            }
            }
            tvStartRecding.setText(time + "''");
            mRecorduUtil.stopRecord();
            btnEventRecording.setVisibility(View.GONE);
            rlStartRecding.setVisibility(View.VISIBLE);
        }
        mHandler.removeCallbacks(mPollTask);
        File folder = new File(RecordUtil.AUDIO_DIR);
        File[] files = folder.listFiles();
        if (files.length != 0) {
            path1 = files[files.length - 1].getAbsolutePath();
            File flacFile = new File(path1);
            IConvertCallback callback = new IConvertCallback() {
                @Override
                public void onSuccess(File convertedFile) {
                    // So fast? Love it!
                    LogUtils.d("voice-222---", "So fast? Love it!");
                    LogUtils.d("voice--222--", convertedFile.getAbsolutePath());
                    path = convertedFile.getAbsolutePath();
                }

                @Override
                public void onFailure(Exception error) {
                    // Oops! Something went wrong
                    LogUtils.d("voice-11---", "Oops! Something went wrong");
                    LogUtils.d("voice-sss---", error.toString());
                }
            };
            AndroidAudioConverter.with(this)
                    // Your current audio file
                    .setFile(flacFile)

                    // Your desired audio format
                    .setFormat(AudioFormat.MP3)

                    // An callback to know when conversion is finished
                    .setCallback(callback)

                    // Start conversion
                    .convert();
        }
    }

錄製基本就緒,我們看一下 效果

錄音前:


錄音中:


錄音後:


大致的效果就是這樣

下面就是播放了

//TODO:播放錄音
                    ivVoice.setVisibility(View.GONE);
                    ivVoiceAnimal.setVisibility(View.VISIBLE);
                    mRecorduUtil.startPlay(path, false);
                    ivVoiceAnimal.setImageResource(R.drawable.animation_yunyin);
                    animationDrawable = (AnimationDrawable) ivVoiceAnimal.getDrawable();
                    animationDrawable.start();
                    if (time != 0) {
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        ivVoiceAnimal.setVisibility(View.GONE);
                                        ivVoice.setVisibility(View.VISIBLE);
                                    }
                                });

                            }
                        }, time * 1000);//up時間
                    } else if (canceltTime != 0) {
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        ivVoiceAnimal.setVisibility(View.GONE);
                                        ivVoice.setVisibility(View.VISIBLE);
                                    }
                                });

                            }
                        }, canceltTime * 1000);//touch:MotionEvent.ACTION_CANCEL時間
                    }

轉換格式:

新增許可權

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Application裡面新增

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        AndroidAudioConverter.load(this, new ILoadCallback() {
            @Override
            public void onSuccess() {
                // Great!
            }
            @Override
            public void onFailure(Exception error) {
                // FFmpeg is not supported by device
            }
        });
    }

在用到的地方呼叫

File folder = new File(RecordUtil.AUDIO_DIR);
        File[] files = folder.listFiles();
        if (files.length != 0) {
            path1 = files[files.length - 1].getAbsolutePath();
            File flacFile = new File(path1);
            IConvertCallback callback = new IConvertCallback() {
                @Override
                public void onSuccess(File convertedFile) {
                    // So fast? Love it!
                    LogUtils.d("voice-222---", "So fast? Love it!");
                    LogUtils.d("voice--222--", convertedFile.getAbsolutePath());
                    path = convertedFile.getAbsolutePath();
                }

                @Override
                public void onFailure(Exception error) {
                    // Oops! Something went wrong
                    LogUtils.d("voice-11---", "Oops! Something went wrong");
                    LogUtils.d("voice-sss---", error.toString());
                }
            };
            AndroidAudioConverter.with(this)
                    // Your current audio file
                    .setFile(flacFile)

                    // Your desired audio format
                    .setFormat(AudioFormat.MP3)

                    // An callback to know when conversion is finished
                    .setCallback(callback)

                    // Start conversion
                    .convert();
        }


基本的錄音和播放,以及轉換格式就可以了,趕快去試試吧

下面是轉換格式的GitHub地址:https://github.com/adrielcafe/AndroidAudioConverter,

圖片什麼的就不上傳了





相關推薦

Android 語音播放錄製以及轉換mp3,伺服器,ios可用

最近在做一個類似微信,QQ語音錄製,上傳資料庫,並進行播放,根據錄製的時間長短,顯示出來的語音條長短也會發生變化,以及在錄製時動畫等,以及適應iOS,對錄製的音訊,進行格式轉換. 下面就讓我們看一下具體的實現吧 先看需要新增的許可權, <uses-permiss

Android實現本地視訊+錄製視訊+視訊壓縮

今天研究了一下視訊上傳的處理,還包括研究可以視訊壓縮,本地視訊、錄製視訊上傳。本地視訊獲取需要適配手機,這個建議自己獲取本地視訊列表自己實現。不然就會出現路徑找不到返回 null 好東西都是要分享給大家的 有問題請留言評論。。。 視訊壓縮我用的是七牛的 ,我們圖片上傳的就是七牛,七牛的視

Android開發,登入註冊介面中如何新增視訊背景,可用

此篇文章屬個人查閱資料整理所著,希望能對您有所幫助,歡迎各位留言指正,抱拳了 一、 首先在res資料夾下新增raw資料夾並將要新增的背景視訊放進去; 二、在MyViewpager.java(此為要顯示的活動檔案)中的onCreate()中新增視訊的程式碼 //設定視訊背景

jdbc連接數據庫以及crud(簡單易懂,本人可用 有源代碼和數據庫)

mce 進行 準備 相關 數據庫 進步 重新 可用 簡單 今天呢!重新整理了一邊jdbc的相關操作:現在來說對於很多框架都使用mybatis和hibernate來操作數據庫 ,也有很多使用自己簡單封裝的ssm或者是其他的一些框架來操作數據庫,但是無論使用哪一種 可以說都是

Android中 BitmapDrawable相互轉換的方法

canvas board null height .com factory oar tool pla 1、Drawable --> Bitmap [java] view plain copy Bitmap drawable2Bitmap(Drawabl

Android中BitmapDrawable相互轉換

一、相關概念 1、Drawable就是一個可畫的物件,其可能是一張點陣圖(BitmapDrawable),也可能是一個圖形(ShapeDrawable),還有可能是一個圖層(LayerDrawable),我們根據畫圖的需求,建立相應的可畫物件 2、Canvas畫布,繪圖的

Android知識架構 · 電話面試 · Android執行緒程序以及安全問題

這篇文章介紹的幾個問題: 3、多執行緒 一 、程序和執行緒,以及區別 程序(Process):當一個程式進入記憶體執行時,即變成一個程序。程序是處於執行過程中的程式,是程式的一個執行例項。 程序是作業系統進行資源分配和排程的一個獨立

android 獲取versionNameversionCode以及作用

android:versionCode: 主要是用於版本升級所用,是INT型別的,第一個版本定義為1,以後遞增,這樣只要判斷該值就能確定是否需要升級,該值不顯示給使用者。 android:versionName: 這個是我們常說明的版本號,由三部分組成..

HTML5實現MP3前的預覽播放時長的獲取

原文出處:http://bbs.csdn.net/topics/390765871<!DOCTYPE html> <html> <head> <!-- @author 夏茂軒@成都資訊工程學院 QQ:1034297177 -

Android 中 pxdp 的轉換

安卓開發中,佈局檔案中我們習慣使用dp單位,但是很多java程式碼的api中預設使用的是px單位(如 setPadding、setButtom、setLeft 等),這就需要我們在很多場景下進行dp和p

Android 語音播放Media Player

語音播放 因為實習工作相關的緣故,最近在學習android語音播放的內容。 MediaPlayer 音訊播放 MediaPlayer可以播放本地或者網路的音訊,流程如下: Uri myUri = ....; // initialize

Android H5App互動以及開啟相簿圖片並顯示

一、H5連結開啟App 點選瀏覽器中的URL,如何啟動App呢? 1、HTML連結處理 首先做成HTML的內容,url格式如下: <a href="[scheme]://[host]/[path]?[query]">啟動應用程式</a> 說明:

Android 中 Bitmap Drawable 相互轉換的方法

一、Drawable 轉換成 Bitmap 方法一 通過 BitmapFactory 中的 decodeResource 方法,將資原始檔中的 R.drawable.ic_drawable 轉化成Bitmap Resources res = getRe

iOS 錄音,播放,轉碼MP3,語音檔案

//語音檔案 AVAudioRecorder *recorder; NSTimer *timer; NSString *urlPlay; BOOL isPlay; #pragma mark ========= 語音檔案 ========== - (vo

Udp實現消息的發送接收、以及圖片的

cat 數據 art ram pan ket length out leo //Udp實現消息的發送和接收 import java.io.IOException; import java.net.DatagramPacket; import java.net.Datagr

通過jQueryC#分別實現對.NET Core Web Api的訪問以及文件

補充 param 詳細 ace lin col mage exp n) 準備工作:    建立.NET Core Web Api項目    新建一個用於Api請求的UserInfo類 public class UserInfo { publ

Android開發:仿微信QQ空間發說說相簿讀取、拍照、圖片裁剪圖片伺服器等功能的實現

第一步:新增依賴包: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.2.1' compile project('

Android開發:相簿讀取、拍照、圖片裁剪圖片伺服器等功能的實現

修改日誌 2016.05.12 之前的程式存在兩個問題: 1)從相簿選擇的圖片如果比較大,會失敗; 2)無法拍照上傳照片。 修改了這兩個bug,之前的程式碼已經被覆蓋掉了,留著太誤人子弟了。同時修改了一下標題和文章的文字描述 拍照示意 相簿示

簡單java(Android)pi4jSocke實現respberry 3BGPIO的LED燈控制

首先下載http://get.pi4j.com/download/pi4j-1.2-SNAPSHOT.zip(使用SNAPSHOT是因為3B要用這個新版本才正常,1.1版本不能在3B上執行),解的jar檔案使用eclipse進行開發,把3B作為伺服器進行socket埠監聽,沒

Strut2 Spring MVC 文件對比

string num control 需要 nsf ping types quest nal 在Java領域中,有兩個常用的文件上傳項目:一個是Apache組織Jakarta的Common-FileUpload組件 (http://commons.apache.org/pr