2008年06月16日

Podcast再生用mp3プレーヤーをAIRで作ってみました

Podcastの再生アプリケーションをAIRで作っていると、動画の再生はvideodisplayやFLVPlaybackのようなコントロールがすでにあってちょっとしたものは簡単に作れるんですが、mp3の再生はsoundクラスを直接扱わないとならないため、やや面倒だったりします。

ということでmp3再生用のクラスとmxmlコンポーネントのコントロールを作って、その辺のアプリケーションの作成を簡単にできないか考えてみました。

ソースとAIRファイルはこちらでダウンロードできます。
後々動画用のプレーヤーと統合したいので、PodcastのデータベースはPoleviのものを流用しています。

まずはmp3再生用のSoundPlayerクラスですが、playmp3とpausemp3メソッドで擬似的なポーズと再生ができるようにしています。soundVolume()で音量の調整
、playTimeで再生の進み具合を0〜1の数値で返すようになっています。

package{
import flash.display.Sprite;
import flash.errors.*;
import flash.events.*;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.net.URLRequest;

public class SoundPlayer{
public var snd:Sound = new Sound();
public var ch:SoundChannel;
public var myContainer:Sprite;
public var pos:Number = 0;
public var st:SoundTransform;
public var playFlag:Boolean = false;
public var pauseFlag:Boolean = false;
public var total:Number;
public var ptime:Number = 0;


public function SoundPlayer(){}
public function playmp3(soundUrl:String):void{
var soundReq:URLRequest = new URLRequest(soundUrl);
if (playFlag != true){
var st:SoundTransform = new SoundTransform(0.5, 0);
snd.load(soundReq);
ch = snd.play();
playFlag = true;
ch.soundTransform = st;
ch.addEventListener(Event.SOUND_COMPLETE, soundComplete);
}else if (pauseFlag == true){
ch = snd.play(pos);
}else if(playFlag == true){
snd.close();
snd.load(soundReq);
ch = snd.play();
}
}
public function seek(position:Number):void{
var t:Number = snd.length*position;
ch = snd.play(t);
playFlag = true;
}
public function pausemp3():void{
if(playFlag == true){
pos = ch.position;
ch.stop();
pauseFlag = true;
}
}

public function stopmp3():void{
if(playFlag == true){
ch.stop();
playFlag = false;
}
}
public function soundComplete(event:Event):void{}

public function soundVolume(vol:Number):void{
st = new SoundTransform(vol, 0);
ch.soundTransform = st;
}
public function playTime(t:Number):Number{
var hPos:Number = ch.position;
ptime = hPos/t;
return ptime;
}
}
}


プレーヤーのスキンはmxmlコンポーネントで作成。
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="288" height="40"
creationComplete="init()">

<mx:Script>
<![CDATA[
import mx.events.SliderEvent;
import mx.controls.sliderClasses.Slider;
import flash.net.URLRequest;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.net.URLRequest;

public var mySp:SoundPlayer;
public var myVol:Number;
public var mySec:Number;
private var check:Number;
public var myUl:String;

private function init():void{
myUl = new String();
playbtn.addEventListener(MouseEvent.CLICK, playsnd);
}
private function playsnd(event:MouseEvent):void{
mySp.playmp3(myUl);
myVs.selectedChild=playing;
this.addEventListener(Event.ENTER_FRAME, spend);
}
private function pausesnd(event:MouseEvent):void{
mySp.pausemp3();
myVs.selectedChild=normal;
this.removeEventListener(Event.ENTER_FRAME, spend);
}
private function volHandler(event:SliderEvent):void{
myVol = sl.value;
mySp.soundVolume(myVol);
}
public function spend(event:Event):void{
var check:Number = mySp.playTime(mySp.snd.length);
ph.value = check;
}
private function onThumbRelease():void{
var myPos:Number = ph.value;
trace("release");
mySp.seek(myPos);
}
private function onThumbPress():void{
mySp.pausemp3();
}
]]>
</mx:Script>
<mx:Canvas x="3" y="2" width="282" height="36" cornerRadius="14"
backgroundColor="#3D3D3D" borderStyle="solid" borderThickness="0"
backgroundAlpha="0.85">

<mx:ViewStack id="myVs">
<!--停止中-->
<mx:Canvas id="normal">
<mx:Button x="18" y="5" id="playbtn"
overSkin="@Embed(source='assets/play_btn_active.png')"
upSkin="@Embed(source='assets/play_btn_over.png')"
downSkin="@Embed(source='assets/play_btn_over.png')"
/>
</mx:Canvas>
<!--再生中-->

<mx:Canvas id="playing">
<mx:Button x="18" y="5" id="pausebtn_b"
overSkin="@Embed(source='assets/pause_btn_active.png')"
upSkin="@Embed(source='assets/pause_btn_over.png')"
downSkin="@Embed(source='assets/pause_btn_over.png')"
click="pausesnd(event)"
/>

</mx:Canvas>
</mx:ViewStack>
<mx:HSlider id="ph"
minimum="0" maximum="1"
x="86" y="3" width="114" themeColor="#ADD4F4"
showTrackHighlight="false" focusThickness="10"
thumbPress="onThumbPress()"
thumbRelease="onThumbRelease()"
thumbDisabledSkin="@Embed(source='assets/skin_vs.png')" allowTrackClick="false"
tickThickness="12" trackSkin="@Embed(source='assets/bg_slider_1.png')" fillAlphas="50"
focusSkin="@Embed(source='assets/icon16.png')"
thumbSkin="@Embed(source='assets/bg_thum_1.png')" trackColors="#666666"/>

<mx:HSlider x="208" y="6" width="65" id="sl"
minimum="0" maximum="1"
thumbSkin="@Embed(source='assets/thumbskin.png')"
change="volHandler(event)" value="0.5"/>

</mx:Canvas>
</mx:Canvas>



アプリケーションの本体はxmlのパーサー等だいたいPoleviと同じ様な構成。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="340" height="276"
creationComplete="init()" xmlns:local="*" backgroundGradientAlphas="[1.0, 1.0]"
backgroundGradientColors="[#363636, #363636]">

<mx:Script>
<![CDATA[
import mx.controls.Image;
import flash.net.*;
import mx.rpc.events.ResultEvent;
import mx.events.ListEvent;
import mx.collections.ArrayCollection;
import mx.controls.TextArea;

private var ap1Window:podcastUrlWindow;

[Bindable]
private var rssList:XMLList;
private var i:uint = new uint;

[Bindable]
private var ul:String;
private var myPhoto:String;

[Bindable]
private var sp:SoundPlayer;
private var pg:SNDProgress;

private function init():void{
ap1Window = new podcastUrlWindow();
ap1Window.systemChrome = NativeWindowSystemChrome.NONE;
ap1Window.transparent = false;
ap1Window.title = "Register Your Podcast";
ap1Window.open();

ap1Window.dg.addEventListener(ListEvent.CHANGE, changeHandler);

sp = new SoundPlayer();
}
//podcast rssを取得
private function changeHandler(event:ListEvent):void{
i = 0;
var newRss:String = event.target.selectedItem.url;
if(newRss!= null){
hs.url = newRss;
hs.send();
}
}
private function resultHandler(event:ResultEvent):void{
rssList = event.result.channel.item;
ul = rssList.enclosure.@url[i];
txt_last.text = rssList.title[i-1];
txt_next.text = rssList.title[i+1];
txt_now.text = rssList.title[i];

var myImage:Image = new Image();
myImage.source = myPhoto;
myImage.width = 100;
myImage.height = 100;
ui.addChild(myImage);

if (sp.playFlag == true){
sp.pausemp3();
sp.stopmp3();
sp = new SoundPlayer();
sp.playmp3(ul);
con.myVs.selectedIndex=1;
this.addEventListener(Event.ENTER_FRAME, con.spend);
}else{
sp = new SoundPlayer();
sp.playmp3(ul);
con.myVs.selectedIndex=1;
this.addEventListener(Event.ENTER_FRAME, con.spend);
}
}
private function lastSound():void{
var rssLength:Number = rssList.length();
var ul:String = new String;
if(i < rssLength){
i--;
sp.stopmp3();
ul = rssList.enclosure.@url[i];
var sec:Number = rssList.enclosure.@length[i];
txt_last.text = rssList.title[i-1];
txt_now.text = rssList.title[i];
txt_next.text = rssList.title[i+1];

sp = new SoundPlayer();
sp.playmp3(ul);
con.myVs.selectedIndex=1
}
}
private function nextSound():void{
var rssLength:Number = rssList.length();
var ul:String = new String;
if(i < rssLength){
i ++;
sp.stopmp3();
ul = rssList.enclosure.@url[i];
var sec:Number = rssList.enclosure.@length[i];
txt_last.text = rssList.title[i-1];
txt_now.text = rssList.title[i];
txt_next.text = rssList.title[i+1];

sp = new SoundPlayer();
sp.playmp3(ul);
con.myVs.selectedIndex=1
}
};
]]>
</mx:Script>
<mx:HTTPService id="hs" result="resultHandler(event)"
resultFormat="e4x" useProxy="false" />

<mx:Canvas x="0" y="0" height="209" borderColor="#454545"
backgroundColor="#999797" width="100%">

<local:SNDControl mySp="{sp}" myUl="{ul}"
y="159" horizontalCenter="0" id="con"/>

<mx:UIComponent id="ui" width="152" height="128" x="93" y="10"/>
</mx:Canvas>
<mx:HBox id="mycv" width="100%" height="30"
backgroundColor="#393939" borderStyle="none"
borderColor="#CFCFCF" verticalAlign="middle"
horizontalAlign="center" y="214">

<mx:Image width="8" height="12" source="@Embed('assets/tri1.png')"/>
<mx:Label id="txt_last" click="lastSound()"
text="last" width="64" color="#909090" fontSize="9"
textAlign="center" height="18"/>

<mx:Label id="txt_now" text="now playing" width="152"
color="#ADADAD" fontSize="10" textAlign="center" height="20"/>

<mx:Label id="txt_next" click="nextSound()"
text="next" width="58" color="#909090" fontSize="9"
textAlign="center" height="18"/>

<mx:Image width="8" height="12" source="@Embed('assets/tri2.png')"/>
</mx:HBox>
</mx:WindowedApplication>

結局、オブジェクト指向なコーディングに(というかコーディング作業そのものに)慣れてないのもあって汎用性のなさそうなコードになってしまうんですよね。

タグ:flex AIR Flash
posted by オーイシ at 23:08| Comment(0) | TrackBack(0) | Flash | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/100755037

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。