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

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

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

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

กล่าวโดยสรุปคือ ออบเจ็กต์ 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 ในโค้ดตัวอย่าง เช่น สำหรับคิวบัฟเฟอร์ เราละไว้ การซิงค์หรือใช้การบล็อกการซิงค์เพื่อความง่าย อย่างไรก็ตาม การปฏิบัติตามข้อกำหนด การซิงค์การบล็อกมีความสำคัญอย่างยิ่งสำหรับโค้ดที่ใช้งานจริง

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

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

โปรดทราบว่าการสนทนานั้นปลอดภัย: เทรดของแอปพลิเคชัน Android ที่ได้ป้อน JNI ได้รับอนุญาตให้ เรียกใช้ API ของ OpenSL ES โดยตรง รวมถึง 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 สำหรับแหล่งที่มาของเสียง ให้ลองมิกซ์เสียงที่ระดับแอปพลิเคชัน อย่าลืมทำลายเสียงของคุณ เมื่อกิจกรรมหยุดชั่วคราว เนื่องจากเป็นทรัพยากรส่วนกลางที่แชร์กับแอปอื่นๆ

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

การคำนวณที่จำเป็นในการแสดงผลบัฟเฟอร์ถัดไป (สำหรับ AudioPlayer) หรือใช้บัฟเฟอร์ก่อนหน้า บัฟเฟอร์ (สำหรับ AudioRecord) ควรใช้เวลาประมาณเท่าเดิมสำหรับการเรียกกลับแต่ละครั้ง หลีกเลี่ยงอัลกอริทึมที่ทำงานโดยไม่กำหนดเวลาหรือมีปริมาณสูง ในการคำนวณได้อีกด้วย การคำนวณการเรียกกลับมีจำนวนมาก หากเวลา CPU ที่ใช้ใน Callback ที่ระบุ สูงกว่าค่าเฉลี่ยอย่างมาก กล่าวโดยสรุปคือเหมาะสำหรับ เวลาในการดำเนินการ 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 (ตัวแปลงรหัสฮาร์ดแวร์ ที่เป็นนามธรรมแต่ขึ้นอยู่กับอุปกรณ์) มีเนื้อหาผิดรูปแบบที่ออกแบบมาเพื่อใช้ประโยชน์จากโปรแกรมแยกวิเคราะห์และตัวแปลงรหัส ช่องโหว่คือเวกเตอร์การโจมตีที่เรารู้จัก เราขอแนะนำให้คุณเล่นสื่อจากความน่าเชื่อถือเท่านั้น หรือคุณแบ่งส่วนแอปพลิเคชันของคุณในลักษณะที่เป็นโค้ดที่จัดการสื่อ แหล่งที่มาที่ไม่น่าเชื่อถือทำงานในสภาพแวดล้อมที่แซนด์บ็อกซ์ ตัวอย่างเช่น คุณสามารถ ประมวลผลสื่อจากแหล่งที่มาที่ไม่น่าเชื่อถือในกระบวนการที่แยกต่างหาก แม้ว่าทั้งสองกระบวนการจะ ที่ทำงานภายใต้ UID เดียวกัน การแยกนี้จะทำให้การโจมตีทำได้ยากขึ้น