C

媒体会话控制器

演示了媒体会话 API 的使用。

"View with one active media session"

构建和部署示例

请参阅有关构建和部署 Qt for Android Automotive 示例的具体步骤

概述

此示例展示了如何使用 Qt 媒体会话 API 来控制在 Android Automotive 上的媒体会话。

媒体会话启动后,应用程序会显示一个包含所有当前活动会话的列表。列表中的每一项代表一个会话,可以通过提供的控件进行操作。

包括 API

我们需要导入两个 Android Automotive 模块:用于媒体会话 API 的 Media 和用于检查通知访问权限的 Base。

import QtAndroidAutomotive.Media
import QtAndroidAutomotive.Base

启动监听服务

为了接收有关媒体会话的数据,应用程序是一个启用通知监听。这可以通过在 AndroidManifest.xml 文件中声明由媒体会话 API 提供的通知监听器服务来实现。

        <service
            android:name="org.qtproject.qt.android.mediasession.QtMediaNotificationListener"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>

默认情况下,应用程序没有访问通知的权限。因此,如果无法访问通知,我们需要引导用户到设置应用,以便他们可以授予访问权限。

if (!hasNotificationAccess()) {
    notificationsDialog.open()
}

列出媒体会话控制器

控制器对象用于控制会话。这些控制器可以从小结MediaSessionManager::activeControllers属性中获取

ListView {
    id: sessionsList

    spacing: 10
    model: MediaSessionManager.activeControllers
    clip: true

    anchors {
        left: parent.left
        top: parent.top
        right: parent.right
        bottom: parent.bottom
        margins: 10
    }

    delegate: MediaControllerItem {}
}

在此列表中,每个控制器都由一个 MediaControllerItem QML 元素表示。

使用控制器

媒体标题和艺术家

示例使用由MediaSessionController::metaData属性返回的QMediaMetaData

Text {
    id: titleText

    width: parent.width
    elide: Text.ElideRight
    color: "#f3f3f4"
    text: root.modelData.metaData.stringValue(MediaMetaData.Title)
}

Text {
    id: artistText

    color: "#cecfd5"
    text: root.modelData.metaData.stringValue(MediaMetaData.AlbumArtist)
}
控制媒体会话

为了控制媒体,我们有一些按钮,它们使用MediaSessionController::pauseMediaSessionController::playMediaSessionController::skipToNextMediaSessionController::skipToPrevious方法。

这些控件是否有可用性由每个会话单独定义。可以使用MediaSessionController::availableActions属性检测控制功能的可用性。

MediaControlButton {
    id: prevButton

    onClicked: root.modelData.skipToPrevious()

    visible: root.modelData.availableActions &
             MediaSessionController.SkipToPreviousAction
    width: buttonRow.buttonSize
    height: buttonRow.buttonSize
    icon.source: "res/previous.png"
}

MediaControlButton {
    id: playButton

    onClicked: {
        if (playing)
            root.modelData.pause()
        else
            root.modelData.play()
    }

    readonly property bool playing: root.modelData.playbackState ===
                                    MediaSessionController.PlayingState
    visible: root.modelData.availableActions &
             (playing ?
                  MediaSessionController.PauseAction :
                  MediaSessionController.PlayAction)
    width: buttonRow.buttonSize
    height: buttonRow.buttonSize
    icon.source: {
        if (root.modelData.playbackState === MediaSessionController.PlayingState) {
            return "res/pause.png";
        } else {
            return "res/play.png";
        }
    }
}

MediaControlButton {
    id: nextButton

    onClicked: root.modelData.skipToNext()

    visible: root.modelData.availableActions &
             MediaSessionController.SkipToNextAction
    width: buttonRow.buttonSize
    height: buttonRow.buttonSize
    icon.source: "res/next.png"
}

MediaControlButton {
    id: stopButton

    onClicked: root.modelData.stop()

    visible: root.modelData.availableActions & MediaSessionController.StopAction
    width: buttonRow.buttonSize
    height: buttonRow.buttonSize
    icon.source: "res/stop.png"
}
在媒体内查找位置

在通过媒体查找的过程中,示例提供了一个使用滑动条的例子,它通过MediaSessionController::position属性读取并控制当前播放位置,并通过MediaSessionController::duration属性读取媒体的长度。

Slider {
    id: progressSlider

    onMoved: {
        // Position is set in milliseconds:
        root.modelData.position = value * 1000
    }

    width: parent.width
    from: 0
    // Duration and position are reported in milliseconds, converting to seconds
    to: (root.modelData.duration / 1000)
    value: (root.modelData.position / 1000)
    enabled: root.modelData.availableActions & MediaSessionController.PositionAction
}

为了完整地显示播放时长和位置,示例中包含两个文本元素。一个用于显示当前位置,另一个用于显示媒体的长度。这些值直接从上面实现的滑动条中读取并格式化为分钟和秒来显示。

Text {
    id: progressText

    readonly property string minutes:
        "%1".arg(parseInt(progressSlider.value / 60)).padStart(2, '0')

    readonly property string seconds:
        "%1".arg(parseInt(progressSlider.value % 60)).padStart(2, '0')

    color: "#cecfd5"
    text: "%1:%2".arg(minutes).arg(seconds)
    verticalAlignment: Text.AlignVCenter

    anchors {
        left: parent.left
        leftMargin: rootColumn.spacing
        verticalCenter: parent.verticalCenter
    }
}

Text {
    id: durationText

    readonly property string minutes:
        "%1".arg(parseInt(progressSlider.to / 60)).padStart(2, '0')
    readonly property string seconds:
        "%1".arg(parseInt(progressSlider.to % 60)).padStart(2, '0')

    color: "#cecfd5"
    text: "%1:%2".arg(minutes).arg(seconds)
    verticalAlignment: Text.AlignVCenter

    anchors {
        right: parent.right
        rightMargin: rootColumn.spacing
        verticalCenter: parent.verticalCenter
    }
}

在某些Qt许可下可用。
了解更多。