зеркало из https://github.com/xamarin/ios-samples.git
[StreamingAudio] Add PlayerViewController instead of using playerController outlet in AppDelegate.cs
This commit is contained in:
Родитель
43dc5c9dbf
Коммит
453ce50ce7
|
@ -0,0 +1,197 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using MonoTouch.Foundation;
|
||||
using MonoTouch.UIKit;
|
||||
using System.Net;
|
||||
using MonoTouch.AudioToolbox;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace StreamingAudio
|
||||
{
|
||||
public partial class PlayerViewController : UIViewController
|
||||
{
|
||||
private NSTimer updatingTimer;
|
||||
private StreamingPlayback player;
|
||||
public Action<string> ErrorOccurred;
|
||||
|
||||
public string SourceUrl { get; private set; }
|
||||
|
||||
public PlayerOption PlayerOption { get; private set; }
|
||||
|
||||
public bool IsPlaying { get; private set; }
|
||||
|
||||
public PlayerViewController (PlayerOption playerOption, string sourceUrl) : base ("PlayerViewController", null)
|
||||
{
|
||||
PlayerOption = playerOption;
|
||||
SourceUrl = sourceUrl;
|
||||
}
|
||||
|
||||
public override void ViewDidLoad ()
|
||||
{
|
||||
base.ViewDidLoad ();
|
||||
|
||||
this.View = View;
|
||||
volumeSlider.TouchUpInside += SetVolume;
|
||||
playPauseButton.TouchUpInside += PlayPauseButtonClickHandler;
|
||||
}
|
||||
|
||||
private void SetVolume (object sender, EventArgs e)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
player.Volume = volumeSlider.Value;
|
||||
}
|
||||
|
||||
public override void ViewWillAppear (bool animated)
|
||||
{
|
||||
base.ViewWillAppear (animated);
|
||||
Title = PlayerOption == PlayerOption.Stream ? "Stream " : "Stream & Save";
|
||||
playPauseButton.TitleLabel.Text = "Pause";
|
||||
timeLabel.Text = string.Empty;
|
||||
|
||||
AudioSession.Initialize ();
|
||||
StartPlayback ();
|
||||
IsPlaying = true;
|
||||
}
|
||||
|
||||
public override void ViewDidDisappear (bool animated)
|
||||
{
|
||||
base.ViewDidDisappear (animated);
|
||||
if (player != null)
|
||||
player.Pause ();
|
||||
}
|
||||
|
||||
private void PlayPauseButtonClickHandler (object sender, EventArgs e)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
if (IsPlaying)
|
||||
player.Pause ();
|
||||
else
|
||||
player.Play ();
|
||||
|
||||
var title = IsPlaying ? "Play" : "Pause";
|
||||
playPauseButton.SetTitle (title, UIControlState.Normal);
|
||||
playPauseButton.SetTitle (title, UIControlState.Selected);
|
||||
IsPlaying = !IsPlaying;
|
||||
}
|
||||
|
||||
private void StartPlayback ()
|
||||
{
|
||||
PreparePlayback ();
|
||||
try {
|
||||
var request = (HttpWebRequest)WebRequest.Create (SourceUrl);
|
||||
request.BeginGetResponse (StreamDownloadedHandler, request);
|
||||
} catch (Exception e) {
|
||||
string.Format ("Error: {0}", e.ToString ());
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseErrorOccurredEvent (string message)
|
||||
{
|
||||
if (ErrorOccurred != null)
|
||||
ErrorOccurred (message);
|
||||
}
|
||||
|
||||
private void PreparePlayback ()
|
||||
{
|
||||
//The following line prevents the audio from stopping when the device autolocks
|
||||
AudioSession.Category = AudioSessionCategory.MediaPlayback;
|
||||
AudioSession.RoutingOverride = AudioSessionRoutingOverride.Speaker;
|
||||
}
|
||||
|
||||
private void StreamDownloadedHandler (IAsyncResult result)
|
||||
{
|
||||
var buffer = new byte [8192];
|
||||
int l = 0;
|
||||
int inputStreamLength;
|
||||
double sampleRate = 0;
|
||||
|
||||
Stream inputStream;
|
||||
AudioQueueTimeline timeline = null;
|
||||
|
||||
var request = result.AsyncState as HttpWebRequest;
|
||||
try {
|
||||
var response = request.EndGetResponse (result);
|
||||
var responseStream = response.GetResponseStream ();
|
||||
|
||||
if (PlayerOption == PlayerOption.StreamAndSave)
|
||||
inputStream = GetQueueStream (responseStream);
|
||||
else
|
||||
inputStream = responseStream;
|
||||
|
||||
using (player = new StreamingPlayback ()) {
|
||||
player.OutputReady += delegate {
|
||||
timeline = player.OutputQueue.CreateTimeline ();
|
||||
sampleRate = player.OutputQueue.SampleRate;
|
||||
};
|
||||
|
||||
InvokeOnMainThread (delegate {
|
||||
if (updatingTimer != null)
|
||||
updatingTimer.Invalidate ();
|
||||
|
||||
updatingTimer = NSTimer.CreateRepeatingScheduledTimer (0.5, () => RepeatingAction (timeline, sampleRate));
|
||||
});
|
||||
|
||||
while ((inputStreamLength = inputStream.Read (buffer, 0, buffer.Length)) != 0) {
|
||||
l += inputStreamLength;
|
||||
player.ParseBytes (buffer, inputStreamLength, false, l == (int)response.ContentLength);
|
||||
|
||||
InvokeOnMainThread (delegate {
|
||||
progressBar.Progress = l / (float)response.ContentLength;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
RaiseErrorOccurredEvent ("Error fetching response stream\n" + e);
|
||||
Debug.WriteLine (e);
|
||||
InvokeOnMainThread (delegate {
|
||||
if (NavigationController != null)
|
||||
NavigationController.PopToRootViewController (true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void RepeatingAction (AudioQueueTimeline timeline, double sampleRate)
|
||||
{
|
||||
var queue = player.OutputQueue;
|
||||
if (queue == null || timeline == null)
|
||||
return;
|
||||
|
||||
bool disc = false;
|
||||
var time = new AudioTimeStamp ();
|
||||
queue.GetCurrentTime (timeline, ref time, ref disc);
|
||||
|
||||
playbackTime.Text = FormatTime (time.SampleTime / sampleRate);
|
||||
}
|
||||
|
||||
private string FormatTime (double time)
|
||||
{
|
||||
double minutes = time / 60;
|
||||
double seconds = time % 60;
|
||||
|
||||
return String.Format ("{0}:{1:D2}", (int)minutes, (int)seconds);
|
||||
}
|
||||
|
||||
private Stream GetQueueStream (Stream responseStream)
|
||||
{
|
||||
var queueStream = new QueueStream (Environment.GetFolderPath (Environment.SpecialFolder.Personal) + "copy.mp3");
|
||||
var t = new Thread ((x) => {
|
||||
var tbuf = new byte [8192];
|
||||
int count;
|
||||
|
||||
while ((count = responseStream.Read (tbuf, 0, tbuf.Length)) != 0)
|
||||
queueStream.Push (tbuf, 0, count);
|
||||
|
||||
});
|
||||
t.Start ();
|
||||
return queueStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// WARNING
|
||||
//
|
||||
// This file has been generated automatically by Xamarin Studio to store outlets and
|
||||
// actions made in the UI designer. If it is removed, they will be lost.
|
||||
// Manual changes to this file may not be handled correctly.
|
||||
//
|
||||
using MonoTouch.Foundation;
|
||||
using System.CodeDom.Compiler;
|
||||
|
||||
namespace StreamingAudio
|
||||
{
|
||||
[Register ("PlayerViewController")]
|
||||
partial class PlayerViewController
|
||||
{
|
||||
[Outlet]
|
||||
MonoTouch.UIKit.UILabel playbackTime { get; set; }
|
||||
|
||||
[Outlet]
|
||||
MonoTouch.UIKit.UIButton playPauseButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
MonoTouch.UIKit.UIProgressView progressBar { get; set; }
|
||||
|
||||
[Outlet]
|
||||
MonoTouch.UIKit.UILabel timeLabel { get; set; }
|
||||
|
||||
[Outlet]
|
||||
MonoTouch.UIKit.UISlider volumeSlider { get; set; }
|
||||
|
||||
void ReleaseDesignerOutlets ()
|
||||
{
|
||||
if (playPauseButton != null) {
|
||||
playPauseButton.Dispose ();
|
||||
playPauseButton = null;
|
||||
}
|
||||
|
||||
if (progressBar != null) {
|
||||
progressBar.Dispose ();
|
||||
progressBar = null;
|
||||
}
|
||||
|
||||
if (timeLabel != null) {
|
||||
timeLabel.Dispose ();
|
||||
timeLabel = null;
|
||||
}
|
||||
|
||||
if (volumeSlider != null) {
|
||||
volumeSlider.Dispose ();
|
||||
volumeSlider = null;
|
||||
}
|
||||
|
||||
if (playbackTime != null) {
|
||||
playbackTime.Dispose ();
|
||||
playbackTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PlayerViewController">
|
||||
<connections>
|
||||
<outlet property="playPauseButton" destination="SP7-sW-LfZ" id="McA-Ba-V84"/>
|
||||
<outlet property="playbackTime" destination="C0l-Uf-RPu" id="Vmp-f6-0bR"/>
|
||||
<outlet property="progressBar" destination="wG9-jD-zWY" id="LLd-y6-2Hr"/>
|
||||
<outlet property="timeLabel" destination="C0l-Uf-RPu" id="Rg0-f5-qgw"/>
|
||||
<outlet property="view" destination="3Mt-jV-nDm" id="2EV-Wk-Xji"/>
|
||||
<outlet property="volumeSlider" destination="Ka9-Cy-B6c" id="LVw-eX-fdw"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="3Mt-jV-nDm">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<slider opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" id="Ka9-Cy-B6c">
|
||||
<rect key="frame" x="18" y="323" width="284" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</slider>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Download Progress:" lineBreakMode="tailTruncation" minimumFontSize="10" id="pEk-Dg-EIy">
|
||||
<rect key="frame" x="20" y="85" width="154" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Volume:" lineBreakMode="tailTruncation" minimumFontSize="10" id="wU8-p7-Dfc">
|
||||
<rect key="frame" x="20" y="281" width="220" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<progressView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="wG9-jD-zWY">
|
||||
<rect key="frame" x="20" y="134" width="280" height="2"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</progressView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Streaming audio:" lineBreakMode="tailTruncation" minimumFontSize="10" id="d3N-Vw-0MV">
|
||||
<rect key="frame" x="20" y="20" width="130" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Sample Time:" lineBreakMode="tailTruncation" minimumFontSize="10" id="CqO-hs-cJP">
|
||||
<rect key="frame" x="20" y="175" width="273" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="SP7-sW-LfZ">
|
||||
<rect key="frame" x="124" y="372" width="72" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="15"/>
|
||||
<state key="normal" title="Pause">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
</button>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Label" textAlignment="right" lineBreakMode="tailTruncation" minimumFontSize="10" id="C0l-Uf-RPu">
|
||||
<rect key="frame" x="198" y="175" width="102" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
Загрузка…
Ссылка в новой задаче