Audio Player

[中文]

1. Introduction

The Audio Player component is a lightweight audio player designed and implemented for the FreeRTOS system.

Supports playlist management, allowing you to add, delete audio files, and clear the playlist.

Supports multiple playback modes, such as: single song playback, sequential playback, single song loop, playlist loop, random playback, etc.

Supports rich playback control functions, such as: start, stop, pause, resume, previous, next, jump, etc.

Supports volume adjustment function, with a volume range of 0-100.

Supports event callback mechanism, through which you can register event callback functions to obtain player status changes, such as: song start, song finish, song failure, pause, resume, playback progress update, etc.

Supports playing audio files in the local VFS file system, and also supports playing network audio streams.

Metadata parsers, decoders, input sources, and output sinks are added by the customer through registration as needed. Built-in plugins cover common formats (e.g. MP3, WAV, AAC, OPUS, M4A, M3U8, TS) and file source, network source, HLS source, onboard speaker sink, file sink; customers may also implement and register custom plugins.

Important

  1. The Audio Player component and the Player Service component are two independent components that do not depend on each other. The Player Service component is mainly used for playing prompt sounds and does not support playing multiple types of music and playlist management.

  2. The Audio Player is adapted for the VFS file system and does not perform file system mounting and unmounting operations internally. Before playing local music files, the customer needs to mount the file system first.

2. Macro Configuration

Basic function macro configuration:

Kconfig

CPU

Format

Value

CONFIG_AUDIO_PLAYER

AP

bool

y

Memory configuration (choose one):

Kconfig

CPU

Format

Value

CONFIG_AUDIO_PLAYER_USE_SRAM

AP

bool

y/n

CONFIG_AUDIO_PLAYER_USE_PSRAM

AP

bool

y/n

Note

  1. Value meanings: y means must be enabled, y/n means choose based on actual needs.

  2. Memory configuration must choose one: use CONFIG_AUDIO_PLAYER_USE_SRAM or CONFIG_AUDIO_PLAYER_USE_PSRAM; PSRAM depends on CONFIG_PSRAM.

3. Built-in Plugins

The component provides the following built-in plugins. Customers obtain the ops table via the corresponding bk_audio_player_get_*_ops() APIs in the plugin headers and register them with bk_audio_player_register_*.

Metadata parsers (for bk_audio_player_register_metadata_parser):

Format

Get ops API

AAC

bk_audio_player_get_aac_metadata_parser_ops()

AMR

bk_audio_player_get_amr_metadata_parser_ops()

FLAC

bk_audio_player_get_flac_metadata_parser_ops()

M4A

bk_audio_player_get_m4a_metadata_parser_ops()

MP3

bk_audio_player_get_mp3_metadata_parser_ops()

OGG

bk_audio_player_get_ogg_metadata_parser_ops()

Opus

bk_audio_player_get_opus_metadata_parser_ops()

WAV

bk_audio_player_get_wav_metadata_parser_ops()

Decoders (for bk_audio_player_register_decoder):

Format

Get ops API

AAC

bk_audio_player_get_aac_decoder_ops()

AMR

bk_audio_player_get_amr_decoder_ops()

FLAC

bk_audio_player_get_flac_decoder_ops()

M4A

bk_audio_player_get_m4a_decoder_ops()

MP3

bk_audio_player_get_mp3_decoder_ops()

OGG

bk_audio_player_get_ogg_decoder_ops()

Opus

bk_audio_player_get_opus_decoder_ops()

MPEG-TS

bk_audio_player_get_ts_decoder_ops()

WAV

bk_audio_player_get_wav_decoder_ops()

Input sources (for bk_audio_player_register_source):

Type

Get ops API

Local file

bk_audio_player_get_file_source_ops()

HLS stream

bk_audio_player_get_hls_source_ops()

Network

bk_audio_player_get_net_source_ops()

Important

  1. Local file: Depends on VFS; enable CONFIG_VFS.

  2. HLS stream and Network: Depend on web client; enable CONFIG_WEBCLIENT.

Output sinks (for bk_audio_player_register_sink):

Type

Get ops API

File output

bk_audio_player_get_file_sink_ops()

Onboard speaker

bk_audio_player_get_onboard_speaker_sink_ops()

Important

  1. File output: Depends on VFS; enable CONFIG_VFS.

  2. Onboard speaker: Depends on ADK raw stream and onboard speaker stream; enable CONFIG_ADK_RAW_STREAM and CONFIG_ADK_ONBOARD_SPEAKER_STREAM.

  3. PA control must be implemented in the sink (e.g. onboard speaker sink or custom sink controlling PA enable/mute pins).

  4. The default onboard speaker sink does not enable PA control; to support PA control, the customer must modify and adapt it (this sink is based on onboard_speaker_stream; onboard_speaker_stream_cfg_t provides PA-related configuration options).

4. Usage Examples

Using the typical application scenario of playing an audio file list from an SD card as an example to illustrate the usage flow of the Audio Player component.

Initialize Audio Player

The process of initializing the Audio Player is as follows:
  1. Define an event callback function to handle player status change events.

  2. Create a player instance and pass configuration (including event callback).

  3. Register metadata parsers, decoders, input sources, and output sinks as needed (using built-in or custom implementations).

  4. Set the playback mode (optional).

  5. Set the volume (optional).

The code example is as follows:

/* 1. Define event callback function */
void player_event_handler(audio_player_event_type_t event, void *extra_info, void *args)
{
    switch (event)
    {
        case AUDIO_PLAYER_EVENT_SONG_START:
            LOGI("Song start playing\n");
            break;
        case AUDIO_PLAYER_EVENT_SONG_FINISH:
            LOGI("Song finish playing\n");
            break;
        case AUDIO_PLAYER_EVENT_SONG_FAILURE:
            LOGE("Song play failure\n");
            break;
        case AUDIO_PLAYER_EVENT_SONG_PAUSE:
            LOGI("Song paused\n");
            break;
        case AUDIO_PLAYER_EVENT_SONG_RESUME:
            LOGI("Song resumed\n");
            break;
        case AUDIO_PLAYER_EVENT_SONG_TICK:
            // Handle playback progress update
            break;
        case AUDIO_PLAYER_EVENT_SEEK_COMPLETE:
        {
            audio_player_seek_result_t *result = (audio_player_seek_result_t *)extra_info;
            if (result && result->status == AUDIO_PLAYER_OK)
            {
                LOGI("Seek success, target=%d\n", result->second);
            }
            else
            {
                LOGE("Seek failed\n");
            }
            break;
        }
        default:
            break;
    }
}

/* 2. Create player instance and get handle */
bk_audio_player_handle_t player_handle = NULL;
bk_audio_player_cfg_t cfg = DEFAULT_AUDIO_PLAYER_CONFIG();
cfg.event_handler = player_event_handler;
cfg.args = NULL;  /* User defined parameters, can be NULL */

int ret = bk_audio_player_new(&player_handle, &cfg);
if (ret != AUDIO_PLAYER_OK || player_handle == NULL)
{
    LOGE("audio player new fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* 3. Register plugins as needed: metadata parsers, decoders, sources, sinks (example: local MP3/WAV to onboard speaker) */
ret = bk_audio_player_register_metadata_parser(player_handle, bk_audio_player_get_mp3_metadata_parser_ops());
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("register mp3 metadata parser fail\n");
    return BK_FAIL;
}

ret = bk_audio_player_register_metadata_parser(player_handle, bk_audio_player_get_wav_metadata_parser_ops());
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("register wav metadata parser fail\n");
    return BK_FAIL;
}

ret = bk_audio_player_register_decoder(player_handle, bk_audio_player_get_mp3_decoder_ops());
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("register mp3 decoder fail\n");
    return BK_FAIL;
}

ret = bk_audio_player_register_decoder(player_handle, bk_audio_player_get_wav_decoder_ops());
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("register wav decoder fail\n");
    return BK_FAIL;
}

ret = bk_audio_player_register_source(player_handle, bk_audio_player_get_file_source_ops());
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("register file source fail\n");
    return BK_FAIL;
}

ret = bk_audio_player_register_sink(player_handle, bk_audio_player_get_onboard_speaker_sink_ops());
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("register onboard speaker sink fail\n");
    return BK_FAIL;
}

/* 4. Set playback mode (optional) */
ret = bk_audio_player_set_play_mode(player_handle, AUDIO_PLAYER_MODE_SEQUENCE_LOOP);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("set play mode fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* 5. Set volume (optional) */
ret = bk_audio_player_set_volume(player_handle, 80);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("set volume fail, ret=%d\n", ret);
    return BK_FAIL;
}

Note

  1. The extra_info of AUDIO_PLAYER_EVENT_SEEK_COMPLETE points to audio_player_seek_result_t whose second and status fields describe the seek result.

  2. For other events, extra_info might be NULL; always check before dereferencing.

  3. Plugin registration: the example above only registers MP3/WAV metadata parsers and decoders, file source, and onboard speaker sink; register additional plugins as needed for other formats, sources, or sinks.

Add Audio Files to Playlist

The detailed process is as follows:
  1. Call the add music interface to add audio files to the playlist.

  2. You can call the add interface multiple times to add multiple audio files.

The code example is as follows:

/* Add audio files to playlist */
ret = bk_audio_player_add_music(player_handle, "song1", "/sd0/music/song1.mp3");
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("add music fail, ret=%d\n", ret);
    return BK_FAIL;
}

ret = bk_audio_player_add_music(player_handle, "song2", "/sd0/music/song2.wav");
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("add music fail, ret=%d\n", ret);
    return BK_FAIL;
}

ret = bk_audio_player_add_music(player_handle, "song3", "/sd0/music/song3.mp3");
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("add music fail, ret=%d\n", ret);
    return BK_FAIL;
}

Note

  1. Audio file paths support VFS file system paths, such as SD card paths, Flash file system paths, etc.

  2. Audio file names are user-defined and are used to identify audio files in the playlist.

Start Playback

The detailed process is as follows:
  1. Call the start interface to start playing audio files in the playlist.

  2. The player will play according to the currently set playback mode.

The code example is as follows:

/* Start playback */
ret = bk_audio_player_start(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player start fail, ret=%d\n", ret);
    return BK_FAIL;
}

Playback Control

The player provides rich playback control functions:

The code example is as follows:

/* Pause playback */
ret = bk_audio_player_pause(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player pause fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Resume playback */
ret = bk_audio_player_resume(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player resume fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Play previous song */
ret = bk_audio_player_prev(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player prev fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Play next song */
ret = bk_audio_player_next(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player next fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Jump to specific song (e.g., jump to the 2nd song, index starts from 0) */
ret = bk_audio_player_jumpto(player_handle, 1);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player jumpto fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Seek to the 60th second of current song (local files only) */
ret = bk_audio_player_seek(player_handle, 60);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player seek fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Stop playback */
ret = bk_audio_player_stop(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("player stop fail, ret=%d\n", ret);
    return BK_FAIL;
}

Note

  1. bk_audio_player_seek only supports local audio files; network or HLS sources return errors.

  2. Seeking is asynchronous, and completion is reported via AUDIO_PLAYER_EVENT_SEEK_COMPLETE with audio_player_seek_result_t.

Playlist Management

The player supports dynamic playlist management:

The code example is as follows:

/* Delete music by name */
ret = bk_audio_player_del_music_by_name(player_handle, "song1");
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("delete music by name fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Delete music by URI */
ret = bk_audio_player_del_music_by_uri(player_handle, "/sd0/music/song2.wav");
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("delete music by uri fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Clear playlist */
ret = bk_audio_player_clear_music_list(player_handle);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("clear music list fail, ret=%d\n", ret);
    return BK_FAIL;
}

Note

  1. Deleting the currently playing song will automatically switch to the next song.

  2. Clearing the playlist will stop the current playback.

Retrieve Audio Metadata

Before playback, you can call bk_audio_player_get_metadata_from_file() to read basic fields (title, artist, bitrate, duration, etc.) from a local audio file using the instance’s registered metadata parsers.

The code example is as follows:

audio_metadata_t metadata;
memset(&metadata, 0, sizeof(metadata));

if (bk_audio_player_get_metadata_from_file(player_handle, "/sd0/music/song1.mp3", &metadata) == 0)
{
    LOGI("title=%s, artist=%s, duration=%.1fs\n",
         metadata.title, metadata.artist, metadata.duration);
}
else
{
    LOGE("parse metadata fail\n");
}

Note

  1. This API only supports local file paths (VFS); network or HTTP URIs are not supported.

  2. Return value 0 means success, while -1/-2/-3/-4 represent open failure, unsupported format, invalid parameter, and file read failure respectively.

Volume Adjustment

The player supports volume adjustment function:

The code example is as follows:

/* Set volume to 50 */
ret = bk_audio_player_set_volume(player_handle, 50);
if (ret != AUDIO_PLAYER_OK)
{
    LOGE("set volume fail, ret=%d\n", ret);
    return BK_FAIL;
}

/* Get current volume */
int volume = bk_audio_player_get_volume(player_handle);
LOGI("current volume: %d\n", volume);

Note

  1. The volume range is 0-100, where 0 means mute and 100 means maximum volume.

Deinitialize Audio Player

The process of deinitializing the Audio Player is as follows:
  1. Stop playback (if playing).

  2. Call the deinitialization interface to release player resources.

The code example is as follows:

/* 1. Stop playback (if playing) */
bk_audio_player_stop(player_handle);

/* 2. Destroy player instance */
bk_audio_player_delete(player_handle);
player_handle = NULL;