angular - استفاده از تایپاسکریپت/وب اودیو ایپیآی در آیاواس
من دارم روی یک وبسایت کار میکنم که فایلهای صوتی را با استفاده از Web Audio API پخش میکند. من از تایپاسکریپت و Angular 2 در Visual Studio Code استفاده میکنم. میتوانم همه چیز را به خوبی روی پلتفرمهای غیر از iOS اجرا کنم؛ اما مثلاً روی یک آیپد، با برخی خطاهای گیجکننده مواجه میشوم.
اولین مشکل این است که چگونه یک AudioContext به دست آوریم که هم روی پلتفرمهای iOS و هم غیر iOS کار کند. میدانم که میتوان این کار را با جاوااسکریپت ساده انجام داد، مثلاً http://gopherwoodstudios.com/wa/mp3/test.htm. نیاز به فشار دادن دکمه آزاردهنده است، اما میتوانم با آن کنار بیایم. بنابراین فکر میکنم مشکلی که دارم مربوط به تایپاسکریپت است. (من تازهکار در تایپاسکریپت هستم، بنابراین ممکن است برخی اصول پایه را اشتباه درک کرده باشم.)
در 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;
}
این هنوز روی پلتفرمهای غیر آیاواس کار میکند؛ و روی آیاواس، موفق میشود یک webkitAudioContext بازگرداند، همراه با متدها و ویژگیهای مورد انتظار. (Object.create(...) تنها راهی بود که توانستم این مقدار را کار کند.) با این حال، بعداً وقتی decodeAudioData را روی این شیء صدا میکنم، با خطایی مواجه میشوم که میگوید
TypeError: Can only call AudioContext.decodeAudioData on instance of AudioContext.
از آنجایی که متغیری که میخواهد متد decodeAudioData را روی آن فراخوانی کند به عنوان 'any' نوعدهی شده است نه 'AudioContext'، نمیدانم این ایده از کجا آمده که باید یک AudioContext باشد. اما در هر صورت، این نمیتواند روش درست برای نزدیک شدن به مسئله باشد. من هیچگونه اطلاعات نوعی درباره webkitAudioContext ندارم، فقط درباره AudioContext دارم. آیا اطلاعات نوع لازم جایی وجود دارد و من هنوز پیدا نکردهام؟ اگر وجود ندارد، ایجاد آن دشوار خواهد بود؟ یا بهطور جایگزین، آیا راهی برای دور زدن بررسی نوع بهطور کامل برای این مجموعه کلاسها وجود دارد (نه گزینه مورد علاقه من، اما اگر بهترین کاری است که فعلاً میتوانیم انجام دهیم، قبول میکنم)؟ یا راهی کاملاً متفاوت برای نزدیک شدن به این مسئله وجود دارد که من نمیدانم؟
پاسخ شماره ۱
حل شد، حداقل به تقریب اولیه. این خط:
PlayerService._audioContext = new ((<any>window).AudioContext || (<any>window).webkitAudioContext)();
یک کانتکست صوتی ایجاد میکند که روی سیستمهای آیاواس و غیر آیاواس کار میکند، و 'any' از شکایت تایپاسکریپت جلوگیری میکند. این برای اهداف من کافی است، تا زمانی که یا همه مرورگرها از پیشوند وبکیت دور شوند، یا توسط تعریف نوع مناسب پشتیبانی شود.
مشکلی که من با decodeAudioData() داشتم ناشی از این بود که کروم در iOS نمیتوانست فایل .ogg ای را که میخواستم پخش کنم درک کند. وقتی به mp3 تغییر دادم، کار کرد.
