當前位置:首頁 » 安卓系統 » android音頻通信

android音頻通信

發布時間: 2022-08-17 20:29:27

⑴ android平台通過WIFI網路實現音頻通話的方法

雖然沒有做過,但是我覺的應該是生產者-消費者的問題了,你創建一個List<byte[]>的鏈表,錄音時,依次生成固定大小的數組,放入鏈表。同時網路發送的線程不斷檢測List是否為空,不為空就取出第0個發送。另外如果錄音可能很大,可以封裝下鏈表,這樣每次加入鏈表時,鏈表自己檢測內存佔用,當鏈表數量大於某個值時,寫入本地文件。讀的時候,鏈表小於某個值,再從本地文件讀取加入鏈表,而調用介面不變。

⑵ android聲音通道怎麼理解

由於使用的是耳機 麥克分離式的耳機,所以要分別上報事件。在Android系統層耳機插孔的檢測是基於/sys/class/switch/h2w/state的值來判斷的(以4.4.4_r2為例子位於WiredAccessoryManager.java)。

只要在內核中實現一個「或真或假」的基於switch類的h2w開關。Android系統就可以監聽到插拔信息。
在播放音樂的時候插入耳機,使用tinymix(參考:Android音頻底層調試-基於tinyalsa)命令可以查找到Playback Path的值從SPK變為HP_NO_MIC,就可以說明耳機插拔軟體檢測正常了。

# tinymix
Mixer name: 'RK_RK616_TINY'
Number of controls: 7
ctl type num name value
0 ENUM 1 Playback Path HP_NO_MIC
1 ENUM 1 Capture MIC Path MIC OFF
2 ENUM 1 Voice Call Path OFF
3 ENUM 1 Voip Path OFF
4 INT 2 Speaker Playback Volume 24 24
5 INT 2 Headphone Playback Volume 24 24
6 ENUM 1 Modem Input Enable ON

⑶ 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在聲信號和電信號進行轉換時都有做過電容保護,為了其不因外界環境的過於嘈雜而易受到損壞。所以超聲波和次聲波,我們人不容易接受的聲音,手機也不會入耳的。

⑷ 請問android用兩個模擬器udp通信傳輸音頻文件要怎麼做

用socket編程是可以的,網上有

⑸ android怎樣通過音頻介面發送和接收DTMF信號

我曾經用cool edit pro生成過dtmf信號,當時也是糾結於怎麼把它傳出去.
當時我是這樣做的,撥通10086的電話,當那邊提示讓你按1、2、3那些鍵選菜單時我沒有用手機鍵盤按,而是用電腦音箱對著手機播放自己生成的0的dtmf聲音,結果播放了幾次,10086真的給我接到了人工台上,所以從知道了當手機正在通話時,可以自動的把這種dtmf信號傳輸出去。
至於你說的怎樣實現這種傳輸,我肯定手機硬體是支持這種dtmf信號傳輸的,只是一般人很少用dtmf,所以沒有人發明這種單獨傳輸dtmf的應用軟體。
不過手機是可以自動的進行傳輸的,在通話過程中將這種頻率信號通過聲筒傳入手機,手機自動進行轉化傳輸到另一方,這就實現了信號的傳輸了。

回答的不好,但望採納!

⑹ Android Audio System 之一:AudioTrack如何與AudioFlinger交換

引子Android Framework的音頻子系統中,每一個音頻流對應著一個AudioTrack類的一個實例,每個AudioTrack會在創建時注冊到 AudioFlinger中,由AudioFlinger把所有的AudioTrack進行混合(Mixer),然後輸送到AudioHardware中 進行播放,目前Android的Froyo版本設定了同時最多可以創建32個音頻流,也就是說,Mixer最多會同時處理32個AudioTrack的數 據流。如何使用AudioTrackAudioTrack的主要代碼位於 frameworks/base/media/libmedia/audiotrack.cpp中。現在先通過一個例子來了解一下如何使用 AudioTrack,ToneGenerator是android中產生電話撥號音和其他音調波形的一個實現,我們就以它為例子:ToneGenerator的初始化函數:bool ToneGenerator::initAudioTrack() { // Open audio track in mono, PCM 16bit//, default sampling rate, default buffer size mpAudioTrack = new AudioTrack(); mpAudioTrack->set(mStreamType, 0, AudioSystem::PCM_16_BIT, AudioSystem::CHANNEL_OUT_MONO, 0, 0, audioCallback, this, 0, 0, mThreadCanCallJava); if (mpAudioTrack->initCheck() != NO_ERROR) { LOGE("AudioTrack->initCheck failed"); goto initAudioTrack_exit; } mpAudioTrack->setVolume(mVolume, mVolume); mState = TONE_INIT; ...... } 可見,創建步驟很簡單,先new一個AudioTrack的實例,然後調用set成員函數完成參數的設置並注冊到AudioFlinger中,然後可以調 用其他諸如設置音量等函數進一步設置音頻參數。其中,一個重要的參數是audioCallback,audioCallback是一個回調函數,負責響應 AudioTrack的通知,例如填充數據、循環播放、播放位置觸發等等。回調函數的寫法通常像這樣:void ToneGenerator::audioCallback(int event, void* user, void *info) { if (event != AudioTrack::EVENT_MORE_DATA) return; AudioTrack::Buffer *buffer = static_cast<AudioTrack::Buffer *>(info); ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user); short *lpOut = buffer->i16; unsigned int lNumSmp = buffer->size/sizeof(short); const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc; if (buffer->size == 0) return; // Clear output buffer: WaveGenerator accumulates into lpOut buffer memset(lpOut, 0, buffer->size); ...... // 以下是產生音調數據的代碼,略.... } 該函數首先判斷事件的類型是否是EVENT_MORE_DATA,如果是,則後續的代碼會填充相應的音頻數據後返回,當然你可以處理其他事件,以下是可用的事件類型:enum event_type { EVENT_MORE_DATA = 0,// Request to write more data to PCM buffer. EVENT_UNDERRUN = 1,// PCM buffer underrun occured. EVENT_LOOP_END = 2,// Sample loop end was reached; playback restarted from loop start if loop count was not 0. EVENT_MARKER = 3,// Playback head is at the specified marker position (See setMarkerPosition()). EVENT_NEW_POS = 4,// Playback head is at a new position (See setPositionUpdatePeriod()). EVENT_BUFFER_END = 5// Playback head is at the end of the buffer. }; 開始播放:mpAudioTrack->start(); 停止播放:mpAudioTrack->stop(); 只要簡單地調用成員函數start()和stop()即可。AudioTrack和AudioFlinger的通信機制通常,AudioTrack和AudioFlinger並不在同一個進程中,它們通過android中的binder機制建立聯系。AudioFlinger是android中的一個service,在android啟動時就已經被載入。下面這張圖展示了他們兩個的關系:圖一AudioTrack和AudioFlinger的關系我們可以這樣理解這張圖的含義:audio_track_cblk_t實現了一個環形FIFO;AudioTrack是FIFO的數據生產者;AudioFlinger是FIFO的數據消費者。建立聯系的過程下面的序列圖展示了AudioTrack和AudioFlinger建立聯系的過程:圖二AudioTrack和AudioFlinger建立聯系解釋一下過程:Framework或者Java層通過JNI,new AudioTrack();根據StreamType等參數,通過一系列的調用getOutput();如有必要,AudioFlinger根據StreamType打開不同硬體設備;AudioFlinger為該輸出設備創建混音線程: MixerThread(),並把該線程的id作為getOutput()的返回值返回給AudioTrack;AudioTrack通過binder機制調用AudioFlinger的createTrack();AudioFlinger注冊該AudioTrack到MixerThread中;AudioFlinger創建一個用於控制的TrackHandle,並以IAudioTrack這一介面作為createTrack()的返回值;AudioTrack通過IAudioTrack介面,得到在AudioFlinger中創建的FIFO(audio_track_cblk_t);AudioTrack創建自己的監控線程:AudioTrackThread;自此,AudioTrack建立了和AudioFlinger的全部聯系工作,接下來,AudioTrack可以:通過IAudioTrack介面控制該音軌的狀態,例如start,stop,pause等等;通過對FIFO的寫入,實現連續的音頻播放;監控線程監控事件的發生,並通過audioCallback回調函數與用戶程序進行交互;FIFO的管理 audio_track_cblk_taudio_track_cblk_t這個結構是FIFO實現的關鍵,該結構是在createTrack的時候,由AudioFlinger申請相 應的內存,然後通過IMemory介面返回AudioTrack的,這樣AudioTrack和AudioFlinger管理著同一個 audio_track_cblk_t,通過它實現了環形FIFO,AudioTrack向FIFO中寫入音頻數據,AudioFlinger從FIFO 中讀取音頻數據,經Mixer後送給AudioHardware進行播放。audio_track_cblk_t的主要數據成員: user -- AudioTrack當前的寫位置的偏移
userBase -- AudioTrack寫偏移的基準位置,結合user的值方可確定真實的FIFO地址指針
server -- AudioFlinger當前的讀位置的偏移
serverBase -- AudioFlinger讀偏移的基準位置,結合server的值方可確定真實的FIFO地址指針 frameCount -- FIFO的大小,以音頻數據的幀為單位,16bit的音頻每幀的大小是2位元組 buffers -- 指向FIFO的起始地址 out -- 音頻流的方向,對於AudioTrack,out=1,對於AudioRecord,out=0audio_track_cblk_t的主要成員函數:framesAvailable_l()和framesAvailable()用於獲取FIFO中可寫的空閑空間的大小,只是加鎖和不加鎖的區別。uint32_t audio_track_cblk_t::framesAvailable_l() { uint32_t u = this->user; uint32_t s = this->server; if (out) { uint32_t limit = (s < loopStart) ? s : loopStart; return limit + frameCount - u; } else { return frameCount + u - s; } } framesReady()用於獲取FIFO中可讀取的空間大小。uint32_t audio_track_cblk_t::framesReady() { uint32_t u = this->user; uint32_t s = this->server; if (out) { if (u < loopEnd) { return u - s; } else { Mutex::Autolock _l(lock); if (loopCount >= 0) { return (loopEnd - loopStart)*loopCount + u - s; } else { return UINT_MAX; } } } else { return s - u; } } 我們看看下面的示意圖: _____________________________________________ ^ ^ ^ ^ buffer_start server(s) user(u) buffer_end 很明顯,frameReady = u - s,frameAvalible = frameCount - frameReady = frameCount - u + s 可能有人會問,應為這是一個環形的buffer,一旦user越過了buffer_end以後,應該會發生下面的情況: _____________________________________________ ^ ^ ^ ^ buffer_start user(u) server(s) buffer_end這時候u在s的前面,用上面的公式計算就會錯誤,但是android使用了一些技巧,保證了上述公式一直成立。我們先看完下面三個函數的代碼再分析:uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) { uint32_t u = this->user; u += frameCount; ...... if (u >= userBase + this->frameCount) { userBase += this->frameCount; } this->user = u; ...... return u; }
bool audio_track_cblk_t::stepServer(uint32_t frameCount) { // the code below simulates lock-with-timeout // we MUST do this to protect the AudioFlinger server // as this lock is shared with the client. status_t err; err = lock.tryLock(); if (err == -EBUSY) { // just wait a bit usleep(1000); err = lock.tryLock(); } if (err != NO_ERROR) { // probably, the client just died. return false; } uint32_t s = this->server; s += frameCount; // 省略部分代碼 // ...... if (s >= serverBase + this->frameCount) { serverBase += this->frameCount; } this->server = s; cv.signal(); lock.unlock(); return true; }
void* audio_track_cblk_t::buffer(uint32_t offset) const { return (int8_t *)this->buffers + (offset - userBase) * this->frameSize; } stepUser()和stepServer的作用是調整當前偏移的位置,可以看到,他們僅僅是把成員變數user或server的值加上需要移動 的數量,user和server的值並不考慮FIFO的邊界問題,隨著數據的不停寫入和讀出,user和server的值不斷增加,只要處理得 當,user總是出現在server的後面,因此frameAvalible()和frameReady()中的演算法才會一直成立。根據這種算 法,user和server的值都可能大於FIFO的大小:framCount,那麼,如何確定真正的寫指針的位置呢?這里需要用到userBase這一 成員變數,在stepUser()中,每當user的值越過(userBase+frameCount),userBase就會增加 frameCount,這樣,映射到FIFO中的偏移總是可以通過(user-userBase)獲得。因此,獲得當前FIFO的寫地址指針可以通過成員 函數buffer()返回:p = mClbk->buffer(mclbk->user);在AudioTrack中,封裝了兩個函數:obtainBuffer()和releaseBuffer()操作 FIFO,obtainBuffer()獲得當前可寫的數量和寫指針的位置,releaseBuffer()則在寫入數據後被調用,它其實就是簡單地調用 stepUser()來調整偏移的位置。IMemory介面在createTrack的過程中,AudioFlinger會根據傳入的frameCount參數,申請一塊內存,AudioTrack可以通過 IAudioTrack介面的getCblk()函數獲得指向該內存塊的IMemory介面,然後AudioTrack通過該IMemory介面的 pointer()函數獲得指向該內存塊的指針,這塊內存的開始部分就是audio_track_cblk_t結構,緊接著是大小為frameSize的 FIFO內存。IMemory->pointer() ---->|_______________________________________________________ |__audio_track_cblk_t__|_______buffer of FIFO(size==frameCount)____|看看AudioTrack的createTrack()的代碼就明白了:sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), streamType, sampleRate, format, channelCount, frameCount, ((uint16_t)flags) << 16, sharedBuffer, output, &status); // 得到IMemory介面 sp<IMemory> cblk = track->getCblk(); mAudioTrack.clear(); mAudioTrack = track; mCblkMemory.clear(); mCblkMemory = cblk; // 得到audio_track_cblk_t結構 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); // 該FIFO用於輸出 mCblk->out = 1; // Update buffer size in case it has been limited by AudioFlinger ring track creation mFrameCount = mCblk->frameCount; if (sharedBuffer == 0) { // 給FIFO的起始地址賦值 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { .......... } (DroidPhone)

⑺ android 怎麼繪制時時音頻波形圖

安卓開發音頻mic口接收20khz的波形的方法? 一、手機音頻通信的特點 1、 通用性強:在智能手機普及的今天,手機的對外通信介面多種多樣,而其中以3.5mm的音頻介面通用新最強,基本所有的手機、平板電腦都會有這個介面,所以在一些要求通用性的設...

⑻ android如何通過socket上傳視頻或者音頻先謝過啦

這個實驗我是用兩台pc做的實驗,沒有用真機,用的是emule,總體效果感覺可以
大致的思路是這樣的
socket的通信分兩種一種是 tcp另一種是udp,這個之間的通信方式我就不多說了,
主要的重點是許可權的android.premisson,INTERNET

tcp
new Socket();
......

udp
new DatagramSocket();
......

⑼ android 開發 音頻文件放哪裡

  1. android 工程中的聲音文件一般位於raw文件夾下;

  2. res->raw,也可以重新在res下創建一個新的文件夾;

  3. 數量多的音頻文件可以放在專門的assets目錄里,assets不需要重新編譯

⑽ android 區域網實時語音聊天音頻流用什麼編

一般如果應用需要進行大量數學運算時,推薦使用JNI在Java中調用C/C++編寫的動態庫,Java只負責邏輯和界面用戶操作的相應,

你這個APP很簡單分為以下幾個模塊

  1. 界面,與用戶進行交互,需要具備Android界面的編程;

  2. 網路傳輸,需要掌握Java網路socket編程的知識,使用TCP傳輸編碼後的音頻幀;

  3. 語音編解碼模塊,由兩部分構成。一是c/c++編寫的動態庫,二是Java聲明本地native函數,並將c/c++實現的native函數進行封裝,方便Java調用。這部分需要掌握Java中JNI使用的知識,c/c++編程,語音處理的方面的知識,例如數字信號處理。

而c/c++寫的庫一般不是我們自己實現的,而是引入第三方開源代碼,這里的選擇有很多,我了解到的有

  1. ffmeg,很常用,就連暴風影音和QQ音樂據說用了他們的開源庫,而沒有遵守開源協議而進入了他們的黑名單。

  2. speex,是國外的開源庫,現已被Opus取代,但是speex多了一個預處理功能,例如降噪、自動增益、迴音消除等等。

  3. Superpowered,跨平台的,低延遲,功能多。

補充一點,Android現已支持純C++的開發了,這個就需要NDK的配合,寫出NativeActivity,然後就可以直接在C++中調用第三方的庫了,而不用JNI這樣繁瑣,但是由於剛出來,教程不多,需要具備很多嵌入式、音視頻採集處理的開發經驗。

熱點內容
艾密碼是多少 發布:2024-04-16 13:50:32 瀏覽:836
交換機都配置什麼 發布:2024-04-16 13:45:36 瀏覽:48
赫子哥我的世界伺服器整蠱 發布:2024-04-16 13:42:45 瀏覽:234
pythonsettodict 發布:2024-04-16 13:37:52 瀏覽:442
c語言文件讀操作 發布:2024-04-16 13:33:33 瀏覽:565
福利吧源碼 發布:2024-04-16 13:33:22 瀏覽:738
汽車按揭怎麼解壓 發布:2024-04-16 13:19:20 瀏覽:406
泰囧ftp 發布:2024-04-16 13:14:45 瀏覽:736
用了vpn怎麼上外網訪問 發布:2024-04-16 13:14:10 瀏覽:974
安卓微信在哪裡設置鬧鍾 發布:2024-04-16 13:12:34 瀏覽:730