Przechwytywanie wejścia dźwiękowego

Flash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje

Klasa Microphone umożliwia połączenie aplikacji z mikrofonem lub innym urządzeniem wejścia dźwiękowego w systemie użytkownika i nadanie dźwiękowego sygnału wejściowego do głośników tego systemu lub wysłanie danych audio na zdalny serwer, taki jak Flash Media Server. Można uzyskiwać dostęp bezpośrednio do danych audio pochodzących z mikrofonu i nagrywać je lub przetwarzać. Można również wysyłać dźwięki bezpośrednio do głośników komputera lub wysyłać skompresowane dane audio na serwer zdalny. W przypadku danych wysłanych do serwera zdalnego można korzystać z kodeka Speex lub Nellymoser. (Kodek Speex jest obsługiwany począwszy od wersji 10 programu Flash Player i wersji 1.5 środowiska Adobe AIR).

Uzyskiwanie dostępu do mikrofonu

Klasa Microphone nie dysponuje metodą konstruktora. Zamiast tego możliwe jest użycie statycznej metody Microphone.getMicrophone() do uzyskania nowej instancji Microphone zgodnie z informacjami poniżej:

var mic:Microphone = Microphone.getMicrophone();

Wywołanie metody Microphone.getMicrophone() bez parametru zwróci pierwsze dźwiękowe urządzenie wejściowe wykryte w systemie użytkownika.

System może dysponować więcej niż jednym dźwiękowym urządzeniem wejściowym podłączonym do niego. Aplikacja może używać właściwości Microphone.names do uzyskiwania tablicy nazw dostępnych dźwiękowych urządzeń wejściowych. Może ona następnie wywoływać metodę Microphone.getMicrophone() z parametrem index odpowiadającym wartości indeksu nazwy urządzenia w tablicy.

System może nie dysponować mikrofonem ani innym dźwiękowym urządzeniem wejściowym. Możliwe jest również użycie właściwości Microphone.names lub metody Microphone.getMicrophone() do sprawdzenia, czy użytkownik zainstalował dźwiękowe urządzenie wejściowe w systemie. Jeśli użytkownik nie zainstalował dźwiękowego urządzenia wejściowego, tablica names ma długość równą zeru, a metoda getMicrophone() zwraca wartość null .

Po wywołaniu przez aplikację metody Microphone.getMicrophone() program Flash Player wyświetla okno dialogowe Ustawienia Flash Player z monitem o zezwolenie lub odmówienie dostępu Flash Player do kamery i mikrofonu zainstalowanych w systemie. Po kliknięciu przez użytkownika przycisku Zezwalaj lub Odmów w tym oknie dialogowym dysponowane jest zdarzenie StatusEvent. Właściwość code tej instancji StatusEvent wskazuje, czy zezwolono, czy też odmówiono dostępu do mikrofonu, zgodnie z poniższym przykładem:

import flash.media.Microphone; 
 
var mic:Microphone = Microphone.getMicrophone(); 
mic.addEventListener(StatusEvent.STATUS, this.onMicStatus); 
 
function onMicStatus(event:StatusEvent):void 
{ 
    if (event.code == "Microphone.Unmuted") 
    { 
        trace("Microphone access was allowed."); 
    }  
    else if (event.code == "Microphone.Muted") 
    { 
         trace("Microphone access was denied."); 
    } 
}

Właściwość StatusEvent.code będzie zawierać wartość „Microphone.Unmuted”, jeśli zezwolono na dostęp, lub „Microphone.Muted”, jeśli na dostęp nie zezwolono.

Wraz z decyzją użytkownika o dostępie do mikrofonu właściwość Microphone.muted jest ustawiana odpowiednio na wartość true lub false . Właściwość muted nie jest ustawiana w wystąpieniu klasy Microphone, dopóki nie zostanie wywołane zdarzenie StatusEvent, dlatego aplikacja powinna zaczekać na wywołanie zdarzenia StatusEvent.STATUS przed sprawdzeniem właściwości Microphone.muted .

Aby program Flash Player wyświetlił okno dialogowe ustawień, okno aplikacji musi mieć odpowiednie wymiary (co najmniej 215 x 138 pikseli). W przeciwnym razie nastąpi automatyczna odmowa dostępu.

Zawartość działająca w obszarze izolowanym aplikacji AIR nie potrzebuje uprawnień w celu uzyskania dostępu do mikrofonu. Oznacza to, że w tym przypadku nigdy nie są wywoływane zdarzenia dotyczące wyciszania i anulowania wyciszenia mikrofonu. Zawartość działająca w środowisku AIR poza obszarem izolowanym aplikacji musi mieć pozwolenie użytkownika, dlatego mogą być wywoływane te zdarzenia zmiany stanu.

Przekierowywanie dźwięku z mikrofonu do lokalnych głośników

Wejście audio z mikrofonu można przekierować do lokalnego systemu głośników, wywołując metodę Microphone.setLoopback() z wartością true parametru.

Po przekierowaniu dźwięku z lokalnego mikrofonu do lokalnych głośników istnieje ryzyko utworzenia sprzężenia zwrotnego, co może spowodować generowanie głośnych i wysokich dźwięków, i grozi uszkodzeniem sprzętu audio. Wywołanie metody Microphone.setUseEchoSuppression() z wartością true parametru redukuje, lecz nie eliminuje kompletnie, ryzyka powstania takiego sprzężenia zwrotnego. Firma Adobe zaleca wywoływanie zawsze metody Microphone.setUseEchoSuppression(true) przed wywołaniem metody Microphone.setLoopback(true) , chyba że istnieje całkowita pewność co do tego, że użytkownik odtworzy dźwięk za pomocą słuchawek lub w dowolny inny sposób, a nie przez głośniki.

Poniższy kod ilustruje sposób przekierowywana audio z lokalnego mikrofonu do lokalnego systemu głośników:

var mic:Microphone = Microphone.getMicrophone(); 
mic.setUseEchoSuppression(true); 
mic.setLoopBack(true);

Zmienianie dźwięku mikrofonu

Aplikacja umożliwia zmianę danych dźwiękowych pochodzących z mikrofonu na dwa sposoby. Po pierwsze, może ona zmienić wzmocnienie wejścia dźwiękowego, co w praktyce powoduje przemnożenie wartości wejściowych przez określoną wielkość i wytworzenie głośniejszego lub cichszego efektu. Właściwość Microphone.gain przyjmuje wartości numeryczne z zakresu od 0 do 100 włącznie. Wartość 50 działa jak mnożnik wynoszący jeden i określa głośność normalną. Wartość zerowa działa jak mnożnik wynoszący zero i w praktyce wycisza całkowicie wejście audio. Wartości powyżej 50 określają głośność wyższa niż normalna.

Ponadto aplikacja może również zmieniać częstotliwość próbkowania wejścia audio. Wyższe częstotliwości próbkowania zwiększają jakość dźwięku, lecz mogą również powodować zagęszczenie strumieni danych w przypadku, jeśli korzystają one z wielu źródeł do transmisji i zapisu. Właściwość Microphone.rate prezentuje częstotliwość próbkowania audio mierzoną w kilohercach (kHz). Domyślna częstotliwość próbkowania wynosi 8 kHz. Możliwe jest ustawienie właściwości Microphone.rate na wartość wyższą niż 8 kHz, jeśli mikrofon obsługuje wyższą częstotliwość. Na przykład: ustawienie właściwości Microphone.rate na wartość 11 powoduje ustawienie częstotliwości próbkowania na wartość 11 kHz; ustawienie jej na wartość 22 powoduje ustawienie częstotliwości próbkowania na wartość 22 kHz itd. Częstotliwości próbkowania są uzależnione od wybranego kodeka. Jeśli używany jest kodek Nellymoser, można określić częstotliwości próbkowania: 5, 8, 11, 16, 22 oraz 44 kHz. W przypadku użycia kodeka Speex (dostępnego począwszy od wersji 10 programu Flash Player i wersji 1.5 środowiska Adobe AIR) dostępna jest tylko częstotliwość 16 kHz.

Wykrywanie aktywności mikrofonu

W celu zachowania szerokości pasma oraz zasobów przetwarzania program Flash Player próbuje wykrywać brak przesyłania dźwięku przez mikrofon. Jeśli działanie mikrofonu pozostaje przez określony czas poniżej progu poziomu ciszy, Flash Player zatrzymuje transmisję danych wejściowych audio i dysponuje zamiast tego proste zdarzenie ActivityEvent. W przypadku użycia kodeka Speex (dostępnego począwszy od wersji 10 programu Flash Player i wersji 1.5 środowiska Adobe AIR) należy poziom ciszy ustawić na 0, aby zapewnić ciągłość przesyłania danych audio przez aplikację. Wykrywanie głosu przez kodek Speex automatycznie redukuje szerokość pasma.

Uwaga: Obiekt Microphone wywołuje zdarzenia activity (dotyczące działań) tylko w przypadku, gdy aplikacja monitoruje mikrofon. Jeśli nie zostanie wywołana metoda setLoopBack(true) , nie zostanie dodany detektor związany ze zdarzeniami danych próbkowania ani mikrofon nie zostanie dołączony do obiektu NetStream, nie będą wywoływane żadne zdarzenia activity.

Za monitorowanie i sterowanie wykrywaniem aktywności klasy Microphone odpowiadają trzy właściwości:

  • Właściwość tylko do odczytu activityLevel wskazuje wielkość dźwięku wykrytą w mikrofonie, na skali od 0 do 100.

  • Właściwość silenceLevel określa ilość dźwięku potrzebną do aktywacji mikrofonu i dysponuje zdarzenie ActivityEvent.ACTIVITY . Właściwość silenceLevel korzysta również ze skali od 0 do 100, gdzie wartością domyślną jest 10.

  • Właściwość silenceTimeout opisuje liczbę milisekund, poniżej której musi pozostać poziom aktywności, aż do chwili zadysponowania zdarzenia ActivityEvent.ACTIVITY w celu wskazania, że mikrofon jest wyciszony. Wartość domyślna silenceTimeout to 2000.

Zarówno właściwość Microphone.silenceLevel jak i właściwość Microphone.silenceTimeout mają atrybut tylko do odczytu, lecz ich wartości można zmienić za pomocą metody Microphone.setSilenceLevel() .

W niektórych przypadkach proces aktywacji mikrofonu po wykryciu nowej czynności może spowodować niewielkie opóźnienie. Zachowanie aktywności mikrofonu przez cały czas może pomóc wyeliminować takie opóźnienia w aktywacji. Aplikacja może wywoływać metodę Microphone.setSilenceLevel() z parametrem silenceLevel ustawionym na wartość zerową w celu przekazania do programu Flash Player informacji o konieczności zachowania aktywności mikrofonu oraz zgromadzonych danych audio, nawet jeśli przez pewien czas nie będą wykrywane żadne dźwięki. I odwrotnie, ustawienie parametru silenceLevel na wartość 100 całkowicie uniemożliwia aktywowanie mikrofonu.

Poniższy przykład ilustruje sposób wyświetlania informacji na temat mikrofonu, a także zdarzeń aktywności oraz statusu dysponowanych przez obiekt Microphone:

import flash.events.ActivityEvent; 
import flash.events.StatusEvent; 
import flash.media.Microphone; 
 
var deviceArray:Array = Microphone.names; 
trace("Available sound input devices:"); 
for (var i:int = 0; i < deviceArray.length; i++) 
{ 
    trace(" " + deviceArray[i]); 
} 
 
var mic:Microphone = Microphone.getMicrophone(); 
mic.gain = 60; 
mic.rate = 11; 
mic.setUseEchoSuppression(true); 
mic.setLoopBack(true); 
mic.setSilenceLevel(5, 1000); 
     
mic.addEventListener(ActivityEvent.ACTIVITY, this.onMicActivity); 
mic.addEventListener(StatusEvent.STATUS, this.onMicStatus); 
     
var micDetails:String = "Sound input device name: " + mic.name + '\n'; 
micDetails += "Gain: " + mic.gain + '\n'; 
micDetails += "Rate: " + mic.rate + " kHz" + '\n'; 
micDetails += "Muted: " + mic.muted + '\n'; 
micDetails += "Silence level: " + mic.silenceLevel + '\n'; 
micDetails += "Silence timeout: " + mic.silenceTimeout + '\n'; 
micDetails += "Echo suppression: " + mic.useEchoSuppression + '\n'; 
trace(micDetails); 
 
function onMicActivity(event:ActivityEvent):void 
{ 
    trace("activating=" + event.activating + ", activityLevel=" +  
        mic.activityLevel); 
} 
 
function onMicStatus(event:StatusEvent):void 
{ 
    trace("status: level=" + event.level + ", code=" + event.code); 
}

Uruchamiając powyższy przykład, należy mówić lub wytwarzać inne dźwięki w pobliżu mikrofonu systemowego i obserwować wyniki wyświetlane w konsoli lub oknie debugowania.

Wysyłanie dźwięku na serwer oraz z serwera multimediów

Korzystanie z serwera przesyłania strumieniowego takiego jak Flash Media Server udostępnia dodatkowe możliwości audio.

W szczególności aplikacja może dołączyć obiekt Microphone do obiektu NetStream i przesyłać dane bezpośrednio z mikrofonu użytkownika na serwer. Dane audio mogą być również przesyłane strumieniowo z serwera do aplikacji lub Flex i odtwarzane jako fragment MovieClip lub za pomocą obiektu Video.

Kodek Speex jest dostępny począwszy od wersji 10 programu Flash Player i wersji 1.5 środowiska Adobe AIR. Aby wybrać kodek używany do przetwarzania dźwięku skompresowanego wysyłanego do serwera multimediów, należy przypisać wartość właściwości codec obiektu Microphone. Ta właściwość może mieć dwie wartości, które są wyliczane w klasie SoundCodec. Ustawienie właściwości codec na wartość SoundCodec.SPEEX powoduje wybranie kodeka Speex do kompresji audio. Ustawienie właściwości na SoundCodec.NELLYMOSER (domyślnie) powoduje wybranie kodeka Nellymoser dla kompresji audio.

Więcej informacji zawiera dokumentacja programu Flash Media Server dostępna pod adresem www.adobe.com/go/learn_fms_docs_pl .

Przechwytywanie danych dźwiękowych z mikrofonu

W programie Flash Player 10.1. i środowisku AIR 2 (oraz w nowszych wersjach) można przechwytywać dane z mikrofonu jako tablicę bajtów (ByteArray) wartości zmiennoprzecinkowych. Każda wartość reprezentuje próbkę dźwięku monofonicznego.

Aby pobierać dane z mikrofonu, należy skonfigurować detektor zdarzenia sampleData wywoływanego przez obiekt Microphone. Obiekt Microphone wywołuje zdarzenia sampleData okresowo, w miarę jak bufor mikrofonu zapełniany jest próbkami dźwięku. Obiekt SampleDataEvent ma właściwość data , która jest tablicą ByteArray zawierającą próbki dźwięku. Każda próbka jest zapisana jako wartość zmiennoprzecinkowa, reprezentująca wartość z jednego kanału (dźwięk monofoniczny).

Poniższy kod przechwytuje monofoniczne dane dźwiękowe do obiektu ByteArray o nazwie soundBytes :

var mic:Microphone = Microphone.getMicrophone(); 
mic.setSilenceLevel(0, DELAY_LENGTH); 
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler); 
function micSampleDataHandler(event:SampleDataEvent):void { 
    while(event.data.bytesAvailable)     { 
        var sample:Number = event.data.readFloat(); 
        soundBytes.writeFloat(sample); 
    } 
}

Ciąg bajtów z próbkami może zostać użyty jako dane dźwiękowe do odtwarzania przez obiekt Sound. W takim wypadku należy ustawić właściwość rate obiektu Microphone na 44, czyli częstotliwość próbkowania używaną przez obiekty Sound. (Można również przekonwertować próbki z mikrofonu przechwycone z niższą częstotliwością na częstotliwość 44 kHz wymaganą przez obiekt Sound). Należy także pamiętać, że obiekt Microphone przechwytuje próbki monofoniczne, a obiekt Sound operuje na dźwięku stereofonicznym; dlatego każdy bajt przechwycony przez obiekt Microphone należy zapisać do obiektu Sound dwukrotnie. W poniższym przykładzie przechwytywane są 4 sekundy danych z mikrofonu, a następnie dane te są odtwarzane za pomocą obiektu Sound:

const DELAY_LENGTH:int = 4000; 
var mic:Microphone = Microphone.getMicrophone(); 
mic.setSilenceLevel(0, DELAY_LENGTH); 
mic.gain = 100; 
mic.rate = 44; 
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler); 
 
var timer:Timer = new Timer(DELAY_LENGTH); 
timer.addEventListener(TimerEvent.TIMER, timerHandler); 
timer.start(); 
 
function micSampleDataHandler(event:SampleDataEvent):void 
{ 
    while(event.data.bytesAvailable) 
    { 
        var sample:Number = event.data.readFloat(); 
        soundBytes.writeFloat(sample); 
    } 
} 
var sound:Sound = new Sound(); 
var channel:SoundChannel; 
function timerHandler(event:TimerEvent):void 
{ 
    mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler); 
    timer.stop(); 
    soundBytes.position = 0; 
    sound.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler); 
    channel.addEventListener( Event.SOUND_COMPLETE, playbackComplete ); 
    channel = sound.play(); 
} 
 
function playbackSampleHandler(event:SampleDataEvent):void 
{ 
    for (var i:int = 0; i < 8192 && soundBytes.bytesAvailable > 0; i++) 
    { 
        trace(sample); 
        var sample:Number = soundBytes.readFloat(); 
        event.data.writeFloat(sample); 
        event.data.writeFloat(sample); 
    } 
} 
 
function playbackComplete( event:Event ):void 
{ 
    trace( "Playback finished."); 
}

Więcej informacji na temat odtwarzania dźwięku z próbek dźwiękowych zawiera sekcja Praca z dźwiękiem generowanym dynamicznie .