The way you will stream from phoenix depends on how you want the client to process it, thus what are you going to do on the client to play it (phoenix only handles the server-side)?
Is it a real-time stream, so as that data is coming in then it’s immediately going out to connected things, or is it being stored somewhere to be served out later?
In that case this is outside of my knowledge. You’ll need to build the mp3 header properly and all to pack the streamed data through it. I think there is an Elixir/Erlang library that can do this but I’ve not needed to do it as of yet so I’m unsure. ^.^;
Sorry I misunderstood. This totally might not work. But you could try:
<audio
controls
src="/get-mp3/some-name.mp3">
Your browser does not support the
<code>audio</code> element.
</audio>
Then in a controller:
def get_mp3(conn, %{"mp3_name" => mp3_name}) do
mp3_binary = get_mp3_from_memory(mp3_name)
conn |> send_download({:binary, mp3_binary}, filename: "#{mp3_name}.mp3")
end
The problem may be send_download sends a header of content-disposition: attachment. I don’t know if the browser’s audio player will play it in that case.
You might be able to utilize the Membrane framework. While it’s still very raw, they recently released 0.2 and one of the features they list is Support for payloads stored in shared memory. Maybe @mspanc or @mat-hek can verify that this is currently a suitable use-case for Membrane?
I managed to get it done, i pushed the audio to the browser as a base64 encoded string via websockets then on the browser side i decoded it to an arraybuffer which can be played as audio.
It’s bad idea, because you need to send 133% of data (after encoding) if I remember correctly. For audio and fast internet it’s not a really big problem, but imagine doing same for video Blue-Ray.
I’m glad you got it to work! Would you be able to post a short snippet of what you ended up with to help anyone who stumbles across this in the future?
Anyway I’m not sure if it’s best solution even for your use case. No matter if file is small or not. Having extra 33% of data transfer is not as scalable solution as Elixir is designed to be. I could be wrong, but browser JavaScript WebSocket standard already determines a way to send raw file contents. If I remember correctly there was even specific type to handle raw file contents, but again I’m not sure about it. Also I’m not sure how well it plays with Phoenix Channels API. Probably somebody from Phoenix Core Team should know best solution for sending files as they have could implemented it in a way they think is best.
Personally I think given the small amount of data in question (less than a second) I would only further optimize the data transfer if I had some extra time available. But that becomes a business decision and we don’t know all the constraints that @r11na is under.