Packages
mob
0.6.14
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.2
0.6.1
0.6.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.11
0.5.10
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
BEAM-on-device mobile framework for Elixir
Current section
Files
Jump to
Current section
Files
lib/mob/audio.ex
defmodule Mob.Audio do
@moduledoc """
Microphone recording and audio playback.
Recording requires `:microphone` permission (`Mob.Permissions.request/2`).
iOS additionally needs `NSMicrophoneUsageDescription` in
`Info.plist`; Android needs `RECORD_AUDIO` in
`AndroidManifest.xml`. The default `mix mob.new` templates ship
both. See the [permissions guide](permissions.html) for the
cross-platform table.
Playback requires no permission.
## Recording
Mob.Audio.start_recording(socket, format: :aac, quality: :medium)
Mob.Audio.stop_recording(socket)
# → handle_info({:audio, :recorded, %{path: path, duration: seconds}}, socket)
# → handle_info({:audio, :error, reason}, socket)
## Playback
Mob.Audio.play(socket, "/path/to/file.m4a")
Mob.Audio.play(socket, "/path/to/file.m4a", loop: true, volume: 0.8)
Mob.Audio.stop_playback(socket)
Mob.Audio.set_volume(socket, 0.5)
# → handle_info({:audio, :playback_finished, %{path: path}}, socket)
# → handle_info({:audio, :playback_error, %{reason: reason}}, socket)
iOS: `AVAudioPlayer` / `AVPlayer`. Android: `MediaPlayer`.
"""
@type format :: :aac | :wav
@type quality :: :low | :medium | :high
@doc """
Start recording audio from the microphone.
Options:
- `format: :aac | :wav` (default `:aac`)
- `quality: :low | :medium | :high` (default `:medium`)
"""
@spec start_recording(Mob.Socket.t(), keyword()) :: Mob.Socket.t()
def start_recording(socket, opts \\ []) do
:mob_nif.audio_start_recording(:json.encode(recording_opts(opts)))
socket
end
@doc false
@spec recording_opts(keyword()) :: %{String.t() => String.t()}
def recording_opts(opts) do
%{
"format" => Keyword.get(opts, :format, :aac) |> Atom.to_string(),
"quality" => Keyword.get(opts, :quality, :medium) |> Atom.to_string()
}
end
@doc """
Stop the in-progress recording and save it to a temp file.
Result arrives as `{:audio, :recorded, %{path: ..., duration: ...}}`.
"""
@spec stop_recording(Mob.Socket.t()) :: Mob.Socket.t()
def stop_recording(socket) do
:mob_nif.audio_stop_recording()
socket
end
@doc """
Play an audio file. Stops any currently playing audio first.
Options:
- `loop: boolean` (default `false`)
- `volume: float 0.0–1.0` (default `1.0`)
Result arrives as:
- `{:audio, :playback_finished, %{path: path}}`
- `{:audio, :playback_error, %{reason: reason}}`
"""
@spec play(Mob.Socket.t(), String.t(), keyword()) :: Mob.Socket.t()
def play(socket, path, opts \\ []) do
:mob_nif.audio_play(path, :json.encode(play_opts(opts)))
socket
end
@doc false
@spec play_opts(keyword()) :: %{String.t() => term()}
def play_opts(opts) do
%{
"loop" => Keyword.get(opts, :loop, false),
"volume" => Keyword.get(opts, :volume, 1.0) * 1.0
}
end
@doc "Stop the currently playing audio."
@spec stop_playback(Mob.Socket.t()) :: Mob.Socket.t()
def stop_playback(socket) do
:mob_nif.audio_stop_playback()
socket
end
@doc "Adjust playback volume (0.0–1.0) without stopping playback."
@spec set_volume(Mob.Socket.t(), float()) :: Mob.Socket.t()
def set_volume(socket, volume) when is_float(volume) or is_integer(volume) do
:mob_nif.audio_set_volume(volume / 1.0)
socket
end
end