这是一个c语言demo程序,android源码环境,编译得到 bin文件,push到设备上在shell环境运行,播放pcm数据。如果是app java开发,没有系统源码,就不建议往下看了。
android native播放音频,可以使用Ndk层提供的Opensl es、AAudio。
如果是在源码级别,可以随意改,比如这里使用framework内部的 TrackPlayer类,经研究源码发现android 对Opensl es 的支持,内部有条通路最后是通过 使用framework native层的TrackPlayer 类,来播放pcm数据。(有关opensl android分析在其他文章再叙述)
上demo:(github**暂未上传)
main.cpp
- /*
- * canok 20220629
- * android aosp 11
- * 参照 android中对opensl的支持 源码
- * 使用TrackPlayer 播放pcm
- * 需要源码环境下编译。
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <iostream>
- #include <atomic>
-
- #include <thread>
- #include <media/TrackPlayerBase.h>
- using namespace android;
- struct PlayerData
- {
- FILE *fp_in = nullptr;
- std::atomic<bool> bEnd = false;
- };
- // namespace android
- // {
- // 在callback中写数据。
- static void audioTrack_callBack_pullFromBuffQueue(int event, void *user, void *info)
- {
- // printf("track[%s%d]\n",__FUNCTION__,__LINE__);
- PlayerData *data = (PlayerData *)user;
- if (data == nullptr)
- {
- printf("[%s%d] data =null \n", __FUNCTION__, __LINE__);
- return;
- }
- FILE *fp_in = data->fp_in;
- if (fp_in == NULL)
- {
- printf("[%s%d] fp_in =null \n", __FUNCTION__, __LINE__);
- return;
- }
-
- switch (event)
- {
- case android::AudioTrack::EVENT_MORE_DATA:
- {
- android::AudioTrack::Buffer *pBuff = (android::AudioTrack::Buffer *)info;
- size_t availSink = pBuff->size;
-
- // void *pSrc =
- // memcpy(pBuff->raw, pSrc, availSink);
- size_t ret = fread(pBuff->raw, 1, pBuff->size, fp_in);
- pBuff->size = ret;
- if (ret < 0)
- {
- data->bEnd = true;
- }
- std::cout << "read :" << ret << std::endl;
- }
- break;
-
- default:
- break;
- }
- }
- int main(int argc, const char *argv[])
- {
-
- // 使用的是一个 callback 的传输方式, 在AudioTrack的callback中写数据。// AudioPlayer_to_android.cpp audioTrack_callBack_pullFromBuffQueue
-
- // threadCanCallJava 在AudioTrack构造函数中调用set() 时给的是false: 而transferType AudioTrack构造函数中为 默认值为 TRANSFER_DEFAULT
- // 在set() 函数中会判断根据参数,最终将 transfertype设置为 TRASNFER_CALLBACk. :: ssharedBuffer==0 cbf !=NULL threadCanCallJava==false
-
- // 将会在 cballck 中得到EVENT_MORE_DATA 消息,然后这里面写数据
-
- PlayerData data;
- data.fp_in = fopen("yk_48000_2_16.pcm", "r");
- if (data.fp_in == nullptr)
- {
- printf("[%s%d]fopen failed ! we need a pcm src file!!!!!!\n", __FUNCTION__, __LINE__);
- return -1;
- }
- sp<android::AudioTrack> pat = new android::AudioTrack(
- AUDIO_STREAM_MUSIC, // pAudioPlayer->mStreamType, // streamType
- 48000, // sampleRate,
- AUDIO_FORMAT_PCM_16_BIT, // sles_to_android_sampleFormat(df_pcm), // format
- AUDIO_CHANNEL_OUT_STEREO, // channelMask, // channel mask
- 0, // frameCount
- AUDIO_OUTPUT_FLAG_NONE, // policy, // flags
- audioTrack_callBack_pullFromBuffQueue, // callback
- (void *)&data, // (void *) pAudioPlayer, // user // 自定义的数据!!!!!会在callback中得到这个参数
- 0, // notificationFrames, // see comment above
- AUDIO_SESSION_ALLOCATE // pAudioPlayer->mSessionId
- );
-
- sp<TrackPlayerBase> player = new TrackPlayerBase();
-
- player->init(pat.get(), PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE, AUDIO_USAGE_MEDIA);
-
- player->start();
-
- player->setVolume(01.0);
-
- while (!data.bEnd)
- {
- std::this_thread::yield();
- }
-
- fclose(data.fp_in);
- return 0;
- }
- // }
Android.bp
- cc_binary {
- name: "TrackPlayerDemo",
- srcs: [
- "main.cpp",
- ],
-
- shared_libs: [
- "libaudioclient",
- "libaudioutils",
- "libutils",
- "libbinder",
- "libmediametrics",
- ],
- header_libs: [
- "libmedia_headers",
- ],
- include_dirs: [
- "frameworks/av/media/libnbaio/include_mono/",
- ],
-
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wno-unused-parameter",
- "-Wno-unused-variable",
- ],
- }
两文件放到framework 一个自定义目录下, 经source lunch 编译环境的配置后,到该自定义子目录 mm -j8
emulator虚拟机可以听到播放的音频:
无声,先要确保emulator 自身能发声,比如去设置里面改一下铃声,看是否有声音。要确保宿主机ubuntu有声音, ubuntu系统可以在设置里面选择输出到hdmi, 🎧,还是扬声器。