読者です 読者をやめる 読者になる 読者になる

プログラムから動的に mp3 file を返すとき、safari で再生されない

携帯電話などではお馴染みだが、Rangeヘッダーがついている場合は、
206 のステータスで部分的に返す必要がある。

safari でだけ再生されなかったが、 返しているデータバイト数が1バイト足りないためだった。

def main

  # 何かの方法で読み込む
  bin = load

  send_response bin
end

def send_response bin
  if headers["Range"].blank?
    send_data(
        bin,
        disposition: "inline",
        type: "audio/mp3",
      )
  else
    match = request.headers['Range'].match /bytes=(\d+)-(\d*)/

    file_size = bin.bytesize
    file_beg = match[1].to_i
    file_end = match[2].blank? ? (file_size - 1) : match[2].to_i

    response.header["Content-Range"] = "bytes #{file_beg}-#{file_end}/#{file_size}"
    response.header["Content-Transfer-Encoding"] = "binary"
    response.header["Content-Length"] = (file_end - file_beg + 1)

    status = file_end == (file_size - 1) ? "200 OK" : "206 Partial Content"

    send_data(
      bin.slice(file_beg, file_end + 1),
      disposition: "inline",
      type: "audio/mp3",
      status: status,
    )
end