Microphone Plugin for NativePHP Mobile#
Audio recording plugin for NativePHP Mobile with pause/resume support, background recording, and native permission handling.
Overview#
The Microphone API provides access to the device's microphone for recording audio. It offers a fluent interface for starting and managing recordings, tracking them with unique identifiers, and responding to completion events.
Installation#
composer require nativephp/mobile-microphone
Usage#
PHP (Livewire/Blade)#
use Native\Mobile\Facades\Microphone; // Start recordingMicrophone::record()->start(); // Stop recordingMicrophone::stop(); // Pause recordingMicrophone::pause(); // Resume recordingMicrophone::resume(); // Get status$status = Microphone::getStatus();// Returns: "idle", "recording", or "paused" // Get last recording path$path = Microphone::getRecording(); // How loud the microphone has been since the last call, 0 to 1, for a level meter$level = Microphone::level();
JavaScript (Vue/React/Inertia)#
import { Microphone, On, Off, Events } from '#nativephp'; // Basic recordingawait Microphone.record(); // With identifier for trackingawait Microphone.record() .id('voice-memo'); // Stop recordingawait Microphone.stop(); // Pause/resumeawait Microphone.pause();await Microphone.resume(); // Get statusconst result = await Microphone.getStatus();if (result.status === 'recording') { // Recording in progress} // Get last recordingconst result = await Microphone.getRecording();if (result.path) { // Process the recording}
PendingMicrophone API#
id(string $id)#
Set a unique identifier for this recording.
Microphone::record() ->id('voice-note-123') ->start();
event(string $eventClass)#
Set a custom event class to dispatch when recording completes.
use App\Events\VoiceMessageRecorded; Microphone::record() ->event(VoiceMessageRecorded::class) ->start();
wav(int $sampleRate = 16000)#
Record mono 16-bit PCM WAV at the given sample rate instead of AAC. Use it when the recording goes to a server that
takes uncompressed audio, or one that only takes a few formats. MicrophoneRecorded then reports audio/wav. A
minute at 16 kHz is about 1.9 MB.
Microphone::record() ->wav() ->start();
maxDuration(float $seconds)#
Stop recording by itself after this many seconds. MicrophoneRecorded is dispatched with what was recorded, as if
Microphone::stop() had been called.
Microphone::record() ->wav() ->maxDuration(60) ->start();
remember()#
Store the recorder's ID in the session for later retrieval.
Microphone::record() ->id('voice-note') ->remember() ->start();
start()#
Explicitly start the audio recording. Returns true if recording started successfully.
Events#
MicrophoneRecorded#
Dispatched when an audio recording completes.
Payload:
string $path- File path to the recorded audiostring $mimeType- MIME type of the audio (default:'audio/m4a')?string $id- The recorder's ID, if one was set
PHP
use Native\Mobile\Attributes\OnNative;use Native\Mobile\Events\Microphone\MicrophoneRecorded; #[OnNative(MicrophoneRecorded::class)]public function handleAudioRecorded(string $path, string $mimeType, ?string $id){ $this->recordings[] = [ 'path' => $path, 'mimeType' => $mimeType, 'id' => $id, ];}
Vue
import { On, Off, Events } from '#nativephp';import { ref, onMounted, onUnmounted } from 'vue'; const recordings = ref([]); const handleAudioRecorded = (payload) => { const { path, mimeType, id } = payload; recordings.value.push({ path, mimeType, id });}; onMounted(() => { On(Events.Microphone.MicrophoneRecorded, handleAudioRecorded);}); onUnmounted(() => { Off(Events.Microphone.MicrophoneRecorded, handleAudioRecorded);});
React
import { On, Off, Events } from '#nativephp';import { useState, useEffect } from 'react'; const [recordings, setRecordings] = useState([]); const handleAudioRecorded = (payload) => { const { path, mimeType, id } = payload; setRecordings(prev => [...prev, { path, mimeType, id }]);}; useEffect(() => { On(Events.Microphone.MicrophoneRecorded, handleAudioRecorded); return () => { Off(Events.Microphone.MicrophoneRecorded, handleAudioRecorded); };}, []);
MicrophoneCancelled#
Dispatched when a recording can't start or breaks off.
Payload:
bool $cancelled- Alwaystrue?string $id- The recorder's ID, if one was setstring $reason-permission_denied,start_failedorrecording_failed
use Native\Mobile\Attributes\On;use Native\Mobile\Events\Microphone\MicrophoneCancelled; #[On(MicrophoneCancelled::class)]public function recordingCancelled(?string $id = null, string $reason = ''){ $this->error = $reason === 'permission_denied' ? 'Allow the microphone in Settings.' : 'Could not record.';}
Testing#
The plugin extends the NativePHP testing suite with microphone-specific helpers, so your app tests can fake recordings and assert recording activity without knowing any bridge internals:
use Native\Mobile\Testing\Native; it('saves a voice memo', function () { Native::fakeBridge()->withRecording('/storage/emulated/0/audio/note.m4a'); Native::test(VoiceMemo::class) ->tap('Record') ->assertRecordingStarted();}); it('shows the paused state in the UI', function () { Native::fakeBridge()->withMicrophoneStatus('paused'); Native::test(VoiceMemo::class) ->assertSet('status', 'paused');});
Helpers#
withRecording(?string $path = null)— fake a completed recording.getStatus()reports"idle"andgetRecording()reports$path(a generic.m4apath when omitted) — the state right after a real recording session ends.withMicrophoneStatus(string $status)— scriptgetStatus()directly (e.g."recording"or"paused"), without a completed recording on disk.assertRecordingStarted()— assert a recording was started.assertRecordingStopped()— assert the recording was stopped.assertNothingRecorded()— assert no recording was ever started.
The helpers are available on Native::fakeBridge() and chain directly off Native::test(...). They register automatically while running tests (requires a core with a macroable FakeBridge; on older cores they simply don't register).
Notes#
-
Microphone Permission: The first time your app requests microphone access, users will be prompted for permission. If it's denied,
MicrophoneCancelledis dispatched with the reasonpermission_denied. -
Background Recording: You can allow your app to record audio while the device is locked by toggling
microphone_backgroundto true in the config. -
File Format: Recordings are stored as M4A/AAC audio files (
.m4a) unless you ask forwav(), which writes mono 16-bit PCM (.wav). -
Audio Session (iOS): Recording switches the shared audio session to play-and-record, and puts back the category it had once the recording ends, so audio played afterwards doesn't come out of the earpiece.
-
Recording State: Only one recording can be active at a time. Calling
start()while a recording is in progress will returnfalse. -
Auto-Start Behavior: If you don't explicitly call
start(), the recording will automatically start when thePendingMicrophoneis destroyed.