MediaPlayerLib — Media Player Library

Audio and video playback for Plan9Basic applets. The library provides two components: a non-visual Media Player for background audio, and a visual Media Control for video display. Both share similar playback APIs (load, play, pause, stop, seek, volume) and event callbacks. 58 functions.

ComponentPrefixTypeUse Case
Media Playermedia_*Non-visualBackground audio, music players, sound effects
Media Controlmedia_ctrl_*Visual (placed on form)Video playback, multimedia presentations
CategoryPlayerControlTotal
Error Handling44
Creation & Destruction224
Loading & Playback448
Properties79 + hasplayer17
Position & Size1010
Events2810
Utility1 (clear)1
Total193958

Cross-Platform Support

Plan9Basic delegates media decoding to the host operating system's native media services. This provides the best performance but means supported formats vary by platform.

PlatformBest Video FormatsBest Audio FormatsNotes
WindowsWMV, AVIWMA, MP3, WAVMP4 may work depending on codecs
LinuxDepends on system codecsMP3, OGG, WAVInstall multimedia codecs for broader support
AndroidMP4 (H.264), 3GP, WebMAAC, MP3Standard mobile codecs
ⓘ Note: Audio files can be loaded from local paths or URLs (http://, https://). Video files should use local paths — URL streaming for video has not been reliably tested.

Cross-Platform Recommendations

StrategyDescription
Use MP3 for audioWorks reliably on all platforms, supports URL streaming
Provide multiple video formatsLoad the appropriate format based on detected platform
Test on target platformsCodec support varies; always verify playback on each target

Media States

Both components use the same state values, returned by media_state() and media_ctrl_state().

ValueStateDescription
0UnavailableNo media loaded or an error occurred
1StoppedMedia is loaded but not playing
2PlayingMedia is currently playing
3PausedPlayback is paused (platform-dependent)

Error Handling

FunctionSignatureDescription
media_error()media_error@Last error code (0 = no error)
media_errormsg$()media_errormsg$@Last error message as string
media_strerror$(code)media_strerror$@nDescription for a given error code
media_clearerror()media_clearerror@Clear the error state
CodeErrorDescription
0ERR_NONENo error
1ERR_INVALID_PLAYERInvalid media player pointer
2ERR_INVALID_CONTROLInvalid media control pointer
3ERR_INVALID_PARENTInvalid parent for control
4ERR_INVALID_VALUEInvalid parameter value
5ERR_CREATE_FAILEDFailed to create component
6ERR_LOAD_FAILEDFailed to load media file
7ERR_FILE_NOT_FOUNDMedia file not found
8ERR_NOT_LOADEDNo media is loaded
9ERR_INVALID_CALLBACKInvalid callback function
ⓘ Note: Some operations may report errors even when they succeed. The most reliable way to verify media loaded correctly is to start playback and monitor state via OnStateChanged.

Media Player (Audio)

A non-visual component for background audio playback. Does not require a form — works entirely in the background.

Creation & Destruction

FunctionSignatureDescription
media_player#()media_player#@Create a new media player (returns pointer)
media_free(player#)media_free@#Destroy media player and release resources

Loading & Playback

FunctionSignatureDescription
media_load#(player#, file$)media_load#@#$Load media file (local path or URL)
media_play(player#)media_play@#Start or resume playback
media_pause(player#)media_pause@#Pause playback
media_stop(player#)media_stop@#Stop playback and reset position to beginning
media_clear(player#)media_clear@#Clear the loaded media

Properties

FunctionSignatureDescription
media_state(player#)media_state@#Current state (0=unavailable, 1=stopped, 2=playing, 3=paused)
media_volume(player#)media_volume@#Get volume (0.0–1.0)
media_volume#(player#, vol)media_volume#@#nSet volume
media_duration(player#)media_duration@#Total duration in seconds
media_position(player#)media_position@#Current playback position in seconds
media_position#(player#, secs)media_position#@#nSeek to position in seconds
media_filename$(player#)media_filename$@#Get the loaded filename/URL
media_isplaying(player#)media_isplaying@#Returns 1 if playing, 0 otherwise

Events

Event SetterCallback SignatureWhen It Fires
media_onend#(player#, func$)function name(sender#)When playback reaches the end
media_onstatechanged#(player#, func$)function name(sender#, state)When state changes (0/1/2/3)
╯ audioplayer.bas
' Complete audio player example
let player# = media_player#()
media_load#(player#, "https://www.w3schools.com/html/horse.mp3")
media_volume#(player#, 0.7)
media_onend#(player#, "OnEnd")
media_onstatechanged#(player#, "OnState")
media_play(player#)

function OnEnd(sender#)
    println "Playback finished!"
endfunction

function OnState(sender#, state)
    if state = 2 then println "Playing"
    if state = 1 then println "Stopped"
endfunction

Media Control (Video)

A visual component that displays video content within a form. Supports both audio and video playback with a visible rendering surface.

Creation & Destruction

FunctionSignatureDescription
media_control#(parent#, x, y, w, h)media_ctrl_control#@#nnnnCreate media control with position and size
media_ctrl_free(ctrl#)media_ctrl_free@#Destroy media control

Loading & Playback

FunctionSignatureDescription
media_ctrl_load#(ctrl#, file$)media_ctrl_load#@#$Load media file (local path recommended)
media_ctrl_play(ctrl#)media_ctrl_play@#Start or resume playback
media_ctrl_pause(ctrl#)media_ctrl_pause@#Pause playback
media_ctrl_stop(ctrl#)media_ctrl_stop@#Stop playback and reset to beginning
media_ctrl_clear(ctrl#)media_ctrl_clear@#Clear loaded media

Playback Properties

FunctionSignatureDescription
media_ctrl_state(ctrl#)media_ctrl_state@#Current state (0–3)
media_ctrl_volume(ctrl#)media_ctrl_volume@#Get volume (0.0–1.0)
media_ctrl_volume#(ctrl#, vol)media_ctrl_volume#@#nSet volume
media_ctrl_duration(ctrl#)media_ctrl_duration@#Total duration in seconds
media_ctrl_position(ctrl#)media_ctrl_position@#Current position in seconds
media_ctrl_position#(ctrl#, secs)media_ctrl_position#@#nSeek to position in seconds
media_ctrl_filename$(ctrl#)media_ctrl_filename$@#Get loaded filename
media_ctrl_isplaying(ctrl#)media_ctrl_isplaying@#Returns 1 if playing, 0 otherwise
media_ctrl_hasplayer(ctrl#)media_ctrl_hasplayer@#Returns 1 if an internal player is available

Position & Size

FunctionSignatureDescription
media_ctrl_x(ctrl#)media_ctrl_x@#Get X position
media_ctrl_y(ctrl#)media_ctrl_y@#Get Y position
media_ctrl_width(ctrl#)media_ctrl_width@#Get width
media_ctrl_height(ctrl#)media_ctrl_height@#Get height
media_ctrl_pos#(ctrl#, x, y)media_ctrl_pos#@#nnSet position
media_ctrl_size#(ctrl#, w, h)media_ctrl_size#@#nnSet size
media_ctrl_bounds#(ctrl#, x, y, w, h)media_ctrl_bounds#@#nnnnSet position and size in one call
media_ctrl_visible(ctrl#)media_ctrl_visible@#Get visibility (0/1)
media_ctrl_visible#(ctrl#, n)media_ctrl_visible#@#nSet visibility
media_ctrl_enabled(ctrl#)media_ctrl_enabled@#Get enabled state (0/1)
media_ctrl_enabled#(ctrl#, n)media_ctrl_enabled#@#nSet enabled state
media_ctrl_align(ctrl#)media_ctrl_align@#Get alignment
media_ctrl_align#(ctrl#, n)media_ctrl_align#@#nSet alignment (0=None, 1=Top, 2=Left, 3=Right, 4=Bottom, 9=Client, 11=Center)

Events

Event SetterCallback SignatureWhen It Fires
media_ctrl_onend#(ctrl#, func$)function name(sender#)When playback reaches the end
media_ctrl_onstatechanged#(ctrl#, func$)function name(sender#, state)When state changes (0/1/2/3)
media_ctrl_onclick#(ctrl#, func$)function name(sender#)When the control is clicked
media_ctrl_ondblclick#(ctrl#, func$)function name(sender#)When double-clicked
media_ctrl_onmousedown#(ctrl#, func$)function name(sender#, button, x, y)Mouse button pressed
media_ctrl_onmouseup#(ctrl#, func$)function name(sender#, button, x, y)Mouse button released
media_ctrl_onmousemove#(ctrl#, func$)function name(sender#, x, y)Mouse moved over control
media_ctrl_onresize#(ctrl#, func$)function name(sender#)When the control is resized

Media Player vs Media Control

FeatureMedia Player (media_*)Media Control (media_ctrl_*)
TypeNon-visual (no form needed)Visual (placed on a form)
Video Display❌ No✅ Yes
Audio Playback✅ Yes✅ Yes
URL Loading✅ Tested with audio URLs❌ Local files recommended
Position/SizeN/AFull position/size/alignment API
Mouse EventsN/AClick, double-click, mouse down/up/move, resize
Best ForBackground music, sound effects, audio-onlyVideo playback, multimedia presentations

Complete Examples

Music Player with Playlist

╯ playlist.bas
dim playlist$(5)
let currentTrack = 0

playlist$(0) = "track1.mp3"
playlist$(1) = "track2.mp3"
playlist$(2) = "track3.mp3"
playlist$(3) = "track4.mp3"
playlist$(4) = "track5.mp3"

function PlayNextTrack(sender#)
    currentTrack = currentTrack + 1
    if currentTrack >= 5 then currentTrack = 0
    media_load#(player#, playlist$(currentTrack))
    media_play(player#)
    label_text#(lblTrack#, "Track " + str$(currentTrack + 1) + ": " + playlist$(currentTrack))
endfunction

function OnPlay(sender#)
    media_load#(player#, playlist$(currentTrack))
    media_play(player#)
    label_text#(lblTrack#, "Track " + str$(currentTrack + 1) + ": " + playlist$(currentTrack))
endfunction

function OnStop(sender#)
    media_stop(player#)
endfunction

function OnNext(sender#)
    PlayNextTrack(player#)
endfunction

function OnPrev(sender#)
    currentTrack = currentTrack - 1
    if currentTrack < 0 then currentTrack = 4
    media_load#(player#, playlist$(currentTrack))
    media_play(player#)
    label_text#(lblTrack#, "Track " + str$(currentTrack + 1) + ": " + playlist$(currentTrack))
endfunction

let frm# = form#("Music Player", 400, 150)
form_position#(frm#, 4)

let lblTrack# = label#(frm#, "Ready")
label_bounds#(lblTrack#, 10, 10, 380, 30)

button_onclick#(button#(frm#, "Prev", 10, 50, 80, 30), "OnPrev")
button_onclick#(button#(frm#, "Play", 100, 50, 80, 30), "OnPlay")
button_onclick#(button#(frm#, "Next", 190, 50, 80, 30), "OnNext")
button_onclick#(button#(frm#, "Stop", 280, 50, 80, 30), "OnStop")

let player# = media_player#()
media_volume#(player#, 0.7)
media_onend#(player#, "PlayNextTrack")

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Video Player with Controls

╯ videoplayer.bas
function OnPlay(sender#)
    media_ctrl_play(video#)
endfunction

function OnPause(sender#)
    media_ctrl_pause(video#)
endfunction

function OnStop(sender#)
    media_ctrl_stop(video#)
    trackbar_value#(trkPos#, 0)
endfunction

function OnVolumeChange(sender#) local vol
    vol = trackbar_value(trkVol#) / 100
    media_ctrl_volume#(video#, vol)
endfunction

function OnPositionChange(sender#) local dur, pos, t
    dur = media_ctrl_duration(video#)
    pos = trackbar_value(trkPos#)
    t = (pos / 1000) * dur
    media_ctrl_position#(video#, t)
endfunction

function OnUpdateUI(sender#) local pos, dur, pct, pm, ps, dm, ds, s$
    pos = media_ctrl_position(video#)
    dur = media_ctrl_duration(video#)
    if dur > 0 then
        pct = (pos / dur) * 1000
        trackbar_value#(trkPos#, int(pct))
        pm = int(pos / 60) : ps = int(pos) mod 60
        dm = int(dur / 60) : ds = int(dur) mod 60
        s$ = str$(pm) + ":" + right$("0" + str$(ps), 2)
        s$ = s$ + " / " + str$(dm) + ":" + right$("0" + str$(ds), 2)
        label_text#(lblStatus#, s$)
    endif
endfunction

function OnVideoEnd(sender#)
    label_text#(lblStatus#, "Playback completed")
    trackbar_value#(trkPos#, 0)
endfunction

let frm# = form#("Video Player", 800, 650)
form_position#(frm#, 4)

let video# = media_control#(frm#, 10, 10, 780, 480)

button_onclick#(button#(frm#, "Play", 10, 500, 80, 30), "OnPlay")
button_onclick#(button#(frm#, "Pause", 100, 500, 80, 30), "OnPause")
button_onclick#(button#(frm#, "Stop", 190, 500, 80, 30), "OnStop")

label#(frm#, "Volume:", 300, 505)
let trkVol# = trackbar#(frm#, 360, 500, 150, 30)
trackbar_max#(trkVol#, 100)
trackbar_value#(trkVol#, 80)
trackbar_onchange#(trkVol#, "OnVolumeChange")

let lblStatus# = label#(frm#, "Ready")
label_bounds#(lblStatus#, 10, 540, 780, 25)

let trkPos# = trackbar#(frm#, 10, 570, 780, 30)
trackbar_max#(trkPos#, 1000)
trackbar_onchange#(trkPos#, "OnPositionChange")

media_ctrl_onend#(video#, "OnVideoEnd")
media_ctrl_load#(video#, "movie.wmv")
media_ctrl_volume#(video#, 0.8)

let tmr# = timer#()
timer_interval#(tmr#, 250)
timer_ontimer#(tmr#, "OnUpdateUI")
timer_start#(tmr#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Audio Progress with Timer

╯ progress.bas
function UpdateProgress(sender#) local pos, dur, pct, bar$, i
    pos = media_position(player#)
    dur = media_duration(player#)
    pct = 0
    if dur > 0 then pct = int((pos / dur) * 100)
    bar$ = "["
    for i = 1 to 20
        if i <= pct / 5 then
            bar$ = bar$ + "="
        else
            bar$ = bar$ + " "
        endif
    next
    bar$ = bar$ + "] " + str$(pct) + "%"
    label_text#(lblProgress#, bar$)
endfunction

function OnSongEnd(sender#)
    timer_stop#(tmr#)
    label_text#(lblProgress#, "Playback complete!")
endfunction

function OnStopClick(sender#)
    timer_stop#(tmr#)
    media_stop(player#)
    form_close(frm#)
endfunction

let frm# = form#("Now Playing", 400, 100)
form_position#(frm#, 4)

let lblProgress# = label#(frm#, "Loading...")
label_bounds#(lblProgress#, 10, 10, 380, 30)
label_fontfamily#(lblProgress#, "Consolas")

button_onclick#(button#(frm#, "Stop", 160, 50, 80, 30), "OnStopClick")

let player# = media_player#()
media_load#(player#, "https://www.w3schools.com/html/horse.mp3")
media_onend#(player#, "OnSongEnd")
media_play(player#)

let tmr# = timer#()
timer_interval#(tmr#, 500)
timer_ontimer#(tmr#, "UpdateProgress")
timer_start#(tmr#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Fullscreen Video

╯ fullscreen.bas
function OnDoubleClick(sender#)
    if form_windowstate(frm#) = 2 then
        form_windowstate#(frm#, 0)
        form_borderstyle#(frm#, 1)
    else
        form_windowstate#(frm#, 2)
        form_borderstyle#(frm#, 0)
    endif
endfunction

function OnVideoEnd(sender#)
    form_close(frm#)
endfunction

let frm# = form#("", 1024, 768)
form_windowstate#(frm#, 2)
form_borderstyle#(frm#, 0)

let video# = media_control#(frm#, 0, 0, 100, 100)
media_ctrl_align#(video#, 9)  ' Client - fills entire form

media_ctrl_load#(video#, "movie.wmv")
media_ctrl_ondblclick#(video#, "OnDoubleClick")
media_ctrl_onend#(video#, "OnVideoEnd")
media_ctrl_play(video#)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Troubleshooting

ProblemLikely CauseSolution
“Unsupported media file”OS cannot decode the formatUse platform-appropriate format (WMV for Windows, MOV/MP4 for macOS/iOS, MP4 for Android)
Video loads but doesn't displayControl not visible or zero-sizedEnsure non-zero width/height, control is parented to a visible form
State remains 0 after loadingState changes asynchronouslyUse OnStateChanged callback; state changes to 1 or 2 after calling play
No audio on video playbackVolume too low or no audio trackCheck media_ctrl_volume#(ctrl#, 1.0); verify file has an audio track
URL streaming not workingServer blocking non-browser requestsVerify URL is accessible; use HTTPS; some servers block programmatic access
Playback stutters on mobileFile too large or high bitrateUse lower bitrate, smaller resolution, or pre-download files

Best Practices

PracticeWhy
Use OnStateChanged to verify playbackMore reliable than checking error codes after load
Use MP3 for cross-platform audioWorks reliably on all platforms, supports URL streaming
Use a Timer for UI position updatesDon't poll in a loop; use timer_interval#(tmr#, 250) for 4×/second updates
Set OnEnd for playlist behaviorAutomatically advance to next track when playback finishes
Use media_ctrl_align#(ctrl#, 9) for fullscreen videoClient alignment fills the entire parent container
Clean up with media_stop + media_freeAlways stop playback before freeing to release resources
Initialize pointers with Pointer#(0)Good practice for all pointer variables
Start volume at 0.7Safer than full volume; let the user adjust
⚠ Warning: Always call media_stop(player#) before media_free(player#). Freeing a player during active playback may cause issues on some platforms.

Quick Reference

Media Player (Audio) — 19 functions

FunctionSignatureDescription
media_error / media_errormsg$ / media_strerror$ / media_clearerrorvariousError handling (4)
media_player#()media_player#@Create audio player
media_free(player#)media_free@#Destroy player
media_load# / play / pause / stop / clearvariousPlayback (5)
media_state / volume / duration / position / filename$ / isplayingvariousProperties get (6)
media_volume# / media_position#variousProperties set (2)
media_onend# / media_onstatechanged#variousEvents (2)

Media Control (Video) — 39 functions

FunctionSignatureDescription
media_control#(parent#, x, y, w, h)media_ctrl_control#@#nnnnCreate video control
media_ctrl_free(ctrl#)media_ctrl_free@#Destroy control
media_ctrl_load# / play / pause / stop / clearvariousPlayback (5)
media_ctrl_state / volume / duration / position / filename$ / isplaying / hasplayervariousProperties get (7)
media_ctrl_volume# / media_ctrl_position#variousProperties set (2)
media_ctrl_x / y / width / height / pos# / size# / bounds# / visible / enabled / alignvariousPosition & visual (13)
media_ctrl_onend# / onstatechanged# / onclick# / ondblclick# / onmousedown# / onmouseup# / onmousemove# / onresize#variousEvents (8)

58 functions total. Part of the Plan9Basic GUI library system.