• Android 音视频深入 十三 OpenSL ES 制作音乐播放器,能暂停和调整音量(附源码下载)


    项目地址
    https://github.com/979451341/OpenSLAudio 

    OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,通过使用它能够做到标准化, 高性能,低响应时间的音频功能实现方法。

    这次是使用OpenSL ES来做一个音乐播放器,它能够播放m4a、mp3文件,并能够暂停和调整音量

    播放音乐需要做一些步骤

    1.创建声音引擎

    首先创建声音引擎的对象接口 
        result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);

    然后实现它
        result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);

    从声音引擎的对象中抓取声音引擎
        result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

    创建"输出混音器"
        result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);

    实现输出混合音
        result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);

    2.创建声音播放器

    创建和实现播放器

        // realize the player
        result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;
    
        // get the play interface
        result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;

    3.设置播放缓冲

    数据格式配置

        SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_8,
                                       SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
                                       SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};

    数据定位器 就是定位要播放声音数据的存放位置,分为4种:内存位置,输入/输出设备位置,缓冲区队列位置,和midi缓冲区队列位置。

    数据定位器配置

        SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

    得到了缓存队列接口,并注册

        // get the buffer queue interface
        result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
                                                 &bqPlayerBufferQueue);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;
    
        // register callback on the buffer queue
        result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;

    4.获得其他接口用来控制播放

    得到声音特效接口

        // get the effect send interface
        result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
                                                 &bqPlayerEffectSend);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;

    得到音量接口

        // get the volume interface
        result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;
    
        // set the player's state to playing
        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;

    5.提供播放数据

    打开音乐文件

        // convert Java string to UTF-8
        const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
        assert(NULL != utf8);
    
        // use asset manager to open asset by filename
        AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
        assert(NULL != mgr);
        AAsset* asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN);
    
        // release the Java string and UTF-8
        (*env)->ReleaseStringUTFChars(env, filename, utf8);
    
        // the asset might not be found
        if (NULL == asset) {
            return JNI_FALSE;
        }
    
        // open asset as file descriptor
        off_t start, length;
        int fd = AAsset_openFileDescriptor(asset, &start, &length);
        assert(0 <= fd);
        AAsset_close(asset);

    设置播放数据

        SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
        SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
        SLDataSource audioSrc = {&loc_fd, &format_mime};

    6.播放音乐


    播放音乐只需要通过播放接口改变播放状态就可以了,暂停也是,停止也是,但是暂停必须之前的播放缓存做了才行,否则那暂停就相当于停止了

            result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, isPlaying ?
                                                                 SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED);

    7.调解音量

    SLVolumeItf getVolume()
    {
        if (fdPlayerVolume != NULL)
            return fdPlayerVolume;
        else
            return bqPlayerVolume;
    }
    
    void Java_com_ywl5320_openslaudio_MainActivity_setVolumeAudioPlayer(JNIEnv* env, jclass clazz,
                                                                          jint millibel)
    {
        SLresult result;
        SLVolumeItf volumeItf = getVolume();
        if (NULL != volumeItf) {
            result = (*volumeItf)->SetVolumeLevel(volumeItf, millibel);
            assert(SL_RESULT_SUCCESS == result);
            (void)result;
        }
    }

    8.释放资源

    关闭app时释放占用资源

    void Java_com_ywl5320_openslaudio_MainActivity_shutdown(JNIEnv* env, jclass clazz)
    {
    
        // destroy buffer queue audio player object, and invalidate all associated interfaces
        if (bqPlayerObject != NULL) {
            (*bqPlayerObject)->Destroy(bqPlayerObject);
            bqPlayerObject = NULL;
            bqPlayerPlay = NULL;
            bqPlayerBufferQueue = NULL;
            bqPlayerEffectSend = NULL;
            bqPlayerMuteSolo = NULL;
            bqPlayerVolume = NULL;
        }
    
        // destroy file descriptor audio player object, and invalidate all associated interfaces
        if (fdPlayerObject != NULL) {
            (*fdPlayerObject)->Destroy(fdPlayerObject);
            fdPlayerObject = NULL;
            fdPlayerPlay = NULL;
            fdPlayerSeek = NULL;
            fdPlayerMuteSolo = NULL;
            fdPlayerVolume = NULL;
        }
    
    
    
        // destroy output mix object, and invalidate all associated interfaces
        if (outputMixObject != NULL) {
            (*outputMixObject)->Destroy(outputMixObject);
            outputMixObject = NULL;
            outputMixEnvironmentalReverb = NULL;
        }
    
        // destroy engine object, and invalidate all associated interfaces
        if (engineObject != NULL) {
            (*engineObject)->Destroy(engineObject);
            engineObject = NULL;
            engineEngine = NULL;
        }
    
    }

    参考文章
    http://blog.csdn.net/u013898698/article/details/72822595

    http://blog.csdn.net/ywl5320/article/details/78503768

  • 相关阅读:
    分享图片到在线服务
    获取和保存照片
    处理图片(updated)
    简化版“询问用户是否退出”
    捕获高像素照片(updated)
    处理高像素的照片
    加强版照片捕获
    图片拍摄、处理、镜头应用
    Windows Phone 推送通知的第四类推送
    网络通信
  • 原文地址:https://www.cnblogs.com/jianpanwuzhe/p/8470036.html
Copyright © 2020-2023  润新知