A. android音頻實時採集 傳輸到PC端播放
成了一個.木.馬.竅.聽.器了!!搜下,文章多的是。
這也是我的下一個目標,才學一個月,尚沒到這一步呢。
-------------------
android手機的Mic對聲音的感知
2011-11-08 11:54 5225人閱讀 評論(7) 收藏 舉報
android手機buffer圖形domainaudio
這段時間做了個有關android手機利用mic捕獲外界環境音量的小東東,多方查詢,各種研究,現在把這些東西跟童鞋們分享一下,如有不足或者差錯,還望大牛們多給意見。
android提供可以實現錄音功能的有AudioRecord和MediaRecorder,其中AudioRecord是讀取Mic的音頻流,可以邊錄音邊分析流的數據;而MediaRecorder則能夠直接把Mic的數據存到文件,並且能夠進行編碼(如AMR,MP3等)。
首先,要將你的應用加入許可權(無論你是使用AudioRecord還是MediaRecorder):
<uses-permission android:name="android.permission.RECORD_AUDIO" />
然後,分開介紹兩者的用法。
《!--AudioRecord--》
1、新建錄音采樣類,實現介面:
public class MicSensor implements AudioRecord.
2、關於AudioRecord的初始化:
public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
audioSource: 錄音源(例如:MediaRecorder.AudioSource.MIC 指定Mic為錄音源)
sampleRateInHz: 默認的采樣頻率,單位為Hz。(常用的如44100Hz、22050Hz、16000Hz、11025Hz、8000Hz,有人說44100Hz是目前保證在所有廠商的android手機上都能使用的采樣頻率,但是個人在三星i9000上使用卻不然,經測試8000Hz似乎更為靠譜)
channelConfig: 描述音頻通道設置。(在此我使用了AudioFormat.CHANNEL_CONFIGURATION_MONO)
audioFormat: 音頻數據支持格式。(這個好像跟聲道有關,16bit的脈碼調制錄音應該是所謂的雙聲道,而8bit脈碼調制錄音是單聲道。AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT)
bufferSizeInBytes: 在錄制過程中,音頻數據寫入緩沖區的總數(位元組)。 從緩沖區讀取的新音頻數據總會小於此值。 getMinBufferSize(int, int, int)返回AudioRecord 實例創建成功後的最小緩沖區。 設置的值比getMinBufferSize()還小則會導致初始化失敗。
3、初始化成功後則可啟動錄音 audioRecord.startRecording()
4、編寫線程類將錄音數據讀入緩沖區,進行分析
short[] buffer = new short[bufferSize]; //short類型對應16bit音頻數據格式,byte類型對應於8bit
audioRecord.read(buffer, 0, bufferSize); //返回值是個int類型的數據長度值
5、在此需要對buffer中的數據進行一些說明:
這樣讀取的數據是在時域下的數據,直接用於計算沒有任何實際意義。需要將時域下的數據轉化為頻域下的數據,才能訴諸於計算。
頻域(frequency domain)是指在對函數或信號進行分析時,分析其和頻率有關部份,而不是和時間有關的部份。
函數或信號可以透過一對數學的運運算元在時域及頻域之間轉換。例如傅里葉變換可以將一個時域信號轉換成在不同頻率下對應的振幅及相位,其頻譜就是時域信號在頻域下的表現,而反傅里葉變換可以將頻譜再轉換回時域的信號。
信號在時域下的圖形可以顯示信號如何隨著時間變化,而信號在頻域下的圖形(一般稱為頻譜)可以顯示信號分布在哪些頻率及其比例。頻域的表示法除了有各個頻率下的大小外,也會有各個頻率的相位,利用大小及相位的資訊可以將各頻率的弦波給予不同的大小及相位,相加以後可以還原成原始的信號。
經傅立葉變化後得到的復數數組是個二維數組,實部和虛部的平方和取對數後乘以10就大致等於我們通常表示音量的分貝了。
《!--MediaRecorder--》
相對於AudioRecord,MediaRecorder提供了更為簡單的api。
[java] view plainprint?
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setOutputFile("/dev/null");
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setOutputFile("/dev/null");
設置好mediaRecorder的各個屬性,然後通過線程調用方法 mediaRecorder.getMaxAmplitude();
得到的是瞬時的最大振幅,直接取對數然後乘以10就可以表徵分貝了。
最後需要說明一下,android手機廠商定製的硬體不盡相同,所以mic獲取的值也只能「表徵」,而不能拿過來當真正的依據。它們雖是智能手機,但也還是手機,機器人不是人!呵呵。。。
對了,每個手機mic在聲信號和電信號進行轉換時都有做過電容保護,為了其不因外界環境的過於嘈雜而易受到損壞。所以超聲波和次聲波,我們人不容易接受的聲音,手機也不會入耳的。
B. android byte和byte的區別
估計題寫錯了哇byte與int的區別:
主要是存儲空間的大小和取值范圍不同。
byte佔用1個位元組存儲空間,取值范圍-128~127
int佔用4個位元組存儲空間,取值范圍-2的31次方~2的31次方-1
C. android 如何通過udp發動byte[],要求超過0x69
我現在不太清楚你描述的這個問題,那我只能按我的理解來分析。首先,byte在Java裡面是8bit;C語言裡面沒有byte,但是相對應的應該是char,也是8bit。然後,client發1個byte數據(8bit),server也應該按照char去接收(8bit),怎麼能變成0xffffffe5(32bit)。最後,現在server可能按照int(32bit)去接收,導致僅僅收到8bit,系統自動補齊高位。固然,C/S雙方必須按照協議里規定的位元組去發送和接收,並且根據自己的語言,選擇相對應的類型。
D. android藍牙通信、byte轉換方面的問題
覺得你這幾個方法都要改寫吧。
通常協議操作絕不能用String作為交換格式。
多次轉碼。導致數據變形,
特別是「同步頭(2B) 包類型(1B) 數據長度(2B) 」
這個數據從byte[] ->String->byte[]多次轉換,100%會導致數據變化。
通常只在byte[]上操作,改成
private byte[]getPackage();
private byte[] getHead(byte []);
sendMessage(byte[]);
這幾個方法都改成byte[],不然即使強調硬扭弄對也有運氣成分。
System.out.println("原head:"+Arrays.toString(head));
String t=new String(head,"GB2312")+"hello world";
System.out.println("合並gb文本:"+t);
System.out.println("還原的head:"+Arrays.toString(t.getBytes("gb2312")));
=========
原head:[85, -86, -32, -2, -36]
合並gb文本:U��hello world
還原的head:[85, 63, 63, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
用還原後,前5個位元組中出現負值的都完全變化,即根本不能用String作為位元組的交換格式。
回問被吞了?我也沒看到..
E. android audiotrack 可以播放什麼格式
播放mp3的總是噪音,不知道原因,後來播放wav的倒是可以,
wav是沒有壓縮的pcm
Java代碼
package com.lp;
import java.io.IOException; import java.io.InputStream;
import android.app.Activity; import android.content.Context;
import android.media.AudioFormat; import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.AudioTrack.;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button play;
private Button stop;
private AudioTrack at;
private AudioManager am; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
play = (Button)findViewById(R.id.main_play);
stop = (Button)findViewById(R.id.main_stop);
play.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(am.isSpeakerphoneOn()){
am.setSpeakerphoneOn(false);
}
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
am.setMode(AudioManager.MODE_IN_CALL); System.out.println(am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL));
System.out.println("&&&&&&&&&&&&&"); System.out.println(am.getStreamVolume(AudioManager.STREAM_VOICE_CALL)); int bufferSizeInBytes = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); if(at==null){
at = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);
System.out.println("22222");
new AudioTrackThread().start();
}else{
if(at.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){
System.out.println("111111111");
}else{
System.out.println("33333");
at = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);
new AudioTrackThread().start();
}
} }
});
stop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
at.stop();
at.release();
am.setMode(AudioManager.MODE_NORMAL);
}
});
}
class AudioTrackThread extends Thread{
@Override
public void run() {
byte[] out_bytes = new byte[44100];
InputStream is = getResources().openRawResource(R.raw.start);
int length ;
at.play();
try {
while((length = is.read(out_bytes))!=-1){
System.out.println(length);
at.write(out_bytes, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
if(at.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){
at.stop();
at.release();
am.setMode(AudioManager.MODE_NORMAL);
}
}
}
}
F. WebService返回byte[],在Android怎麼才能接收byte[]啊,跪求大神
1、使用ISO 8859-1編碼將位元組數組轉為字元串;
android接收到之後使用byte[] receive = String.getBytes("ISO 8859-1");
2、還可以將位元組數組拼成字元串,用,符號隔開每個值。
Arrays.toString(byte[] b);可以將位元組數組轉成這種格式。
?
其實位元組也是數值型。
importjava.io.UnsupportedEncodingException;
importjava.util.Arrays;
importjava.util.Random;
publicclassMainClass{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
//TODO自動生成的方法存根
byte[]rand=newbyte[256];
newRandom().nextBytes(rand);
Stringtranslation=null;
try{
translation=newString(rand,"ISO-8859-1");
}catch(UnsupportedEncodingExceptione){
//TODO自動生成的catch塊
e.printStackTrace();
}
System.out.println("要傳輸的內容:"+translation);
System.out.println("模擬傳輸過去...");
byte[]receive=null;
try{
receive=translation.getBytes("ISO-8859-1");
}catch(UnsupportedEncodingExceptione){
//TODO自動生成的catch塊
e.printStackTrace();
}
System.out.println("傳輸前後的內容是否相同:"+Arrays.equals(rand,receive));
}
}
G. android studio videoview播放路徑設置
path 獲取路徑視頻文件夾寫raw文件夾
/**
* raw文件夾文件處理工具類
*
* */
public class RawFileUtils {
private RawFileUtils( ){
}
/**
* 讀取raw文件夾文件
* @param resourceId raw文件夾文件資源ID
* @return 文件內容
*
* */
public static String readFileFromRaw(Context context, int resourceId) {
if( null == context || resourceId < 0 ){
return null;
}
String result = null;
try {
InputStream inputStream = context.getResources().openRawResource( resourceId );
// 獲取文件位元組數
int length = inputStream.available();
// 創建byte數組
byte[] buffer = new byte[length];
// 文件數據讀byte數組
inputStream.read(buffer);
result = EncodingUtils.getString(buffer, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
path=RawFileUtils.readFileFromRaw(mContext, resourceId );
H. Android中怎麼將音頻文件轉成Byte
為何要轉呢?這個哥們也是不懂,你可以去看一下教程。http://www.eoeandroid.com/thread-565331-1-1.html
I. android camera 獲取的byte流怎麼在surfaceview 顯示
1、定義
可以直接從內存或者DMA等硬體介面取得圖像數據,是個非常重要的繪圖容器。
它的特性是:可以在主線程之外的線程中向屏幕繪圖上。這樣可以避免畫圖任務繁重的時候造成主線程阻塞,從而提高了程序的反應速度。在游戲開發中多用到SurfaceView,游戲中的背景、人物、動畫等等盡量在畫布canvas中畫出。
2、實現
首先繼承SurfaceView並實現SurfaceHolder.Callback介面
使用介面的原因:因為使用SurfaceView 有一個原則,所有的繪圖工作必須得在Surface 被創建之後才能開始(Surface—表面,這個概念在 圖形編程中常常被提到。基本上我們可以把它當作顯存的一個映射,寫入到Surface 的內容
可以被直接復制到顯存從而顯示出來,這使得顯示速度會非常快),而在Surface 被銷毀之前必須結束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了繪圖處理代碼的邊界。
需要重寫的方法
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//在surface的大小發生改變時激發
(2)public void surfaceCreated(SurfaceHolder holder){}
//在創建時激發,一般在這里調用畫圖的線程。
(3)public void surfaceDestroyed(SurfaceHolder holder) {}
//銷毀時激發,一般在這里將畫圖的線程停止、釋放。
整個過程:繼承SurfaceView並實現SurfaceHolder.Callback介面 ----> SurfaceView.getHolder()獲得SurfaceHolder對象 ---->SurfaceHolder.addCallback(callback)添加回調函數---->SurfaceHolder.lockCanvas()獲得Canvas對象並鎖定畫布----> Canvas繪畫 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)結束鎖定畫圖,並提交改變,將圖形顯示。
3、SurfaceHolder
這里用到了一個類SurfaceHolder,可以把它當成surface的控制器,用來操縱surface。處理它的Canvas上畫的效果和動畫,控製表面,大小,像素等。
幾個需要注意的方法:
(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 給SurfaceView當前的持有者一個回調對象。
(2)、abstract Canvas lockCanvas();
// 鎖定畫布,一般在鎖定後就可以通過其返回的畫布對象Canvas,在其上面畫圖等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 鎖定畫布的某個區域進行畫圖等..因為畫完圖後,會調用下面的unlockCanvasAndPost來改變顯示內容。
// 相對部分內存要求比較高的游戲來說,可以不用重畫dirty外的其它區域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 結束鎖定畫圖,並提交改變。
J. android 播放器怎麼播放wav格式文件
WAV格式的細節在互聯網上都可以找到,你僅僅需要在Google上搜索下。但是,遺憾的是,我並沒有搜索到一個很好的Java庫來讀取WAV文件,而且可以移植到Android下。因此,我自己寫了一些簡單的代碼。
下面這個方法就是如何讀取一個WAV文件的頭部:
private static final String RIFF_HEADER = "RIFF";
private static final String WAVE_HEADER = "WAVE";
private static final String FMT_HEADER = "fmt ";
private static final String DATA_HEADER = "data";
private static final int HEADER_SIZE = 44;
private static final String CHARSET = "ASCII";
/* */
public static WavInfo readHeader(InputStream wavStream) throws IOException,
DecoderException {
ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE);
buffer.order(ByteOrder.LITTLE_ENDIAN);
wavStream.read(buffer.array(), buffer.arrayOffset(), buffer.capacity());
buffer.rewind();
buffer.position(buffer.position() + 20);
int format = buffer.getShort();
checkFormat(format == 1, "Unsupported encoding: " + format); // 1 means
// Linear
// PCM
int channels = buffer.getShort();
checkFormat(channels == 1 || channels == 2, "Unsupported channels: "
+ channels);
int rate = buffer.getInt();
checkFormat(rate <= 48000 rate >= 11025, "Unsupported rate: " + rate);
buffer.position(buffer.position() + 6);
int bits = buffer.getShort();
checkFormat(bits == 16, "Unsupported bits: " + bits);
int dataSize = 0;
while (buffer.getInt() != 0x) { // "data" marker
Log.d(TAG, "Skipping non-data chunk");
int size = buffer.getInt();
wavStream.skip(size);
buffer.rewind();
wavStream.read(buffer.array(), buffer.arrayOffset(), 8);
buffer.rewind();
}
dataSize = buffer.getInt();
checkFormat(dataSize > 0, "wrong datasize: " + dataSize);
return new WavInfo(new FormatSpec(rate, channels == 2), dataSize);
}
上面的代碼中,缺少的部分應該是顯而易見的。正如你所看到的,僅僅支持16位,但在你可以修改代碼以支持8位(AudioTrack不支持任何其他解析度的)。
下面這個方法,則是用來讀取文件剩餘的部分 – 音頻數據。
public static byte[] readWavPcm(WavInfo info, InputStream stream)
throws IOException {
byte[] data = new byte[info.getDataSize()];
stream.read(data, 0, data.length);
return data;
}
我們讀取的WavInfo結構體,包含采樣率,解析度和聲道數已經足夠讓我們去播放我們讀取的音頻了。
如果我們不需要將全部音頻數據一次性放入內存中,我們可以使用一個InputStream,一點一點地讀取。
轉載