Android10.0Auidio之MediaPlayer(五)

前言

前边分析了MediaPlayer从java通过jni到native层的过程,其实mediaplayer的真正的逻辑存在是在mediaPlayerService中处理的,那么今天我们就从源码看下mediaplayerService的初始化过程

正文

MediaPlayerService通过mediaserver.rc启动,我们先看下man函数,源码位置/frameworks/av/media/mediaserver/

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    AIcu_initializeIcuOrDie();
    //注册服务
    MediaPlayerService::instantiate();
    //后续分析
    ResourceManagerService::instantiate();
    registerExtensions();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

main函数基本就是将MediaPlayerService加到servicemanager中,

void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

我们继续看它的构造函数

MediaPlayerService::MediaPlayerService()
{
    ALOGV("MediaPlayerService created");
    mNextConnId = 1;

    MediaPlayerFactory::registerBuiltinFactories();
}

调用了MediaPlayerFactory的registerBuiltinFactories,

void MediaPlayerFactory::registerBuiltinFactories() {
    Mutex::Autolock lock_(&sLock);
   // 默认false
    if (sInitComplete)
        return;
   // 创建NuPlayerFactory并registerFactory_l
    IFactory* factory = new NuPlayerFactory();
    if (registerFactory_l(factory, NU_PLAYER) != OK)
        delete factory;
    factory = new TestPlayerFactory();
    if (registerFactory_l(factory, TEST_PLAYER) != OK)
        delete factory;
   // 启动一次后置为true
    sInitComplete = true;
}

我们发现只new了两个player分别是NuPlayerFactory和TestPlayerFactory。我们再看下NU_PLAYER和TEST_PLAYER的定义

enum player_type {
    STAGEFRIGHT_PLAYER = 3,
    NU_PLAYER = 4,
    // Test players are available only in the 'test' and 'eng' builds.
    // The shared library with the test player is passed passed as an
    // argument to the 'test:' url in the setDataSource call.
    TEST_PLAYER = 5,
};

只有3个,我们发现是从3开始的,那么说明 1和2应该是被放弃了。这里注释着重说明了TEST_PLAYER的使用场景only in the ‘test’ and ‘eng’ builds,创建了两个player后继续registerFactory_l

status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
                                               player_type type) {
    // factory 不是null                                            
    if (NULL == factory) {
        ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
              " NULL.", type);
        return BAD_VALUE;
    }
    // 第一次应该是<0,因为sFactoryMap里就不会包含我们传入的type
    if (sFactoryMap.indexOfKey(type) >= 0) {
        ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
              " already registered.", type);
        return ALREADY_EXISTS;
    }
     // 将我们的player加入sFactoryMap容器中
    if (sFactoryMap.add(type, factory) < 0) {
        ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
              " to map.", type);
        return UNKNOWN_ERROR;
    }

    return OK;
}

MediaPlayerService的创建到此就结束了,接下来我们在看下mediaplayer中的client的创建过程,我们还记得在Android10.0Auidio之MediaPlayer(四)中我们分析setDataSource的过程的时候get了MediaPlayerService然后调用了service->create

sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        audio_session_t audioSessionId)
{
    pid_t pid = IPCThreadState::self()->getCallingPid();
    int32_t connId = android_atomic_inc(&mNextConnId);

    sp<Client> c = new Client(
            this, pid, connId, client, audioSessionId,
            IPCThreadState::self()->getCallingUid());

    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
         IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;
    {
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    return c;
}

也就是我们在Mediaplayer的SetDataSource的时候才会在service中创建client,继续看下new Client的过程

MediaPlayerService::Client::Client(
        const sp<MediaPlayerService>& service, pid_t pid,
        int32_t connId, const sp<IMediaPlayerClient>& client,
        audio_session_t audioSessionId, uid_t uid)
{
    ALOGV("Client(%d) constructor", connId);
    mPid = pid;
    mConnId = connId;
    mService = service;
    mClient = client;
    mLoop = false;
    mStatus = NO_INIT;
    mAudioSessionId = audioSessionId;
    mUid = uid;
    mRetransmitEndpointValid = false;
    mAudioAttributes = NULL;
    //创建了Listener,注这个不是我们注册下来的那个listener
    mListener = new Listener(this);
//默认0 没有使用
#if CALLBACK_ANTAGONIZER
    ALOGD("create Antagonizer");
    mAntagonizer = new Antagonizer(mListener);
#endif
}

通过Client的构造函数,我们看到又new了一个Listener,这个listener时一个public MediaPlayerBase::Listener主要内部callback用的,后续用到具体说。我们按着setDataSource继续分析MediaPlayerService

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
    struct stat sb;
    int ret = fstat(fd, &sb);
    if (ret != 0) {
        ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
        return UNKNOWN_ERROR;
    }

    ALOGV("st_dev  = %llu", static_cast<unsigned long long>(sb.st_dev));
    ALOGV("st_mode = %u", sb.st_mode);
    ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
    ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
    ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));

    if (offset >= sb.st_size) {
        ALOGE("offset error");
        return UNKNOWN_ERROR;
    }
    if (offset + length > sb.st_size) {
        length = sb.st_size - offset;
        ALOGV("calculated length = %lld", (long long)length);
    }
	// 现在的版本 player_type只有3个了  STAGEFRIGHT_PLAYER NU_PLAYER TEST_PLAYER ,这里涉及一个跑分的逻辑下章分析,这里我们得到的是NU_PLAYER

    player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                               fd,
                                                               offset,
                                                               length);
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
    if (p == NULL) {
        return NO_INIT;
    }

    // now set data source
    return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
}

这里我也是简单分析了其中的一个我们一直分析的setDataSource函数(有多个),通过跑分机制拿到一个NU_PLAYER的type然后setDataSource_pre

sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
        player_type playerType)
{
    ALOGV("player type = %d", playerType);

    // create the right type of player
    //最终拿到的是一个NuPlayerDriver分析在后面
    sp<MediaPlayerBase> p = createPlayer(playerType);
    if (p == NULL) {
        return p;
    }

    std::vector<DeathNotifier> deathNotifiers;

    // Listen to death of media.extractor service
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("media.extractor"));
    if (binder == NULL) {
        ALOGE("extractor service not available");
        return NULL;
    }
    deathNotifiers.emplace_back(
            binder, [l = wp<MediaPlayerBase>(p)]() {
        sp<MediaPlayerBase> listener = l.promote();
        if (listener) {
            ALOGI("media.extractor died. Sending death notification.");
            listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
                                MEDIAEXTRACTOR_PROCESS_DEATH);
        } else {
            ALOGW("media.extractor died without a death handler.");
        }
    });

    {
        using ::android::hidl::base::V1_0::IBase;

        // Listen to death of OMX service
        {
            sp<IBase> base = ::android::hardware::media::omx::V1_0::
                    IOmx::getService();
            if (base == nullptr) {
                ALOGD("OMX service is not available");
            } else {
                deathNotifiers.emplace_back(
                        base, [l = wp<MediaPlayerBase>(p)]() {
                    sp<MediaPlayerBase> listener = l.promote();
                    if (listener) {
                        ALOGI("OMX service died. "
                              "Sending death notification.");
                        listener->sendEvent(
                                MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
                                MEDIACODEC_PROCESS_DEATH);
                    } else {
                        ALOGW("OMX service died without a death handler.");
                    }
                });
            }
        }

        // Listen to death of Codec2 services
        {
            for (std::shared_ptr<Codec2Client> const& client :
                    Codec2Client::CreateFromAllServices()) {
                sp<IBase> base = client->getBase();
                deathNotifiers.emplace_back(
                        base, [l = wp<MediaPlayerBase>(p),
                               name = std::string(client->getServiceName())]() {
                    sp<MediaPlayerBase> listener = l.promote();
                    if (listener) {
                        ALOGI("Codec2 service \"%s\" died. "
                              "Sending death notification.",
                              name.c_str());
                        listener->sendEvent(
                                MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
                                MEDIACODEC_PROCESS_DEATH);
                    } else {
                        ALOGW("Codec2 service \"%s\" died "
                              "without a death handler.",
                              name.c_str());
                    }
                });
            }
        }
    }

    Mutex::Autolock lock(mLock);

    mDeathNotifiers.clear();
    mDeathNotifiers.swap(deathNotifiers);
    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);

    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
    }

    return p;
}

代码有点长,先看createPlayer

sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
    // determine if we have the right player type
    // getPlayer()第一次为null 需要create
    sp<MediaPlayerBase> p = getPlayer();
    if ((p != NULL) && (p->playerType() != playerType)) {
        ALOGV("delete player");
        p.clear();
    }
    if (p == NULL) {
        // 
        p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
    }

    if (p != NULL) {
        p->setUID(mUid);
    }

    return p;
}

又跑到MediaPlayerFactory::createPlayer里去createPlayer,刨根问底拦不住了,继续查,

sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
        player_type playerType,
        const sp<MediaPlayerBase::Listener> &listener,
        pid_t pid) {
    sp<MediaPlayerBase> p;
    IFactory* factory;
    status_t init_result;
    Mutex::Autolock lock_(&sLock);

    if (sFactoryMap.indexOfKey(playerType) < 0) {
        ALOGE("Failed to create player object of type %d, no registered"
              " factory", playerType);
        return p;
    }
	// 这里我们知道得到的是NuplayerFactory
    factory = sFactoryMap.valueFor(playerType);
    CHECK(NULL != factory);
    //又跑到NuplayerFactory的createPlayer,最终拿到的是一个NuPlayerDriver
    p = factory->createPlayer(pid);

    if (p == NULL) {
        ALOGE("Failed to create player object of type %d, create failed",
               playerType);
        return p;
    }
	// initCheck的源码不贴了,贴出来可能会被骂,因为进去直接return ok。尴尬
    init_result = p->initCheck();
    if (init_result == NO_ERROR) {
        //listener就是我们创建client的时候new的 Listener
        p->setNotifyCallback(listener);
    } else {
        ALOGE("Failed to create player object of type %d, initCheck failed"
              " (res = %d)", playerType, init_result);
        p.clear();
    }

    return p;
}

一个createPlayer层层剥离,终于看到希望在NuPlayerFactory中终于发现最终new 了一个NuPlayerDriver

    virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
        ALOGV(" create NuPlayer");
        return new NuPlayerDriver(pid);
    }
};

整个createPlayer过程我们总结一下,从SetDataSource开始现根据跑分机制拿到playerType是NUPLAYER,根据playerType找到对应factory是NuplayerFactory然后create一个NuPlayerDriver。 回到setDataSource_pre继续,拿到NuPlayerDriver后,跳过中间无用的一些死亡代理,只剩一点逻辑

//hardwareOutput()未实现,默认return false
    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
    }

我们知道p即NuPlayerDriver,而hardwareOutput默认return false则便到了new AudioOutput中

MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
    : mCallback(NULL),
      mCallbackCookie(NULL),
      mCallbackData(NULL),
      mStreamType(AUDIO_STREAM_MUSIC),
      mLeftVolume(1.0),
      mRightVolume(1.0),
      mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
      mSampleRateHz(0),
      mMsecsPerFrame(0),
      mFrameSize(0),
      mSessionId(sessionId),
      mUid(uid),
      mPid(pid),
      mSendLevel(0.0),
      mAuxEffectId(0),
      mFlags(AUDIO_OUTPUT_FLAG_NONE),
      mVolumeHandler(new media::VolumeHandler()),
      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
      mDeviceCallbackEnabled(false),
      mDeviceCallback(deviceCallback)
{
    ALOGV("AudioOutput(%d)", sessionId);
    if (attr != NULL) {
        mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
        if (mAttributes != NULL) {
            memcpy(mAttributes, attr, sizeof(audio_attributes_t));
            mStreamType = AudioSystem::attributesToStreamType(*attr);
        }
    } else {
        mAttributes = NULL;
    }

    setMinBufferCount();
}

new AudioOutput的过程初始化了好多东西,这里就不一一说了,等到具体用到时候在具体分析,这里简单提下mAttributes,这个是我们在java层setAudioAttributes传下来的,因此setAudioAttributes一定要在setDataSource前设置这个是很多时候被忽略的错误。拿到AudioOutput之后又调用了p.get())->setAudioSink(mAudioOutput)其实AudioOutput就是一个AudioSink,这个具体后续分析,还剩最后一块setDataSource_post这里主要的逻辑是 p->setDataSource(fd, offset, length)等分析到NuPlayerDriver的时候细说。

总结

我们知道了MediaPlayerService是在mediaserver.rc中启动的,启动后通过工厂类的方式创建了NuplayerFactory和TestPlayerFactory,供我们播放使用,具体使用哪个player使根据我们setDataSource时会有个跑分机制选取的,之后我们又继续分析了SetDataSource的过程,通过java层的mediaplayer创建native层的MediaPlayer,然后在native层的setDataSource过程中,又会调用到MediaPlayerService中创建对应的client,client会最终创建NuPlayerDriver,总结一句话就是我们的setDataSource从Java到native又通过binder到service中的clent,最终到NuPlayerDriver里做codec。
(以上如有问题,欢迎大家交流指正~)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 要在Android 10.0上实现本地音乐播放,可以遵循以下步骤: 1. 准备音乐文件:在设备上准备音乐文件,可以将其放在应用的资源文件夹中或者存储在设备的特定位置。 2. 添加权限:在AndroidManifest.xml文件中添加适当的权限,以便应用可以访问设备上的音乐文件。例如,添加READ_EXTERNAL_STORAGE权限以读取外部存储器的音乐文件。 3. 创建MediaPlayer对象:在应用的活动或服务中,创建MediaPlayer对象,用于控制音乐的播放。 4. 设置数据源和准备MediaPlayer:使用MediaPlayer.setDataSource()方法将音乐文件的路径传递给MediaPlayer对象,并调用MediaPlayer.prepare()方法来准备音乐播放。 5. 控制音乐播放:使用MediaPlayer对象的方法来控制音乐的播放,如start()启动播放,pause()暂停播放,stop()停止播放等。 以下是实现本地音乐播放的示例代码: ```java import android.media.MediaPlayer; import android.os.Bundle; import android.view.View; import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; public class MainActivity extends AppCompatActivity { private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mediaPlayer = new MediaPlayer(); } public void playMusic(View view) { if (mediaPlayer.isPlaying()) { mediaPlayer.reset(); } try { mediaPlayer.setDataSource("/path/to/music/file.mp3"); mediaPlayer.prepare(); mediaPlayer.start(); } catch (IOException e) { e.printStackTrace(); } } public void pauseMusic(View view) { if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); } } public void stopMusic(View view) { if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); mediaPlayer.reset(); } } @Override protected void onDestroy() { super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } } ``` 在此示例中,我们创建了一个包含三个按钮(播放、暂停和停止)的布局。点击相应按钮时,将调用对应的方法。 注意:请将"/path/to/music/file.mp3"替换为实际的音乐文件路径。 你可以通过以下链接下载示例代码:[https://example.com/music_player.zip](https://example.com/music_player.zip) ### 回答2: 实现Android 10.0上的本地音乐播放非常简单,以下是一段示例代码,也可以在附加的源码链接中找到完整的项目代码。 首先,在AndroidManifest.xml文件中添加以下权限: ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 接下来,创建一个音乐播放器的类,并在其中定义播放音乐的方法。首先,需要获取音乐文件存储的路径,然后使用MediaPlayer类来播放音乐。以下是一个简单的示例代码: ```java import android.media.MediaPlayer; import android.net.Uri; public class MusicPlayer { private MediaPlayer mediaPlayer; public void playMusic(String filePath) { stopMusic(); mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(filePath); mediaPlayer.prepare(); mediaPlayer.start(); } catch (Exception e) { e.printStackTrace(); } } public void stopMusic() { if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } } ``` 使用上面的代码,可以在其他地方的代码中调用音乐播放器的playMusic方法,将文件路径作为参数传入,即可实现本地音乐的播放。 完整的示例项目代码可以在以下链接中下载: [链接](https://example.com) 希望可以帮助到你! ### 回答3: 要实现在Android 10.0上本地音乐播放,可以使用MediaPlayer类进行操作。以下是实现本地音乐播放的简单示例代码: 1. 在布局文件中添加一个按钮用于播放音乐: ```xml <Button android:id="@+id/btn_play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="播放音乐" /> ``` 2. 在Activity中,初始化MediaPlayer并设置音乐文件的路径: ```java public class MainActivity extends AppCompatActivity { private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mediaPlayer = new MediaPlayer(); String filePath = Environment.getExternalStorageDirectory().getPath() + "/music.mp3"; // 假设音乐文件名为music.mp3 mediaPlayer.setDataSource(filePath); mediaPlayer.prepare(); // 准备音乐文件 } } ``` 3. 在按钮的点击事件中,控制音乐的播放和暂停: ```java public class MainActivity extends AppCompatActivity { private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mediaPlayer = new MediaPlayer(); String filePath = Environment.getExternalStorageDirectory().getPath() + "/music.mp3"; // 假设音乐文件名为music.mp3 mediaPlayer.setDataSource(filePath); mediaPlayer.prepare(); // 准备音乐文件 Button btnPlay = findViewById(R.id.btn_play); btnPlay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); // 暂停音乐 } else { mediaPlayer.start(); // 播放音乐 } } }); } } ``` 这样,当按钮被点击时,如果音乐正在播放,则暂停音乐;如果音乐没有播放,则开始播放音乐。 你可以在Android开发官方网站或其他资源中下载完成的代码进行更详细的学习和实践。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轻量级LZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值