OpenSL ES programlama notları

UYARI: OpenSL ES desteği sonlandırılmıştır. Geliştiriciler, GitHub'da bulunan obua kitaplığını kullanabilirsiniz. Obua, Aaudio. Oboe, AAudio kullanılabilir olduğunda AAudio'yu çağırır ve AAudio kullanılamıyorsa OpenSL ES'ye geri döner.

Bu bölümdeki notlar, OpenSL ES 1.0.1 spesifikasyonlarına göz atın.

Nesneler ve arayüzü başlatma

OpenSL ES programlama modelinin yeni geliştiricilere aşina olmayabilecek iki yönü şunlardır: ve başlatma sırası arasındaki farkları ele alacağız.

Kısacası, OpenSL ES nesnesi şuradaki nesne kavramına benzerdir: Java gibi programlama dilleri ve C++ (OpenSL ES nesnesi yalnızca ilişkili arayüzleri aracılığıyla görünür olmalıdır). Buna tüm nesneler için SLObjectItf adlı ilk arayüz de dahildir. Nesnenin tutma yeri yok kendisi, yalnızca nesnenin SLObjectItf arayüzüne ait bir tutma yeri.

İlk olarak bir OpenSL ES nesnesi oluşturulur. Bu işlem, SLObjectItf, ardından belirlemiştir. Bu, ilk önce bir proje başlatma belgesi oluşturmaya yönelik yaygın programlama kalıbına nesne (bellek veya geçersiz parametreler dışında hiçbir zaman başarısız olması gerekmez) ve ardından başlatma işlemi tamamlanır (kaynak yetersizliğinden dolayı başarısız olabilir). Gerçekleştirme adımı, gerekirse uygulamaya ek kaynaklar ayırmak için mantıklı bir yer sağlar.

Nesne oluşturma API'sinin parçası olarak uygulama, istenen arayüz dizisini belirtir. daha sonra satın almayı planlıyor. Bu dizinin otomatik olarak Arayüzleri edinme, bu yalnızca onları gelecekte edinme niyetini gösterir. Arayüzler aşağıdaki şekillerde ayırt edilir: dolaylı veya uygunsuz olabilir. Açık bir arayüz, dizide listelenmeli edinilir. Örtülü arayüzün nesne oluşturma dizisi, ancak onu burada listelemenin bir sakıncası yoktur. OpenSL ES, dinamik; nesnede belirtilmesi gerekmez dizi oluşturabilir ve eklenebilir. otomatik olarak eklenir. Android uygulaması, bu karmaşıklıktan kaçınmak için bir kolaylık özelliği sağlar. Bu özellik Nesne oluşturma sırasında dinamik arayüzler bölümünde açıklanmıştır.

Nesne oluşturulup gerçekleştirildikten sonra uygulama, ilk SLObjectItf üzerinde GetInterface kullanarak ihtiyaç duyduğu her özellik için arayüz edinmelidir.

Son olarak, nesne, arayüzleri aracılığıyla kullanılabilir ancak bazı nesneler yapmanız gerekir. Özellikle URI veri kaynağına sahip bir ses oynatıcının, bağlantı hatalarını algılayabilmesi için biraz daha hazırlık yapması gerekir. Bkz. Ayrıntılı bilgi için Ses çalar önceden getirme bölümüne bakın.

Uygulamanız nesneyle işlem bittikten sonra nesneyi açıkça yok etmeniz gerekir. Aşağıdaki Yok etme bölümüne bakın.

Ses çaların önceden getirilmesi

URI veri kaynağına sahip bir ses çalar için Object::Realize, kaynakları ayırır ancak veri kaynağına bağlanmaz (hazırlanmaz) veya verileri önceden getirmeye başlamaz. Bunlar, oynatıcı durumu SL_PLAYSTATE_PAUSED veya SL_PLAYSTATE_PLAYING olarak ayarlanır.

Bazı bilgiler bu sürecin nispeten sonuna kadar bilinmeyebilir. Özellikle, başlangıçta Player::GetDuration SL_TIME_UNKNOWN döndürür ve MuteSolo::GetChannelCount, kanal sayısı sıfır olan başarılı bir sonuç veya SL_RESULT_PRECONDITIONS_VIOLATED hata sonucunu döndürür. Bu API'ler uygun değerleri döndürür yardımcı olur.

Başlangıçta bilinmeyen diğer özellikler arasında örnek hızı ve gerçek medya içeriği türü içeriğin başlığını incelemek veya uygulama tarafından belirtilen MIME türü ve kapsayıcı türü) olduğunu unutmayın. Bunlar daha sonra proje ekibinin ancak bunları önceden getirmesini geri yükleyebilirsiniz.

Önceden getirme durumu arayüzü, tüm bilgilerin ne zaman oluşturulacağını ve mevcutsa veya belirli aralıklarla yoklama yapabilir. MP3'lerin oynatma süresi gibi bazı bilgilerin hiçbir zaman bilinemeyeceğini unutmayın.

Önceden getirme durumu arayüzü, hataları tespit etmek için de yararlıdır. Geri arama kaydedin ve en az SL_PREFETCHEVENT_FILLLEVELCHANGE ve SL_PREFETCHEVENT_STATUSCHANGE etkinlikler. Bu etkinliklerin her ikisi de aynı anda yayınlanıyorsa ve PrefetchStatus::GetFillLevel sıfır düzeyi bildiriyorsa, PrefetchStatus::GetPrefetchStatus ise SL_PREFETCHSTATUS_UNDERFLOW bildiriyorsa bu, veri kaynağında kurtarılamaz bir hata olduğunu gösterir. Ayrıca bu kişilerin şuna bağlan: veri kaynağına ilişkin ek açıklamaları görüntüleyin.

OpenSL ES'nin bir sonraki sürümünün, sırasındaki veri kaynağına da bakabilirsiniz. Bununla birlikte, gelecekteki ikili program uyumluluğu için, mevcut proje yönetimi metodolojilerini bir hata bildirme yöntemi kullanmanızı öneririz.

Özet olarak, önerilen kod sırası şu şekildedir:

  1. Engine::CreateAudioPlayer
  2. Object:Realize
  3. SL_IID_PREFETCHSTATUS için Object::GetInterface
  4. PrefetchStatus::SetCallbackEventsMask
  5. PrefetchStatus::SetFillUpdatePeriod
  6. PrefetchStatus::RegisterCallback
  7. SL_IID_PLAY için Object::GetInterface
  8. Play::SetPlayState - SL_PLAYSTATE_PAUSED veya SL_PLAYSTATE_PLAYING

Not: Hazırlık ve önceden getirme burada gerçekleşir; bu süre zarfında geri arama düzenli durum güncellemeleri.

Yok Et

Uygulamanızdan çıkarken tüm nesneleri yok ettiğinizden emin olun. Nesneler şurada yok edilmeli: Herhangi bir bağımlı öğe içeren bir nesneyi yok etmek güvenli olmadığından, yaratılış sırasının tersi nesneler'i tıklayın. Örneğin, şu sırayla yok edin: ses çalarlar ve kaydediciler, çıkış mix'i ve sonra son olarak da motor.

OpenSL ES, otomatik atık toplamayı desteklemez veya referans arayüzlerin sayımı. Object::Destroy adlı kişiyi aradıktan sonra, mevcut olanların hiçbiri her bir ekip üyesinin tanımsız hale gelir.

Android OpenSL ES uygulaması, bu tür arayüzlerin yanlış kullanımını algılamaz. Nesne yok edildikten sonra bu tür arayüzleri kullanmaya devam etmek, uygulamanızın tahmin edilemeyen şekillerde çökmesine veya davranmasına neden olabilir.

Hem birincil nesne arayüzünü hem de ilişkili tüm öğeleri açık bir şekilde ayarlamanızı öneririz. nesne yok etme dizinizin bir parçası olarak NULL ile arayüz oluşturur. Böylece, eski arayüz tanıtıcılarının hatalı kullanımı.

Stereo kaydırma

Mono kaynağın stereo kaydırmayı etkinleştirmek için Volume::EnableStereoPosition kullanıldığında toplamda 3 dB küçülme var ses gücü düzeyi tıklayın. Bu, toplam ses gücü seviyesinin sabit kalmasını sağlamak için gereklidir. kaynak bir kanaldan diğerine kaydırıldı. Bu nedenle, stereo konumlandırmayı yalnızca somut olarak ortaya koyar. Daha fazla bilgi için ses kaydırma.

Geri aramalar ve mesaj dizileri

Geri çağırma işleyiciler genellikle uygulama tarafından algılandığında unutmayın. Bu nokta, uygulamayla ilişkili olarak eşzamansız olduğundan, engellemeyen bir nokta kullanmanız gerekir. uygulama ve kullanıcı arasında paylaşılan değişkenlere erişimi kontrol etmek için geri çağırma işleyici. Örnek kodda (ör. arabellek sıraları için) bunu ya senkronizasyonun kullanılması veya engelleme senkronizasyonunun kullanılmasıdır. Ancak, herhangi bir üretim kodu için engellemeyen uygun senkronizasyon çok önemlidir.

Geri çağırma işleyiciler Android çalışma zamanı nedeniyle JNI kullanılamaz. Bu dahili ileti dizileri kritik önem taşır ve OpenSL ES uygulamasının bütünlüğünü bozuyorsa geri çağırma işleyici de veya gerçekleştir fazla iş yükü olabilir.

Geri çağırma işleyicinizin JNI kullanması veya geri çağırması için işleyicinin, bunun yerine başka bir iş parçacığının işlemesi için bir etkinlik yayınlaması gerekir. Örnekler Kabul edilebilir geri çağırma iş yükü arasında sonraki çıkış arabelleğinin oluşturulması ve sıraya alınması yer alır. (bir AudioPlayer için), az önce doldurulmuş giriş arabelleğini işleme ve sonraki boş arabellek (AudioRecorder için) veya Get ailesinin çoğu gibi basit API'leri kullanabilir. Bkz. İş yüküyle ilgili olarak aşağıdaki Performans bölümüne bakın.

Bunun tersinin de güvenli olduğunu unutmayın: JNI URL'sine giren bir Android uygulaması ileti dizisi şunları yapmasına izin verilir: OpenSL ES API'lerini doğrudan çağırır. Ancak, aramaları engellemek veya Uygulama Yanıt Vermiyor (ANR).

Geri arama işleyici çağıran iş parçacığının belirlenmesi, büyük ölçüde bazı ipuçları vereceğim. Bu esnekliğin nedeni, gelecekteki optimizasyonlara izin vermektir. bilhassa şuralarda: çok çekirdekli cihazlara sahip olması gerekir.

Geri çağırma işleyicinin çalıştırıldığı iş parçacığının, genelinde aynı kimliğe sahip olacağı garanti edilmez. anlamına gelir. Bu nedenle, pthread_self() tarafından döndürülen pthread_t veya gettid() tarafından döndürülen pid_t değerinin çağrılar arasında tutarlı olmasını beklemeyin. Aynı nedenle, pthread_setspecific() ve pthread_getspecific() gibi iş parçacığı yerel depolama (TLS) API'lerini geri çağırma işlevinden kullanmayın.

Uygulama, Search Ads 360 için aynı türde eşzamanlı geri çağırmaların aynı nesne için meydana gelmez. Ancak farklı mesaj dizilerinde aynı nesne için farklı türde eşzamanlı geri çağırmalar mümkündür.

Performans

OpenSL ES yerel bir C API olduğundan, OpenSL ES çağrısı yapan çalışma zamanı olmayan uygulama iş parçacıkları atık toplama duraklatmaları gibi çalışma zamanıyla ilgili ek yük anlamına gelir. Aşağıda açıklanan bir istisna dışında, Bunun dışında OpenSL ES kullanımının ek performans faydası yoktur. Özellikle OpenSL ES'in kullanılması, platformun genel olarak sunduğundan daha düşük ses gecikmesi ve daha yüksek planlama önceliği gibi iyileştirmeler sunma garantisi vermez. Diğer yandan, Bir OpenSL ES uygulaması olan Android platformu ve belirli cihaz uygulamaları gelişmeye devam ediyor sistem performansı iyileştirmelerinden yararlanmayı bekleyebilirsiniz.

Bu gelişmelerden biri, ses çıkış gecikmesinin azaltılmasına yönelik destektir. Daraltılmış kampanya için temel çıkış gecikmesi ilk olarak Android 4.1 (API düzeyi 16) sürümüne dahil edildi ve ardından, Android 4.2'de (API düzeyi 17) sürekli ilerleme kaydedildi. Bu iyileştirmelere Cihaz uygulamaları için OpenSL ES, hak talebinde bulunma özelliği android.hardware.audio.low_latency. Cihaz bu özelliği desteklemiyorsa ancak Android 2.3'ü (API düzeyi 9) destekliyorsa ya da sonrasında OpenSL ES API'lerini kullanmaya devam edebilirsiniz ancak çıkış gecikmesi daha yüksek olabilir. Alt çıkış gecikmesi yolu yalnızca uygulama bir arabellek boyutu ve örnek hızı isterse kullanılır Bunlar, Cihazın yerel çıkış yapılandırmasıyla uyumlu. Bu parametreler cihaza özgü aşağıda açıklandığı şekilde elde edilmelidir.

Android 4.2 (API düzeyi 17) sürümünden itibaren, bir uygulama Cihazın birincil çıkışı için platformda yerel veya optimum çıkış örnek hızı ve arabellek boyutu akış şeklinde gösterilir. Uygulamalar, daha önce bahsedilen özellik testiyle birlikte artık destek olduğunu iddia eden cihazlarda daha düşük gecikme süresi çıkışı için kendisini uygun şekilde yapılandırabilir.

Android 4.2 (API düzeyi 17) ve önceki sürümler için iki veya daha fazla arabellek sayısı daha düşük gecikme için gereklidir. Android 4.3 (API düzeyi 18) sürümünden itibaren, bir arabellek daha düşük gecikme için bir değerin yeterli olması gerekir.

Çıkış efektleri için tüm OpenSL ES arayüzleri düşük gecikme yolunu engeller.

Önerilen adım sırası aşağıdaki gibidir:

  1. OpenSL ES kullanımını onaylamak için API düzeyi 9 veya üstünü kontrol edin.
  2. Aşağıdakine benzer bir kod kullanarak android.hardware.audio.low_latency özelliğini kontrol edin:

    Kotlin

    import android.content.pm.PackageManager
    ...
    val pm: PackageManager = context.packageManager
    val claimsFeature: Boolean = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY)
    

    Java

    import android.content.pm.PackageManager;
    ...
    PackageManager pm = getContext().getPackageManager();
    boolean claimsFeature = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
    
  3. android.media.AudioManager.getProperty()
  4. Bu cihazın şu sürümü için yerel veya optimum çıkış örnek hızını ve arabellek boyutunu alın: birincil çıkış akışı için aşağıdaki gibi bir kod kullanabilirsiniz:

    Kotlin

    import android.media.AudioManager
    ...
    val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    val sampleRate: String = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
    val framesPerBuffer: String = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)
    

    Java

    import android.media.AudioManager;
    ...
    AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
    String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
    
    sampleRate ve framesPerBuffer değerlerinin dize olduğunu unutmayın. İlk kontrol: null ve ardından Integer.parseInt() kullanarak int'e dönüştürün.
  5. Şimdi OpenSL ES'yi kullanarak PCM arabellek sırası veri bulucusuyla bir AudioPlayer oluşturun.

Not: Ses cihazınızdaki OpenSL ES ses uygulamaları için yerel arabellek boyutunu ve örnekleme hızını belirlemek üzere Ses Arabellek Boyutu test uygulamasını kullanabilirsiniz. Ayrıca, adresini görüntülemek için GitHub'ı ziyaret edebilirsiniz ses-arabellek boyutu örnekleri.

Düşük gecikmeli ses oynatıcıların sayısı sınırlıdır. Uygulamanız için daha fazla daha az ses kaynaklarını uygulama düzeyinde miksleyin. Sesinizi yok etmeyi unutmayın diğer uygulamalarla paylaşılan küresel bir kaynak olduğundan, etkinliğiniz duraklatıldığında görüntüleyen oynatıcılar ekleyin.

Sesli arızaları önlemek için arabellek sırası geri çağırma işleyicisi, bir zaman aralığı belirleyin. Bu, genellikle kilitleme, koşul veya G/Ç işlemlerinde sınırsız engelleme olmadığı anlamına gelir. Bunun yerine kilitleri deneyin, kilitleri ve zaman aşımlarıyla beklemelerini kullanın kullanmaya devam edebilirsiniz.

Sonraki arabelleği oluşturmak (AudioPlayer için) veya önceki arabelleği kullanmak için gereken hesaplama arabellek (AudioRecord için), her geri arama için yaklaşık olarak aynı süre sürer. Belirgin olmayan bir süre içinde çalışan veya çalışma sırasında zorlu algoritmalardan kaçının daha iyi anlamanızı sağlayabilir. Belirli bir geri çağırmada harcanan CPU süresi varsa geri çağırma hesaplaması seri hâlindedir ortalamadan önemli ölçüde daha büyüktür. Özet olarak, işleyicinin CPU yürütme süresinin sıfıra yakın bir varyansa sahip olması ve işleyicinin sınırsız süre boyunca engellememesi idealdir.

Yalnızca şu çıkışlarda ses daha düşük gecikmeli olabilir:

  • Cihazdaki hoparlörler.
  • Kablolu kulaklıklar.
  • Kablolu kulaklıklar.
  • Çizgiyi çizin.
  • USB dijital ses.

Bazı cihazlarda, cihazlar için dijital sinyal işleme nedeniyle hoparlör gecikmesi diğer yollardan daha yüksektir hoparlör düzeltme ve koruması.

Android 5.0 (API Düzeyi 21) sürümünden itibaren, daha düşük gecikme ses girişi belirli cihazlarda desteklenir. Bu özellikten yararlanmak için önce yukarıda açıklandığı şekilde daha düşük gecikmeli çıkışın kullanılabildiğini onaylayın. Daha düşük gecikmeli çıkış elde etme özelliği daha düşük gecikmeli giriş özelliğinin ön koşuludur. Ardından, aynı çıkış için kullanılacak örnek hızı ve arabellek boyutu. Giriş efektleri için OpenSL ES arayüzleri daha düşük gecikmeli yolu hariç tutar. Kayıt hazır ayarı Daha düşük gecikme için SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION kullanılmalıdır; bu hazır ayar, giriş yolunda gecikmeye neden olabilecek cihaza özel dijital sinyal işlemeyi devre dışı bırakır. Kayıt hazır ayarlarıyla ilgili daha fazla bilgi için Android yapılandırması arayüz bölümünü inceleyin.

Eş zamanlı giriş ve çıkış için her biri için ayrı arabellek sırası tamamlama işleyicileri kullanılır yanı sıra. Bu geri aramaların göreli sırasına veya her iki taraf da aynı örnek hızını kullansa bile ses saatinde çalışır. Uygulamanız senkronize edildiğinden emin olun.

Bağımsız olabilecek ses saatlerinin sonuçlarından biri, eşzamansız örnek hızına duyulan ihtiyaçtır. gösterir. Zaman uyumsuz örnek hızı dönüşümü için basit (ses kalitesi açısından ideal olmasa da) bir teknik, sıfır geçiş noktasının yakınında gerektiği gibi örnekleri kopyalamak veya silmektir. Daha sofistike dönüşümlerinin nasıl mümkün olduğunu gösterir.

Performans modları

Android 7.1 (API Düzeyi 25) sürümünden itibaren OpenSL ES, performans modunu belirtmenin bir yolunu sundu seçin. Seçenekler şunlardır:

  • SL_ANDROID_PERFORMANCE_NONE: Belirli bir performans şartı yoktur. Donanım ve yazılım efektlerine izin verir.
  • SL_ANDROID_PERFORMANCE_LATENCY: Gecikmeye öncelik verilir. Herhangi bir donanım veya oluşturmak için de kullanabilirsiniz. Bu, varsayılan moddur.
  • SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS: Gecikmeye öncelik verilir yine de donanım ve yazılım efektlerine izin verir.
  • SL_ANDROID_PERFORMANCE_POWER_SAVING: Güç tasarrufuna öncelik verilir. Donanım ve yazılım efektlerine izin verir.

Not: Düşük gecikmeli bir yola ihtiyacınız yoksa ve cihazın yerleşik ses efektlerinden (örneğin, ses efektleri ve kalitesi için) değer kullanıyorsanız performans modunu özel olarak SL_ANDROID_PERFORMANCE_NONE.

Performans modunu ayarlamak için Android üzerinden SetConfiguration yöntemini çağırmanız gerekir. aşağıdaki gibi yapılandırma arayüzü:

  // Obtain the Android configuration interface using a previously configured SLObjectItf.
  SLAndroidConfigurationItf configItf = nullptr;
  (*objItf)->GetInterface(objItf, SL_IID_ANDROIDCONFIGURATION, &configItf);

  // Set the performance mode.
  SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
    result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
                                                     &performanceMode, sizeof(performanceMode));

Güvenlik ve izinler

Android'de güvenlik, kimlerin ne yapabileceğine göre işlem düzeyinde sağlanır. Java programlama dili kodu, yerel koddan daha fazlasını yapamaz ve yerel kod da Java programlama dili kodundan daha fazlasını yapamaz. Aralarındaki tek fark, kullanılabilir API'lerdir.

OpenSL ES kullanan uygulamalar, benzer API'lerle başlayın. Örneğin, uygulamanız ses kaydediyorsa android.permission.RECORD_AUDIO izni. Ses efektleri kullanan uygulamalar android.permission.MODIFY_AUDIO_SETTINGS Ağ URI kaynaklarını oynatan uygulamalar android.permission.NETWORK gerekiyor. Daha fazla bilgi için bkz. Sistemle Çalışma İzinler.

Platform sürümüne ve uygulamaya bağlı olarak, medya içeriği ayrıştırıcılar ve yazılım codec'leri çalışması, OpenSL ES (donanım codec'leri) çağıran Android uygulaması bağlamında soyut ama cihaza bağlı) olabilir. Ayrıştırıcı ve codec'i kötüye kullanmak için tasarlanmış hatalı biçimlendirilmiş içerik bilinen bir saldırı vektörüdür. Yalnızca güvenilir kaynaklardan medya oynatmanızı öneririz veya uygulamanızı, bu sayfadaki medya içeriklerini işleyen kod güvenilir olmayan kaynaklar nispeten korumalı bir ortamda çalışır. Örneğin herkesin güvenilir olmayan kaynaklardan gelen medya içeriklerini ayrı bir işlemde işleyebilir. Her iki süreç de aynı UID altında çalıştırıldığında, bu ayırma, saldırıyı daha zor hale getirir.