当前位置: 首页>>技术教程>>正文


如何将实时音频流设置为DLNA兼容设备?

, , , , ,

问题描述

有没有办法将声卡的实时输出从我们的12.04.1 LTS amd64桌面流式传输到我们网络中的DLNA-compliant外部设备?使用Rygel,miniDLNA和uShare选择共享目录中的媒体内容总是很好 – 但到目前为止,我们完全无法通过DLNA向客户端获取实时音频流。

Pulseaudio声称有一个DLNA /UPnP媒体服务器,与Rygel一起应该这样做。但我们无法让它运行。

我们遵循live.gnome.orgthis answer中列出的步骤,以及另一个similar guide中列出的步骤。


在12.04 LTS中,我们可以在DLNA客户端中选择本地音频设备或我们的GST-Launch流,但Rygel显示以下消息,并且客户端声明它到达播放列表的末尾:

(rygel:7380): Rygel-WARNING **: rygel-http-request.vala:97: Invalid seek request

无法在客户端上收听实时音频流。


只有在分发升级到14.04 LTS之后,我们才能从设置很好的outlined in below answer中选择我们的DLNA渲染器上的实时流。仍然,我们需要在启动rygel之后选择已建立的流,并且无法将新流推送到我们的UPnP设备。音频元数据未传输。


有没有其他选择将我们的声卡的音频作为实时流发送到DLNA客户端?

最佳解决方法

Pulseaudio-DLNA

我创建了一个小型服务器,可以发现网络中的所有upnp渲染器,并将它们作为接收器添加到pulseaudio。因此,您可以通过pavucontrol控制每个应用程序在您的upnp设备上播放。

这是我在linux下处理upnp设备时一直想要的那种舒适感。

应用程序可以从源代码或DEB包downloadable from git安装,或者在我们将项目的官方ppa:qos/pulseaudio-dlna添加到我们的源代码后:

sudo apt-get update && sudo apt-get install pulseaudio-dlna

然后,我们从命令行运行pulseaudio-dlna,其中包含以下选项:

pulseaudio-dlna [--host <host>] [--port <port>] [--encoder <encoder>] [--renderer-urls <urls>] [--debug]
pulseaudio-dlna [-h | --help | --version]

有关更多信息,另请参阅pulseaudio-dlna “About”

当存在DLNA渲染器时,我们可以从声音菜单中选择它作为输出接收器:

pulseaudio,streaming,upnp,dlna,rygel,ubuntu

次佳解决方法

Pavucontrol是这个拼图游戏中缺少的项目!我也正确设置了一切,外部设备(LG电视)显示声音正在播放,但我没有听到任何声音。今天我安装了pavucontrol,当我打开它时,我找到了通过DLNA服务器引导声音的选项。仅当播放器向pulseaudio输出声音时,才会显示DLNA选项。

pulseaudio,streaming,upnp,dlna,rygel,ubuntu

第三种解决方法

对不起,我根本无法帮助你使用Rygel,但可能有一个替代方案可能适合你。

原理是获取一个程序将流记录到audiofile,然后使用指向流所在目录的自定义配置启动miniDLNA。

示例:假设我们在〜/stream /中工作。创建〜/stream /minidlna.conf

network_interface=wlan0
media_dir=/home/<user>/stream/
friendly_name=Live Audio Stream
db_dir=/home/<user>/stream/
album_art_names=Cover.jpg/cover.jpg/AlbumArtSmall.jpg/albumartsmall.jpg/AlbumArt.jpg/albumart.jpg/Album.jpg/album.jpg/Folder.jpg/folder.jpg/Thumb.jpg/thumb.jpg
inotify=no
enable_tivo=no
strict_dlna=no
notify_interval=900
serial=12345678
model_number=1

然后将流保存到该目录中的audiofile。谷歌搜索“FFmpeg记录声卡音频”产生了这个命令

ffmpeg -f alsa -i default -acodec flac ~/stream/OutputStream.flac

但我没有太多运气。另一个选择是vlc,你有一个GUI可用,但这不起作用。

然后在另一个终端窗口中启动miniDLNA:

minidlna -d -f ~/stream/minidlna.conf -P ~/stream/minidlna.pid

它应该找到OutputStream.flac,然后可以从您的网络设备访问。

希望如果你还没有解决它给你一些想法。

第四种方法

我必须将“我听到的”流式传输到DLNA渲染器(如WDTV)的一个想法是使用VLC作为http流服务流,并将pulse://alsa_output.xxx.monitor作为输入,并将其转码为MP3或FLAC。然后我想使用一些DLNA控制点让渲染器播放taht流。 VLC确实正确地为转码流提供服务,但它不允许设置mime类型,因此渲染器拒绝播放它。

接下来的想法是在python中编写一个http服务器来代替服务流。它使用parec从脉冲获取音频流,使用flac(或lame或您想要的任何内容)对其进行编码,并正确设置mime类型。

它适用于以下(非常简单)脚本:

#!/usr/bin/python

import BaseHTTPServer
import SocketServer
import subprocess

PORT = 8080
# run "pactl list short |grep monitor" to see what monitors are available
# you may add a null sink for streaming, so that what is streamed is not played back locally
# add null sink with "pactl load-module module-null-sink"
MONITOR = 'null.monitor'
MIMETYPE = 'audio/flac'
ENCODER = 'flac - -c --channels 2 --bps 16 --sample-rate 44100 --endian little --sign signed'
BUFFER = 65536

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_HEAD(s):
    print s.client_address, s.path, s.command
    s.send_response(200)
    s.send_header('content-type', MIMETYPE)
    s.end_headers()
def do_GET(s):
    s.do_HEAD()
    pa = subprocess.Popen('parec -d {} | {}'.format(MONITOR, ENCODER), shell = True, bufsize = BUFFER, stdout = subprocess.PIPE)
    while True:
        data = pa.stdout.read(1024)
        if len(data) == 0: break
        s.wfile.write(data)
    print 'stream closed'


httpd = SocketServer.TCPServer(("", PORT), Handler)

print "listening on port", PORT

try:
httpd.serve_forever()
except KeyboardInterrupt:
pass

httpd.server_close()

调整参数,运行它,并将DLNA渲染器指向您的机器。它适用于我的WDTV作为渲染器和带有BubbleUPnP作为控制点的Android手机(您可以在手动将新项目添加到播放列表时输入流URL)。但它应该适用于任何DLNA兼容设备。

第五种方法

注意:此解决方案有效,但Massimo已提出newer and probably better solution

以下是Ubuntu 14.04(也经过测试并在15.04上工作)的答案,完整性:

  1. 安装任何所需的包:sudo apt-get install rygel rygel-preferences rygel-gst-launch

  2. 创建包含以下内容的文件~/.config/rygel.conf

    [GstLaunch]
    enabled=true
    title=@REALNAME@'s stream
    launch-items=myaudioflac;myaudiompeg
    
    myaudioflac-title=FLAC audio on @HOSTNAME@
    myaudioflac-mime=audio/flac
    myaudioflac-launch=pulsesrc device=upnp.monitor ! flacenc quality=8
    
    myaudiompeg-title=MPEG audio on @HOSTNAME@
    myaudiompeg-mime=audio/mpeg
    myaudiompeg-launch=pulsesrc device=upnp.monitor ! lamemp3enc target=quality quality=6
    
    [Playbin]
    enabled=true
    title=Audio/Video playback on @REALNAME@'s computer
    
    [general]
    interface=
    upnp-enabled=true
    
    [MediaExport]
    uris=
    
  3. 从命令行执行以下命令(如果需要,可以将这些命令放入脚本中):

    pactl load-module module-http-protocol-tcp
    pactl load-module module-rygel-media-server 
    rygel &
    
  4. 运行paprefs命令,并确保在”Network Server”选项卡上启用(选中)两个DLNA选项。

  5. 在您的计算机上播放一些音频。运行pavucontrol程序,在”Playback”选项卡上,将输出设备更改为“DLNA /UPnP Streaming”。

此时,您应该能够从DLNA客户端(渲染器/控制点)播放MPEG和FLAC流。

注意:您可能需要重新启动计算机(或重新启动脉冲)才能开始工作。

第六种方法

来自Adam的python脚本正是我所需要的。辉煌。带有gst-launch的Rygel不能与我的一个渲染器一起使用,但是这个脚本适用于两者。在我的情况下,我正在从squeezelite(用于squeezebox)输入音频流并发送到渲染器。该脚本也可以原始形式工作,从脉冲音频监视器获取输入,如果需要的话。

对这些知之甚少,我设法对脚本做了一些补充:

i)允许它从shell脚本运行并以SIGTERM /SIGKILL终止(‘except’语句现在包含’systemexit’)

ii)允许脚本停止并重新启动,并且re-use是相同的端口(因为重新启动的脚本往往失败,说如果渲染器仍然打开它就无法打开端口) – (allow_reuse_address = True语句)

iii)创建一个从stdin获取输入的版本,并使用sox对其进行重新采样,以wav格式输出(在端口8082上)

所以我的版本看起来像:

#!/usr/bin/python

import BaseHTTPServer
import SocketServer
import subprocess

PORT = 8082

MIMETYPE = 'audio/x-wav'
BUFFER = 65536

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
  def do_HEAD(s):
    print s.client_address, s.path, s.command
    s.send_response(200)
    s.send_header('content-type', MIMETYPE)
    s.end_headers()
  def do_GET(s):
    s.do_HEAD()
    pa = subprocess.Popen('sox -t raw -r 96000 -b 24 -L -e signed -c 2 - -t wav -r 44100 -b 16 -L -e signed -c 2 - ', shell = True, bufsize = BUFFER, stdout = subprocess.PIPE)
    while True:
        data = pa.stdout.read(1024)
        if len(data) == 0: break
        s.wfile.write(data)
    print 'stream closed'

SocketServer.TCPServer.allow_reuse_address = True
httpd = SocketServer.TCPServer(("", PORT), Handler)

print "listening on port", PORT

try:
 httpd.serve_forever()

except (KeyboardInterrupt, SystemExit):
 pass

httpd.server_close()

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/1597.html,未经允许,请勿转载。