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中 Bitmap和Drawable相互轉換的方法
canvas board null height .com factory oar tool pla 1、Drawable --> Bitmap [java] view plain copy Bitmap drawable2Bitmap(Drawabl
Android中Bitmap和Drawable相互轉換
一、相關概念 1、Drawable就是一個可畫的物件,其可能是一張點陣圖(BitmapDrawable),也可能是一個圖形(ShapeDrawable),還有可能是一個圖層(LayerDrawable),我們根據畫圖的需求,建立相應的可畫物件 2、Canvas畫布,繪圖的
Android知識架構 · 電話面試 · Android執行緒和程序以及安全問題
這篇文章介紹的幾個問題: 3、多執行緒 一 、程序和執行緒,以及區別 程序(Process):當一個程式進入記憶體執行時,即變成一個程序。程序是處於執行過程中的程式,是程式的一個執行例項。 程序是作業系統進行資源分配和排程的一個獨立
android 獲取versionName和versionCode以及作用
android:versionCode: 主要是用於版本升級所用,是INT型別的,第一個版本定義為1,以後遞增,這樣只要判斷該值就能確定是否需要升級,該值不顯示給使用者。 android:versionName: 這個是我們常說明的版本號,由三部分組成..
HTML5實現MP3上傳前的預覽和播放時長的獲取
原文出處:http://bbs.csdn.net/topics/390765871<!DOCTYPE html> <html> <head> <!-- @author 夏茂軒@成都資訊工程學院 QQ:1034297177 -
Android 中 px和dp 的轉換
安卓開發中,佈局檔案中我們習慣使用dp單位,但是很多java程式碼的api中預設使用的是px單位(如 setPadding、setButtom、setLeft 等),這就需要我們在很多場景下進行dp和p
Android 語音播放Media Player
語音播放 因為實習工作相關的緣故,最近在學習android語音播放的內容。 MediaPlayer 音訊播放 MediaPlayer可以播放本地或者網路的音訊,流程如下: Uri myUri = ....; // initialize
Android H5和App互動以及開啟相簿上傳圖片並顯示
一、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
通過jQuery和C#分別實現對.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)pi4j和Socke實現respberry 3B上GPIO的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