OpenSL ES programlama notları

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 şunlar dâhildir: tüm nesneler için SLObjectItf adlı ilk arayüz kullanılır. 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 olarak bir proje başlatma belgesi oluşturmaya yönelik yaygın programlama kalıbına (bellek eksikliği 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). Fark etme adımı, ihtiyaç duyulması halinde ek kaynaklar atamak için mantıklı bir yer edinmenizi öneririz.

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, proje zaman çizelgesini aşağıda açıklanan karmaşıklıktan kaçınabilirsiniz: Nesne oluşturulurken dinamik arayüzler.

Nesne oluşturulduktan ve gerçekleştirildikten sonra, uygulama her biri için arayüzler edinmelidir. özelliği (ilk SLObjectItf üzerinde GetInterface kullanarak).

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

Uygulamanız nesneyle tamamlandıktan sonra nesneyi açıkça yok etmeniz gerekir; bkz. Aşağıdaki Kaldır bölümünü tıklayın.

Ses çaların önceden getirilmesi

URI veri kaynağına sahip bir ses çalar için Object::Realize şunları ayırır: kaynakları kullanır ancak veri kaynağına bağlanma (hazırlık) başlatma veya verileri önceden getirme işlemine başlama. Bunlar, oynatıcı durumu SL_PLAYSTATE_PAUSED veya SL_PLAYSTATE_PLAYING olarak ayarlanır.

Bazı bilgiler, bu dizinin nispeten sonlarına kadar bilinmemeye devam edebilir. İçinde özellikle, başlangıçta Player::GetDuration, SL_TIME_UNKNOWN ve MuteSolo::GetChannelCount, başarılı bir şekilde kanal sayısı sıfır veya hata sonucu SL_RESULT_PRECONDITIONS_VIOLATED. 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. Örneğin, akışın süresi MP3, hiçbir zaman bilinmeyebilir.

Önceden getirme durumu arayüzü, hataların algılanmasında da yararlıdır. Geri arama kaydedin ve en az SL_PREFETCHEVENT_FILLLEVELCHANGE ve SL_PREFETCHEVENT_STATUSCHANGE etkinlikler. Bu etkinliklerin ikisi de aynı anda yayınlanıyorsa ve PrefetchStatus::GetFillLevel, sıfır seviyesini ve PrefetchStatus::GetPrefetchStatus, SL_PREFETCHSTATUS_UNDERFLOW, bu veri kaynağında düzeltilemeyen 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. Ancak gelecekteki ikili program uyumluluğu için, mevcut proje yönetimi metodolojilerini bir hata bildirme yöntemi kullanmanızı öneririz.

Özetle, önerilen bir kod dizisi şöyledir:

  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, senkronizasyonunu engellemesi, tüm üretim kodları için kritik öneme sahiptir.

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 hakkında bilgi edindiniz. 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_t pthread_self() veya pid_t, gettid() tarafından şu şekilde döndürüldü: ve aramalar arasında tutarlılık sağlar. Aynı nedenle şunun gibi iş parçacığı yerel depolama (TLS) API'lerini kullanmayın: Bir geri aramadan pthread_setspecific() ve pthread_getspecific().

Uygulama, Search Ads 360 için aynı türde eşzamanlı geri çağırmaların aynı nesne için meydana gelmez. Bununla birlikte, yardımcı olabilir.

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 kullanımı, daha düşük ses gecikmesi ve daha yüksek ses gibi geliştirmeleri garanti etmez platformun sağladığı önceliklerden daha önceliklidir. 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 tür gelişmelerden biri de ses çıkışı gecikmesi. 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. Az önce bahsedilen özellik testiyle birlikte uygulamalar artık kendini yapılandırabilir uygun şekilde otomatikleştirmenizi sağlar.

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: URL parametrelerinin Google tarafından nasıl ele alınmasını istediğinizi belirtmek için Ses Arabelleği Boyutu OpenSL ES ses için yerel arabellek boyutunu ve örnek hızını belirleyen test uygulaması ses cihazınızdaki uygulamalar. Ayrıca, adresini görüntülemek için GitHub'ı ziyaret edebilirsiniz ses-arabellek boyutu örnekleri.

Düşük gecikmeli ses çalarları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, karşılıklı müzakerelerde, koşullarda, veya G/Ç işlemleri. 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ğlar. 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. Özetle, ideal olan, görevlerin çoğunun işleyicinin sıfıra yakın varyansa sahip olmasını ve işleyicinin sınırsız zamanlarda engelleme yapmamasını sağlar.

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'i tıklayın.

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 şunu onaylayın: daha düşük gecikmeli çıkışın yukarıda açıklandığı gibi mevcuttur. 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. Eşzamansız örnek hızına yönelik basit (ancak ses kalitesi için ideal değildir) bir teknik bir sıfır kesişim noktasına yakın bir noktada örnekleri gerektiği gibi kopyalamak veya bırakmaktır. 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

Kimin ne yapabileceğine gelince Android'de güvenlik işlem düzeyinde yapılır. Java programlama dil kodu, yerel koddan başka bir şey yapamaz, yerel kod da Java programlama dili kodu. 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.