aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukePulverenti Luke Pulverenti luke pulverenti <LukePulverenti Luke Pulverenti luke.pulverenti@gmail.com>2012-08-12 11:41:40 -0400
committerLukePulverenti Luke Pulverenti luke pulverenti <LukePulverenti Luke Pulverenti luke.pulverenti@gmail.com>2012-08-12 11:41:40 -0400
commit55aa5cb87388a7422831e795d30ef457395f5267 (patch)
treec739a010e3e202578eca4834ed2e27f3d4b8ab14
parentf7ea68615b1e2463fd21989b051db2bf8cde6779 (diff)
Added more audio streaming improvements and extracted BaseMediaHandler
-rw-r--r--MediaBrowser.Api/HttpHandlers/AudioHandler.cs157
-rw-r--r--MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs165
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj1
-rw-r--r--MediaBrowser.Common/Net/MimeTypes.cs8
4 files changed, 180 insertions, 151 deletions
diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
index 51d7ba06a..c3c27c568 100644
--- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
@@ -1,21 +1,16 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Net;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Logging;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Net.Handlers;
-using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
public class AudioHandler : BaseMediaHandler<Audio>
{
+ /// <summary>
+ /// Supported values: mp3,flac,ogg,wav,asf
+ /// </summary>
public IEnumerable<string> AudioFormats
{
get
@@ -35,7 +30,7 @@ namespace MediaBrowser.Api.HttpHandlers
{
get
{
- string val = QueryString["audioformats"];
+ string val = QueryString["audiobitrates"];
if (string.IsNullOrEmpty(val))
{
@@ -48,13 +43,13 @@ namespace MediaBrowser.Api.HttpHandlers
private int? GetMaxAcceptedBitRate(string audioFormat)
{
- int index = AudioFormats.ToList().IndexOf(audioFormat);
-
if (!AudioBitRates.Any())
{
return null;
}
+ int index = AudioFormats.ToList().IndexOf(audioFormat);
+
return AudioBitRates.ElementAt(index);
}
@@ -134,144 +129,4 @@ namespace MediaBrowser.Api.HttpHandlers
return "-i \"" + LibraryItem.Path + "\" -vn " + string.Join(" ", audioTranscodeParams.ToArray()) + " -";
}
}
-
- public abstract class BaseMediaHandler<T> : BaseHandler
- where T : BaseItem, new()
- {
- private T _LibraryItem;
- /// <summary>
- /// Gets the library item that will be played, if any
- /// </summary>
- protected T LibraryItem
- {
- get
- {
- if (_LibraryItem == null)
- {
- string id = QueryString["id"];
-
- if (!string.IsNullOrEmpty(id))
- {
- _LibraryItem = Kernel.Instance.GetItemById(Guid.Parse(id)) as T;
- }
- }
-
- return _LibraryItem;
- }
- }
-
- public int? AudioChannels
- {
- get
- {
- string val = QueryString["audiochannels"];
-
- if (string.IsNullOrEmpty(val))
- {
- return null;
- }
-
- return int.Parse(val);
- }
- }
-
- public int? AudioSampleRate
- {
- get
- {
- string val = QueryString["audiosamplerate"];
-
- if (string.IsNullOrEmpty(val))
- {
- return 44100;
- }
-
- return int.Parse(val);
- }
- }
-
- public override string ContentType
- {
- get
- {
- return MimeTypes.GetMimeType("." + GetOutputFormat());
- }
- }
-
- public override bool CompressResponse
- {
- get
- {
- return false;
- }
- }
-
- public override void ProcessRequest(HttpListenerContext ctx)
- {
- HttpListenerContext = ctx;
-
- if (!RequiresConversion())
- {
- new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx);
- return;
- }
-
- base.ProcessRequest(ctx);
- }
-
- protected abstract string GetCommandLineArguments();
- protected abstract string GetOutputFormat();
- protected abstract bool RequiresConversion();
-
- protected async override Task WriteResponseToOutputStream(Stream stream)
- {
- ProcessStartInfo startInfo = new ProcessStartInfo();
-
- startInfo.CreateNoWindow = true;
-
- startInfo.UseShellExecute = false;
- startInfo.RedirectStandardOutput = true;
- startInfo.RedirectStandardError = true;
-
- startInfo.FileName = ApiService.FFMpegPath;
- startInfo.WorkingDirectory = ApiService.FFMpegDirectory;
- startInfo.Arguments = GetCommandLineArguments();
-
- Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
-
- Process process = new Process();
- process.StartInfo = startInfo;
-
- // FFMpeg writes debug info to StdErr. This is useful when debugging so let's put it in the log directory.
- FileStream logStream = new FileStream(Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid().ToString() + ".txt"), FileMode.Create);
-
- try
- {
- process.Start();
-
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- // If we ever decide to disable the ffmpeg log then you must uncomment the below line.
- //process.BeginErrorReadLine();
-
- Task errorTask = Task.Run(async () => { await process.StandardError.BaseStream.CopyToAsync(logStream); });
-
- await process.StandardOutput.BaseStream.CopyToAsync(stream);
-
- process.WaitForExit();
-
- await errorTask;
-
- Logger.LogInfo("FFMpeg exited with code " + process.ExitCode);
- }
- catch (Exception ex)
- {
- Logger.LogException(ex);
- }
- finally
- {
- logStream.Dispose();
- process.Dispose();
- }
- }
- }
}
diff --git a/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs b/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs
new file mode 100644
index 000000000..f3b217c0d
--- /dev/null
+++ b/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Logging;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Controller;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+ public abstract class BaseMediaHandler<T> : BaseHandler
+ where T : BaseItem, new()
+ {
+ private T _LibraryItem;
+ /// <summary>
+ /// Gets the library item that will be played, if any
+ /// </summary>
+ protected T LibraryItem
+ {
+ get
+ {
+ if (_LibraryItem == null)
+ {
+ string id = QueryString["id"];
+
+ if (!string.IsNullOrEmpty(id))
+ {
+ _LibraryItem = Kernel.Instance.GetItemById(Guid.Parse(id)) as T;
+ }
+ }
+
+ return _LibraryItem;
+ }
+ }
+
+ public int? AudioChannels
+ {
+ get
+ {
+ string val = QueryString["audiochannels"];
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return null;
+ }
+
+ return int.Parse(val);
+ }
+ }
+
+ public int? AudioSampleRate
+ {
+ get
+ {
+ string val = QueryString["audiosamplerate"];
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return 44100;
+ }
+
+ return int.Parse(val);
+ }
+ }
+
+ public override string ContentType
+ {
+ get
+ {
+ return MimeTypes.GetMimeType("." + GetOutputFormat());
+ }
+ }
+
+ public override bool CompressResponse
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override void ProcessRequest(HttpListenerContext ctx)
+ {
+ HttpListenerContext = ctx;
+
+ if (!RequiresConversion())
+ {
+ new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx);
+ return;
+ }
+
+ base.ProcessRequest(ctx);
+ }
+
+ protected abstract string GetCommandLineArguments();
+ protected abstract string GetOutputFormat();
+ protected abstract bool RequiresConversion();
+
+ protected async override Task WriteResponseToOutputStream(Stream stream)
+ {
+ ProcessStartInfo startInfo = new ProcessStartInfo();
+
+ startInfo.CreateNoWindow = true;
+
+ startInfo.UseShellExecute = false;
+
+ // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+
+ startInfo.FileName = ApiService.FFMpegPath;
+ startInfo.WorkingDirectory = ApiService.FFMpegDirectory;
+ startInfo.Arguments = GetCommandLineArguments();
+
+ Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
+
+ Process process = new Process();
+ process.StartInfo = startInfo;
+
+ // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
+ FileStream logStream = new FileStream(Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid().ToString() + ".txt"), FileMode.Create);
+
+ try
+ {
+ process.Start();
+
+ // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+ // If we ever decide to disable the ffmpeg log then you must uncomment the below line.
+ //process.BeginErrorReadLine();
+
+ Task debugLogTask = Task.Run(async () => { await process.StandardError.BaseStream.CopyToAsync(logStream); });
+
+ await process.StandardOutput.BaseStream.CopyToAsync(stream);
+
+ process.WaitForExit();
+
+ Logger.LogInfo("FFMpeg exited with code " + process.ExitCode);
+
+ await debugLogTask;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogException(ex);
+
+ // Hate having to do this
+ try
+ {
+ process.Kill();
+ }
+ catch
+ {
+ }
+ }
+ finally
+ {
+ logStream.Dispose();
+ process.Dispose();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index dafce9510..544dec6a9 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -48,6 +48,7 @@
<ItemGroup>
<Compile Include="ApiService.cs" />
<Compile Include="HttpHandlers\AudioHandler.cs" />
+ <Compile Include="HttpHandlers\BaseMediaHandler.cs" />
<Compile Include="HttpHandlers\GenreHandler.cs" />
<Compile Include="HttpHandlers\GenresHandler.cs" />
<Compile Include="HttpHandlers\ImageHandler.cs" />
diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs
index c4967e37f..89264feb8 100644
--- a/MediaBrowser.Common/Net/MimeTypes.cs
+++ b/MediaBrowser.Common/Net/MimeTypes.cs
@@ -115,6 +115,14 @@ namespace MediaBrowser.Common.Net
{
return "audio/x-ms-wma";
}
+ else if (ext.EndsWith("flac", StringComparison.OrdinalIgnoreCase))
+ {
+ return "audio/flac";
+ }
+ else if (ext.EndsWith("aac", StringComparison.OrdinalIgnoreCase))
+ {
+ return "audio/x-aac";
+ }
else if (ext.EndsWith("ogg", StringComparison.OrdinalIgnoreCase) || ext.EndsWith("oga", StringComparison.OrdinalIgnoreCase))
{
return "audio/ogg";