惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
MyScale Blog
MyScale Blog
PCI Perspectives
PCI Perspectives
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security
L
Lohrmann on Cybersecurity
C
Cybersecurity and Infrastructure Security Agency CISA
Spread Privacy
Spread Privacy
量子位
P
Proofpoint News Feed
T
Tailwind CSS Blog
腾讯CDC
G
Google Developers Blog
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
博客园 - 司徒正美
GbyAI
GbyAI
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
A
About on SuperTechFans
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
Recorded Future
Recorded Future
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
aimingoo的专栏
aimingoo的专栏
美团技术团队
Engineering at Meta
Engineering at Meta
博客园 - 【当耐特】
小众软件
小众软件
F
Fortinet All Blogs
Last Week in AI
Last Week in AI
U
Unit 42
T
The Blog of Author Tim Ferriss
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
Recent Announcements
Recent Announcements
S
SegmentFault 最新的问题
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
A
Arctic Wolf
C
CERT Recently Published Vulnerability Notes
Security Latest
Security Latest
L
LINUX DO - 热门话题

博客园 - 吴文力

VC 开机自动启动程序代码 Symbian中音频API的使用(摘录) symbian 游戏开发中一些技术细节(摘录) 动态库的调用等技术 VC小技巧 15个问题 - 吴文力 - 博客园 VC 常见问题百问 VC/MFC Q&A 200409 DELL 电脑的区别 报表式CListCtrl的使用详解初稿 俄罗斯科学家语出惊人:怀孕前就能预设生男生女 PE文件格式详解 怎样在目录中寻找文件 如何让程序自动管理线程 WinNT & Win2K下实现进程的完全隐藏——宿主程序 木马病毒是如何利用文件关联和设置名感染的 104种清除木马完全攻略 Programming Applications for Microsoft Windows(四) Programming Applications for Microsoft Windows(三) Programming Applications for Microsoft Windows(二)
Symbian中声音处理
吴文力 · 2009-08-16 · via 博客园 - 吴文力

引擎中使用CMdaAudioOutputStream和MMdaAudioOutputStreamCallback完成声音播放功能。它主要有三个类组成:
  CAudioStreamPlayer。它复合CMdaAudioOutputStream,继承CActive,实现MMdaAudioOutputStreamCallback接口。我们需要小心的维持缓冲区的大小以获得低延迟播放。CActive不断的建立新的任务,在RunL函数中估算缓冲区中的剩余数据,向其中追加适当的数据,维持缓冲区的预期大小。
  CSimpleMixer。它实现CAudioGenerator接口。因为CMdaAudioOutputStream是一个单一的流式播放器,所以需要写一个混音器进行波形混合。这里波形混合就是简单的数据相加。混音器有许多的声道(channel)。每个channel记录了其中的CAudio指针和当前播放位置。
  CAudio。包含一个音频缓冲区。对每个声音文件,我们还需要一个类把它载入到内存缓冲区中。
        我不会在此讲解如何实现音频播放,那需要单独的一篇文章。如果你也使用这种方法实现声音播放,我只想在此和大家讨论两个问题。
需要学习声音基础的话,可以参考www.newlc.com/article.php?id_article=113。(可惜我当时学习声音时那篇文章和代码找不到了)

1.5.1. 声音的关闭和开启
        因为整个音频系统是一个拉的结构,音频流从混音器那里拉数据,混音器从音频缓冲区中拉数据。所以,只要把CMdaAudioOutputStream和写数据的CActive对象delete掉,声音播放就全部停止了。在我的实现中,也就是delete CAudioStreamPlayer对象即可。再想要开启声音,只需要重新创建这个对象。
这个实现的好处是程序的其它部分不需要保存声音是否开启这个状态。因为CAudio和CSimpleMixer对象是存在的,CAudio就可以把自己插入到Mixer的channel中,觉得自己好像在播放一样。其实因为CAudioStreamPlayer根本没有从Mixer向外拉数据,声音设备是完全停止的。
        但是在恢复声音播放时有一点需要注意,恢复前需要清空混音器中的声音数据。因为经过了长时间的运行,混音器中的各个channel中已经塞满了各种声音。如果此时突然打开,会传出各种延迟了的杂音。

1.5.2. 特殊错误处理
        MMdaAudioOutputStreamCallback接口中的几个回调函数MaoscOpenComplete、MaoscBufferCopied和MaoscPlayComplete都有一个错误码参数。你不能忽略这个参数。
比如MaoscPlayComplete函数,是在音频停止播放时被调用。停止播放的原因可能是多种多样的。我们都知道要处理KErrUnderflow这个情况,这个错误吗意味着混音器没有及时的供给它音频数据。此时需要重新启动声音流。但是还有一些情况比如KErrDied和KErrInUse很容易被忽略。KErrDied发生在接听电话时,此时声音线程已经死了,那么就需要重建整个音频系统。KErrInUse发生在收到短信时,此时声音设备被抢占,用来播放短信提示音。此时你也需要重建整个声音系统,但是此时不能立刻重建,否则还是一样的结果。你应该等待几秒钟之后才重建它。
上面说的重启声音流和重建声音系统深度不同。重启声音流在稍后的代码中可以看到。其中RunAudioL向音频流写入了第一个声音缓冲区。重建声音系统在我的实现中就是指先delete 再NewL创建CAudioStreamPlayer对象。
这三个错误的处理代码如下:
// Audio stream API callback: Called when playback has finished.
void CAudioStreamPlayer::MaoscPlayComplete(TInt anError) 
{
 if (m_bInDelay)
  return;
 // If we finish due to an underflow, we"ll need to restart playback.
 // Normally KErrUnderlow is raised at stream end, but in our case the API
 // should never see the stream end -- we are continuously feeding it more
 // data! Many underflow errors mean that the latency target is too low.
 if ( anError == KErrUnderflow ) {
  iObserver->MasoMessage(_L("Play Underflow"));
  // The number of samples played gets resetted to zero when we restart
  // playback after underflow
  iBaseSamplesPlayed = iSamplesWritten;

  // Stop and restart
  iStream->Stop();
  Cancel();
#ifdef RATE_16K
  iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate16000Hz, 
          TMdaAudioDataSettings::EChannelsMono);
#else
  iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate8000Hz, 
          TMdaAudioDataSettings::EChannelsMono);
#endif
  iStream->SetVolume(iStream->MaxVolume() / 4);
  TRAPD(error, RunAudioL());
  if ( error != KErrNone ) {
   User::Panic(KPlay, error);
  }

  return;      
 } 
 else if ( anError == KErrDied )
 {
  m_bInDelay = ETrue;
  m_RebuildDelay = 0; // no delay
 }
 else if ( anError == KErrInUse )
 {
  m_bInDelay = ETrue;
  m_RebuildDelay = 3000; // delay 3 second
 }
 else if ( anError != KErrNone ) {
  // Some other error, panic!
  User::Panic(KPlayComplete, anError);
 }
}
        由外界发现m_RebuildDelay标志,重建CAduioStreamPlayer这个对象。
除了MaoscPlayComplete,我在MaoscBufferCopied中忽略了KErrUnderflow和KErrAbort错误。在MaoscBufferCopied和MaoscOpenComplete也处理了KErrInUse错误。
经过上面的处理,我的程序已经可以安全的应对来电、短信、切换程序等特殊情况了。