1. 程式人生 > >Android 音訊系統:從 AudioTrack 到 AudioFlinger

Android 音訊系統:從 AudioTrack 到 AudioFlinger

1. Android 音訊框架概述

Android_Audio_Architecture

Audio 是整個 Android 平臺非常重要的一個組成部分,負責音訊資料的採集和輸出、音訊流的控制、音訊裝置的管理、音量調節等,主要包括如下部分:

  • Audio Application Framework:音訊應用框架 
    • AudioTrack:負責回放資料的輸出,屬 Android 應用框架 API 類
    • AudioRecord:負責錄音資料的採集,屬 Android 應用框架 API 類
    • AudioSystem: 負責音訊事務的綜合管理,屬 Android 應用框架 API 類
  • Audio Native Framework:音訊本地框架 
    • AudioTrack:負責回放資料的輸出,屬 Android 本地框架 API 類
    • AudioRecord:負責錄音資料的採集,屬 Android 本地框架 API 類
    • AudioSystem: 負責音訊事務的綜合管理,屬 Android 本地框架 API 類
  • Audio Services:音訊服務 
    • AudioPolicyService:音訊策略的制定者,負責音訊裝置切換的策略抉擇、音量調節策略等
    • AudioFlinger:音訊策略的執行者,負責輸入輸出流裝置的管理及音訊流資料的處理傳輸
  • Audio HAL:音訊硬體抽象層,負責與音訊硬體裝置的互動,由 AudioFlinger 直接呼叫

與 Audio 強相關的有 MultiMedia,MultiMedia 負責音視訊的編解碼,MultiMedia 將解碼後的資料通過 AudioTrack 輸出,而 AudioRecord 採集的錄音資料交由 MultiMedia 進行編碼。

本文分析基於 Android 7.0 - Nougat

////////////////////////////////////////////////////////////////////////////////////// 
// 宣告:本文由 http://blog.csdn.net/zyuanyun 原創,轉載請註明出處,謝謝! 
//////////////////////////////////////////////////////////////////////////////////////

2. AudioTrack API 概述

播放聲音可以使用 MediaPlayer 和 AudioTrack,兩者都提供 Java API 給應用開發者使用。兩者的差別在於:MediaPlayer 可以播放多種格式的音源,如 mp3、flac、wma、ogg、wav 等,而 AudioTrack 只能播放解碼後的 PCM 資料流。從上面 Android 音訊系統架構圖來看:MediaPlayer 在 Native 層會建立對應的音訊解碼器和一個 AudioTrack,解碼後的資料交由 AudioTrack 輸出。所以 MediaPlayer 的應用場景更廣,一般情況下使用它也更方便;只有一些對聲音時延要求非常苛刻的應用場景才需要用到 AudioTrack。

2.1. AudioTrack Java API

AudioTrack Java API 兩種資料傳輸模式:

Transfer Mode Description
MODE_STATIC 應用程序將回放資料一次性付給 AudioTrack,適用於資料量小、時延要求高的場景
MODE_STREAM 用程序需要持續呼叫 write() 寫資料到 FIFO,寫資料時有可能遭遇阻塞(等待 AudioFlinger::PlaybackThread 消費之前的資料),基本適用所有的音訊場景

AudioTrack Java API 音訊流型別:

Stream Type Description
STREAM_VOICE_CALL 電話語音
STREAM_SYSTEM 系統聲音
STREAM_RING 鈴聲聲音,如來電鈴聲、鬧鐘鈴聲等
STREAM_MUSIC 音樂聲音
STREAM_ALARM 警告音
STREAM_NOTIFICATION 通知音
STREAM_DTMF DTMF 音(撥號盤按鍵音)

Android 為什麼要定義這麼多的流型別?這與 Android 的音訊管理策略有關,例如:

  • 音訊流的音量管理,調節一個型別的音訊流音量,不會影響到其他型別的音訊流
  • 根據流型別選擇合適的輸出裝置;比如插著有線耳機期間,音樂聲(STREAM_MUSIC)只會輸出到有線耳機,而鈴聲(STREAM_RING)會同時輸出到有線耳機和外放

這些屬於 AudioPolicyService 的內容,本文不展開分析了。應用開發者應該根據應用場景選擇相應的流型別,以便系統為這道流選擇合適的輸出裝置。

一個 AudioTrack Java API 的測試例子(MODE_STREAM 模式):

    //Test case 1: setStereoVolume() with max volume returns SUCCESS
    @LargeTest
    public void testSetStereoVolumeMax() throws Exception {
        // constants for test
        final String TEST_NAME = "testSetStereoVolumeMax";
        final int TEST_SR = 22050;
        final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
        final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
        final int TEST_MODE = AudioTrack.MODE_STREAM;
        final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;

        //-------- initialization --------------
        // 稍後詳細分析 getMinBufferSize
        int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
        // 建立一個 AudioTrack 例項
        AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, 
                minBuffSize, TEST_MODE);
        byte data[] = new byte[minBuffSize/2];
        //--------    test        --------------
        // 呼叫 write() 寫入回放資料
        track.write(data, 0, data.length);
        track.write(data, 0, data.length);
        // 呼叫 play() 開始播放
        track.play();
        float maxVol = AudioTrack.getMaxVolume();
        assertTrue(TEST_NAME, track.setStereoVolume(maxVol, maxVol) == AudioTrack.SUCCESS);
        //-------- tear down      --------------
        // 播放完成後,呼叫 release() 釋放 AudioTrack 例項
        track.release();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

詳細說明下 getMinBufferSize() 介面,字面意思是返回最小資料緩衝區的大小,它是聲音能正常播放的最低保障,從函式引數來看,返回值取決於取樣率、取樣深度、聲道數這三個屬性。MODE_STREAM 模式下,應用程式重點參考其返回值然後確定分配多大的資料緩衝區。如果資料緩衝區分配得過小,那麼播放聲音會頻繁遭遇 underrun,underrun 是指生產者(AudioTrack)提供資料的速度跟不上消費者(AudioFlinger::PlaybackThread)消耗資料的速度,反映到現實的後果就是聲音斷續卡頓,嚴重影響聽覺體驗。

// AudioTrack.java
/**
     * Returns the estimated minimum buffer size required for an AudioTrack
     * object to be created in the {@link #MODE_STREAM} mode.
     * The size is an estimate because it does not consider either the route or the sink,
     * since neither is known yet.  Note that this size doesn't
     * guarantee a smooth playback under load, and higher values should be chosen according to
     * the expected frequency at which the buffer will be refilled with additional data to play.
     * For example, if you intend to dynamically set the source sample rate of an AudioTrack
     * to a higher value than the initial source sample rate, be sure to configure the buffer size
     * based on the highest planned sample rate.
     * @param sampleRateInHz the source sample rate expressed in Hz.
     *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
     * @param channelConfig describes the configuration of the audio channels.
     *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
     *   {@link AudioFormat#CHANNEL_OUT_STEREO}
     * @param audioFormat the format in which the audio data is represented.
     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
     *   {@link AudioFormat#ENCODING_PCM_8BIT},
     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
     * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
     *   or {@link #ERROR} if unable to query for output properties,
     *   or the minimum buffer size expressed in bytes.
     */
    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
        int channelCount = 0;
        switch(channelConfig) {
        case AudioFormat.CHANNEL_OUT_MONO:
        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
            channelCount = 1; // 單聲道
            break;
        case AudioFormat.CHANNEL_OUT_STEREO:
        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
            channelCount = 2; // 雙聲道
            break;
        default:
            if (!isMultichannelConfigSupported(channelConfig)) {
                loge("getMinBufferSize(): Invalid channel configuration.");
                return ERROR_BAD_VALUE;
            } else {
                channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
            }
        }

        if (!AudioFormat.isPublicEncoding(audioFormat)) {
            loge("getMinBufferSize(): Invalid audio format.");
            return ERROR_BAD_VALUE;
        }

        // sample rate, note these values are subject to change
        // Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed
        if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
                (sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) {
            loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");
            return ERROR_BAD_VALUE; // 取樣率支援:4KHz~192KHz
        }

        // 呼叫 JNI 方法,下面分析該函式
        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
        if (size <= 0) {
            loge("getMinBufferSize(): error querying hardware");
            return ERROR;
        }
        else {
            return size;
        }
    }

// android_media_AudioTrack.cpp
// ----------------------------------------------------------------------------
// returns the minimum required size for the successful creation of a streaming AudioTrack
// returns -1 if there was an error querying the hardware.
static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env,  jobject thiz,
    jint sampleRateInHertz, jint channelCount, jint audioFormat) {

    size_t frameCount;
    // 呼叫 AudioTrack::getMinFrameCount,這裡不深究,到 native 層再分析
    // 這個函式用於確定至少設定多少個 frame 才能保證聲音正常播放,也就是最低幀數
    const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
            sampleRateInHertz);
    if (status != NO_ERROR) {
        ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
                sampleRateInHertz, status);
        return -1;
    }
    const audio_format_t format = audioFormatToNative(audioFormat);
    if (audio_has_proportional_frames(format)) {
        const size_t bytesPerSample = audio_bytes_per_sample(format);
        return frameCount * channelCount * bytesPerSample; // PCM 資料最小緩衝區大小
    } else {
        return frameCount;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

可見最小緩衝區的大小 = 最低幀數 * 聲道數 * 取樣深度,(取樣深度以位元組為單位),到這裡大家應該有所明悟了吧,在視訊中,如果幀數過低,那麼畫面會有卡頓感,對於音訊,道理也是一樣的。最低幀數如何求得,我們到 native 層再解釋。

關於 MediaPlayer、AudioTrack,更多更詳細的 API 介面說明請參考 Android Developer:

2.2. AudioTrack Native API

AudioTrack Native API 四種資料傳輸模式:

Transfer Mode Description
TRANSFER_CALLBACK 在 AudioTrackThread 執行緒中通過 audioCallback 回撥函式主動從應用程序那裡索取資料,ToneGenerator 採用這種模式
TRANSFER_OBTAIN 應用程序需要呼叫 obtainBuffer()/releaseBuffer() 填充資料,目前我還沒有見到實際的使用場景
TRANSFER_SYNC 應用程序需要持續呼叫 write() 寫資料到 FIFO,寫資料時有可能遭遇阻塞(等待 AudioFlinger::PlaybackThread 消費之前的資料),基本適用所有的音訊場景;對應於 AudioTrack Java API 的 MODE_STREAM 模式
TRANSFER_SHARED 應用程序將回放資料一次性付給 AudioTrack,適用於資料量小、時延要求高的場景;對應於 AudioTrack Java API 的 MODE_STATIC 模式

AudioTrack Native API 音訊流型別:

Stream Type Description
AUDIO_STREAM_VOICE_CALL 電話語音
AUDIO_STREAM_SYSTEM 系統聲音
AUDIO_STREAM_RING 鈴聲聲音,如來電鈴聲、鬧鐘鈴聲等
AUDIO_STREAM_MUSIC 音樂聲音
AUDIO_STREAM_ALARM 警告音
AUDIO_STREAM_NOTIFICATION 通知音
AUDIO_STREAM_DTMF DTMF 音(撥號盤按鍵音)

AudioTrack Native API 輸出標識:

AUDIO_OUTPUT_FLAG Description
AUDIO_OUTPUT_FLAG_DIRECT 表示音訊流直接輸出到音訊裝置,不需要軟體混音,一般用於 HDMI 裝置聲音輸出
AUDIO_OUTPUT_FLAG_PRIMARY 表示音訊流需要輸出到主輸出裝置,一般用於鈴聲類聲音
AUDIO_OUTPUT_FLAG_FAST 表示音訊流需要快速輸出到音訊裝置,一般用於按鍵音、遊戲背景音等對時延要求高的場景
AUDIO_OUTPUT_FLAG_DEEP_BUFFER 表示音訊流輸出可以接受較大的時延,一般用於音樂、視訊播放等對時延要求不高的場景
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 表示音訊流沒有經過軟體解碼,需要輸出到硬體解碼器,由硬體解碼器進行解碼

我們根據不同的播放場景,使用不同的輸出標識,如按鍵音、遊戲背景音對輸出時延要求很高,那麼就需要置 AUDIO_OUTPUT_FLAG_FAST,具體可以參考 ToneGenerator、SoundPool 和 OpenSL ES。

一個 AudioTrack Natvie API 的測試例子(MODE_STATIC/TRANSFER_SHARED 模式),程式碼檔案位置:frameworks/base/media/tests/audiotests/shared_mem_test.cpp:

int AudioTrackTest::Test01() {

    sp<MemoryDealer> heap;
    sp<IMemory> iMem;
    uint8_t* p;

    short smpBuf[BUF_SZ];
    long rate = 44100;
    unsigned long phi;
    unsigned long dPhi;
    long amplitude;
    long freq = 1237;
    float f0;

    f0 = pow(2., 32.) * freq / (float)rate;
    dPhi = (unsigned long)f0;
    amplitude = 1000;
    phi = 0;
    Generate(smpBuf, BUF_SZ, amplitude, phi, dPhi);  // fill buffer

    for (int i = 0; i < 1024; i++) {
        // 分配一塊匿名共享記憶體
        heap = new MemoryDealer(1024*1024, "AudioTrack Heap Base");

        iMem = heap->allocate(BUF_SZ*sizeof(short));

        // 把音訊資料拷貝到這塊匿名共享記憶體上
        p = static_cast<uint8_t*>(iMem->pointer());
        memcpy(p, smpBuf, BUF_SZ*sizeof(short));

        // 構造一個 AudioTrack 例項,該 AudioTrack 的資料方式是 MODE_STATIC
        // 音訊資料已經一次性拷貝到共享記憶體上了,不用再呼叫 track->write() 填充資料了
        sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream type
               rate,
               AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
               AUDIO_CHANNEL_OUT_MONO,
               iMem);

        // 檢查 AudioTrack 例項是否構造成功餓了
        status_t status = track->initCheck();
        if(status != NO_ERROR) {
            track.clear();
            ALOGD("Failed for initCheck()");
            return -1;
        }

        // start play
        ALOGD("start");
        track->start(); // 開始播放

        usleep(20000);

        ALOGD("stop");
        track->stop(); // 停止播放
        iMem.clear();
        heap.clear();
        usleep(20000);
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 相關推薦

    Android 音訊系統 AudioTrackAudioFlinger

    1. Android 音訊框架概述 Audio 是整個 Android 平臺非常重要的一個組成部分,負責音訊資料的採集和輸出、音訊流的控制、音訊裝置的管理、音量調節等,主要包括如下部分: Audio Application Framework:音訊

    ANDROID音訊系統散記之三resample-2

    這篇是承接上一篇提到的底層resample處理,以Samsung的tiny alsa-lib為例說明。 tiny alsa-lib 這個tiny alsa-lib位於android2.3.1-gingerbread/device/samsung/crespo/libau

    ANDROID音訊系統散記之二resample

    預設的情況下,Android放音的取樣率固定為44.1khz,錄音的取樣率固定為8khz,因此底層的音訊裝置驅動只需設定好這兩個固定的取樣率。如果上層傳過來的取樣率與其不符的話,則Android Framework層會對音訊流做resample(重取樣)處理。 Resamp

    Android音訊系統AudioFlinger(一)

    在上面的框架圖中,我們可以看到AudioFlinger(下面簡稱AF)是整個音訊系統的核心與難點。作為Android系統中的音訊中樞,它同時也是一個系統服務,啟到承上(為上層提供訪問介面)啟下(通過HAL來管理音訊裝置)的作用。只有理解了AudioFlinger,才能以此

    ANDROID音訊系統散記之二resample-1

    Android上的resample處理 預設的情況下,Android放音的取樣率固定為44.1khz,錄音的取樣率固定為8khz,因此底層的音訊裝置驅動只需設定好這兩個固定的取樣率。如果上層傳過來的取樣率與其不符的話,則Android Framework層會對音訊流做resample(重取樣)處理。 Re

    視頻直播系統直播源碼當中我們能看到什麽?

    直播軟件開發越來越多的數據表明直播行業發展的曲線,是一種良性又快速的增長。這種增長方式得益於各大主流網絡直播平臺的領頭作用,又得益於視頻直播開發的良性循環。從視頻直播開發當中,能清晰的看到,直播源碼在其中占著絕大的“領地”。而我們由大及小,單單從直播源碼當中,就能看到這個行業發展的路程。視頻直播開發,用長遠的

    Android音訊系統適配《C++功能層》

    繼上一篇Android音訊系統適配《java邏輯層》之後,我們需要知道整個功能介面的實現路由,其實相對而言要簡單很多。上一篇有提到AudioManager.java所呼叫的介面的最終實現是在AudioSystem.java。本篇我們就從AudioSystem.java開始。  

    android音訊系統簡介

    音訊基礎知識 聲音有哪些重要屬性呢? 響度(Loudness) 響度就是人類可以感知到的各種聲音的大小,也就是音量。響度與聲波的振幅有直接關係。 音調(Pitch) 音調與聲音的頻率有關係,當聲音的頻率越大時,人耳所感知到的音調就越高,否則就越低。 音色(Qualit

    android 音訊系統/音效卡驅動 codec

    0. 專用術語 1. 物理結構 2. 系統架構 本文基於Freescale IMX平臺Codec ALC5625為例。 0. 專用術語  ASLA - Advanced Sound Linux Architecture  OSS - 以前的Linux音訊體系結構,被ASL

    Android音訊系統框架簡述

    情景1:音效卡驅動比較複雜,提供一個lib層對驅動進行封裝,APP調驅動.。框圖如下: 情景2:廠家對音效卡的配置更瞭解,設定的引數在HAL層,HAL呼叫lib,傳入不同引數,提供給APP.框圖如下: 情景3: 如果多個APP播放聲音,把聲音合成播放,則多了AudioFlinger層。

    Linux ALSA 音訊系統邏輯裝置篇

    6. 音效卡和 PCM 裝置的建立過程 前面幾章分析了 Codec、Platform、Machine 驅動的組成部分及其註冊過程,這三者都是物理裝置相關的,大家應該對音訊物理鏈路有了一定的認知。接著分析音訊驅動的中間層,由於這些並不是真正的物理裝置,故我們稱之

    Android外掛化入門到放棄

     本文根據包建強在2016GMTC全球移動開發大會上的演講整理而成。 首先自我介紹一下,我叫包建強,是這個分場的主持人。我去年寫了一本書,叫《App研發錄》,相信有很多從事技術的朋友看過或買過。 引言 先簡單介紹一下Android外掛化。很早之前已經有公司在研究這

    Android音訊系統音訊框架

    Android的音訊系統在很長一段時間內都是外界詬病的焦點。的確,早期的android系統在音訊處理上相比於iOS有一定的差距,這也是很多專業的音樂播放軟體開發商沒有推出Android平臺產品的一個重要原因。但這並不代表它的音訊框架一無是處,相反,基於Linux系統的

    Android 音訊系統

    http://blog.csdn.net/qianjin0703/article/details/6387662 0. 專用術語 1. 物理結構 2. 系統架構 本文基於Freescale IMX平臺Codec ALC5625為例。 0. 專用術語  ASLA - Advanced Sound Linux

    Android音訊系統

    Muti-media時多種形式的媒體內容(文字、音訊、視訊、圖片、動畫)的組合。多媒體可以是“MediaPlayer和MediaRecorder”的實現,Android的一大特性時高度封裝,提高了軟體的開發效率。這也使得整個多媒體系統顯得異常龐大,各種類定義、C

    Android核心開發原始碼樹中刪除出廠的app應用

    公開課1060:組策略(下) 12345678910 本文是《Android核心開發》系列的第十一篇文章,本文重點介紹如何從Android原始碼中刪除出廠的app應用。 上一篇文章中提到過,系統出廠的app應用,其實就是被安裝到/system分割槽的app

    Android音訊系統音訊基礎

    轉載請註明:LXS, http://blog.csdn.net/uiop78uiop78/article/details/8787779 對於一部嵌入式裝置來說,除了若干基礎功能外(比如手機通話、簡訊),最重要的可能就是多媒體了——那麼一個最簡單的問題,什麼是多媒體呢?

    Android程序系統程序的建立、啟動與排程流程

    Android程序框架:程序的建立、啟動與排程流程 文章目錄 一 程序的建立與啟動流程 二 程序的優先順序 三 程序的排程流程 Android系統的啟動流程如下圖(點選檢視大圖)所示: Loader層 當手機處於關機狀態時,長按電源鍵開機,引

    Linux ALSA 音訊系統物理鏈路篇

    1. Overview 硬體平臺及軟體版本: Kernel - 3.4.5 SoC - Samsung exynos CODEC - WM8994 Machine - goni_wm8994 Userspace - tinyalsa Linux ALS

    通用Android應用架構建專案開始

    1.專案結構 現在的MVP模式越來越流行。就預設採用了。 如果專案比較小的話: app——Application Activity Fragment Presenter等的頂級父類 config——API,常量表等 model——資料層 entit