หมายเหตุเกี่ยวกับการเขียนโปรแกรม OpenSL ES

คำเตือน: OpenSL ES เลิกใช้งานแล้ว นักพัฒนาซอฟต์แวร์ควรใช้โอเพนซอร์ส ไลบรารีโอโบที่พร้อมใช้งานบน GitHub Oboe เป็น Wrapper ของ C++ ที่มี API ที่คล้ายกับ AAudio มาก โอโบเรียก AAudio เมื่อ AAudio เป็น ว่าง และจะกลับไปใช้ OpenSL ES หาก AAudio ไม่พร้อมใช้งาน

หมายเหตุในส่วนนี้ช่วยเสริม OpenSL ES 1.0.1 ข้อกำหนดเฉพาะ

ออบเจ็กต์และการเริ่มต้นอินเทอร์เฟซ

2 ด้านของรูปแบบการเขียนโปรแกรม OpenSL ES ที่นักพัฒนาแอปมือใหม่อาจไม่คุ้นเคยคือความแตกต่างระหว่างออบเจ็กต์กับอินเทอร์เฟซ และลําดับการเริ่มต้น

กล่าวโดยย่อ ออบเจ็กต์ OpenSL ES จะคล้ายกับแนวคิดออบเจ็กต์ในภาษาโปรแกรม เช่น Java และ C++ ยกเว้นออบเจ็กต์ OpenSL ES จะมองเห็นได้ผ่านอินเทอร์เฟซที่เกี่ยวข้องเท่านั้น ซึ่งรวมถึง อินเทอร์เฟซเริ่มต้นสำหรับออบเจ็กต์ทั้งหมด ซึ่งเรียกว่า SLObjectItf จะไม่มีแฮนเดิลสำหรับออบเจ็กต์เอง มีเพียงแฮนเดิลสำหรับอินเทอร์เฟซ SLObjectItf ของออบเจ็กต์เท่านั้น

ระบบจะสร้างออบเจ็กต์ OpenSL ES ก่อน ซึ่งจะแสดงผล SLObjectItf จากนั้นจึงสร้าง ซึ่งคล้ายกับรูปแบบการเขียนโปรแกรมทั่วไปของการสร้าง (ซึ่งไม่ควรล้มเหลวนอกเหนือจากการขาดหน่วยความจำหรือพารามิเตอร์ที่ไม่ถูกต้อง) จากนั้น เริ่มต้นให้เสร็จสมบูรณ์ (ซึ่งอาจล้มเหลวเนื่องจากมีทรัพยากรไม่เพียงพอ) ขั้นตอนการรับรู้จะทำให้คุณ วางพื้นที่ที่เหมาะสมเพื่อจัดสรรทรัพยากรเพิ่มเติม หากจำเป็น

แอปพลิเคชันจะระบุอาร์เรย์ของอินเทอร์เฟซที่ต้องการ ซึ่งเป็นส่วนหนึ่งของ API ในการสร้างออบเจ็กต์ บริษัทมีแผนจะซื้อกิจการในภายหลัง โปรดทราบว่าอาร์เรย์นี้จะไม่สร้าง การได้มาซึ่งอินเทอร์เฟซ แต่แสดงถึงความตั้งใจในอนาคตที่จะได้มาซึ่งกลุ่มเป้าหมาย อินเทอร์เฟซแบ่งออกเป็น implicit หรือ Explicit ต้องระบุอินเทอร์เฟซที่ชัดเจนไว้ในอาร์เรย์ ถ้า จะได้รับในภายหลัง อินเทอร์เฟซโดยนัยไม่จำเป็นต้องแสดงอยู่ใน สร้างอาร์เรย์ของออบเจ็กต์ แต่ ก็ไม่เสียหายใดๆ ในรายชื่อนั้น OpenSL ES มีอินเทอร์เฟซอีกหนึ่งชนิดที่เรียกว่า ไดนามิก ซึ่งไม่จำเป็นต้องระบุในออบเจ็กต์ สร้างอาร์เรย์และเพิ่มได้ หลังจากสร้างออบเจ็กต์แล้ว การใช้ Android ช่วยให้ คุณลักษณะที่ช่วยให้ ให้หลีกเลี่ยงความซับซ้อนนี้ ซึ่งอธิบายไว้ใน อินเทอร์เฟซแบบไดนามิกในการสร้างออบเจ็กต์

หลังจากสร้างออบเจ็กต์และรับรู้แล้ว แอปพลิเคชันควรได้รับอินเทอร์เฟซสำหรับแต่ละ ฟีเจอร์ที่ต้องการ โดยใช้ GetInterface ใน SLObjectItf เริ่มต้น

สุดท้าย สามารถใช้ออบเจ็กต์ผ่านอินเทอร์เฟซได้ แต่โปรดทราบว่า ออบเจ็กต์บางอย่างต้องการ ตั้งค่าเพิ่มเติม โดยเฉพาะอย่างยิ่งโปรแกรมเล่นเสียงที่มีแหล่งข้อมูล URI ต้องการ การเตรียมความพร้อมเพิ่มเติมใน เพื่อตรวจหาข้อผิดพลาดในการเชื่อมต่อ โปรดดู ดูรายละเอียดในส่วนการดึงข้อมูลโปรแกรมเล่นเสียงล่วงหน้า

หลังจากแอปพลิเคชันใช้งานออบเจ็กต์เสร็จแล้ว คุณควรทำลายออบเจ็กต์อย่างชัดเจน ดูส่วนทำลายด้านล่าง

การดึงข้อมูลโปรแกรมเล่นเสียงล่วงหน้า

Object::Realize จะจัดสรรสำหรับโปรแกรมเล่นเสียงที่มีแหล่งข้อมูล URI แต่ไม่ เชื่อมต่อกับแหล่งข้อมูล (เตรียมพร้อม) หรือเริ่มดึงข้อมูลล่วงหน้า ซึ่งจะเกิดขึ้นเมื่อตั้งค่าสถานะผู้เล่นเป็น SL_PLAYSTATE_PAUSED หรือ SL_PLAYSTATE_PLAYING

ข้อมูลบางอย่างอาจยังไม่ทราบจนกว่าจะเข้าสู่ช่วงท้ายของลำดับนี้ โดยเฉพาะอย่างยิ่ง ในช่วงแรก Player::GetDuration จะแสดงผลเป็น SL_TIME_UNKNOWN และ MuteSolo::GetChannelCount จะแสดงผลสำเร็จโดยมีจํานวนช่องเป็น 0 หรือแสดงผลลัพธ์ที่เป็นข้อผิดพลาด SL_RESULT_PRECONDITIONS_VIOLATED API เหล่านี้จะแสดงค่าที่เหมาะสม ทันทีที่เป็นที่รู้จัก

พร็อพเพอร์ตี้อื่นๆ ที่ไม่ทราบตั้งแต่แรกได้แก่ อัตราการสุ่มตัวอย่าง และ ประเภทเนื้อหาสื่อตามจริง โดยอิงจากการตรวจสอบส่วนหัวของเนื้อหา (ตรงข้ามกับ ประเภท MIME ที่ระบุแอปพลิเคชันและ ประเภทคอนเทนเนอร์) ซึ่งจะพิจารณาในภายหลังระหว่าง เตรียมพร้อม/ดึงข้อมูลล่วงหน้า แต่ไม่มี API สำหรับ เพื่อเรียกดูข้อมูล

อินเทอร์เฟซสถานะการดึงข้อมูลล่วงหน้ามีประโยชน์ในการตรวจหาเมื่อข้อมูลทั้งหมด พร้อมใช้งาน หรือ แอปพลิเคชันสามารถสำรวจความคิดเห็นเป็นระยะๆ โปรดทราบว่าข้อมูลบางอย่าง เช่น ระยะเวลาการสตรีม MP3 อาจไม่อาจรู้จักได้

อินเทอร์เฟซสถานะการดึงข้อมูลล่วงหน้ายังมีประโยชน์ในการตรวจหาข้อผิดพลาดด้วย ลงทะเบียนการเรียกกลับ และเปิดใช้เหตุการณ์ SL_PREFETCHEVENT_FILLLEVELCHANGE และ SL_PREFETCHEVENT_STATUSCHANGE เป็นอย่างน้อย หากทั้ง 2 เหตุการณ์นี้นำส่งพร้อมกัน และ PrefetchStatus::GetFillLevel รายงานระดับเป็น 0 และ PrefetchStatus::GetPrefetchStatus รายงาน SL_PREFETCHSTATUS_UNDERFLOW แล้วนี่ ระบุข้อผิดพลาดที่กู้คืนไม่ได้ในแหล่งข้อมูล ซึ่งรวมถึงกรณีที่เชื่อมต่อกับแหล่งข้อมูลไม่ได้เนื่องจากไม่มีชื่อไฟล์ในเครื่องหรือ URI ของเครือข่ายไม่ถูกต้อง

คาดว่า OpenSL ES เวอร์ชันถัดไปจะเพิ่มการสนับสนุนที่ชัดเจนมากขึ้นสำหรับ การจัดการข้อผิดพลาดใน แหล่งข้อมูล อย่างไรก็ตาม เราจะยังคงรองรับวิธีการปัจจุบันในการรายงานข้อผิดพลาดที่กู้คืนไม่ได้ต่อไปเพื่อรองรับการใช้งานไฟล์ไบนารีในอนาคต

โดยสรุป ลำดับโค้ดที่แนะนำคือ

  1. Engine::CreateAudioPlayer
  2. Object:Realize
  3. Object::GetInterface เป็นเวลา SL_IID_PREFETCHSTATUS
  4. PrefetchStatus::SetCallbackEventsMask
  5. PrefetchStatus::SetFillUpdatePeriod
  6. PrefetchStatus::RegisterCallback
  7. Object::GetInterface เป็นเวลา SL_IID_PLAY
  8. Play::SetPlayState ถึง SL_PLAYSTATE_PAUSED หรือ SL_PLAYSTATE_PLAYING

หมายเหตุ: การเตรียมและการดึงข้อมูลล่วงหน้าเกิดขึ้นที่นี่ ในระหว่างนี้จะมีการเรียก Callback ของคุณด้วย การอัปเดตสถานะเป็นระยะ

ทำลาย

อย่าลืมทำลายออบเจ็กต์ทั้งหมดเมื่อออกจากแอปพลิเคชันของคุณ ควรทำลายออบเจ็กต์ใน ย้อนลำดับการสร้างผลงานเนื่องจากการทำลายวัตถุที่พึ่งพาไม่ได้ ออบเจ็กต์ เช่น ลบตามลำดับต่อไปนี้ โปรแกรมเล่นและเครื่องบันทึกเสียง การมิกซ์เอาต์พุต จากนั้น สุดท้ายคือเครื่องยนต์

OpenSL ES ไม่รองรับการเก็บขยะอัตโนมัติ หรือ แหล่งอ้างอิง การนับของอินเทอร์เฟซ หลังจากเรียก Object::Destroy แล้ว อินเทอร์เฟซที่มีอยู่ทั้งหมดซึ่งมาจากออบเจ็กต์ที่เชื่อมโยงจะกลายเป็น "ไม่ระบุ"

การใช้งาน Android OpenSL ES ไม่ตรวจพบการใช้อินเทอร์เฟซดังกล่าวอย่างไม่ถูกต้อง การใช้อินเทอร์เฟซดังกล่าวต่อไปหลังจากออบเจ็กต์ถูกทำลายอาจทำให้แอปพลิเคชัน ขัดข้องหรือทำงานในลักษณะที่คาดเดาไม่ได้

เราขอแนะนำให้คุณตั้งค่าทั้งอินเทอร์เฟซออบเจ็กต์หลักและอินเทอร์เฟซที่เชื่อมโยงทั้งหมดอย่างชัดเจน เชื่อมต่อกับ NULL เป็นส่วนหนึ่งของลำดับการทำลายวัตถุของคุณ ซึ่งจะป้องกันเหตุการณ์ การใช้แฮนเดิลอินเทอร์เฟซที่ไม่อัปเดตในทางที่ผิด

การแพนกล้องแบบสเตอริโอ

เมื่อใช้ Volume::EnableStereoPosition เพื่อเปิดการแพนเสียงสเตอริโอของเสียงแบบโมโน เสียงจะลดลงทั้งหมด 3 dB พลังเสียง ระดับ จำเป็นต้องทำให้ระดับพลังเสียงรวมคงที่ตาม แหล่งที่มาคือ จากช่องหนึ่งไปยังอีกช่องหนึ่ง ดังนั้น ให้เปิดใช้การกำหนดตำแหน่งเสียงสเตอริโอเฉพาะเมื่อจำเป็นเท่านั้น สำหรับข้อมูลเพิ่มเติม โปรดดูบทความ Wikipedia เกี่ยวกับ การแพนเสียง

การติดต่อกลับและชุดข้อความ

โดยทั่วไป เครื่องจัดการการเรียกกลับจะถูกเรียกแบบซิงโครนัสเมื่อการใช้งานตรวจพบ กิจกรรม จุดนี้ไม่พร้อมกันในแง่ของแอปพลิเคชัน ดังนั้นคุณควรใช้แบบไม่บล็อก กลไกการซิงค์เพื่อควบคุมการเข้าถึงตัวแปรที่แชร์ระหว่างแอปพลิเคชันและ Callback Handler ในโค้ดตัวอย่าง เช่น สำหรับคิวบัฟเฟอร์ เราละไว้ การซิงค์หรือใช้การบล็อกการซิงค์เพื่อความง่าย อย่างไรก็ตาม การปฏิบัติตามข้อกำหนด การซิงค์การบล็อกมีความสำคัญอย่างยิ่งสำหรับโค้ดที่ใช้งานจริง

แฮนเดิลการเรียกกลับจะเรียกจากเธรดภายในที่ไม่ใช่แอปพลิเคชันซึ่งไม่ได้แนบอยู่กับรันไทม์ Android จึงไม่มีสิทธิ์ใช้ JNI เนื่องจากชุดข้อความภายใน สำคัญอย่างยิ่งต่อ ความสมบูรณ์ของการใช้งาน OpenSL ES เครื่องจัดการ Callback ก็ไม่ควรบล็อก หรือดำเนินการ งานมากเกินไป

หากตัวแฮนเดิล Callback ของคุณจำเป็นต้องใช้ JNI หรือเรียกใช้งานที่ไม่ได้เป็นสัดส่วนกับ Callback ตัวแฮนเดิลควรโพสต์เหตุการณ์เพื่อให้เทรดอื่นประมวลผลแทน ตัวอย่างของ ภาระงานของ Callback ที่ยอมรับได้รวมถึงการแสดงผลและการจัดคิวบัฟเฟอร์เอาต์พุตถัดไป (สำหรับ AudioPlayer) กำลังประมวลผลบัฟเฟอร์อินพุตที่เพิ่งป้อนและจัดคิวถัดไป บัฟเฟอร์ว่าง (สำหรับ AudioRecorder) หรือ API ทั่วไป เช่น ตระกูล Get ส่วนใหญ่ โปรดดู ส่วนประสิทธิภาพด้านล่างเกี่ยวกับภาระงาน

โปรดทราบว่าการดำเนินการแบบย้อนกลับนั้นปลอดภัย นั่นคือ อนุญาตให้เธรดแอปพลิเคชัน Android ที่เข้าสู่ JNI เรียกใช้ OpenSL ES API ได้โดยตรง รวมถึง API ที่บล็อก แต่การบล็อกสายเรียกเข้าจะไม่ ที่แนะนำจากเทรดหลัก เนื่องจากอาจทําให้ แอปพลิเคชันไม่ตอบสนอง (ANR)

การตัดสินใจเกี่ยวกับเทรดที่เรียกใช้ตัวแฮนเดิล Callback มักขึ้นอยู่กับ การใช้งานของคุณ เหตุผลที่มีความยืดหยุ่นนี้คือการอนุญาตให้มีการเพิ่มประสิทธิภาพในอนาคต โดยเฉพาะใน อุปกรณ์หลายแกน

เราไม่รับประกันว่าเทรดที่ตัวแฮนเดิล Callback ทำงานจะมีข้อมูลระบุตัวตนเดียวกัน การโทรต่างๆ ดังนั้นโปรดอย่าอาศัย pthread_t ที่แสดงผลโดย pthread_self() หรือ pid_t ส่งคืนโดย gettid() สอดคล้องกันในทุกการโทร ด้วยเหตุเดียวกันนี้ คุณจึงไม่ควรใช้ API พื้นที่เก็บข้อมูลในระบบของเธรด (TLS) เช่น pthread_setspecific() และ pthread_getspecific() จากคอลแบ็ก

การใช้งานจะรับประกันว่าจะมีการส่งกลับประเภทเดียวกันพร้อมกันสำหรับ วัตถุเดียวกันไม่ ไม่ได้เกิดขึ้น อย่างไรก็ตาม อาจมีการเรียกกลับพร้อมกันประเภทต่างๆ สำหรับออบเจ็กต์เดียวกันใน ชุดข้อความต่างๆ กัน

ประสิทธิภาพ

เนื่องจาก OpenSL ES เป็น C API ดั้งเดิม เธรดแอปพลิเคชันที่ไม่ใช่รันไทม์ซึ่งเรียกใช้ OpenSL ES จะไม่มีข้อมูล ค่าใช้จ่ายในการดำเนินการที่เกี่ยวข้องกับรันไทม์ เช่น การหยุดเก็บรวบรวมขยะไว้ชั่วคราว โดยมีข้อยกเว้น 1 ข้อที่อธิบายไว้ด้านล่าง การใช้ OpenSL ES ไม่มีประโยชน์เพิ่มเติมด้านประสิทธิภาพนอกเหนือจากเรื่องนี้ โดยเฉพาะอย่างยิ่ง การใช้ OpenSL ES ไม่ได้รับประกันว่าจะสามารถเพิ่มประสิทธิภาพ เช่น เวลาในการตอบสนองของเสียงที่ต่ำลง ลำดับความสำคัญของกำหนดการที่แพลตฟอร์มมีให้โดยทั่วไป ในทางกลับกัน ในฐานะที่เป็น แอปพลิเคชัน OpenSL ES ยังคงพัฒนาแพลตฟอร์ม Android และการใช้งานอุปกรณ์ที่เฉพาะเจาะจงอย่างต่อเนื่อง จะได้รับประโยชน์จากการปรับปรุงประสิทธิภาพของระบบในอนาคต

หนึ่งในการเปลี่ยนแปลงดังกล่าวคือการรองรับเวลาในการตอบสนองของเอาต์พุตเสียงที่ลดลง รากฐานสำหรับ เวลาในการตอบสนองของเอาต์พุตรวมอยู่ใน Android 4.1 (API ระดับ 16) ก่อน จากนั้น ความคืบหน้าอย่างต่อเนื่องเกิดขึ้นใน Android 4.2 (API ระดับ 17) การปรับปรุงเหล่านี้พร้อมใช้งานผ่าน OpenSL ES สําหรับการติดตั้งใช้งานอุปกรณ์ที่อ้างสิทธิ์ฟีเจอร์ android.hardware.audio.low_latency หากอุปกรณ์ไม่ได้อ้างสิทธิ์ฟีเจอร์นี้ แต่รองรับ Android 2.3 (API ระดับ 9) หรือหลังจากนั้น คุณจะยังสามารถใช้ OpenSL ES API ได้ แต่เวลาในการตอบสนองของเอาต์พุตอาจสูงขึ้น ยิ่งน้อย เส้นทางเวลาในการตอบสนองของเอาต์พุตใช้เฉพาะในกรณีที่แอปพลิเคชันขอขนาดบัฟเฟอร์และอัตราการสุ่มตัวอย่างเท่านั้น ที่ เข้ากันได้กับการกำหนดค่าเอาต์พุตดั้งเดิมของอุปกรณ์ พารามิเตอร์เหล่านี้เป็นพารามิเตอร์เฉพาะอุปกรณ์และควรได้รับตามที่อธิบายไว้ด้านล่าง

เริ่มตั้งแต่ Android 4.2 (API ระดับ 17) แอปพลิเคชันสามารถค้นหา อัตราการสุ่มตัวอย่างและขนาดบัฟเฟอร์เอาต์พุตดั้งเดิมของแพลตฟอร์มหรือที่ดีที่สุดสำหรับเอาต์พุตหลักของอุปกรณ์ สตรีม เมื่อรวมกับการทดสอบฟีเจอร์ที่เพิ่งพูดถึง ตอนนี้แอปกำหนดค่าตัวเองได้แล้ว อย่างเหมาะสมสำหรับเอาต์พุตของเวลาในการตอบสนองที่ลดลงในอุปกรณ์ที่กล่าวอ้างถึงการรองรับ

สำหรับ Android 4.2 (API ระดับ 17) และเวอร์ชันก่อนหน้า จำนวนบัฟเฟอร์ตั้งแต่ 2 รายการขึ้นไปคือ เพื่อเวลาในการตอบสนองที่ต่ำ เริ่มตั้งแต่ Android 4.3 (API ระดับ 18) แค่ 1 ครั้งก็เพียงพอสำหรับเวลาในการตอบสนองต่ำ

อินเทอร์เฟซ OpenSL ES ทั้งหมดสำหรับเอฟเฟกต์เอาต์พุตจะป้องกันไม่ให้เส้นทางเวลาในการตอบสนองต่ำ

ลำดับที่แนะนำมีดังนี้

  1. ตรวจสอบ API ระดับ 9 ขึ้นไปเพื่อยืนยันการใช้ OpenSL ES
  2. ตรวจสอบฟีเจอร์ android.hardware.audio.low_latency โดยใช้โค้ด เช่น

    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. ตรวจสอบ API ระดับ 17 ขึ้นไปเพื่อยืนยันการใช้ android.media.AudioManager.getProperty()
  4. รับอัตราตัวอย่างและขนาดบัฟเฟอร์สำหรับเอาต์พุตเนทีฟหรือที่ดีที่สุดสำหรับอุปกรณ์นี้ เอาต์พุตหลัก สตรีมโดยใช้โค้ดดังต่อไปนี้

    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 และ framesPerBuffer เป็นสตริง ก่อนอื่นให้ตรวจสอบว่าค่าเป็น null หรือไม่ จากนั้นแปลงเป็น int โดยใช้ Integer.parseInt()
  5. ใช้ OpenSL ES เพื่อสร้าง AudioPlayer พร้อมตัวระบุตำแหน่งข้อมูลคิวบัฟเฟอร์ PCM

หมายเหตุ: คุณสามารถใช้ ขนาดบัฟเฟอร์ของเสียง แอปทดสอบเพื่อระบุขนาดบัฟเฟอร์ดั้งเดิมและอัตราการสุ่มตัวอย่างสำหรับเสียง OpenSL ES แอปพลิเคชันบนอุปกรณ์เสียงของคุณ คุณยังไปที่ GitHub เพื่อดู ได้ด้วย ตัวอย่างขนาดบัฟเฟอร์เสียง

มีการจำกัดจำนวนโปรแกรมเล่นเสียงที่มีเวลาในการตอบสนองต่ำ หากแอปพลิเคชันของคุณต้องใช้ มากกว่า 2-3 สำหรับแหล่งที่มาของเสียง ให้ลองมิกซ์เสียงที่ระดับแอปพลิเคชัน อย่าลืมทำลายเสียงของคุณ เมื่อกิจกรรมหยุดชั่วคราว เนื่องจากเป็นทรัพยากรส่วนกลางที่แชร์กับแอปอื่นๆ

แฮนเดิลการเรียกกลับคิวบัฟเฟอร์ต้องดำเนินการภายในกรอบเวลาขนาดเล็กที่คาดการณ์ได้เพื่อหลีกเลี่ยงข้อบกพร่องที่ได้ยิน ซึ่งก็หมายความว่าไม่มีการบล็อกแบบไม่มีขอบเขตใน Mutex, เงื่อนไข หรือ I/O ให้ลองใช้try locks, ล็อกและรอโดยมีการหมดเวลา และอัลกอริทึมที่ไม่มีการบล็อกแทน

การคํานวณที่จําเป็นสําหรับการแสดงผลบัฟเฟอร์ถัดไป (สําหรับ AudioPlayer) หรือการใช้บัฟเฟอร์ก่อนหน้า (สําหรับ AudioRecord) ควรใช้เวลาเท่าๆ กันสําหรับการเรียกกลับแต่ละครั้ง หลีกเลี่ยงอัลกอริทึมที่ทำงานโดยไม่กำหนดเวลาหรือมีปริมาณสูง ในการคำนวณได้อีกด้วย การคํานวณการเรียกกลับจะทำงานเป็นช่วงๆ หากเวลาที่ใช้ CPU ในการเรียกกลับหนึ่งๆ นานกว่าค่าเฉลี่ยอย่างมาก กล่าวโดยสรุปคือเหมาะสำหรับ เวลาในการดำเนินการ CPU เครื่องจัดการให้มีค่าความแปรปรวนใกล้ 0 และเพื่อให้ตัวแฮนเดิลไม่บล็อกสำหรับเวลาที่ไม่มีขอบเขต

เวลาในการตอบสนองจะต่ำลงสำหรับเอาต์พุตต่อไปนี้เท่านั้น

ในบางอุปกรณ์ เวลาในการตอบสนองของลำโพงสูงกว่าเส้นทางอื่นๆ เนื่องจากการประมวลผลสัญญาณดิจิทัลสำหรับ การแก้ไขและการปกป้องลำโพง

สำหรับ Android 5.0 (API ระดับ 21) เวลาในการตอบสนองต่ำลง อินพุตเสียงใช้ได้กับอุปกรณ์บางรุ่น ยืนยันก่อนเพื่อใช้ประโยชน์จากฟีเจอร์นี้ เอาต์พุตของเวลาในการตอบสนองที่ต่ำกว่านั้นมีให้ตามที่อธิบายไว้ข้างต้น ความสามารถในการลดเวลาในการตอบสนอง เป็นข้อกำหนดเบื้องต้นสำหรับฟีเจอร์อินพุตของเวลาในการตอบสนองที่ต่ำ จากนั้น ให้สร้างโปรแกรมบันทึกเสียงด้วย อัตราการสุ่มตัวอย่างและขนาดบัฟเฟอร์ตามที่จะใช้ในการแสดงผล อินเทอร์เฟซ OpenSL ES สำหรับเอฟเฟกต์การป้อนข้อมูล จะป้องกันเส้นทางเวลาในการตอบสนองที่ต่ำกว่า ค่าที่กำหนดล่วงหน้าของการบันทึก ต้องใช้ SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION เพื่อให้เวลาในการตอบสนองต่ำลง นี้ ค่าที่กำหนดล่วงหน้าจะปิดใช้การประมวลผลสัญญาณดิจิทัลเฉพาะอุปกรณ์ ซึ่งอาจเพิ่มเวลาในการตอบสนองให้กับเส้นทางอินพุต ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าที่กำหนดล่วงหน้าของระเบียนได้ที่ การกำหนดค่า Android ของอินเทอร์เฟซด้านบน

สำหรับอินพุตและเอาต์พุตพร้อมกัน ระบบจะใช้ตัวจัดการคิวบัฟเฟอร์แยกกันสำหรับแต่ละรายการ ไม่มีการรับประกันอันดับที่เกี่ยวข้องของ Callback เหล่านี้ หรือการซิงค์ แม้ว่าทั้ง 2 ฝั่งจะใช้อัตราการสุ่มตัวอย่างเดียวกันก็ตาม การสมัครของคุณ ควรบัฟเฟอร์ ข้อมูลที่มีการซิงค์บัฟเฟอร์อย่างเหมาะสม

ผลที่ตามมาหนึ่งของนาฬิกาเสียงที่อาจเป็นอิสระคือความต้องการอัตราการสุ่มตัวอย่างแบบไม่พร้อมกัน Conversion เทคนิคง่ายๆ (แต่ไม่เหมาะสำหรับคุณภาพเสียง) สำหรับอัตราการสุ่มตัวอย่างแบบไม่พร้อมกัน Conversion คือ การทำซ้ำหรือปล่อยตัวอย่างตามความจำเป็นใกล้กับจุดตัดขวางที่เป็นศูนย์ ซับซ้อนมากขึ้น Conversion ได้

โหมดประสิทธิภาพ

ตั้งแต่ Android 7.1 (API ระดับ 25) OpenSL ES ได้แนะนำวิธีระบุโหมดประสิทธิภาพ สำหรับเส้นทางเสียง ตัวเลือกมีดังนี้

  • SL_ANDROID_PERFORMANCE_NONE: ไม่มีข้อกำหนดด้านประสิทธิภาพที่เฉพาะเจาะจง อนุญาตเอฟเฟกต์ฮาร์ดแวร์และซอฟต์แวร์
  • SL_ANDROID_PERFORMANCE_LATENCY: ให้ความสำคัญกับเวลาในการตอบสนอง ไม่มีเอฟเฟกต์ฮาร์ดแวร์หรือซอฟต์แวร์ นี่คือโหมดเริ่มต้น
  • SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS: กำหนดลำดับความสำคัญให้กับเวลาในการตอบสนอง ในขณะที่ยังอนุญาตให้ใช้เอฟเฟกต์ฮาร์ดแวร์และซอฟต์แวร์ได้
  • SL_ANDROID_PERFORMANCE_POWER_SAVING: ลำดับความสำคัญที่สำคัญต่อการประหยัดพลังงาน อนุญาตเอฟเฟกต์ฮาร์ดแวร์และซอฟต์แวร์

หมายเหตุ: หากไม่ต้องการเส้นทางที่มีเวลาในการตอบสนองต่ำและต้องการใช้ประโยชน์จากเอฟเฟกต์เสียงในตัวของอุปกรณ์ (เช่น เพื่อปรับปรุงคุณภาพเสียงสำหรับการเล่นวิดีโอ) คุณต้องตั้งค่าโหมดประสิทธิภาพเป็น SL_ANDROID_PERFORMANCE_NONE อย่างชัดเจน

หากต้องการตั้งค่าโหมดประสิทธิภาพ คุณต้องโทรหา SetConfiguration โดยใช้ Android ของอินเทอร์เฟซการกำหนดค่า ดังที่แสดงด้านล่าง

  // 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));

ความปลอดภัยและสิทธิ์

ความปลอดภัยใน Android ทำงานในระดับกระบวนการ ในแง่ของผู้ใช้ที่มีสิทธิ์ดำเนินการต่างๆ การเขียนโปรแกรม Java โค้ดภาษาไม่สามารถทำอะไรมากไปกว่าโค้ดแบบเนทีฟ และโค้ดแบบเนทีฟไม่สามารถทำอะไรได้มากกว่า รหัสภาษาโปรแกรม Java สิ่งเดียวที่แตกต่างกันคือ API ที่ใช้ได้

แอปพลิเคชันที่ใช้ OpenSL ES ต้องขอสิทธิ์ที่ต้องใช้สำหรับ API ที่ไม่ใช่แบบเนทีฟ เช่น หากแอปพลิเคชันบันทึกเสียง ก็จะต้องมีสิทธิ์ android.permission.RECORD_AUDIO แอปพลิเคชันที่ใช้เอฟเฟกต์เสียงจำเป็นต้องใช้ android.permission.MODIFY_AUDIO_SETTINGS แอปพลิเคชันที่เล่นทรัพยากร URI ของเครือข่าย ต้องการ android.permission.NETWORK ดูข้อมูลเพิ่มเติมได้ที่หัวข้อการทํางานกับสิทธิ์ของระบบ

โปรแกรมแยกวิเคราะห์เนื้อหาสื่อ และ ตัวแปลงรหัสของซอฟต์แวร์อาจ ทำงานภายในบริบทของแอปพลิเคชัน Android ที่เรียกใช้ OpenSL ES (ตัวแปลงรหัสฮาร์ดแวร์ ที่เป็นนามธรรมแต่ขึ้นอยู่กับอุปกรณ์) มีเนื้อหาผิดรูปแบบที่ออกแบบมาเพื่อใช้ประโยชน์จากโปรแกรมแยกวิเคราะห์และตัวแปลงรหัส ช่องโหว่คือเวกเตอร์การโจมตีที่เรารู้จัก เราขอแนะนำให้คุณเล่นสื่อจากความน่าเชื่อถือเท่านั้น หรือคุณแบ่งส่วนแอปพลิเคชันของคุณในลักษณะที่เป็นโค้ดที่จัดการสื่อ แหล่งที่มาที่ไม่น่าเชื่อถือทำงานในสภาพแวดล้อมที่แซนด์บ็อกซ์ ตัวอย่างเช่น คุณสามารถ ประมวลผลสื่อจากแหล่งที่มาที่ไม่น่าเชื่อถือในกระบวนการที่แยกต่างหาก แม้ว่าทั้ง 2 กระบวนการจะยังคงทำงานภายใต้ UID เดียวกัน แต่การแยกนี้ทำให้การโจมตีทำได้ยากขึ้น