Танцы с бубном вокруг Flex Framework
Вот и напросился новый блог - пост.
В этот раз буду писать о всеми любимом компоненте VideoDisplay. Немало я слышал “хороших” отзывов в UAFPUG чате о нем, но все же решил покопать его исходный код. Зачем я надумал это сделать, да только затем чтобы побольше узнавать Framework, да еще приловчиться debug-ить
Flex приложения, хотя нет, у нас есть проект, которому уже год, видео плеер для множества телеканалов. И захотелось мне переписать все на Flex, потому как проект писался на AS2. В один прекрасный день я открыл Flex Builder, сделал малейшее приложение с использованием VideoDisplay компонента, выглядело это примерно так:
К слову: rtmp://localhost/vod/sample.flv - это стандартное видео поставляемое с Flash Media Server 3, тоесть все что я делал, могли сделать и вы, не настраивая сервер и не задумываясь о последствиях.
К моему удивлению, я получил видео, только с дублированием звука. Это было что-то, именно этот артефакт меня заставил копаться в компоненте.Но сначала я проверил Flash Media Administration Console на факт подключений к серверу, и увидел картину
На работе стоит еще вторая версия сервера, но это смысла не меняет.
Оказалось что создается два объекта VideoPlayerNetStream (наследник обычного NetStream), вот и найдена проблема дублирования звука, осталось найти проблему возникновения данной проблемы
Скопировав все классы из Flex 3 SDK в свой проект, я начал разбираться. Хотя нет, сначала ручками свернул все методы классов , да я извращенец, но по-другому мой Flex Builder не сворачивает методы, а самое главное он не настраивается. Первой находкой был массив допустимых протоколов и портов. Интересно, ведь Flex 3 SDK вышел почти одновременно с Flash Media Server 3. Так вот к чему я это все, я увидел это:
private static var RTMP_CONN:Array =[
{ protocol: “rtmp:/”, port: “1935″ },
{ protocol: “rtmp:/”, port:”443″ },
{ protocol: “rtmpt:/”, port:”80″ },
{ protocol: “rtmps:/”, port:”443″ },
];
А кто мне скажет, где парни из Adobe потеряли RTMPE и RTMPTE протоколы? Хотя в последствии я нашел метод с проверкой на протокол, в нем уже учитывались протоколы, вошедшие в новый FMS. Танцы с бубном начались собственно с этого массива.
Далее, несколько операторов проверки на “гадость” и продолжение дебага. В процессе, я нахожу приятнейшую вещь - в компоненте VideoDisplay есть свойство autoBandWidthDetection, так вот как бы вы не старались назначать ему значения true либо false, это было бы только для вас любимых, но не для дела. Да, именно так, оно не использовалось в дальнейшем, простой проброс в VideoPlayer объект (VideoDisplay содержит в себе этот объект, который являеться наследником Video, именно того видео, который можно наблюдать во Flash IDE, а именно создать экземпляр через меню в библиотеке символов, либо попросту это класс принадлежащий Flash Player API), и то на public поле, а не на свойство.
Для многих уже не является загадкой то, что Flash Media Server устанавливает два предопределенных сервиса (vod - video on demand(подготовленное заранее видео), live - трансляция в реальном времени). Те кто еще не щупал, не бойтесь когда увидете в папке vod main.far файл, это архив, просто адаптированный под Flash Media Server. В нем можно найти все что нужно для вашего приложения, а именно файл main.asc (серверный ActionScript). Именно в него я полез, дабы узнать, а что же серверу передается для определения BandWidth. Простой trace, и мы видим в нашей Flash Media Administration Console все что передано на сервер. Оказалось - всегда false.
Для менеджмента подключения к серверу VideoPlayer хранит в себе объект NCManager, который в свою очередь имеет свойство autoSenseBW, именно оно передается серверу при подключении, и вот что я увидел в методе connectToURL() :
autoSenseBW = (_streamName.indexOf(”,”) >= 0);Для меня навсегда останется загадкой, что этим хотели сказать разработчики Flex SDK. Может у кого-то из вас есть некоторые соображения, буду рад если поделитесь. Но судя из этой строки я понял, что всегда передавалось серверу значение false, потому как в строке названия стрима у меня не было запятых. Это приводило к тому, что мы никогда бы не получили bandwidth от сервера. Незамедлительно последовала замена именно на то значение, которое задается в VideoDisplay компоненте.
Немного об FMS:
Не смотря на то, что предустановленный vod сервис на FMS хранит в себе файл main.asc, позволяющий определить BandWidth, мы можем создать свое приложение без каких либо серверных скриптов. Простым движением руки создаем папку с названием приложения, в ней папку streams, а в ней _definst_, в последнюю льем видео контент и можем обратиться к нему по пути - rtmp://[server_domain(в моем случае это был localhost)]/[application_name]/[video_content_name.extension].
В классе NCManager есть чудесный метод connectOnStatus, он являеться листнером NetConnection объекта. Так вот, когда сервер нам отвечает на попытку подключиться, в случае с серверным скриптом или без него, вызывается connectOnStatus, и если ответ success, метод проверяет на false значение autoBandWidthDetection объект VideoPlayer, который собственно и хранит NCManager. Если это подтверждалось, а это подтверждалось, происходил вызов ncConnected у VideoPlayer объекта и тот в свою очередь создавал стрим объект. Все логично, да не так логично, как хотелось бы. При создании объекта NetConnection мы должны серверу дать объект клиента, для получения метаданных и того же bandwidth. Роман Шупер по-моему говорил на первой встрече UAFPUG о том, что сервер передает неопределенное количество параметров клиенту по факту определения bandwidth, он был прав, метод на то и расчитан. Метод onBWDone выглядел так :
public function onBWDone(… rest):void{
var p_bw:Number;
if (rest.length > 0) p_bw = rest[0];
owner.onConnected(netConnection, p_bw);
}
Все отлично, переберем мусор и узнаем bandwidth, так я подумал в первую секунду. Но подождите, а если bw не передан нам сервером, и мы не хотели его узнавать, onConnected вызоветься у NCManager, за ним последует вызов ncConnected у VideoPlayer, что поведет за собой создание еще одного стрим объекта. Вот она загадка дублирующегося звука.
Исходный код прилагается. Можно использовать, только одна проблема, в Design Mode во Flex Builder вы не будете видеть темный бекграунд как в стандартном компоненте. Протестировано только на проблему, которую я описывал, если что-нибудь еще найдете пишите. VideoDisplayControl.
Пример использования:
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” xmlns:ui=”com.agilemind.controls.*”> <ui:VideoDisplay width=”512″ height=”288″ source=”rtmp://localhost/vod/sample.flv”> </ui:VideoDisplay> </mx:Application>Перед использованием следует папку из архива поместить в соурсы проекта.
.jpg)
