Wiele przeglądarek ma teraz dostęp do danych wejściowych wideo i dźwięku od użytkownika. Jednak w zależności od przeglądarki może to być pełne, dynamiczne wrażenia w ramach strony lub funkcja delegowana do innej aplikacji na urządzeniu użytkownika.
Zacznij od prostych i stopniowo przejdź do bardziej zaawansowanych
Najłatwiej jest poprosić użytkownika o wcześniej nagrany plik. Aby to zrobić, utwórz prosty element wejścia pliku i dodaj filtr accept
, który wskazuje, że akceptujemy tylko pliki audio, oraz atrybut capture
, który wskazuje, że chcemy pobrać dane bezpośrednio z mikrofonu.
<input type="file" accept="audio/*" capture />
Ta metoda działa na wszystkich platformach. Na komputerze użytkownik zostanie poproszony o przesłanie pliku z systemu plików (ignorując atrybut capture
). W Safari na iOS otworzy aplikację mikrofonu, która umożliwi Ci nagrywanie dźwięku i wysłanie go z powrotem na stronę internetową. W Androidzie użytkownik będzie mógł wybrać aplikację, której mikrofonem chce użyć do nagrania dźwięku, zanim wyśle go z powrotem na stronę internetową.
Gdy użytkownik zakończy nagrywanie i wróci do witryny, musisz w jakiś sposób uzyskać dane pliku. Aby uzyskać szybki dostęp, do elementu wejściowego dołącz zdarzenie onchange
, a potem odczytaj właściwość files
obiektu zdarzenia.
<input type="file" accept="audio/*" capture id="recorder" />
<audio id="player" controls></audio>
<script>
const recorder = document.getElementById('recorder');
const player = document.getElementById('player');
recorder.addEventListener('change', function (e) {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
// Do something with the audio file.
player.src = url;
});
</script>
</audio>
Gdy masz dostęp do pliku, możesz z nim zrobić wszystko, co chcesz. Możesz na przykład:
- Dołącz go bezpośrednio do elementu
<audio>
, aby móc go odtworzyć. - Pobierz na urządzenie użytkownika.
- Prześlij go na serwer, dołączając do
XMLHttpRequest
- Prześlij je przez Web Audio API i zastosuj do niego filtry.
Chociaż metoda dostępu do danych audio za pomocą elementu wejściowego jest powszechna, jest to najmniej atrakcyjna opcja. Chcemy uzyskać dostęp do mikrofonu, aby zapewnić użytkownikom wygodę bezpośrednio na stronie.
Dostęp do mikrofonu w interaktywny sposób
Nowoczesne przeglądarki mogą mieć bezpośredni dostęp do mikrofonu, co pozwala nam tworzyć wrażenia, które są w pełni zintegrowane ze stroną internetową, a użytkownik nie musi opuszczać przeglądarki.
Uzyskiwanie dostępu do mikrofonu
Możemy uzyskać bezpośredni dostęp do mikrofonu, korzystając z interfejsu API w specyfikacji WebRTC o nazwie getUserMedia()
. getUserMedia()
poprosi użytkownika o dostęp do podłączonych mikrofonów i kamer.
Jeśli wszystko pójdzie dobrze, interfejs API zwróci obiekt Stream
zawierający dane z kamery lub mikrofonu. Następnie możesz go dołączyć do elementu <audio>
, strumienia WebRTC, pliku audio Web AudioContext
lub zapisać za pomocą interfejsu API MediaRecorder
.
Aby uzyskać dane z mikrofonu, wystarczy ustawić wartość audio: true
w obiekcie ograniczeń przekazywanym do interfejsu API getUserMedia()
.
<audio id="player" controls></audio>
<script>
const player = document.getElementById('player');
const handleSuccess = function (stream) {
if (window.URL) {
player.srcObject = stream;
} else {
player.src = stream;
}
};
navigator.mediaDevices
.getUserMedia({audio: true, video: false})
.then(handleSuccess);
</script>
Jeśli chcesz wybrać konkretny mikrofon, najpierw musisz wymienić dostępne mikrofony.
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'audioinput');
});
Następnie możesz przekazać deviceId
, którego chcesz użyć, gdy dzwonisz na numer getUserMedia
.
navigator.mediaDevices.getUserMedia({
audio: {
deviceId: devices[0].deviceId,
},
});
Samo w sobie nie jest zbyt przydatne. Możemy tylko pobrać dane audio i je odtworzyć.
Dostęp do nieprzetworzonych danych z mikrofonu
Aby uzyskać dostęp do nieprzetworzonych danych z mikrofonu, musimy wziąć strumień utworzony przez
getUserMedia()
, a następnie przetworzyć dane za pomocą interfejsu Web Audio API. Interfejs Web Audio API to prosty interfejs API, który pobiera źródła danych wejściowych i łączy je z węzłami, które mogą przetwarzać dane audio (np. dostosowywać wzmocnienie), a ostatecznie z głośnikiem, aby użytkownik mógł je usłyszeć.
Jednym z węzłów, które możesz połączyć, jest AudioWorkletNode
. Ten węzeł zapewnia funkcje niskiego poziomu do niestandardowego przetwarzania dźwięku. Rzeczywiste przetwarzanie dźwięku odbywa się w metodzie wywołania process()
w komponencie AudioWorkletProcessor
.
Wywołaj tę funkcję, aby podać dane wejściowe i parametry oraz pobrać dane wyjściowe.
Aby dowiedzieć się więcej, zapoznaj się z workletem Enter Audio.
<script>
const handleSuccess = async function(stream) {
const context = new AudioContext();
const source = context.createMediaStreamSource(stream);
await context.audioWorklet.addModule("processor.js");
const worklet = new AudioWorkletNode(context, "worklet-processor");
source.connect(worklet);
worklet.connect(context.destination);
};
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(handleSuccess);
</script>
// processor.js
class WorkletProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
// Do something with the data, e.g. convert it to WAV
console.log(inputs);
return true;
}
}
registerProcessor("worklet-processor", WorkletProcessor);
Dane przechowywane w buforach to dane nieprzetworzone z mikrofonu. Możesz je wykorzystać na kilka sposobów:
- Prześlij je bezpośrednio na serwer
- przechowywać lokalnie,
- Konwertuj je na dedykowany format pliku, np. WAV, a następnie zapisz na serwerach lub lokalnie.
Zapisz dane z mikrofonu
Najprostszym sposobem zapisywania danych z mikrofonu jest użycie interfejsu API MediaRecorder
.
Interfejs API MediaRecorder
przejmuje strumień utworzony przez getUserMedia
, a następnie stopniowo zapisuje dane z tego strumienia w wybranej lokalizacji docelowej.
<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
const downloadLink = document.getElementById('download');
const stopButton = document.getElementById('stop');
const handleSuccess = function(stream) {
const options = {mimeType: 'audio/webm'};
const recordedChunks = [];
const mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.addEventListener('dataavailable', function(e) {
if (e.data.size > 0) recordedChunks.push(e.data);
});
mediaRecorder.addEventListener('stop', function() {
downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
downloadLink.download = 'acetest.wav';
});
stopButton.addEventListener('click', function() {
mediaRecorder.stop();
});
mediaRecorder.start();
};
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(handleSuccess);
</script>
W naszym przypadku dane są zapisywane bezpośrednio w tablicy, którą później możemy przekształcić w Blob
. Można go następnie użyć do zapisania danych na serwerze WWW lub bezpośrednio na urządzeniu użytkownika.
Prośba o dostęp do mikrofonu
Jeśli użytkownik nie zezwolił wcześniej Twojej witrynie na dostęp do mikrofonu, gdy wywołasz funkcję getUserMedia
, przeglądarka poprosi użytkownika o przyznanie Twojej witrynie uprawnień do korzystania z mikrofonu.
Użytkownicy nie lubią otrzymywać próśb o dostęp do potężnych urządzeń na swoich komputerach. Często blokują one prośby lub ignorują je, jeśli nie rozumieją kontekstu, w którym zostały utworzone. Najlepiej prosić o dostęp do mikrofonu tylko wtedy, gdy jest to konieczne. Gdy użytkownik przyzna dostęp, nie będziesz musiał ponownie o to prosić. Jeśli jednak odmówi, nie będziesz mógł/mogła prosić o pozwolenie ponownie.
Sprawdzanie, czy masz już dostęp, za pomocą interfejsu API uprawnień
Interfejs API getUserMedia
nie informuje, czy masz już dostęp do mikrofonu. To stwarza problem, ponieważ aby zapewnić wygodę korzystania z aplikacji, musisz poprosić użytkownika o dostęp do mikrofonu.
W niektórych przeglądarkach można to rozwiązać, korzystając z interfejsu Permission API. Interfejs API navigator.permission
umożliwia wysyłanie zapytań o stan możliwości dostępu do określonych interfejsów API bez konieczności ponownego wyświetlania prośby.
Aby sprawdzić, czy masz dostęp do mikrofonu użytkownika, możesz przekazać parametr {name: 'microphone'}
do metody zapytania. W zależności od tego, co zwróci:
granted
– użytkownik wcześniej przyznał Ci dostęp do mikrofonu;prompt
– użytkownik nie przyznał Ci dostępu i zostanie o to poproszony podczas rozmowy telefonicznej zgetUserMedia
;denied
– system lub użytkownik zablokował dostęp do mikrofonu i nie będziesz mieć do niego dostępu.
Możesz też szybko sprawdzić, czy musisz zmienić interfejs, aby uwzględnić działania, które musi wykonać użytkownik.
navigator.permissions.query({name: 'microphone'}).then(function (result) {
if (result.state == 'granted') {
} else if (result.state == 'prompt') {
} else if (result.state == 'denied') {
}
result.onchange = function () {};
});