title: Defold 中的声音流传输
虽然默认行为是完整加载声音数据,但在使用前分块加载数据可能也是有益的。这通常被称为"流传输"。
声音流传输的一个好处是需要更少的运行时内存,另一个好处是如果您从例如 http url 流式传输内容,您可以随时更新内容,并避免初始下载。
有一个展示此设置的示例项目:https://github.com/defold/example-sound-streaming
使用声音流传输的最简单方法是在 game.project 中启用 sound.stream_enabled
设置。启用此选项后,引擎将开始流式传输声音。
注意:如果您同时加载了许多声音文件,可能需要增加 sound.stream_cache_size
值(见下文)。
您也可以创建一个新的声音数据资源,并将其设置为声音组件。
您可以通过以下方式执行此操作:
resource.create_sound_data()
创建一个新的声音数据资源go.set()
将新的声音数据资源设置为声音组件以下是示例项目中的摘录,使用 http.request()
获取初始声音文件。
::: sidenote 您从中加载内容的 Web 服务器必须支持 HTTP 范围请求。 :::
local function play_sound(self, hash)
go.set(self.component, "sound", hash) -- 覆盖组件上的资源数据
sound.play(self.component) -- 开始播放声音
end
local function parse_range(s)
local _, _, rstart, rend, size = string.find(s, "(%d+)-(%d+)/(%d+)") -- "bytes 0-16383/103277"
return rstart, rend, size
end
-- http 响应的回调函数
local function http_result(self, _id, response, extra)
if response.status == 200 or response.status == 206 then
-- 成功的请求
local relative_path = self.filename
local range = response.headers['content-range'] -- content-range = "bytes 0-16383/103277"
local rstart, rend, filesize = parse_range(range)
-- 创建 Defold 资源
-- "partial" 将启用流传输模式
print("Creating resource", relative_path)
local hash = resource.create_sound_data(relative_path, { data = response.response, filesize = filesize, partial = true })
-- 发送 "play_sound" 到组件
play_sound(self, hash)
end
end
local function load_web_sound(base_url, relative_path)
local url = base_url .. "/" .. relative_path
local headers = {}
headers['Range'] = string.format("bytes=%d-%d", 0, 16384-1)
http.request(url, "GET", http_result, headers, nil, { ignore_cache = true })
end
您可以使用其他方式加载声音文件的初始块。重要的是要记住,其余的块是从资源系统及其资源提供者加载的。在此示例中,我们通过调用使用 liveupdate.add_mount() 添加一个新的 (http) 文件提供者,通过添加实时更新挂载点。
您可以在 https://github.com/defold/example-sound-streaming 中找到一个工作示例。
-- 参见上面示例中的 http_result()
local function load_web_sound(base_url, relative_path)
local url = base_url .. "/" .. relative_path
local headers = {}
-- 请求文件的初始部分
headers['Range'] = string.format("bytes=%d-%d", 0, 16384-1)
http.request(url, "GET", http_result, headers, nil, { ignore_cache = true })
end
function init(self)
self.base_url = "http://my.server.com"
self.filename = "/path/to/sound.ogg"
liveupdate.add_mount("webmount", self.base_url, 100, function ()
-- 一旦挂载点准备就绪,我们就可以开始请求下载第一个块
load_web_sound(self.base_url, self.filename)
end)
end
function final(self)
liveupdate.remove_mount("webmount")
end
运行时声音消耗的内存量由 game.project 中的 sound.stream_cache_size
设置 控制。在此限制下,加载的声音数据永远不会超过此限制。
每个声音文件的初始块不能被驱逐,只要资源被加载,它们就会占用缓存。初始块的大小由 game.project 中的 sound.stream_preload_size
设置 控制。
您还可以通过更改 game.project 中的 sound.stream_chunk_size
设置 来控制每个声音块的大小。如果您同时加载了许多声音文件,这可能有助于进一步降低声音缓存大小。小于声音块大小的声音文件不会被流式传输,如果新块不适合放入缓存中,最旧的块将被驱逐。
::: important 声音块缓存的总大小应大于加载的声音文件数量乘以流块大小。否则,您可能会冒着每帧驱逐新块的风险,声音将无法正常播放。 :::