版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
第十一章多媒體服務
1第十一章多媒體服務1完成本章內(nèi)容之后我們將能夠:了解多媒體框架(MMF)使用MMF音頻API了解MMF視頻概念,框架和相關API本章目標2本章目標2概述本章先講述多媒體架構(gòu),包括它的發(fā)展簡史。然后,描述多媒體子系統(tǒng)的各個單獨部分。3概述本章先講述多媒體架構(gòu),包括它的發(fā)展簡史。然后,描多媒體組件架構(gòu)
在討論多媒體的當前狀態(tài)之前,先回顧SymbianOS中多媒體的發(fā)展歷史。從歷史上看,多媒體子系統(tǒng)包括用于處理下面多媒體領域的單獨API:音頻——回放、錄音和操作。靜態(tài)圖像——解碼、編碼和操作。直到SymbianOS7.0,這一切都沒有發(fā)生變化,不過,對應的子系統(tǒng)卻發(fā)生了相當大的變化。SymbianOS7.0中的多媒體API主要是以前版本中出現(xiàn)的API的超集,在某些地方,同時存在新方法和遺留的方法。
4多媒體組件架構(gòu)在討論多媒體的當前狀態(tài)之前,先回顧S多媒體組件架構(gòu)
為了解釋在SymbianOS7.0中對多媒體子系統(tǒng)進行許多基本改進的原因,有必要回顧這—操作系統(tǒng)以前版本中的子系統(tǒng)以及它們所面臨的問題。這一節(jié)簡要概述6.1和7.0中的Media服務器及進行更改的原因。5多媒體組件架構(gòu)為了解釋在SymbianOS7.0媒體服務器
在SymbianOS6.1和7.0中,所有多媒體處理都通過媒體服務器(mediaserver)進行。這是一個標準SymbianOS服務器,是提供全部多媒體功能的單個進程。該服務器支持音頻回放和錄音,還支持對靜止圖像的編碼/解碼和處理。操作系統(tǒng)支持大量音頻和圖像格式,可以通過編寫插件擴展這些格式。為了使用該服務器,用戶可以顯示實例化一個與服務器的連接,或允許客戶端API自動提供一個連接。每個客戶端用戶將提供一個服務器的觀察器類,使該服務器能夠與用戶應用程序或庫通信傳遞消息。
6媒體服務器在SymbianOS6.1和7.0中媒體服務器
服務器保持一個客戶端對象列表,并且并發(fā)循環(huán)處理多媒體請求。這意味著,許多不同的客戶端用戶可以同時使用該服務器,例如,讓一個用戶應用程序播放音頻,同時解碼用于顯示的圖像。盡管這聽起來很理想,但產(chǎn)生這種行為的實際問題很復雜并且困難重重。例如,如果用戶實際上希望同時使用服務器的兩部分功能,讓一個進程控制這兩部分造成的潛伏期可能使系統(tǒng)實際上不可用。例如,一項處理器密集型任務(如解碼圖像)將阻止使用任何實時多媒體任務(如音頻流式處理),音頻流在設備驅(qū)動器中將非常迅速地下溢。當使用編寫得很差的第三方插件(常常轉(zhuǎn)換自非Symbian代碼,并包含消耗大量處理器時間的冗長程序)時,情況更糟。插件框架本身就使得為之編程非常復雜,這并不會改善上述狀況。7媒體服務器服務器保持一個客戶端對象列表,并媒體服務器
上述各種問題,加上連接到服務器在最壞的情況下可能花費幾秒鐘的事實,意味著必須對此作出改進。8媒體服務器上述各種問題,加上連接到服務器在最新時代的開始
Symbian開始編寫全新的多媒體子系統(tǒng),它將成功允許該子系統(tǒng)的不同功能同時使用,也提供手機制造商和第三方可以輕松擴展的輕量級框架。新系統(tǒng)不是只基于一個服務器,而是拆分不同的多媒體部分,以使用單獨的服務器和進程。新的子系統(tǒng)使用多個并發(fā)多媒體線程,沒有在媒體服務器中看到的任何副作用。它使用許多與媒體服務器相同的客戶端API,但是使用了一個新的插件解決方案,稱作ECom。這使得在電話制造過程中或出產(chǎn)以后,手機生產(chǎn)商和第三方能夠編寫和集成插件。
9新時代的開始Symbian開始編寫全新的多媒體子系多媒體框架(MMF)由于這個新的子系統(tǒng)如此成功,以至于很快被集成到SymbianOS7.0中,SymbianOS7.0只是剛剛開始它的開發(fā)生命周期。隨著SymbianOS7.0的發(fā)展進步,這個子系統(tǒng)演變成現(xiàn)在所謂的多媒體框架(MMF,MultimediaFramework)。MMF提供了在SymbianOS7.0中能夠處理多媒體的框架。這個框架本身十分輕量化,并且提供了一個基于ECom的多線程系統(tǒng),它保留了從6.1到7.0中原始API的子集,還進行了很多改進。MMF的基本結(jié)構(gòu)包括一個客戶端API層、一個控制器框架、控制器插件和低層次子系統(tǒng)。圖7.1顯示了這個架構(gòu)的概觀。10多媒體框架(MMF)由于這個新的子系統(tǒng)如此成功,多媒體框架(MMF)圖7.1MMF架構(gòu)11多媒體框架(MMF)圖7.1MMF架構(gòu)11多媒體框架(MMF)在圖7.1中,控制器框架可以看作是客戶端/服務器層,它為MMF端控制器插件提供接口。子系統(tǒng)的每一部分的描述如下。12多媒體框架(MMF)在圖7.1中,控制器框架可以看作是客客戶端API客戶端API(有時也稱為“應用程序API”)位于子系統(tǒng)中的最高抽象層。這些API為開發(fā)人員提供了MMF的基本功能。在SymbianOS7.0中,存在用來生成正弦波音頻音、音頻和視頻剪輯操作以及音頻流的客戶端API。除兩種API以外,其余所有控制器框架都用來獲取并控制相關的控制器插件,以執(zhí)行多媒體任務。上述兩種例外是音頻流API和音頻聲音生成API,二者都不使用控制器框架,而是直接與DevSound層接口。DevSound層是一個低層API,這將在本章后續(xù)部分簡短討論。13客戶端API客戶端API(有時也稱為“應用程序API”)控制器框架
控制器框架提供了支持MMF內(nèi)部多媒體插件的框架。它提供了MMF的客戶API層與實際MMF控制器插件間的客戶端服務器通信。它由以下幾個邏輯模塊構(gòu)成??刂破鞑寮馕銎鲗τ谔囟ǖ膽贸绦?,控制器插件解析器允許系統(tǒng)選擇最佳插件。它提供了—個API集,客戶可以使用它們來獲取插件(MMF客戶端API就是其中之一)。2.控制器代理控制器代理用來管理控制器框架之內(nèi)的所有線程處理和線程間通信。這是標準SymbianOS客戶端/服務器機制之上的一個簡單層,用來提供控制器API的客戶端與服務器端之間通信的方式。它不能直接使用,我們只是為了完整性而在此提及。
14控制器框架控制器框架提供了支持MMF內(nèi)部多媒體控制器框架
3.控制器API層控制器API層由控制器代理的客戶端和服務器端的匹配類構(gòu)成。應用程序(或MMF)使用客戶端類(即RMMFController)來運用控制器插件的功能。服務器端類(CMMFController)是控制器插件編寫者為了實現(xiàn)他們的插件而必須派生的類。這個類也把所有發(fā)送給控制器插件的信息解包。
15控制器框架3.控制器API層15控制器框架
4.自定義命令根據(jù)設計,控制器插件API局限于非?;A的數(shù)據(jù)流操作。為了擴展該API,可以使用—種自定義命令框架,它允許客戶訪問控制器特定的擴展。在一般情況下,MMF使用該框架為常規(guī)命令(稱做“標準自定義命令”,如設置音量和獲取平衡)的處理定義API??刂破鞑寮纳a(chǎn)商特定API也可以使用該技術(shù)進行暴露。16控制器框架4.自定義命令16控制器插件
控制器插件為MMF提供特定的多媒體功能??刂破鞯幕救蝿帐菑囊粋€或者多個源中引導數(shù)據(jù),把數(shù)據(jù)轉(zhuǎn)變成不同的格式,然后把數(shù)據(jù)傳輸?shù)揭粋€或者多個接收器。數(shù)據(jù)源一般是文件、麥克風或攝像頭,而接收器一般為文件,揚聲器或屏幕??刂破鞑寮话愣贾С植シ藕弯浿埔环N或多種多媒體格式,比如mp3或avi格式。它能夠解讀相關源或接收器中的原始數(shù)據(jù),并從源中讀取數(shù)據(jù),進行必要的數(shù)據(jù)轉(zhuǎn)換,然后寫入接收器??刂破鞑寮募軜?gòu)略為復雜,超出了本書的討論范圍。不過,我們將簡要介紹實現(xiàn)控制器插件的步驟,如下所述:17控制器插件控制器插件為MMF提供特定的多媒體功能??刂破鞑寮?/p>
實現(xiàn)MMF控制器插件的API。如上面“控制器框架”所述,所有MMF控制器插件都是由CMMFController基類派生而來。該基類提供控制器API,而且還提供諸如通過ECom插件框架實例化控制器插件的功能。在該基類中,需要重載的最基本函數(shù)集聲明為純虛函數(shù),包括PlayL()和StopL()等函數(shù)。必須實現(xiàn)所有標準自定義命令集所需要的函數(shù)。這可以通過以下方式實現(xiàn),先用適當?shù)摹白远x命令實現(xiàn)器”類派生控制器程序,然后使用CMMFController()和AddCustomCommandParserL()函數(shù)來注冊這個該控制器,使其能夠處理標準命令集。18控制器插件實現(xiàn)MMF控制器插件的API。如上面“控制器框控制器插件
MMF提供了一組基類來協(xié)助編寫控制器插件。這些基類包括數(shù)據(jù)源和接收器類,以及緩沖類。數(shù)據(jù)源和接收器類本身就是ECom插件,并且封裝了文件、描述符、音頻輸入和輸出的使用功能。當把數(shù)據(jù)由源傳送到接收器的時候,緩沖用來存儲這些數(shù)據(jù)。緩沖類的類型有很多,但它們都是從CMMBuffer類派生而來。不同緩沖類的主要區(qū)別在如何存儲數(shù)據(jù),例如,數(shù)據(jù)是存儲于描述符中,還是存儲在內(nèi)核端緩沖中。19控制器插件MMF提供了一組基類來協(xié)助編寫控制器插件。這些控制器插件
為了與控制器框架插件解析器一起工作,每個控制器插件(實際是每個ECom插件)均要求一個ECom插件資源文件??刂破骺蚣懿寮馕銎魇褂盟鼧俗R該插件的多媒體功能,比如是否能夠播放和錄音,支持什么格式。20控制器插件為了與控制器框架插件解析器一起工作,每個控制器插控制器插件
可以在SDK中找到有關ECom插件的更多信息。MMF控制器插件可以具有硬件特定的源和接收器。對于所涉及的硬件,它通常是一種設計驅(qū)動器或一個自定義API,它由授權(quán)商或硬件商來實現(xiàn)。在SymbianOS7.0中,惟一的例外是DevSoundAPl,它具有標準的實現(xiàn),供參考音頻控制器使用。
21控制器插件可以在SDK中找到有關ECom插件的更多底層子系統(tǒng)
在MMF架構(gòu)的底層,存在許多子系統(tǒng)。授權(quán)商在生產(chǎn)新手機時可以實現(xiàn)這些子系統(tǒng),它們一般與硬件相對應。子系統(tǒng)包含的內(nèi)容主要取決于授權(quán)商的要求,這些層規(guī)定了手機的大部分多媒體功能。這些底層一般與第三方用戶無關,不過,下面會簡短介紹其中一個主要子系統(tǒng)DevSound。DevSound將SymbianOS移植到新平臺時,授權(quán)商或硬件商實現(xiàn)CMMFDevSound類。它的API提供了MMF中音頻回放和錄音的最底層抽象,在音頻設備驅(qū)動器之上提供了獨立于硬件的層。DevSoundAPI提供了對音頻數(shù)據(jù)播放和錄音的支持、對播放音頻音的支持以及對音量、對平衡等音頻硬件屬性修改的支持。22底層子系統(tǒng)在MMF架構(gòu)的底層,存在許多子系統(tǒng)。授權(quán)底層子系統(tǒng)
另外,DevSound包括一種在同時使用聲音硬件的不同客戶間進行仲裁的方式。這種仲裁層處理聲音的優(yōu)先級(在客戶API中設置),它的單個優(yōu)先級層由授權(quán)商定義。典型用法是在中斷低優(yōu)先級客戶(如MP3播放器)時,決定DevSound處理高優(yōu)先級客戶(如電話鈴聲)的方式。也可以包含“優(yōu)先級首選”的使用,它可以按請求優(yōu)先級的同樣方式來請求,用于決定高優(yōu)先級聲音掛起時,對低優(yōu)先級聲音如何處理。例如,可以選擇終止低優(yōu)先級的聲音,或與高優(yōu)先級聲音進行混音。23底層子系統(tǒng)另外,DevSound包括一種在同時使用使用MMF
觀察器模式在開始前,有必要提一下整個MMF的通用設計模式,即所謂的“觀察器模式(observerpattern)”。使用觀察器類可以為API用戶提供反饋。這些類是作為“混合”類而實現(xiàn),并定義了—組觀察器純虛函數(shù)。該模式不局限于MMF,而廣泛應用于SymbianOS。在第4章可以看到利用觀察器類向控件報告重要事件的例子。為使用MMF客戶API,你需要創(chuàng)建一個派生自相關觀察器類的對象,提供其虛函數(shù)的實現(xiàn),并將該對象的一個引用傳遞給MMF客戶實用程序。正如下述實例所示,常常從觀察器類派生MMF客戶本身。24使用MMF觀察器模式24使用MMF
在MMF中,觀察器函數(shù)的通常用途是通知實用程序的創(chuàng)建、或者特定范圍內(nèi)操作的開始或結(jié)束,并提供錯誤碼和狀態(tài)信息。值得注意的是,觀察器模式依賴于活動對象的使用,也就是說活動規(guī)劃器必須一直運行,以便客戶API能夠正常工作,因為它處于標準GUI應用程序中。25使用MMF在MMF中,觀察器函數(shù)的通常用途是通使用音頻
MMF音頻API可用于處理簡單的音調(diào)產(chǎn)生、音頻剪輯處理(播放、錄制和轉(zhuǎn)換)以及音頻流化(播放和錄音)。當初次在軟件中使用音頻時,可能難以理解實際發(fā)生的事情以及聲音是如何保存的。圖7.3說明了一些基本概念。圖7.3模數(shù)轉(zhuǎn)換和數(shù)模轉(zhuǎn)換26使用音頻MMF音頻API可用于處理簡單的音調(diào)產(chǎn)生、使用音頻
模數(shù)轉(zhuǎn)換將音頻轉(zhuǎn)換為數(shù)字形式的第一步,通常是模擬到數(shù)字的轉(zhuǎn)換。這是通過所謂的“模數(shù)轉(zhuǎn)換器”或“ADC”的微型芯片實現(xiàn)的。例如,在用麥克風錄音時,麥克風將聲音波形轉(zhuǎn)換為電子信號,然后在ADC階段將電子信號轉(zhuǎn)換為二進制數(shù)據(jù)?二進制數(shù)據(jù)就可以被處理,并存入內(nèi)存或保存到文件中。2.數(shù)模轉(zhuǎn)換相反的處理稱為數(shù)模轉(zhuǎn)換。在這一步,音頻數(shù)據(jù)的二進制序列通過所謂的“數(shù)模轉(zhuǎn)換器”或“DAC”的微型芯片進行轉(zhuǎn)換。這些芯片輸出模擬電子信號,然后電子信號再通過揚聲器等硬件轉(zhuǎn)變?yōu)槁曇舨ㄐ巍?7使用音頻模數(shù)轉(zhuǎn)換27使用音頻
3.數(shù)字音頻格式所有數(shù)字音頻均以特定格式存儲,該格式描述音頻的各個細節(jié)。此信息包括音頻錄制的取樣速率(ADC的每秒取樣個數(shù))、通道個數(shù)以及是否將音頻編碼為要求分離解碼階段的狀態(tài)。未壓縮的音頻稱為脈沖編碼調(diào)制(PCM,PulseCodeModulation),在任一給定時刻,將音頻取樣直接度量為已知音頻信號的振幅。例如,一個50Hz正弦波的數(shù)字PCM取樣看起來如圖7.4所示。在此圖中,使用了16位PCM編碼格式。這也就意味著,數(shù)字音頻取樣將以16位存儲,該值的范圍為—32768~+32767。這些值對應正弦波的波谷和波峰。圖上的每個點對應需要保存的取樣。28使用音頻3.數(shù)字音頻格式28使用音頻
圖7.4正弦波的數(shù)字取樣以PCM音頻格式存儲,這些取樣不需要再進行任何處理,因此每個取樣將占用16位或兩個字節(jié)。音頻數(shù)據(jù)如何以其他格式存儲,依賴于應用到信號上的附加處理。比如,壓縮信號的音頻數(shù)據(jù)可能包含所使用的轉(zhuǎn)換系數(shù)。29使用音頻圖7.4正弦波的數(shù)字取樣以PCM音頻格式存使用音頻
4.音頻剪輯剪輯可以看做是音頻或視頻的一個“包”。它有明確定義的開始和結(jié)束,并且通常將描述其格式的信息一起打包,如取樣速率和編碼方式。剪輯通常包含在文件或描述符中,盡管某些客戶API也允許將URL看做剪輯。5.音頻流音頻流由音頻數(shù)據(jù)的連續(xù)流組成,它沒有明確定義的開始和結(jié)束。音頻數(shù)據(jù)流可以是大小不等的間斷塊。例如,從因特網(wǎng)上獲取流的RealAudio。30使用音頻4.音頻剪輯30播放音調(diào)音調(diào)播放器實用工具類CMdaAudioToneUtility在mdaaudiotoneplayer.h中定義。它提供播放單獨的單聲道正弦波音調(diào)、用戶自定義雙音(Nokia6600手機不提供)、雙音多頻(DTMF)或音調(diào)序列的能力。在典型應用程序中,DTMF用于在打電話期間模仿電話按鍵,音調(diào)序列文件用于產(chǎn)生鈴聲。希望使用音調(diào)播放器實用工具的客戶,必須先從MMdaAudioToneObserver派生一個觀察器類,MMdaAudioToneObserver的類定義顯示如下:31播放音調(diào)音調(diào)播放器實用工具類CMdaAudioTon播放音調(diào)classMMdaAudioToneObserver{ Public: virtualvoidMatoPrepareComplete(TintaError)=0; virtualvoidMatoPlayComplete(TIntaError)=0;};通過調(diào)用NewL()函數(shù)創(chuàng)建的音調(diào)播放器實用工具,向觀察器類提供一個引用作為參數(shù)。然后需要以下兩個步驟來播放音調(diào)。32播放音調(diào)classMMdaAudioToneObs播放音調(diào)(1)調(diào)用適當?shù)摹邦A備”函數(shù)預備待播放的音調(diào)。客戶通過觀察器的MatoPrepareComplete()函數(shù)獲知預備工作已完成。如果預備工作成功完成,則以錯誤值KEn'None調(diào)用該函數(shù),否則將報告相應的錯誤碼,例如,當設備不支持音調(diào)回放時,錯誤碼為KErrNotSupported。(2)如果預備成功,客戶就可以開始播放音調(diào),或者針對該音調(diào)執(zhí)行其他處理,比如設置音量。如果發(fā)生錯誤,則決不可以調(diào)用這些函數(shù),因為底層子系統(tǒng)沒有正確初始化。通過調(diào)用觀察器的MatoPlayComplete()函數(shù),客戶可以知道何時音調(diào)播放完成。這組事件對于三種音調(diào)播放API是通用的。惟一不同的是,作為參數(shù)傳遞給相關“預備”函數(shù)的數(shù)據(jù)。33播放音調(diào)(1)調(diào)用適當?shù)摹邦A備”函數(shù)預備待播放的音調(diào)播放音調(diào)audi04例程演示了如何使用音調(diào)播放實用工具,并播放3秒2600Hz的音調(diào)。按照前面所描述的觀察器模式,應用程序的引擎類實現(xiàn)了音頻音調(diào)觀察器的函數(shù)。如下所示:classCAudio4Engine:publicCBase,publicMMdaAudioToneObserver{… public://從MMdaAudioToneObservervoidMatoPrepareComplete(TIntaError);voidMatoPlayComplete(TIntaError);…};34播放音調(diào)audi04例程演示了如何使用音調(diào)播放實用工播放音調(diào)應用程序引擎的ConstructL()很簡單:voidCAudio4Engine::ConstructL(){ iUtility=CMdaAudioToneUtility::NewL (*this); iUtility->PrepareToPlayTone(KFrequency, TTimeIntervalMicroSeconds(KDuration));}35播放音調(diào)應用程序引擎的ConstructL()很簡單:35播放音調(diào)它首先通過調(diào)用NewL()函數(shù)創(chuàng)建CMdaAudioToneUtility的一個實例,并傳遞自身的一個引月作為觀察器。然后調(diào)用實用工具的PrepareToPlayTone()函數(shù)預備音調(diào),并傳遞以赫茲為單位的音調(diào)頻率和以微秒為單位的音調(diào)持續(xù)時間。在該例中,KFrequency和KDuration的值為2600和3000000。需要注意的是,在任一給定時刻,只能存在一個預備的音調(diào)。如果再次調(diào)用PrepareToPlayTone(),則新的音調(diào)將取代原先的那個音調(diào)。當音調(diào)實用工具預備好音調(diào)以后,它調(diào)用MatoPrepareComplete():36播放音調(diào)它首先通過調(diào)用NewL()函數(shù)創(chuàng)建CMdaA播放音調(diào)voidCAudio4Engine::MatoPrepareComplete(TintaError){ if(aError==KErrNone) { iUtility->SetVolume(iUtility->MaxVolume ()); iState=EReady; }}如果預備成功,傳遞給該函數(shù)的錯誤碼為KErrNone。任何其他值都表明—個錯誤。例如,如果聲音設備已經(jīng)被一個更高優(yōu)先級的進程使用,則該值為KErrlnUse。37播放音調(diào)voidCAudio4Engine::MatoPr播放音調(diào)有重要的一點需要注意,音調(diào)實用工具預備音調(diào)和調(diào)用MatoPrepareComplete()的時間沒有定義。在有些設備上可能立即發(fā)生,而在另外一些設備上則可能存在非常明顯的延遲,因此,不要使用單個音調(diào)播放API來播放由一系列音調(diào)組成的曲子。這種情況下,應該使用音調(diào)序列API來代替。現(xiàn)在音調(diào)已準備好,客戶可以調(diào)用Play()來播放它了:voidCAudio4Engine::PlayL(){ iUtility->Play(); iState=EPlaying;}38播放音調(diào)有重要的一點需要注意,音調(diào)實用工具預備音調(diào)和播放音調(diào)當音調(diào)播放完以后,將調(diào)用MatoPlayComplete()函數(shù):voidCAudio4Engine::MatoPlayComplete(TInt/*aError*/){ iState=EReady;}回放成功的話,會傳遞錯誤碼KErrNone給該函數(shù)。在該例中,忽略了錯誤碼,但在真正的應用程序中,卻要注意可能由于試圖再次開始播放音調(diào)所造成的錯誤。通過多次調(diào)用P1ay()函數(shù)而不必調(diào)用PrepareToPlayTone(),可以重復播放音調(diào)。然而,如果想播放不同類型的音調(diào),則必須另外再調(diào)用PrepareToPlayTone()。39播放音調(diào)當音調(diào)播放完以后,將調(diào)用MatoPlayCo播放音調(diào)注意一個有趣的地方,音頻實用工具不像后面將看到的其他許多實用工具,它沒有Stop()函數(shù)。作為代替,可以使用CancelPlay()函數(shù)停止一個已開始播放的音調(diào):voidCAudio4Engine::StopL(){ iUtility->CancelPlay();…}在完成播放以前取消音調(diào),會阻止對觀察器的MatoPlayComplete()函數(shù)的調(diào)用。使用完音調(diào)實用工具之后,通過簡單地銷毀音調(diào)發(fā)生器對象,就可以完成音頻設備的所有必要的清除工作。40播放音調(diào)注意一個有趣的地方,音頻實用工具不像后面將看播放音調(diào)該實例演示了如何播放單個正弦波音調(diào)音調(diào),不過播放雙音、DTMF音和音調(diào)序列的原理相同。對于每種音調(diào),都有一個對應的“預備”函數(shù),一旦預備好,就可以利用Play()和CancelPlay()來播放音調(diào)和停止音調(diào)。在每一種情形中,都會調(diào)用上述的相同的觀察器函數(shù)。作為導引,下面列出用于其他音調(diào)類型的“預備”函數(shù)的信息:雙音——具有同一持續(xù)時間的兩個音調(diào)頻率。DTMF——對包含DTMF音調(diào)列表的描述符的引用。來自文件的序列——對音調(diào)序列文件的文件名的引用。來自描述符的序列——對包含音調(diào)序列的描述符的引用。固定序列——引用通過硬編碼預定義音調(diào)序列的整數(shù)。41播放音調(diào)該實例演示了如何播放單個正弦波音調(diào)音調(diào),不過播放音調(diào)SymbianOS不指定用于定義音調(diào)序列的格式,因此,通常手機與手機之間的格式會不同。DTMF音調(diào)序列通常由包含0123456789#*字符集中字符的文本串指定,但該格式也可以由設備指定。請參考特定手機的SDK,獲得特定手機所使用的準確格式的詳細信息。42播放音調(diào)SymbianOS不指定用于定義音調(diào)序列的播放剪輯
音頻播放器實用工具CMdaAudioPlayerUtility定義在mdaaudiosampleplayer.h中,它提供播放取樣音頻數(shù)據(jù)的能力。取樣音頻數(shù)據(jù)可由文件(如WAV文件)或描述符(TDes8或TDesC8)提供,或者也可以定位于特定的URL地址。音頻播放器實用工具提供標準的功能,用于播放和停止播放音頻數(shù)據(jù),以及設置音量和平衡等等。它還提供許多更高級的操作,如音量傾斜、重復設置、元數(shù)據(jù)處理和傳遞定制命令到當前MMF控制器。元數(shù)據(jù)是包含在音頻剪輯中的非音頻數(shù)據(jù)。例如,WAV文件可以包含該文件何時創(chuàng)建、以及由誰創(chuàng)建的信息。43播放剪輯音頻播放器實用工具CMdaAudioPla播放剪輯
在決定使用哪個實用工具來播放剪輯時,可以選擇音頻播放器或音頻記錄器(描述見下一節(jié)),記錄器包含播放和錄制剪輯兩種功能。通常會使用音頻記錄器實用工具,它提供最為靈活的選擇,不過使用音頻播放器實用工具是播放剪輯的最簡單方法。希望使用音頻播放器實用工具的客戶,必須首先從MMdaAudioPlayerCa!lback類中派生一個觀察器類,MMdaAudioPlayerCallback類的定義如下:
44播放剪輯在決定使用哪個實用工具來播放剪輯時,可以選播放剪輯
classMMdaAudioPlayerCallback{ public: virtualvoidMapcInitComplete(TIntaError, constTTimeIntervalMicroSeconds&aDuration)=0; virtualvoidMapcPlayComplete(TIntaError)=0;};創(chuàng)建音頻播放器實用工具的標準方式是使用NewL()函數(shù),該函數(shù)同樣將一個引用傳遞給觀察器類。與音調(diào)播放實用工具一樣,播放剪輯也分為兩個不連續(xù)的階段。45播放剪輯classMMdaAudioPlayerCall播放剪輯
(1)剪輯必須使用下面介紹的相應“打開”函數(shù)來打開。調(diào)用觀察器的MapclnitComplete()函數(shù)表示這一階段完成。如果剪輯成功打開,則以錯誤碼KErrNone調(diào)用該函數(shù),但是如果剪輯格式不可識別,則錯誤碼為KErrNotSupported。(2)如果剪輯成功打開,則客戶既可以開始播放剪輯,也可以處理設置,如音量。當剪輯完成播放時,調(diào)用觀察器的MapcPlayComplete()函數(shù)。對于播放三種可能來源中的每一種音頻,這組事件都是通用的,惟一的不同是傳遞給相應“打開”函數(shù)的數(shù)據(jù)——傳遞給OpenFileL()的是一個文件名,傳遞給OpenDesL()的是一個描述符,而傳遞給OpenUrlL()的是一個URL。46播放剪輯(1)剪輯必須使用下面介紹的相應“打開”函播放剪輯
使用OpenUrlL()函數(shù),也可以指定一個因特網(wǎng)接入點ID。這將指示控制器使用特定的接入點代替其默認接入點。有關此參數(shù)類型的更多信息,請參考mmfurl.h中的CMMFUrlSink類。如果知道了音頻實用工具只是用于處理某一特定類型的剪輯時,就可以通過使用NewDesPlayerL()、NewDesPlayerReadOnlyL()或NewFilePlayerL()函數(shù)中的一個來創(chuàng)建一個實例,代替調(diào)用NewL()。另外要為這些函數(shù)提供包含音頻數(shù)據(jù)本身或者音頻剪輯文件名的描述符。這些函數(shù)封裝了播放器實用工具的實例化和打開階段,所以在完成時,它們會嘗試打開提供的剪輯,并以相應的錯誤碼調(diào)用觀察器的MapclnitComplete()函數(shù)。47播放剪輯使用OpenUrlL()函數(shù),也可以指定一播放剪輯
實例audi01說明了如何打開一個WAV文件并播放它。利用實用工具的NewFilePlayerL()函數(shù),應用程序引擎的SetFileL()函數(shù)創(chuàng)建音頻播放器實用工具類的一個實例,創(chuàng)建它的明確目的就是播放一個單獨的文件:voidCAudiolEngine::SetFileL(constTDesC&aFileName){ if(iUtility) { deleteiUtility; }iUtility=CMdaAudioPlayerUtility::NewFilePlayerL(aFileName,*this);}48播放剪輯實例audi01說明了如何打開一個WAV文播放剪輯
引擎本身派生于觀察器類。NewFilePiayerL()不僅創(chuàng)建實用工具,而且嘗試打開剪輯、導致調(diào)用觀察器的MapclnitComplete()函數(shù)、傳遞錯誤碼和音頻剪輯的持續(xù)時間。voidCAudiolEngine::MapcInitComplete(TIntaError,constTTimeIntervalMicroSeconds&/*aDuration*/){ if(aError==KErrNone) { iState=EReady; iAppUi.UpdateViewL(); }}49播放剪輯引擎本身派生于觀察器類。NewFilePi播放剪輯
在該例中,持續(xù)時間被忽略,但在真正的應用程序中可能會用到,比如顯示剪輯的剩余播放時間。有一點很重要,在沒有調(diào)用錯誤碼為KErrNone的MapclnitComplete()之前,不要調(diào)用Play()、SetVolume()或SetRepeats()之類的函數(shù),否則會發(fā)生嚴重錯誤。在使用這些函數(shù)時,這種錯誤是最常犯的錯誤。確保不發(fā)生這種錯誤的一個有效方法,是從MapclnitComplete()函數(shù)中直接調(diào)用Play()。如果剪輯已經(jīng)成功打開,就可以使用Play()函數(shù)播放它。voidCAudiolEngine::PlayL(){ iUtility->Play(); iState=EPlaying;}50播放剪輯在該例中,持續(xù)時間被忽略,但在真正的應用程播放剪輯
當剪輯播放完時,調(diào)用MapcPlayComplete()函數(shù)。voidCAudiolEngine::MapcPlayComplete(Tint/*aError*/){ iState=EReady;}成功的回放會導致調(diào)用錯誤碼為KErrNone的MapcPlayComplete()函數(shù)。如同前面的例子,忽略錯誤碼。例如,更實際的應用程序?qū)ErrlnUse錯誤的響應,可能會是再次嘗試播放剪輯。
51播放剪輯當剪輯播放完時,調(diào)用MapcPlayCom播放剪輯
播放完成之后,可以通過再次調(diào)用Play()重放剪輯,而不必調(diào)用“打開”函數(shù)。在播放新剪輯之前,必須通過調(diào)用實用工具的Close()函數(shù)關閉當前剪輯,并利用相應的“打開”函數(shù)打開新的剪輯。如果像這個例子中一樣,創(chuàng)建了用于播放指定剪輯類型的實用工具,那么為了播放不同類型的數(shù)據(jù),必須要創(chuàng)建一個新實例。播放剪輯以前,可以通過SetPlayWindow()函數(shù)設置—個“播放窗口”,并以微秒為單位提供窗口的開始和結(jié)束時間。完成后,播放就要受限于窗口中的剪輯部分。默認情況下,播放窗口為剪輯的整個長度。在播放剪輯時,可以利用實用工具的Stop()和Pause()函數(shù)停止播放。Stop()函數(shù)把剪輯的位置復位到當前播放窗口的開始,而不是復位到整個剪輯的開始。52播放剪輯播放完成之后,可以通過再次調(diào)用Play()錄制剪輯
定義在mdaaudiosampleeditor.h中的音頻記錄器實用工具CMdaAudioRecorderUtility派生自CMdaAudioClipUtility。它包含CMdaAudioPlayerUtility所提供的功能超集,增加了錄制和播放剪輯的功能。與播放器實用工具一樣,音頻數(shù)據(jù)可以在文件(如WAV文件)、描述符(TDes8或TDesC8)或遠程URL中進行處理。如前所述,當播放或錄制剪輯時,通常會選擇使用這個類。除了提供播放、錄制、停止、設置音量、設置平衡等基本功能外,該類還允許從當前剪輯中裁剪數(shù)據(jù),從當前讀/寫位置到數(shù)據(jù)的開頭或結(jié)尾進行處理。與播放器實用工具一樣,該類還提供許多更高級的操作,如音量傾斜、重復設置、元數(shù)據(jù)處理和傳遞定制命令給當前MMF控制器。53錄制剪輯定義在mdaaudiosampleedit錄制剪輯
除有一個例外(后面會解釋),音頻記錄器實用工具的播放功能與播放器實用工具的功能—樣,所以這里將著重介紹錄制功能。與使用其他實用工具一樣,希望使用音頻記錄器實用工具的客戶,必須首先從MmdaObjectStateChangeObserver派生一個觀察器類,以下是MMdaObjectStateChangeObserver的類定義:classMMdaObjectStateChangeObserver{public: virtualvoidMoscoStateChangeEvent(CBase*aObject, TIntaPreviousState, TIntaCurrentState, TIntaErrorCode)=0;};54錄制剪輯除有一個例外(后面會解釋),音頻記錄器實用錄制剪輯
使用這個觀察器類比使用播放器和音調(diào)實用工具的觀察器類稍微復雜一點。只要記錄器實用工具對象的狀態(tài)發(fā)生變化,就會調(diào)用MoscoStateChangeEvent(),并傳遞一個指向?qū)嵱霉ぞ邔ο蟊旧淼闹羔?、以前狀態(tài)和當前狀態(tài)以及一個錯誤碼。因為提供了對象指針,觀察器就能夠觀察不止一個實用工具對象。記錄器實用工具可能的操作狀態(tài)在CMdaAudioClipUtility父類中枚舉,如下所示:55錄制剪輯使用這個觀察器類比使用播放器和音調(diào)實用工具錄制剪輯
使用這個觀察器類比使用播放器和音調(diào)實用工具的觀察器類稍微復雜一點。只要記錄器實用工具對象的狀態(tài)發(fā)生變化,就會調(diào)用MoscoStateChangeEvent(),并傳遞一個指向?qū)嵱霉ぞ邔ο蟊旧淼闹羔?、以前狀態(tài)和當前狀態(tài)以及一個錯誤碼。因為提供了對象指針,觀察器就能夠觀察不止一個實用工具對象。記錄器實用工具可能的操作狀態(tài)在CMdaAudioClipUtility父類中枚舉,如下所示:enumTState{ ENotReady=0 EOpen, EPlaying, ERecording};56錄制剪輯使用這個觀察器類比使用播放器和音調(diào)實用工具錄制剪輯
音頻記錄器實用工具利用NewL()函數(shù)創(chuàng)建,通常,該函數(shù)以觀察器的引用為參數(shù)。然后,音頻的錄制按照與使用播放器實用工具進行播放的相似步驟進行。(1)必須使用相應的“打開”函數(shù)打開剪輯。在完成時,調(diào)用觀察器的MoscoStateChangeEvent()函數(shù),以EOpen的當前狀態(tài)和一個錯誤碼為參數(shù),如果剪輯打開成功,該錯誤碼是KErrNone。(2)如果成功打開,則客戶既可以開始錄制剪輯,也可以處理設置。與播放器實用工具—樣,當發(fā)生錯誤的狀態(tài)時,不能調(diào)用這些函數(shù)。在開始錄制剪輯時,調(diào)用觀察器的MoscoStateChangeEvent()函數(shù),以當前狀態(tài)ERecording為參數(shù)進行調(diào)用。當完成錄制剪輯時,再次調(diào)用觀察器的MoscoStateChangeEvent()函數(shù)。如果錄制被一個Stop()調(diào)用中斷,則錯誤碼為KErrNone;如果剪輯錄制達到用戶定義的限定長度,則錯誤碼為KErrEof;如果發(fā)生其他錯誤情況,則會是其他錯誤碼。57錄制剪輯音頻記錄器實用工具利用NewL()函數(shù)創(chuàng)建錄制剪輯
與使用播放器實用工具一樣,對于三種音頻記錄剪輯類型,這組事件都是通用的,惟一的不同也是傳遞給相應“打開”函數(shù)的數(shù)據(jù)。與剪輯播放實用工具相比,這里有更多種類的“打開”函數(shù)。其中有些函數(shù)采用一個TMdaClipFormat參數(shù)(該數(shù)據(jù)結(jié)構(gòu)將在后面音頻轉(zhuǎn)換的章節(jié)中作簡要介紹),有些允許調(diào)用者選擇特定的控制器插件,而不是由MMF架構(gòu)選擇它認為適用的插件。最后,記錄器實用工具提供了一些接受媒體服務器遺留參數(shù)的“打開’’函數(shù)。通常,如果作為參數(shù)提供給“打開”函數(shù)的目標文件并不存在,則創(chuàng)建該文件,并使用特定的文件擴展名作為使用格式的線索。
58錄制剪輯與使用播放器實用工具一樣,對于三種音頻記錄錄制剪輯
audi02例程演示了記錄器和轉(zhuǎn)換實用工具的使用,并且直接使用了7.6節(jié)所描述的控制器框架。本節(jié)著眼于使用記錄器實用工具打開一個WAV文件并進行錄制。59錄制剪輯audi02例程演示了記錄器和轉(zhuǎn)換實用工錄制剪輯
在實例audi02的引擎中,ConstructL()函數(shù)創(chuàng)建音頻記錄器實用工具類的—個實例,使用的是現(xiàn)在已經(jīng)變得熟悉的模式,表明引擎本身就是實用工具的觀察器:voidCAudio2Engine::ConstructL(){ deleteiUtility;iUtility=NULL;iUtility= CMdaAudioRecorderUtility::NewL(*this);iUtility->OpenFileL(KFileName);}
60錄制剪輯在實例audi02的引擎中,Constru錄制剪輯
創(chuàng)建了實用工具之后,ConstructL()打開用于錄制的文件,這會引起觀察器的MoscoStateChangeEvent()函數(shù)被調(diào)用,并以EOpen的當前狀態(tài)及一個錯誤碼KErrNone為參數(shù)。voidCAudio2Engine::MoscoStateChangeEvent(CBase*aObject,TIntaPreviousState,TIntaCurrentState,TIntaErrorCode){ if(aErrorCode!=KErrNone) {//消息 iState=ENotReady; return;}61錄制剪輯創(chuàng)建了實用工具之后,ConstructL(錄制剪輯
if(aObject==iUtility) { switch(aCurrentState) { caseCMdaAudioClipUtility::EOpen: iState=EReady; break; caseCMdaAudioClipUtility::ERecording: iState=ERecording; break; caseCMdaAudioClipUtility::EPlaying: iState=EPlaying; break; default:; } }
62錄制剪輯if(aObject==iUtili錄制剪輯
else//必須為轉(zhuǎn)換器 { … }}在該例中,MoscoStateChangeEvent()所報告的狀態(tài)用于維護一個內(nèi)部狀態(tài)機。任何錯誤都會使內(nèi)部狀態(tài)置為ENotReady,該狀態(tài)用于表示實用工具類不可用。63錄制剪輯else//必須為轉(zhuǎn)換器63錄制剪輯
在開始錄制之前,可能會使用如下函數(shù)設置一或多個錄制參數(shù):SetDestinationDataTypeL0。SetDestinationFormat()。SetDestinationBitRate()。SetDestinationSampleRateL()。SetDestinationNumberOfChannels()。SetMaxWriteLength()。目標數(shù)據(jù)類型是作為TFourCC提供的,它規(guī)定使用MmfFourCC.h中所定義的正確編碼方法。
64錄制剪輯在開始錄
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年鐵礦石采購協(xié)議3篇
- 二零二五年度旅游區(qū)臨時車位租賃服務協(xié)議書3篇
- 二零二五美容院員工勞動合同及福利待遇協(xié)議4篇
- 2025年度建筑材料出口協(xié)議(綠色建筑認證)4篇
- 2025年度廠房租賃與環(huán)保達標承諾協(xié)議4篇
- 2025年度快速充電樁場地租賃及維護合作協(xié)議4篇
- 二零二五版重型機械吊裝作業(yè)安全協(xié)議書2篇
- 二零二五年度高空作業(yè)安全免責協(xié)議及高空作業(yè)現(xiàn)場安全監(jiān)督合同3篇
- 2025版門衛(wèi)室安保培訓服務合同范本4篇
- 2025年度現(xiàn)代農(nóng)業(yè)項目投資履約類保函擔保合同4篇
- 銳途管理人員測評試題目的
- 焊接材料-DIN-8555-標準
- 工程索賠真實案例范本
- 重癥醫(yī)學科運用PDCA循環(huán)降低ICU失禁性皮炎發(fā)生率品管圈QCC持續(xù)質(zhì)量改進成果匯報
- 個人股權(quán)證明書
- 醫(yī)院運送工作介紹
- 重癥患者的容量管理
- 學習游戲?qū)χ行W生學業(yè)成績的影響
- 小學四年級上冊遞等式計算100題及答案
- 新版?zhèn)€人簡歷Excel表格模板共2聯(lián)
- (完整)中國象棋教案
評論
0/150
提交評論