новости сообщество форум вики
Erlang по-русски. Форум » Erlang »

elang:port_close - закрывать stdin перед stdout

(12 posts)

  1. Столкнулся с необычной проблемой.

    Ситуация: пи?у декодер mp3->raw с помощью вызова mpg123 через порты.

    Decoder = open_port({spawn, "mpg123 -s -"}, [binary]),

    Логика простая - мне нужно получать сырые данные в реальном времени (именно в реальном, не быстрее), поэтому я постепенно скармливаю в порт mp3-данные и так же постепенно читаю из него декодированные данные. На этапе открытия-декодирования всё ок. Проблемы начинаются при попытке закрытия порта.

    Обычно логика должна работать так: входящий поток для mpg123 закрывается. mpg123 думает. что файл закончился и флу?ит наружу остаток данных (данные идут кадрами, поэтому внутри mpg123 есть неболь?ой буфер с предыдущим, нераскодированным до конца куском, т.е. с половиной кадра).
    Соответственно, если вначале закрыть ему stdin, то в момент закрытия в stdout придёт остав?ийся кусок данных. Если закрыть stdout, а потом stdin, то mpg123 падает с примерно следущей о?ибкой:

    [audio.c:596] error: Error in writing audio (Broken pipe?)!
    [mpg123.c:583] error: Deep trouble! Cannot flush to my output anymore!

    Что, впринципе, понятно.

    Так вот. port_close, похоже, работает именно так - вначале закрывается stdout порта, а потом stdin. Соответственно, часть данных mpg123 непофлу?ила и они потерялись для меня.

    Перерыл документацию, но способа закрыть отдельно потоки внутри порта не на?ел.
    Что делать?

    Отправлено 1 год назад #
  2. P.S. Аналогичный прикол получается с ogg123, только там вообще он не закрывается полностью (один процесс остаётся бежать и отжирает 100% процессора).

    На сколько вообще работоспособны порты? Может я чего-то не понимаю?

    Отправлено 1 год назад #
  3. Более чем работоспособны. Проверено уже много раз, в том числе и с mpg123. Надо попробовать более традиционным способом работать с ними: подключить библиотеку к драйверу порта, данные пересылать не через стандартные потоки, а через сам порт (port_command). Как в эрланговской документации описано. Сделать специальные команды для инициализации библиотеки и настройки параметров декодирования. Ну и для flush тоже отдельную команду.
    В общем случае все равно не получится только stdin и stdout обойтись.

    Отправлено 1 год назад #
  4. Потыкайте по документации, плз. Я находил некое понятие "драйвер порта", но не на?ёл никакой документации.
    Как мне делать flush или что-то боль?ее, если всё что у меня есть - port_command, который тупо ?лёт в stdin программе данные и всё?

    Отправлено 1 год назад #
  5. > В общем случае все равно не получится только stdin и stdout обойтись.

    Я бы и рад какой-то боль?ий контроль получить, но как? С горя полез по исходникам искать реализацию port_* -комманд и не на?ёл :(

    Отправлено 1 год назад #
  6. Достаточно подробно в документации описано. Раздел:
    Erlang Programming -> Interability Tutorial -> Port Drivers.

    Там все элементарно - если первый ?аг удастся сделать (в Эрланге всегда так :) ). Начните прямо с примера.
    Основной смысл в том, что надо создать С-библиотеку, экспортирующую пару предопределенных функций, необходимых для связи с Эрлангом. А уже из этой библиотеки вызывать методы целевой библиотеки - mpg123.

    Отправлено 1 год назад #
  7. Т.е. я правильно понимаю, что ?татный механизм предназначен только для простых случаев, а что-то боль?ее требует написание своих драйверов порта?

    Отправлено 1 год назад #
  8. Штатный - это о портах? По своей сути просто порты и порты с драйверами - суть одно и то же. В драйверах сделано неболь?ое укра?ательство и пользоваться ими немного удобнее. В обоих случаях надо писать интерфейсный модуль на С.

    Напрямую подлинковать к порту произвольную библиотеку в боль?инстве случаев не получится.

    Отправлено 1 год назад #
  9. Так мне не библиотека нужна была, а просто запущенный в под?елле бинарник, который я могу как-то контролировать (писать-читать в его stdin/stdout и посылать сигналы).

    Отправлено 1 год назад #
  10. Что имеется в виду под бинарником? Подозреваю, что мы все-таки об одном и том же говорим.

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

    А вот если надо автономному С/С++ приложению взаимодействовать с Эрланг-программой, тогда используется другой механизм - СNode и erl_interface. Порты здесь не подойдут.

    Отправлено 1 год назад #
  11. ?звиняюсь, что пропал...

    Луч?е покажу код :)

    Я порождаю декодер

    Decoder = open_port({spawn, "mpg123 -s -"}, [binary]),

    Потом я туда пи?у данные

    port_command(Decoder, Data)

    ? жду декодированные данные

    receive
    {Decoder, {data, Buf}} ->
    %io:format("Decoded data received of length: ~p~n", [length(binary_to_list(Buf))]),
    file:write(Output, Buf),
    loop(Decoder, Output);
    {decoder, eof} ->
    io:format("Eof reached. Switching to next file~n"),
    loop(Decoder, Output);

    .....

    Вот port_command умеет только писать данные, но не умеет закрывать stdin запущенной программы (т.е. не могу туда отправить eof). А мне это надо. ? хотелось без написания промежуточной программы-драйвера порта, потому что имеющийся функционал меня почти устраивает :)

    Отправлено 1 год назад #
  12. Да, все именно так.
    Промежуточную программу (драйвер порта) написать надо. open_port вызывать для этой промежуточной программы, а в нее уже загружать mpg123.

    Хотя... это все ?МХО. Возможно и получится конкретно с mpg123 обойтись и без дополнительного драйвера. Не знаю.

    Отправлено 1 год назад #

RSS экспорт этой темы

Отправить сообщение

Вы должны войти в систему, чтобы оставлять сообщения.

 
 

так же

Популярные тэги



Currently online

No Members around.

twitter