Написание музыкального стримера Python

Я хотел бы реализовать сервер на Python, который транслирует музыку в формате MP3 через HTTP. Я хотел бы, чтобы он транслировал музыку таким образом, чтобы клиент мог подключиться к потоку и начать слушать все, что сейчас играет, как радиостанцию.

Ранее я реализовал свой собственный HTTP-сервер на Python, используя SocketServer.TCPServer (да, я знаю, что BaseHTTPServer существует, просто хотел сам написать мини-стек HTTP), так чем же архитектурно отличается музыкальный стример? Какие библиотеки мне нужно посмотреть на стороне сети и на стороне MP3?


person AJ.    schedule 16.04.2011    source источник
comment
Вы хотите, чтобы такие вещи, как VLC, могли подключаться к потоку, или вы просто кодируете свой собственный клиент?   -  person thenoviceoof    schedule 17.04.2011
comment
@thenoviceoof - отличный вопрос, да, я бы хотел, чтобы обычные клиенты могли подключаться. iTunes, Winamp, VLC и т. д.   -  person AJ.    schedule 17.04.2011
comment
Вы сжимаете звук в реальном времени или транслируете предварительно созданные файлы MP3?   -  person rakslice    schedule 24.04.2011
comment
@rakslice - меня просто интересует потоковая передача предварительно созданного сжатого звука.   -  person AJ.    schedule 24.04.2011


Ответы (5)


Формат mp3 был разработан для потоковой передачи, что делает некоторые вещи проще, чем вы могли ожидать. Данные представляют собой поток аудиокадров со встроенными граничными маркерами, а не чем заголовок файла, за которым следуют необработанные данные. Это означает, что как только клиент ожидает получить аудиоданные, вы можете просто начать отправлять ему байты из любой точки существующего источника mp3, будь то живой или файл, и клиент будет синхронизироваться со следующим найденным кадром и начать воспроизведение аудио. Ура!

Конечно, вам придется предоставить клиентам возможность установить соединение. Стандартом де-факто является протокол SHOUTcast (ICY). Это очень похоже на HTTP, но поля состояния и заголовка настолько отличаются, что несовместимы напрямую со встроенными библиотеками http-сервера Python. Вы могли бы заставить эти библиотеки сделать часть работы за вас, но их документированных интерфейсов будет недостаточно, чтобы сделать это; вам придется прочитать их код, чтобы понять, как заставить их говорить SHOUTcast.

Вот несколько ссылок для начала:

http://forums.winamp.com/showthread.php?threadid=70403

http://forums.radiotoolbox.com/viewtopic.php?t=74

http://www.smackfu.com/stuff/programming/shoutcast.html

http://en.wikipedia.org/wiki/Shoutcast

Я предлагаю начать с одного mp3-файла в качестве источника данных, настроить соединение клиент-сервер и запустить воспроизведение, а затем перейти к таким проблемам, как живые источники, несколько битрейтов кодирования, внутриполосные метаданные и списки воспроизведения.

Списки воспроизведения обычно представляют собой файлы .pls или .m3u и, по сути, просто статические текстовые файлы, указывающие на URL-адрес вашего прямого эфира. Они не сложны и даже не обязательны, поскольку многие (большинство?) потоковых mp3-клиентов будут принимать URL-адрес прямой трансляции вообще без плейлиста.

Что же касается архитектуры, то поле здесь довольно широкое. У вас столько же вариантов, сколько и для HTTP-серверов. Резьбовой? Рабочие процессы? События? Тебе решать. Для меня более интересным является вопрос, как разделить данные из одного входного потока (вещателя) с сетевыми обработчиками, обслуживающими несколько выходных потоков (проигрыватели). Чтобы избежать сложностей с IPC и синхронизацией, я бы, вероятно, начал с однопоточного дизайна, управляемого событиями. В Python 2 такая библиотека, как gevent, даст вам очень хорошая производительность ввода-вывода, позволяя вам структурировать свой код очень понятным образом. В python 3 я бы предпочел сопрограммы asyncio.

person ʇsәɹoɈ    schedule 18.01.2013
comment
потребует ли для потоковой передачи динамически сгенерированных данных .mp3 расширенное программирование на Python? - person MikeiLL; 10.09.2014

Поскольку у вас уже есть хороший опыт работы с Python (учитывая, что вы уже написали HTTP-сервер), я могу дать только несколько советов о том, как расширить начатую работу, которую вы уже сделали:

  • Подготовьте свой сервер к обработке заголовков запросов, таких как: Accept-Encoding, Range, TE (Transfer Encoding) и т. д. Плеер MP3-over-HTTP (т. е. VLC) — это не что иное, как mp3-плеер, умеющий «говорить» на HTTP. и «искать» разные позиции в файле.

  • Используйте wireshark или tcpdump, чтобы обнюхивать фактические HTTP-запросы, выполняемые VLC при воспроизведении mp3 через HTTP, чтобы вы знали, какие заголовки запросов вы будете получать, и реализовывали их.

Удачи тебе с твоим проектом!

person Oerd    schedule 23.01.2013

Вам следует изучить возможность обслуживания m3u или pls. Это должно дать вам формат файла, который игроки понимают достаточно хорошо, чтобы попасть на ваш http-сервер в поисках mp3-файлов.

Минимальный файл m3u будет просто текстовым файлом с одним URL-адресом песни в строке. Предполагая, что на вашем сервере доступны следующие URL-адреса:

/playlists/<playlist_name/playlist_id>
/songs/<song_name/song_id>

Вы бы обслуживали плейлист по URL-адресу:

/playlists/myfirstplaylist

И содержимое ресурса будет просто:

/songs/1
/songs/mysong.mp3

Плеер (например, Winamp) сможет открыть URL-адрес файла m3u на вашем HTTP-сервере, а затем начнет потоковую передачу первой песни в списке воспроизведения. Все, что вам нужно сделать, чтобы поддержать это, — это обслуживать mp3-файл так же, как вы обслуживаете любой другой статический контент.

В зависимости от того, сколько клиентов вы хотите поддерживать, вы можете захотеть изучить асинхронный ввод-вывод с помощью библиотеки, такой как Twisted, для поддержки множества одновременных потоки.

person stderr    schedule 22.04.2011
comment
Это похоже на SHOUTcast (en.wikipedia.org/wiki/SHOUTcast), который мне нравится. . Мой вопрос: как мне заставить его работать, чтобы файл списка воспроизведения был просто общим URL-адресом, указывающим на поток, а не на конкретный mp3-файл? Даже если URL-адрес /somefile.mp3, я не хочу создавать список воспроизведения с каждой песней. Скорее, я хочу, чтобы это был непрерывный поток песен/рекламы и т. д., как радиостанция. На самом деле, это отличный пример. Как радиостанции делают это со своих сайтов, где можно послушать их прямой эфир там? - person AJ.; 22.04.2011
comment
Я предполагаю, что они просто продолжают записывать аудиоконтент в http-соединение клиентов. Нет причин, по которым данный URL-адрес не может представлять бесконечный поток данных. Если вы не закроете соединение, клиент будет продолжать слушать, поэтому, когда вы закончите потоковую передачу файла песни, просто начните записывать свой рекламный ролик в сокет, а затем другую песню. Можете ли вы поделиться некоторым кодом, чтобы мы могли взглянуть на ваш простой HTTP-сервер и, возможно, поговорить более конкретно о том, что вам нужно сделать? - person stderr; 26.04.2011
comment
Этот ответ не касается начала прослушивания того, что сейчас играет, как радиостанции. - person Craig McQueen; 17.01.2013

Изучите их, прежде чем зайти слишком далеко:

http://wiki.python.org/moin/PythonInMusic

Конкретно

http://edna.sourceforge.net/

person qneill    schedule 28.04.2011
comment
Эдна не говорит о том, чтобы начать слушать то, что сейчас играет, как радиостанцию. - person Craig McQueen; 17.01.2013

Вам понадобится файл .m3u или .pls, указывающий на статический URI (например, http://example.com/now_playing.mp3), а затем дайте им mp3-данные, начиная с того места, где вы находитесь в песне, когда они запросят этот файл. Вероятно, есть куча мелких проблем, которые я здесь умалчиваю... Однако, по крайней мере, как указывает лес, вы можете просто начать потоковую передачу данных mp3 с любого байта.

person mike    schedule 17.01.2013
comment
На самом деле, вы в значительной степени можете просто начать передавать mp3-данные клиенту, как только клиент попросит об этом. Кодирование MP3 не использует заголовок файла. - person ʇsәɹoɈ; 18.01.2013
comment
Хм, интересно. Вы правы, это чередование заголовков/данных по всему файлу. Однако при этом будут пропущены все теги ID3, и моя главная мысль заключается в том, что вам, вероятно, не следует просто начинать с любой позиции байта, вам придется начинать с одного из заголовков. - person mike; 20.01.2013
comment
Вы абсолютно должны просто начать с любой позиции байта. Формат был создан именно для этого. Биты синхронизации присутствуют в каждом кадре специально для этой цели. - person ʇsәɹoɈ; 21.01.2013
comment
Хорошо, я изменил ответ. Спасибо - person mike; 31.01.2013
comment
Как бы вы могли сказать, какой кадр запрашивается? Я хотел бы отслеживать кадры, воспроизводимые в mp3-файле. - person TheRealChx101; 26.10.2020