Media file server
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#lang racket/base
|
||||
|
||||
(require racket-upnp)
|
||||
|
||||
(define files
|
||||
(start-media-file-server
|
||||
"http://10.7.3.118:8080/media/"
|
||||
#:listen-ip "10.7.3.118"))
|
||||
|
||||
(define current-uri
|
||||
(media-file-server-publish!
|
||||
files
|
||||
"C:/muziek/current.flac"
|
||||
"current.flac"))
|
||||
|
||||
(define next-uri
|
||||
(media-file-server-publish!
|
||||
files
|
||||
"C:/muziek/next.flac"
|
||||
"next.flac"))
|
||||
|
||||
(define renderer
|
||||
(get-media-renderer "Denon"))
|
||||
|
||||
(when renderer
|
||||
(media-renderer-play-uri!
|
||||
renderer
|
||||
current-uri
|
||||
#:next-uri next-uri))
|
||||
|
||||
;; Call this after playback no longer needs the URLs:
|
||||
;;
|
||||
;; (media-file-server-unpublish! files current-uri)
|
||||
;; (media-file-server-unpublish! files next-uri)
|
||||
;; (media-file-server-stop! files)
|
||||
@@ -1,23 +1,17 @@
|
||||
#lang racket/base
|
||||
|
||||
;; Main public interface for racket-upnp.
|
||||
;;
|
||||
;; This module provides:
|
||||
;; - generic UPnP device discovery and service inspection;
|
||||
;; - the high-level media-renderer interface;
|
||||
;; - the high-level media-server browser interface.
|
||||
;;
|
||||
;; Service-specific interfaces remain available through:
|
||||
;; racket-upnp/services/<service>
|
||||
|
||||
(require "query.rkt"
|
||||
"service.rkt"
|
||||
"media-renderer.rkt"
|
||||
"media-server.rkt")
|
||||
"media-server.rkt"
|
||||
"media-file-server.rkt")
|
||||
|
||||
(provide
|
||||
(all-from-out
|
||||
"query.rkt"
|
||||
"service.rkt"
|
||||
"media-renderer.rkt"
|
||||
"media-server.rkt"))
|
||||
"media-server.rkt"
|
||||
"media-file-server.rkt"))
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#lang scribble/manual
|
||||
|
||||
@(require
|
||||
(for-label
|
||||
racket/base
|
||||
(file "../media-file-server.rkt")))
|
||||
|
||||
@title{Publishing Media Files}
|
||||
|
||||
@defmodule[(file "../media-file-server.rkt")]
|
||||
|
||||
This module publishes local files through a small Racket web server. The
|
||||
underlying Racket file dispatcher streams files and supports both @tt{HEAD}
|
||||
requests and HTTP byte ranges. Byte ranges are important for media-renderer
|
||||
probing and seeking.
|
||||
|
||||
@defproc[(start-media-file-server
|
||||
[url string?]
|
||||
[#:listen-ip listen-ip (or/c #f string?) #f])
|
||||
media-file-server?]{
|
||||
|
||||
Starts a server for the HTTP origin and path prefix in @racket[url].
|
||||
The URL must be an absolute @tt{http://} URL. A trailing slash is added when
|
||||
needed.
|
||||
|
||||
When @racket[listen-ip] is @racket[#f], the server listens on all local
|
||||
interfaces. Supply a local address, such as @tt{10.7.3.118}, to restrict the
|
||||
listener to that interface.
|
||||
}
|
||||
|
||||
@defproc[(media-file-server-url
|
||||
[server media-file-server?])
|
||||
string?]{
|
||||
|
||||
Returns the normalized base URL of @racket[server].
|
||||
}
|
||||
|
||||
@defproc[(media-file-server-publish!
|
||||
[server media-file-server?]
|
||||
[file path-string?]
|
||||
[url string?]
|
||||
[#:mime-type mime-type (or/c #f bytes? string?) #f])
|
||||
string?]{
|
||||
|
||||
Publishes @racket[file] at @racket[url] and returns the absolute URL.
|
||||
|
||||
The URL may be relative to the server URL:
|
||||
|
||||
@racketblock[
|
||||
(define uri
|
||||
(media-file-server-publish!
|
||||
files
|
||||
"C:/muziek/test.flac"
|
||||
"test.flac"))
|
||||
]
|
||||
|
||||
It may also be the complete URL, provided that its origin and path prefix match
|
||||
the server:
|
||||
|
||||
@racketblock[
|
||||
(media-file-server-publish!
|
||||
files
|
||||
"C:/muziek/test.flac"
|
||||
"http://10.7.3.118:8080/media/test.flac")
|
||||
]
|
||||
|
||||
The MIME type is inferred for common audio, video, and image extensions.
|
||||
Use @racket[#:mime-type] to override it.
|
||||
}
|
||||
|
||||
@defproc[(media-file-server-unpublish!
|
||||
[server media-file-server?]
|
||||
[url string?])
|
||||
void?]{
|
||||
|
||||
Removes the URL mapping. Requests that are already in progress may still
|
||||
finish.
|
||||
}
|
||||
|
||||
@defproc[(media-file-server-stop!
|
||||
[server media-file-server?])
|
||||
void?]{
|
||||
|
||||
Stops the web server. Repeated calls have no effect.
|
||||
}
|
||||
|
||||
@section{Playing local files}
|
||||
|
||||
@racketblock[
|
||||
(define files
|
||||
(start-media-file-server
|
||||
"http://10.7.3.118:8080/media/"
|
||||
#:listen-ip "10.7.3.118"))
|
||||
|
||||
(define first-uri
|
||||
(media-file-server-publish!
|
||||
files
|
||||
"C:/muziek/first.flac"
|
||||
"first.flac"))
|
||||
|
||||
(define second-uri
|
||||
(media-file-server-publish!
|
||||
files
|
||||
"C:/muziek/second.flac"
|
||||
"second.flac"))
|
||||
|
||||
(media-renderer-play-uri!
|
||||
renderer
|
||||
first-uri
|
||||
#:next-uri second-uri)
|
||||
]
|
||||
|
||||
Keep the URLs published until the renderer has finished reading them.
|
||||
@@ -1,51 +1,114 @@
|
||||
#lang scribble/manual
|
||||
|
||||
@(require (for-label racket/base
|
||||
racket/contract
|
||||
(file "../main.rkt")
|
||||
(file "../media-renderer.rkt")
|
||||
(file "../services/av-transport.rkt")))
|
||||
@(require
|
||||
(for-label
|
||||
racket/base
|
||||
(file "../media-renderer.rkt")))
|
||||
|
||||
@title{Media Renderer}
|
||||
@title{Media Renderers}
|
||||
|
||||
@defmodule[@racketmodname[racket-upnp/media-renderer] #:module-paths ((file "../media-renderer.rkt"))]
|
||||
@defmodule[(file "../media-renderer.rkt")]
|
||||
|
||||
This module hides AVTransport and RenderingControl for common playback code.
|
||||
The returned renderer remains an @racket[upnp-device?], so generic service
|
||||
inspection is still available.
|
||||
This module provides a device-oriented interface for UPnP and DLNA media
|
||||
renderers. It hides the AVTransport and RenderingControl services used for
|
||||
common playback and volume operations.
|
||||
|
||||
@defproc[(query-media-renderers [#:interface interface (or/c #f string?) #f]
|
||||
@defproc[(query-media-renderers
|
||||
[#:interface interface (or/c #f string?) #f]
|
||||
[#:dns? dns? boolean? #f]
|
||||
[#:dlna-only? dlna-only? boolean? #f])
|
||||
(listof upnp-device?)]{
|
||||
Discovers UPnP MediaRenderers. When @racket[dlna-only?] is true, only devices
|
||||
advertising an @tt{X_DLNADOC} value are returned.
|
||||
(listof media-renderer?)]{
|
||||
|
||||
Discovers media renderers. When @racket[dlna-only?] is true, only devices that
|
||||
advertise a DLNA document identifier are returned.
|
||||
}
|
||||
|
||||
@defproc[(media-renderer? [value any/c]) boolean?]{Recognises a MediaRenderer device.}
|
||||
@defproc[(media-renderer-dlna? [renderer media-renderer?]) boolean?]{Reports whether the device description advertises a DLNA document identifier.}
|
||||
@defproc[(media-renderer-play-uri! [renderer media-renderer?]
|
||||
@defproc[(get-media-renderer [filter-name string?])
|
||||
(or/c #f media-renderer?)]{
|
||||
|
||||
Returns the first discovered renderer whose name contains
|
||||
@racket[filter-name], ignoring case, or @racket[#f] when no renderer matches.
|
||||
}
|
||||
|
||||
@defproc[(media-renderer? [value any/c]) boolean?]
|
||||
@defproc[(media-renderer-name [renderer media-renderer?]) string?]
|
||||
@defproc[(media-renderer-address [renderer media-renderer?]) string?]
|
||||
@defproc[(media-renderer-manufacturer [renderer media-renderer?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-renderer-model [renderer media-renderer?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-renderer-dlna? [renderer media-renderer?]) boolean?]
|
||||
|
||||
@section{Playback}
|
||||
|
||||
@defproc[(media-renderer-play-uri!
|
||||
[renderer media-renderer?]
|
||||
[uri string?]
|
||||
[#:metadata metadata string? ""]) void?]{Sets the URI and starts playback.}
|
||||
@defproc[(media-renderer-pause! [renderer media-renderer?]) void?]{Pauses playback.}
|
||||
@defproc[(media-renderer-stop! [renderer media-renderer?]) void?]{Stops playback.}
|
||||
@defproc[(media-renderer-seek! [renderer media-renderer?] [seconds nonnegative-real?]) void?]{Seeks to a relative time.}
|
||||
@defproc[(media-renderer-status [renderer media-renderer?]) symbol?]{Returns the abstracted transport state.}
|
||||
@defproc[(media-renderer-position [renderer media-renderer?]) transport-position?]{Returns current position information.}
|
||||
@defproc[(media-renderer-volume [renderer media-renderer?]) (or/c #f exact-integer?)]{Returns the device-specific volume value.}
|
||||
@defproc[(media-renderer-set-volume! [renderer media-renderer?] [volume (integer-in 0 65535)]) void?]{Sets the device-specific volume value.}
|
||||
@defproc[(media-renderer-muted? [renderer media-renderer?]) boolean?]{Returns the mute state.}
|
||||
@defproc[(media-renderer-set-muted! [renderer media-renderer?] [muted? boolean?]) void?]{Sets the mute state.}
|
||||
[#:metadata metadata string? ""]
|
||||
[#:next-uri next-uri (or/c #f string?) #f]
|
||||
[#:next-metadata next-metadata string? ""])
|
||||
any]{
|
||||
|
||||
@section[#:tag "media-renderer-example"]{Example}
|
||||
Sets @racket[uri] as the current resource and starts playback.
|
||||
|
||||
@racketblock[
|
||||
(define renderer
|
||||
(car (query-media-renderers #:interface "10.7.3.118")))
|
||||
When @racket[next-uri] is supplied, it is installed with
|
||||
@tt{SetNextAVTransportURI} before playback starts. A supporting renderer can
|
||||
open and buffer the next resource while the current resource is playing,
|
||||
allowing a gapless or near-gapless transition.
|
||||
}
|
||||
|
||||
(media-renderer-play-uri!
|
||||
renderer
|
||||
"http://10.7.3.32:50002/music/track.flac")
|
||||
@defproc[(media-renderer-next-uri-supported?
|
||||
[renderer media-renderer?])
|
||||
boolean?]{
|
||||
|
||||
(media-renderer-set-volume! renderer 30)
|
||||
]
|
||||
Reports whether the renderer advertises the optional
|
||||
@tt{SetNextAVTransportURI} action.
|
||||
}
|
||||
|
||||
@defproc[(media-renderer-set-next-uri!
|
||||
[renderer media-renderer?]
|
||||
[uri string?]
|
||||
[#:metadata metadata string? ""])
|
||||
any]{
|
||||
|
||||
Sets the resource that follows the currently playing resource. The action
|
||||
describes one next resource, not a complete queue. After playback advances to
|
||||
that resource, call this function again to preload the following track.
|
||||
}
|
||||
|
||||
@defproc[(media-renderer-pause! [renderer media-renderer?]) any]
|
||||
@defproc[(media-renderer-stop! [renderer media-renderer?]) any]
|
||||
@defproc[(media-renderer-seek!
|
||||
[renderer media-renderer?]
|
||||
[seconds exact-nonnegative-integer?])
|
||||
any]
|
||||
@defproc[(media-renderer-status [renderer media-renderer?]) symbol?]
|
||||
@defproc[(media-renderer-position [renderer media-renderer?])
|
||||
transport-position?]
|
||||
|
||||
@defproc[(transport-position-track
|
||||
[position transport-position?])
|
||||
exact-nonnegative-integer?]
|
||||
@defproc[(transport-position-seconds
|
||||
[position transport-position?])
|
||||
(or/c #f number?)]
|
||||
@defproc[(transport-position-duration
|
||||
[position transport-position?])
|
||||
(or/c #f number?)]
|
||||
@defproc[(transport-position-uri
|
||||
[position transport-position?])
|
||||
(or/c #f string?)]
|
||||
|
||||
@section{Volume and mute}
|
||||
|
||||
@defproc[(media-renderer-volume [renderer media-renderer?])
|
||||
exact-nonnegative-integer?]
|
||||
@defproc[(media-renderer-set-volume!
|
||||
[renderer media-renderer?]
|
||||
[volume exact-nonnegative-integer?])
|
||||
any]
|
||||
@defproc[(media-renderer-muted? [renderer media-renderer?]) boolean?]
|
||||
@defproc[(media-renderer-set-muted!
|
||||
[renderer media-renderer?]
|
||||
[muted? boolean?])
|
||||
any]
|
||||
|
||||
@@ -1,114 +1,120 @@
|
||||
#lang scribble/manual
|
||||
|
||||
@(require (for-label racket/base
|
||||
racket/contract
|
||||
racket/list
|
||||
(file "../main.rkt")
|
||||
@(require
|
||||
(for-label
|
||||
racket/base
|
||||
(file "../media-server.rkt")))
|
||||
|
||||
@title{Media Server Browser}
|
||||
@title{Media Servers}
|
||||
|
||||
@defmodule[@racketmodname[racket-upnp/media-server] #:module-paths ((file "../media-server.rkt"))]
|
||||
@defmodule[(file "../media-server.rkt")]
|
||||
|
||||
This module turns the DIDL-Lite returned by
|
||||
@racketmodname[racket-upnp/services/content-directory] into ordinary Racket
|
||||
values. Containers are browsed one level at a time; the module does not
|
||||
recursively load an entire media library. This is suitable for a browser that
|
||||
requests children when the user expands a container.
|
||||
This module provides a higher-level browser for UPnP and DLNA media servers.
|
||||
It converts ContentDirectory DIDL-Lite XML into containers, items, and media
|
||||
resources.
|
||||
|
||||
The hierarchy is the logical hierarchy published by the media server. A server
|
||||
may offer views such as artist, album, genre, and physical folder, so a track
|
||||
can occur in more than one container.
|
||||
@defproc[(query-media-servers
|
||||
[#:interface interface (or/c #f string?) #f]
|
||||
[#:dns? dns? boolean? #f])
|
||||
(listof media-server?)]{
|
||||
|
||||
Discovers media servers.
|
||||
}
|
||||
|
||||
@defproc[(get-media-server [filter-name string?])
|
||||
(or/c #f media-server?)]{
|
||||
|
||||
Returns the first discovered media server whose name contains
|
||||
@racket[filter-name], ignoring case, or @racket[#f].
|
||||
}
|
||||
|
||||
@defproc[(media-server? [value any/c]) boolean?]
|
||||
@defproc[(media-server-name [server media-server?]) string?]
|
||||
@defproc[(media-server-address [server media-server?]) string?]
|
||||
@defproc[(media-server-manufacturer [server media-server?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-server-model [server media-server?])
|
||||
(or/c #f string?)]
|
||||
|
||||
@section{Browsing}
|
||||
|
||||
@defproc[(query-media-servers [#:interface interface (or/c #f string?) #f]
|
||||
[#:dns? dns? boolean? #f])
|
||||
(listof media-server?)]{
|
||||
Discovers UPnP MediaServer devices that provide a ContentDirectory service.
|
||||
}
|
||||
|
||||
@defproc[(media-server? [value any/c]) boolean?]{
|
||||
Recognises a MediaServer device with a ContentDirectory service.
|
||||
}
|
||||
|
||||
@defproc[(media-server-root [server media-server?]
|
||||
@defproc[(media-server-root
|
||||
[server media-server?]
|
||||
[#:start start exact-nonnegative-integer? 0]
|
||||
[#:count count exact-nonnegative-integer? 0])
|
||||
(listof media-entry?)]{
|
||||
Returns the direct children of ContentDirectory object @tt{0}. The optional
|
||||
paging arguments are passed to ContentDirectory. A count of zero asks the
|
||||
server to return all available children, subject to the server's own limits.
|
||||
|
||||
Browses object @tt{0}, the ContentDirectory root.
|
||||
}
|
||||
|
||||
@defproc[(media-server-browse [server media-server?]
|
||||
@defproc[(media-server-browse
|
||||
[server media-server?]
|
||||
[container (or/c string? media-container?) "0"]
|
||||
[#:start start exact-nonnegative-integer? 0]
|
||||
[#:count count exact-nonnegative-integer? 0])
|
||||
(listof media-entry?)]{
|
||||
Returns the direct children of an object identifier or previously returned
|
||||
container.
|
||||
|
||||
Browses one level below a container ID or a previously returned container.
|
||||
|
||||
In ContentDirectory, @racket[count] equal to zero asks the server to return all
|
||||
remaining entries. Use a positive count for large containers.
|
||||
}
|
||||
|
||||
@defproc[(media-container-children [server media-server?]
|
||||
@defproc[(media-container-children
|
||||
[server media-server?]
|
||||
[container media-container?]
|
||||
[#:start start exact-nonnegative-integer? 0]
|
||||
[#:count count exact-nonnegative-integer? 0])
|
||||
(listof media-entry?)]{
|
||||
Convenience form of @racket[media-server-browse] for a container value.
|
||||
|
||||
Equivalent to browsing the supplied container.
|
||||
}
|
||||
|
||||
@section{Entries}
|
||||
|
||||
@defproc[(media-entry? [value any/c]) boolean?]{Recognises a media container or media item.}
|
||||
@defproc[(media-entry-id [entry media-entry?]) (or/c #f string?)]{Returns the ContentDirectory object identifier.}
|
||||
@defproc[(media-entry-parent-id [entry media-entry?]) (or/c #f string?)]{Returns the parent object identifier.}
|
||||
@defproc[(media-entry-title [entry media-entry?]) string?]{Returns the displayed title.}
|
||||
@defproc[(media-entry-class [entry media-entry?]) (or/c #f string?)]{Returns the original UPnP class, such as @tt{object.item.audioItem.musicTrack}.}
|
||||
@defproc[(media-entry-restricted? [entry media-entry?]) boolean?]{Reports whether the server marks the object as restricted.}
|
||||
@defproc[(media-entry? [value any/c]) boolean?]
|
||||
@defproc[(media-entry-id [entry media-entry?]) (or/c #f string?)]
|
||||
@defproc[(media-entry-parent-id [entry media-entry?]) (or/c #f string?)]
|
||||
@defproc[(media-entry-title [entry media-entry?]) string?]
|
||||
@defproc[(media-entry-class [entry media-entry?]) (or/c #f string?)]
|
||||
@defproc[(media-entry-restricted? [entry media-entry?]) boolean?]
|
||||
|
||||
@defproc[(media-container? [value any/c]) boolean?]{Recognises a browsable container.}
|
||||
@defproc[(media-container-child-count [container media-container?]) (or/c #f exact-nonnegative-integer?)]{Returns the advertised number of children, when present.}
|
||||
@defproc[(media-container-searchable? [container media-container?]) boolean?]{Reports whether the container is advertised as searchable.}
|
||||
@defproc[(media-container? [value any/c]) boolean?]
|
||||
@defproc[(media-container-child-count [container media-container?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-container-searchable? [container media-container?])
|
||||
boolean?]
|
||||
|
||||
@defproc[(media-item? [value any/c]) boolean?]{Recognises a media item.}
|
||||
@defproc[(media-item-creator [item media-item?]) (or/c #f string?)]{Returns the Dublin Core creator.}
|
||||
@defproc[(media-item-artists [item media-item?]) (listof string?)]{Returns the advertised artists.}
|
||||
@defproc[(media-item-album [item media-item?]) (or/c #f string?)]{Returns the album title.}
|
||||
@defproc[(media-item-genres [item media-item?]) (listof string?)]{Returns the advertised genres.}
|
||||
@defproc[(media-item-date [item media-item?]) (or/c #f string?)]{Returns the advertised date without imposing a date format.}
|
||||
@defproc[(media-item-album-art-uri [item media-item?]) (or/c #f string?)]{Returns the album-art URI. Relative URIs are resolved against the device-description URL.}
|
||||
@defproc[(media-item-resources [item media-item?]) (listof media-resource?)]{Returns all playable or retrievable resources. One item may advertise several encodings.}
|
||||
@defproc[(media-item? [value any/c]) boolean?]
|
||||
@defproc[(media-item-creator [item media-item?]) (or/c #f string?)]
|
||||
@defproc[(media-item-artists [item media-item?]) (listof string?)]
|
||||
@defproc[(media-item-album [item media-item?]) (or/c #f string?)]
|
||||
@defproc[(media-item-genres [item media-item?]) (listof string?)]
|
||||
@defproc[(media-item-date [item media-item?]) (or/c #f string?)]
|
||||
@defproc[(media-item-album-art-uri [item media-item?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-item-resources [item media-item?])
|
||||
(listof media-resource?)]
|
||||
|
||||
@section{Resources}
|
||||
|
||||
@defproc[(media-resource? [value any/c]) boolean?]{Recognises a DIDL-Lite resource.}
|
||||
@defproc[(media-resource-uri [resource media-resource?]) string?]{Returns the resource URI, resolved to an absolute URI where possible.}
|
||||
@defproc[(media-resource-protocol-info [resource media-resource?]) (or/c #f string?)]{Returns the complete UPnP @tt{protocolInfo} value.}
|
||||
@defproc[(media-resource-content-type [resource media-resource?]) (or/c #f string?)]{Returns the content-format portion of @tt{protocolInfo}, such as @tt{audio/flac}.}
|
||||
@defproc[(media-resource-size [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the size in bytes.}
|
||||
@defproc[(media-resource-duration [resource media-resource?]) (or/c #f nonnegative-real?)]{Returns the duration in seconds.}
|
||||
@defproc[(media-resource-bitrate [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the advertised bitrate in bytes per second, as defined by DIDL-Lite.}
|
||||
@defproc[(media-resource-sample-frequency [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the sample frequency in hertz.}
|
||||
@defproc[(media-resource-bits-per-sample [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the advertised bits per sample.}
|
||||
@defproc[(media-resource-channels [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the number of audio channels.}
|
||||
@defproc[(media-resource-resolution [resource media-resource?]) (or/c #f string?)]{Returns an advertised image or video resolution.}
|
||||
|
||||
@section[#:tag "media-server-example"]{Example}
|
||||
|
||||
@racketblock[
|
||||
(define synology
|
||||
(car (query-media-servers #:interface "10.7.3.118")))
|
||||
|
||||
(define root (media-server-root synology))
|
||||
(define music
|
||||
(findf (lambda (entry)
|
||||
(and (media-container? entry)
|
||||
(string=? (media-entry-title entry) "Muziek")))
|
||||
root))
|
||||
|
||||
(for ([entry (in-list (media-container-children synology music))])
|
||||
(printf "~a: ~a\n"
|
||||
(if (media-container? entry) 'container 'item)
|
||||
(media-entry-title entry)))
|
||||
]
|
||||
@defproc[(media-resource? [value any/c]) boolean?]
|
||||
@defproc[(media-resource-uri [resource media-resource?]) string?]
|
||||
@defproc[(media-resource-protocol-info [resource media-resource?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-resource-content-type [resource media-resource?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-resource-size [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-duration [resource media-resource?])
|
||||
(or/c #f number?)]
|
||||
@defproc[(media-resource-bitrate [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-sample-frequency [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-bits-per-sample [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-channels [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-resolution [resource media-resource?])
|
||||
(or/c #f string?)]
|
||||
|
||||
Reference in New Issue
Block a user