ค้นหาเว็บไซต์

angular - การใช้ typescript/web audio api บน ios


ฉันกำลังทำงานบนเว็บไซต์ที่จะเล่นไฟล์เสียงโดยใช้ Web Audio API ฉันกำลังใช้ TypeScript และ Angular 2 ใน Visual Studio Code ทุกอย่างทำงานได้ดีบนแพลตฟอร์มอื่น ๆ ยกเว้น iOS; แต่บนเช่น iPad ฉันพบข้อผิดพลาดที่ทำให้สับสนบางอย่าง

ปัญหาแรกคือวิธีการหาค่า AudioContext ที่สามารถใช้งานได้ทั้งบนแพลตฟอร์ม iOS และไม่ใช่ iOS ฉันรู้ว่ามันสามารถทำได้ด้วย JavaScript ธรรมดา เช่น http://gopherwoodstudios.com/wa/mp3/test.htm ความจำเป็นในการกดปุ่มค่อนข้างน่ารำคาญ แต่ฉันสามารถอยู่กับมันได้ ดังนั้นฉันคิดว่าปัญหาที่ฉันเจอนั้นเกี่ยวข้องกับ TypeScript (ฉันยังเป็นมือใหม่กับ TypeScript ดังนั้นอาจจะเข้าใจพื้นฐานบางอย่างผิดก็ได้)

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

export class PlayerService {
private static _audioContext: any = null;
//......
public static getAudioContext(): any {
  if (!PlayerService._audioContext) {
    try {
      if (typeof AudioContext !== "undefined") {
        // We have an AudioContext type, so use it.
        PlayerService._audioContext = new AudioContext();
      } else if (window['webkitAudioContext'] !== "undefined") {
        // We don't have AudioContext, but we do have webkitAudioContext,
        // so attempt to use that.
        PlayerService._audioContext = Object.create(window['webkitAudioContext'].prototype);
      } else {
        throw new Error('AudioContext not supported. :(');
      }
    } catch (err) {
      console.log(err.message);
      alert('Cannot create audio context.');
      throw err;
    }
  }
  return PlayerService._audioContext;
} 

สิ่งนี้ยังคงทำงานบนแพลตฟอร์มที่ไม่ใช่ iOS; และบน iOS มันสามารถคืนค่าเป็น webkitAudioContext ได้ พร้อมทั้งวิธีการและคุณสมบัติที่คาดไว้ (การใช้ Object.create(...) เป็นวิธีเดียวที่ฉันสามารถทำให้สิ่งนี้ทำงานได้มากขนาดนี้) แต่ต่อมาเมื่อฉันเรียก decodeAudioData บนวัตถุนี้ ฉันจะได้รับข้อผิดพลาดที่กล่าวว่า

TypeError: Can only call AudioContext.decodeAudioData on instance of AudioContext.

เนื่องจากตัวแปรที่มันพยายามเรียกใช้เมธอด decodeAudioData นั้นถูกกำหนดประเภทเป็น 'any' แทนที่จะเป็น 'AudioContext' ผมจึงไม่รู้ว่ามันได้ไอเดียมาจากไหนว่าต้องเป็น AudioContext แต่ในกรณีใด ๆ นี่คงไม่ใช่วิธีที่ถูกต้องในการแก้ปัญหา ผมไม่มีข้อมูลประเภทใด ๆ เกี่ยวกับ webkitAudioContext มีแต่ข้อมูลเกี่ยวกับ AudioContext ข้อมูลประเภทที่จำเป็นมีอยู่ที่ไหนสักแห่งหรือเปล่าและผมแค่ยังหาไม่เจอ? ถ้าไม่มี มันจะยากไหมที่จะสร้างขึ้น? หรืออีกทางหนึ่ง มีวิธีข้ามการตรวจสอบประเภททั้งหมดสำหรับชุดคลาสนี้ไหม (ไม่ใช่ตัวเลือกที่ผมชอบ แต่ถ้านี่คือทางเดียวที่ดีที่สุดตอนนี้ ผมก็จะใช้มัน) หรือมีวิธีการอื่นที่แตกต่างโดยสิ้นเชิงที่ผมไม่รู้จัก?

คำตอบ #1

แก้ไขแล้ว อย่างน้อยก็ในเชิงประมาณครั้งแรก บรรทัดนี้:

    PlayerService._audioContext = new ((<any>window).AudioContext || (<any>window).webkitAudioContext)();

สร้างบริบทเสียงที่ใช้งานได้ทั้งบน iOS และแพลตฟอร์มที่ไม่ใช่ iOS และ "any's" จะช่วยให้ TypeScript ไม่แสดงข้อผิดพลาด วิธีนี้ใช้ได้สำหรับวัตถุประสงค์ของฉัน จนกว่าทั้งหมดของเบราว์เซอร์จะเลิกใช้ webkit prefix หรือจนกว่าจะมีการรองรับโดย definition ของ type ที่เหมาะสม

ปัญหาที่ฉันพบกับ decodeAudioData() เกิดจาก Chrome บน iOS ไม่สามารถเข้าใจไฟล์ .ogg ที่ฉันพยายามเล่นได้ เมื่อฉันเปลี่ยนไปใช้ mp3 มันก็ใช้งานได้