Стволовые клетки могут успешно заменить умершие клетки мозга

Исследователи Мюнхенского университета Людвига-Максимилиана, Института нейробиологии имени Макса Планка, а также исследовательского Центра им. Гельмгольца в Мюнхене продемонстрировали, что у мышей пересаженные нейроны, полученные из эмбриональных клеток, действительно могут быть включены в существующую сеть и правильно выполнять задачи, за которые отвечали поврежденные клетки. Эта работа имеет большое значение в потенциальном лечении всех приобретенных заболеваний головного мозга, включая инсульты, травмы, нейродегенеративные заболевания вроде болезней Альцгеймера или Паркинсона. Каждый из этих недугов приводит к необратимой потере нервных клеток и пожизненному неврологическому дефициту.

Когда речь заходит о восстановлении, например, после инсульта, у мозга взрослого человека очень мало возможностей для компенсации утраченных нервных клеток. Поэтому врачи и исследователи в области биомедицины изучают возможность использования пересаженных нервных клеток, чтобы заменить нейроны, которые пострадали в результате травмы или болезни. Предыдущие исследования показывают, что существует возможность устранить по крайней мере некоторые клинические симптомы посредством трансплантации фетальных нервных клеток в поврежденные нейронные сети. Однако процесс получения фетальных клеток порождает множество этических вопросов, поскольку добыть этот биоматериал можно только из плода после аборта, примерно на 9-12 неделе беременности. Кроме этого, до конца не ясно, смогут ли пересаженные неповрежденные нейроны достаточно хорошо интегрироваться, чтобы восстановить функции нейронной сети.

В ходе исследования, опубликованного в журнале Nature 26 октября, ученые выяснили, можно ли пересадить эмбриональные нервные клетки так, чтобы они удачно интегрировались в нейронную сеть и функционировали в зрительной коре головного мозга взрослых мышей. «Мы так много знаем о функциях нервных клеток в этой области, что можем легко оценить, действительно ли имплантированные клетки выполняют те задачи, которые возложены на нейронную сеть» — отмечает профессор Марк Хюбенер, один из руководителей исследования. Хюбенер специализируется на структуре и функциях зрительной системы млекопитающих.

В своих экспериментах команда исследователей пересаживала эмбриональные клетки в пораженные области зрительной зоны взрослых мышей. В течение следующих месяцев они наблюдали за поведением имплантированных незрелых нейронов с помощью двухфотонной микроскопии. Этот метод помог выяснить, дифференцируются ли они в так называемые «пирамидальные клетки» — возбудительные нейроны. Тот факт, что клетки выжили и продолжали развиваться, является весьма обнадеживающим. Все стало интереснее, когда исследователи внимательнее изучили электрическую активность трансплантированных клеток. Совместное исследование аспиранта Сюзанны Фолкнер и
постдока Софии Грейд показало, что новые клетки сформировали синаптические связи, которые обычно устанавливаются между клетками сети, и ответили на визуальные стимулы.


На изображении видно, как нервные трансплантанты (синего цвета) связываются с неповрежденными участками сети (желтого цвета)

Затем команда продолжила изучать установленные связи после пересадки нейронов. Они обнаружили, что пирамидальные клетки, полученные из трансплантированных зрелых нейронов, образовали функциональные связи с соответствующими нервными клетками по всему мозгу. Другими словами, они благополучно заняли место своих предшественников. Кроме того, они были в состоянии обрабатывать поступающую информацию и передать ее дальше по сети. «Эти результаты показывают, что имплантированные нервные клетки с исключительной точностью объединялись в нейронную сеть, в которую, при нормальных условиях, никогда не включились бы новые нервные клетки» — объясняет профессор Магдалена Гётц, работа которой заключалась в поиске способов замены утраченных нейронов в центральной нервной системе. Новое исследование показывает, что незрелые нейроны способны правильно реагировать на сигналы в мозге взрослых млекопитающих и могут закрывать функциональные «пробелы» в существующей нейронной сети.

Одним из главных плюсов трансплантации именно эмбриональных стволовых клеток заключается в том, что они не вырабатывают антигены тканевой совместимости. Когда наборы антигенов у донора и реципиента не совпадают, это приводит к отторжению клеток. Но в случае с трансплантацией ЭСК этого не происходит, и шанс, что клетки приживутся, обычно очень велик. Однако ученые выяснили, что существуют механизмы, которые могут помешать приживлению новых клеток.

Процесс создания нейронов из стволовых клеток и клеток-предшественников получил название «нейрогенез». Ученые показали, что на дальнейшую судьбу нейронов-новичков значительное влияние оказывают эпигенетические механизмы, которые вступают в игру на ранних стадиях нейрогенеза. Эти механизмы влияют на наследуемые изменения в фенотипе или экспрессии генов, но при этом не приводят к изменению последовательности в ДНК. Чтобы выяснить, какое значение ранние эпигенетические модификации оказывают на развитие нервных клеток во время эмбриогенеза у мышей, Магдалина Гётц и её коллеги целенаправленно заблокировали активность гена UHRF1. Ген управляет многими эпигенетическими функциями, в том числе и метилированием ДНК — модификацией молекулы ДНК без влияния на последовательность нуклеотидов. Метилирование определенных оснований нуклеотида в ДНК часто служит для того, чтобы «выключать» определенные гены.

Блокировка UHRF1 в передней области мозга крыс привела к активации ретровиральных элементов в геноме, которые до этого подавлялись метилированием. Активация вызвала накопление ретровиральных белков в пораженных клетках и дерегулированию генов. Это, в свою очередь, привело к прогрессирующим нарушениям в жизненно важных клеточных процессах и ускорило массовую гибель клеток. Результаты этого исследования показали, что даже такие факторы, которые действуют только в самом начале нейрогенеза, способны оказывать влияние на судьбу клеток, которое может проявиться только недели спустя.
ссылка на оригинал статьи https://geektimes.ru/post/282080/

Советы по пропорциям и масштабу в играх

Вы создаёте новый хит и хотите, чтобы ваши персонажи вписывались в игру? Многие разработчики часто испытывают проблемы при подборе пропорций отдельных персонажей и соотношений между персонажами и окружением. Вы можете воспользоваться подходом, описанным в статье.

Очевидно, если в вашей игре нет персонажей, этот пост может быть бесполезен для вас (но может быть, он пригодится вам в следующем проекте). Такой подход не ограничивается гуманоидными песонажами и может применяться к антропоморфным и неодушевлённым объектам.

Шаг первый: определитесь с размером тайлов

Подбор размера тайлов — это отдельная задача, решаемая на ранних этапах разработки игры. Тайлы могут измеряться в единицах измерения мира (дюймы, метры и т.д.) или в пикселях.

Если в вашей игре нет сетки тайлов, можно создать черновой макет и использовать соотношения размеров для первоначальной настройки проекта. В моих примерах я воспользуюсь изометрической сеткой, но тип проецирования ни на что не влияет.

Вопросы, которые нужно задать:

  1. Каким будет самый мелкий объект, с которым взаимодействует игрок? Это маленький сундук на земле, или здание, или планета?
  2. Какими будут размер экрана, соотношение сторон и разрешение?
  3. Какой в игре будет масштаб (с точки зрения темы и механики)? Самое важное в игре — это персонажи? Это игра о насекомых или вы управляете городом? Сколько объектов должен видеть игрок (или взаимодействовать с ними) во время игры?
  4. Поддерживает ли игра перемещение камеры? Каким будет положение камеры по умолчанию?


Вариант «A» подходит для клаустрофобного хоррора (можно даже ещё больше приблизиться), «B» лучше использовать для RPG или RTS, вариантом «C» уже невозможно управлять с мобильного телефона или планшета, но он может подойти для крупномасштабных военных действий. «D» слишком мелок для любого взаимодействия: с таким размером тайла невозможно выбрать отдельный тайл (если ваша аудитория не инопланетяне с тонкими пальцами). Есть бесконечное количество промежуточных между «A» и «D» вариантов. Выбор зависит от типа создаваемой игры.

После выбора самого подходящего размера тайла можно перейти к персонажам.

Шаг второй: считаем по головам

Сколько голов помещается в вашем персонаже?


Иллюстрация Эндрю Лумиса (Andrew Loomis)

Небольшая справка: реалистичные взрослые персонажи имеют рост в 7-8 голов. Если в ваших персонажей по высоте помещается 8 или больше голов, то они будут напоминать греческих богов или супергероев.

Но мы не будем обсуждать стиль или рост. Рост относителен, два персонажа с одинаковыми пропорциями могут быть разного роста.

Любой стиль может быть адаптирован под различные пропорции головы и тела.


Иллюстрация Гарона Россиньоля (Garon Rossignol)

Основное, что нам нужно здесь учесть — это соотношение размеров головы персонажа и остальной его части. Например, при создании персонажа высотой в 8 голов можно сказать, что его тело в 7 раз крупнее головы. Бóльшая часть коммуникативной информации и деталей передаётся через тело, а голова и лицо имеют вторичную роль. Я не хочу сказать, что голова не важна: мы обычно всегда рисуем первыми лица и руки (и некоторые другие выдающиеся части тела). Но в силуэте высотой в 8 голов детали и выражения лица будут излишними.


«A» — лицо и тело чётко видны.
«B1» — тело занимает больше пространства, когда персонажи в высоту 8 голов. Детали лица трудно считываются.
«B2» — если в вашей игре необходимо показать эмоции персонажей с реалистичными пропорциями, нужно будет воспользоваться крупными планами.


Левый край: преувеличенные эмоции, «мультяшные» движения, игривое настроение.
Правый край: слабовыраженные эмоции, реалистичные движения, серьёзное настроение.

Большинство анимированных персонажей относится к категории «2-6 голов». Хотя персонажи высотой 8 голов тоже могут быть гиперболизированными и шутливыми, чаще всего они будут относиться к категории серьёзных и реалистичных. Персонажи выше 8 голов тоже могут быть игривыми, но, повторюсь, тело будет привлекать больше внимания, чем голова и лицо.

Вопросы, которые нужно задать:

  1. Насколько важны выражения лиц в игре?
  2. Важно ли реалистичное движение?
  3. Насколько серьёзна/дурашлива ваша игра? Реалистичные пропорции предполагают серьёзный и реалистичный геймплей.
  4. Каким будет угол камеры и меняется ли он во время игры?
  5. Какова средняя ширина головы и тела?

Широкие головы имеют бóльшую площадь поверхности, привлекают больше внимания и перекрывают бóльшую часть тела, когда камера направлена вниз. Если для визуального стиля требуются широкие головы, увеличьте рост на 1-2 головы и добавьте больше тела.

Обратное справедливо для ширины тела.

У вас широкотелые персонажи, которым нужно проявлять больше эмоций? Увеличьте размер головы.

Запомните важное правило: персонажи с небольшим телом можно делать значительно крупнее на экране, они могут выражать больше эмоций и обладать большей артистической свободой и искажённостью. Это позволяет разместить в пространстве экрана больше объектов и информации.


(© Microsoft)
В Age of Empires выражения лиц не важны. Отдельные юниты слабо различаются.


(© Beeline Interactive)
Выражения лиц важны в Smurfs’ Village, и ещё важнее в Minions Paradise. На экране персонажи (и их головы) выглядят больше.


(© EA)

Шаг третий: относительный масштаб и соотношения

Итак, у нас есть персонажи и размер тайлов. Насколько большими должны быть другие объекты относительно персонажей? Настал подходящий момент проверить, соответствуют ли выбранные визуальный стиль и пропорции требованиям игры.

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


(© Firaxis Games)


(© Firaxis Games)
Можно допустить ещё бóльшие искажения, если вы создаёте игру «настольного» типа с иконографикой, похожую на Civilization и нацеленную на взрослую аудиторию.

Давайте пройдём по общему сценарию:

  • Игрок может взаимодействовать со зданиями.
  • Игрок может взаимодействовать с персонажами.
  • Рост персонажей — 3 головы.

В качестве отправной точки выберем золотое сечение (1:1,618).

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

Используем 1:1,618 как отправную точку для определения границ высоты персонажей и зданий.


Слева: правдоподобие, важны здания. Справа: преувеличение, важны персонажи.

Очевидно, персонаж должен быть меньше зданий, чтобы заходить в них.

Можно также использовать соотношение для создания зданий и архитектурных элементов. Если в вашей игре нужны высокие здания, можно расширить выбранное соотношение на дополнительные этажи.


Используйте вариант «A» (простая конструкция), если персонаж должен пермещаться между этажами. Выбирайте «B» (упрощённое золотое сечение) и «C» (расширенное золотое сечение), если перемещение не требуется.

Не забывайте о дверных проёмах.


Убедитесь, что дверные проёмы достаточно велики, чтобы в них помещались персонажи.

Это не единственный способ решения проблемы масштаба, но надеюсь, он будет вам полезен.

Удачного вам гейм-дизайна!


Автор статьи Юрий Сиверс (Yuriy Sivers) — ведущий графический дизайнер в Kongregate. Он занимается гейм-дизайном, концепт-артом, иллюстрациями и анимацией.
ссылка на оригинал статьи https://habrahabr.ru/post/313948/

TextBlock с подсветкой текста (WPF)

Привет Хабр! Я создал контрол на основе TextBlock с возможностью подсветки текста. Для начала приведу пример его использования, затем опишу, как он создавался.

Пример использования контрола

<local:HighlightTextBlock TextWrapping="Wrap">     <local:HighlightTextBlock.HighlightRules>         <local:HighlightRule HightlightedText="{Binding Filter, Source={x:Reference thisWindow}}">             <local:HighlightRule.Highlights>                 <local:HighlightBackgroung Brush="Yellow"/>                 <local:HighlightForeground Brush="Black"/>             </local:HighlightRule.Highlights>         </local:HighlightRule>     </local:HighlightTextBlock.HighlightRules>     <Run FontWeight="Bold">Property:</Run>     <Run Text="{Binding Property}"/> </local:HighlightTextBlock> 

Начало разработки

Потребовалось мне подсветить текст в TextBlock, введенный в строку поиска. На первый взгляд задача показалась простой. Пришло в голову разделить текст на 3 элемента Run, которые бы передавали в конвертер весь текст, строку поиска и свое положение (1/2/3). Средний Run имеет Backgroung.

Не успел я приступить к реализации, как пришла в голову мысль, что совпадений может быть несколько. А значит такой подход не подходит.

Была еще мысль формировать Xaml «на лету», парсить его при помощи XamlReader и кидать в TextBlock. Но эта мысль тоже сразу отвалилась, потому что попахивает.

Следующей (и окончательной) идеей стало создать систему правил подсветки и прикрутить ее к TextBlock. Тут 2 варианта: свой контрол с блэкджеком и девочками на основе TextBlock или AttachedProperty. После недолгих раздумий, я решил, что все таки лучше создать отдельный контрол, потому что функционал подсветки может наложить некоторые ограничения на функциональность самого TextBlock, а разруливать это проще, если от него унаследоваться.

Исходники готового контрола

Итак, приступим. Сразу предупрежу, что контрол я делал в том же проекте, где собирался тестировать первую идею, поэтому не обращайте внимание на неймспейсы. До ума такие вещи я доведу уже, когда буду включать контрол в основной проект (или буду выкладывать на гитхаб).

В Xaml разметке контрола все чисто, за исключением обработчика события Loaded

<TextBlock x:Class="WpfApplication18.HighlightTextBlock"              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"              Loaded="TextBlock_Loaded"> </TextBlock> 

Переходим к коду:

Заголовок спойлера

    public partial class HighlightTextBlock : TextBlock     {         // Здесь сохраняется сериализованное оригинальное наполнение TextBlock          // (подсветка накладывается на оригинал и потом уже подставляется в TextBlock)         string _content;          // Это словарь для правил подсветки и соответствующих им очередей задач         Dictionary<HighlightRule, TaskQueue> _ruleTasks;          /// <summary>         /// Коллекция правил подсветки         /// </summary>         public HighlightRulesCollection HighlightRules         {             get             {                 return (HighlightRulesCollection)GetValue(HighlightRulesProperty);             }             set             {                 SetValue(HighlightRulesProperty, value);             }         }          public static readonly DependencyProperty HighlightRulesProperty =             DependencyProperty.Register("HighlightRules", typeof(HighlightRulesCollection), typeof(HighlightTextBlock), new FrameworkPropertyMetadata(null) { PropertyChangedCallback = HighlightRulesChanged });           static void HighlightRulesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)         {             var col = e.NewValue as HighlightRulesCollection;             var tb = sender as HighlightTextBlock;             if (col != null && tb != null)             {                 col.CollectionChanged += tb.HighlightRules_CollectionChanged;                 foreach (var rule in col)                 {                     rule.HighlightTextChanged += tb.Rule_HighlightTextChanged;                 }             }         }          public HighlightTextBlock()         {             _ruleTasks = new Dictionary<HighlightRule, TaskQueue>();             HighlightRules = new HighlightRulesCollection();             InitializeComponent();         }          // Обработчик события на изменение коллекции правил подсветки         void HighlightRules_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)         {             switch (e.Action)             {                 case System.Collections.Specialized.NotifyCollectionChangedAction.Add:                     foreach (HighlightRule rule in e.NewItems)                     {                         _ruleTasks.Add(rule, new TaskQueue(1));                         SubscribeRuleNotifies(rule);                         BeginHighlight(rule);                     }                     break;                 case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:                     foreach (HighlightRule rule in e.OldItems)                     {                         rule.HightlightedText = string.Empty;                         _ruleTasks.Remove(rule);                         UnsubscribeRuleNotifies(rule);                     }                     break;                 case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:                     foreach (HighlightRule rule in e.OldItems)                     {                         rule.HightlightedText = string.Empty;                         _ruleTasks.Remove(rule);                         UnsubscribeRuleNotifies(rule);                     }                     break;             }         }          // Подписка на события правила подсветки         void SubscribeRuleNotifies(HighlightRule rule)         {             rule.HighlightTextChanged += Rule_HighlightTextChanged;         }          // Отписка от событий правила подсветки         void UnsubscribeRuleNotifies(HighlightRule rule)         {             rule.HighlightTextChanged -= Rule_HighlightTextChanged;         }          // Обработчик события, которое срабатывает, когда текст для подсветки изменился         void Rule_HighlightTextChanged(object sender, HighlightTextChangedEventArgs e)         {             BeginHighlight((HighlightRule)sender);         }          // Здесь запускается механизм подсвечивания в созданном мною диспетчере задач.         // Смысл в том, что если текст вводится/стирается слишком быстро,         // предыдущая подсветка не успеет закончить работу, поэтому новая подсветка         // добавляется в очередь. Если в очереди уже что то есть, то это удаляется из очереди         // и вставляется новая задача. Для каждого правила очередь своя.         void BeginHighlight(HighlightRule rule)         {             _ruleTasks[rule].Add(new Action(() => Highlight(rule)));         }          // Механизм подсветки         void Highlight(HighlightRule rule)         {             // Если передали не существующее правило, покидаем процедуру             if (rule == null)                 return;              // Так как правила у нас задаются в Xaml коде, они будут принадлежать основному потоку, в котором крутится форма,             // поэтому некоторые свойства можно достать/положить только таким образом             ObservableCollection<Highlight> highlights = null;             Application.Current.Dispatcher.Invoke(new ThreadStart(() =>             {                 highlights = rule.Highlights;             }));              // Даже если существует правило, но в нем не задано, чем подсвечивать, покидаем процедуру подсветки             if (highlights.Count == 0)                 return;              // Еще ряд условий для выхода из процедуры подсветки             var exitFlag = false;             exitFlag = exitFlag || string.IsNullOrWhiteSpace(_content);             Application.Current.Dispatcher.Invoke(new ThreadStart(() =>             {                 exitFlag = exitFlag || Inlines.IsReadOnly || Inlines.Count == 0 ||                  HighlightRules == null || HighlightRules.Count == 0;             }));              if (exitFlag)                 return;              // Создадим параграф. Все манипуляции будем проводить внутри него, потому что выделить что либо             // непосредственно в TextBlock нельзя, если это выделение затрагивает несколько элементов             var par = new Paragraph();              // Парсим _content, в котором у нас сериализованный Span с оригинальным содержимым TextBlock'a.             var parsedSp = (Span)XamlReader.Parse(_content);              // Сам Span нам не нужен, поэтому сливаем все его содержимое в параграф             par.Inlines.AddRange(parsedSp.Inlines.ToArray());              // Обозначаем стартовую позицию (просто для удобства) и выдергиваем из TextBlock'a голый текст.              // Искать вхождения искомой строки будем именно в нем             var firstPos = par.ContentStart;             var curText = string.Empty;             Application.Current.Dispatcher.Invoke(new ThreadStart(() =>             {                 curText = Text;             }));              // Выдергиваем из основного потока текст для подсветки             var hlText = string.Empty;             Application.Current.Dispatcher.Invoke(new ThreadStart(() =>             {                 hlText = rule.HightlightedText;             }));              // Если текст для подсветки не пустой и его длина не превышает длину текста, в котором ищем,              // то продолжим, иначе просто выведем в конце оригинал             if (!string.IsNullOrEmpty(hlText) && hlText.Length <= curText.Length)             {                 // Выдергиваем в основном потоке из правила свойство IgnoreCase.                 // Решил логику оставиьт в основном потоке, потому что нагрузка операции очень низкая                 // и не стоит моего пота :)                 var comparison = StringComparison.CurrentCulture;                 Application.Current.Dispatcher.Invoke(new ThreadStart(() =>                 {                     comparison = rule.IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;                 }));                  // Формируем список индексов, откуда начинаются вхождения искомой строки в тексте                 var indexes = new List<int>();                 var ind = curText.IndexOf(hlText, comparison);                 while (ind > -1)                 {                     indexes.Add(ind);                     ind = curText.IndexOf(hlText, ind + hlText.Length, StringComparison.CurrentCultureIgnoreCase);                 }                  TextPointer lastEndPosition = null;                 // Проходим по всем индексам начала вхождения строки поиска в текст                 foreach (var index in indexes)                 {                     // Эта переменная нужна была в моих соисканиях наилучшего места для начала поиска,                     // ведь индекс положения в string не соответствует реальному положению TextPointer'a.                     // Поиск продолжается, поэтому переменную я оставил.                     var curIndex = index;                      // Начинаем поиск с последней найденной позиции либо перемещаем TextPointer вперед                      // на значение, равное индексу вхождения подстроки в текст                     var pstart = lastEndPosition ?? firstPos.GetInsertionPosition(LogicalDirection.Forward).GetPositionAtOffset(curIndex);                      // startInd является длиной текста между начальным TextPointer и текущей точкой начала подсветки                     var startInd = new TextRange(pstart, firstPos.GetInsertionPosition(LogicalDirection.Forward)).Text.Length;                      // В результате нам нужно, чтобы startInd был равен curIndex                     while (startInd != curIndex)                     {                         // Если честно, мне неще не встречались случаи, когда я обгонял startInd обгонял curIndex, однако                         // решил оставить продвижение назад на случай более оптимизированного алгоритма поиска                         if (startInd < curIndex)                         {                             // Смещаем точку начала подсветки на разницу curIndex - startInd                             var newpstart = pstart.GetPositionAtOffset(curIndex - startInd);                              // Иногда TextPointer оказывается между \r и \n, в этом случае начало подсветки                             // сдвигается вперед. Чтобы этого избежать, двигаем его в следующую позицию для вставки                             if (newpstart.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)                                 newpstart = newpstart.GetInsertionPosition(LogicalDirection.Forward);                              var len = new TextRange(pstart, newpstart).Text.Length;                             startInd += len;                             pstart = newpstart;                         }                         else                         {                             var newpstart = pstart.GetPositionAtOffset(curIndex - startInd);                             var len = new TextRange(pstart, newpstart).Text.Length;                             startInd -= len;                             pstart = newpstart;                         }                     }                      // Ищем конечную точку подсветки аналогичным способом, как для начальной                     var pend = pstart.GetPositionAtOffset(hlText.Length);                     var delta = new TextRange(pstart, pend).Text.Length;                     while (delta != hlText.Length)                     {                         if (delta < hlText.Length)                         {                             var newpend = pend.GetPositionAtOffset(hlText.Length - delta);                             var len = new TextRange(pend, newpend).Text.Length;                             delta += len;                             pend = newpend;                         }                         else                         {                             var newpend = pend.GetPositionAtOffset(hlText.Length - delta);                             var len = new TextRange(pend, newpend).Text.Length;                             delta -= len;                             pend = newpend;                         }                     }                      // К сожалению, предложенным способом не получается разделить Hyperlink.                     // Скорее всего это придется делать вручную, но пока такой необходимости нет,                      // поэтому, если начальной или конечной частью подсветки мы режем гиперссылку,                     // то просто сдвигаем эти позиции. В общем ссылка либо полностью попадает в подсветку,                     // либо не попадает совсем                     var sHyp = (pstart?.Parent as Inline)?.Parent as Hyperlink;                     var eHyp = (pend?.Parent as Inline)?.Parent as Hyperlink;                     if (sHyp != null)                         pstart = pstart.GetNextContextPosition(LogicalDirection.Forward);                      if (eHyp != null)                         pend = pend.GetNextContextPosition(LogicalDirection.Backward);                      // Ну а тут применяем к выделению подсветки.                     if (pstart.GetOffsetToPosition(pend) > 0)                     {                         var sp = new Span(pstart, pend);                         foreach (var hl in highlights)                             hl.SetHighlight(sp);                     }                     lastEndPosition = pend;                 }             }              // Здесь сериализуем получившийся параграф и в основном потоке помещаем его содержимое в TextBlock             var parStr = XamlWriter.Save(par);             Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() =>             {                 Inlines.Clear();                 Inlines.AddRange(((Paragraph)XamlReader.Parse(parStr)).Inlines.ToArray());             })).Wait();         }          void TextBlock_Loaded(object sender, RoutedEventArgs e)         {             // Здесь дергаем наполнение TextBlock'a и сериализуем его в строку,             // чтобы накатывать подсветку всегда на оригинал.             // Это лучше вынести в отдельный поток, но пока и так сойдет.             var sp = new Span();             sp.Inlines.AddRange(Inlines.ToArray());             var tr = new TextRange(sp.ContentStart, sp.ContentEnd);             using (var stream = new MemoryStream())             {                 tr.Save(stream, DataFormats.Xaml);                 stream.Position = 0;                 using(var reader = new StreamReader(stream))                 {                     _content = reader.ReadToEnd();                 }             }             Inlines.AddRange(sp.Inlines.ToArray());              // Запускаем подсветку для всех правил             foreach (var rule in HighlightRules)                 BeginHighlight(rule);         }     } 

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

Вот код очереди задач:

Заголовок спойлера

    public class TaskQueue     {         Task _worker;         Queue<Action> _queue;         int _maxTasks;         bool _deleteOld;         object _lock = new object();          public TaskQueue(int maxTasks, bool deleteOld = true)         {             if (maxTasks < 1)                 throw new ArgumentException("TaskQueue: максимальное число задач должно быть больше 0");             _maxTasks = maxTasks;             _deleteOld = deleteOld;             _queue = new Queue<Action>(maxTasks);         }          public bool Add(Action action)         {             if (_queue.Count() < _maxTasks)             {                 _queue.Enqueue(action);                 DoWorkAsync();                 return true;             }             if (_deleteOld)             {                 _queue.Dequeue();                 return Add(action);             }             return false;         }          void DoWorkAsync()         {             if(_queue.Count>0)                 _worker = Task.Factory.StartNew(DoWork);         }          void DoWork()         {             lock (_lock)             {                 if (_queue.Count > 0)                 {                     var currentTask = Task.Factory.StartNew(_queue.Dequeue());                     currentTask.Wait();                     DoWorkAsync();                 }             }         }     }  

Здесь все довольно просто. Поступает новая задача. Если в очереди есть место, то она помещается в очередь. Иначе, если поле _deleteOld == true, то удаляем следующую задачу (наиболее позднюю) и помещаем новую, иначе возвращаем false (задача не добавлена).

Вот код коллекции правил. По идее, можно было обойтись ObservableCollection, но от этой коллекции в дальнейшем может потребоваться дополнительный функционал.

Заголовок спойлера

    public class HighlightRulesCollection : DependencyObject, INotifyCollectionChanged, ICollectionViewFactory, IList, IList<HighlightRule>     {         ObservableCollection<HighlightRule> _items;          public HighlightRulesCollection()         {             _items = new ObservableCollection<HighlightRule>();             _items.CollectionChanged += _items_CollectionChanged;         }          public HighlightRule this[int index]         {             get             {                 return ((IList<HighlightRule>)_items)[index];             }              set             {                 ((IList<HighlightRule>)_items)[index] = value;             }         }          object IList.this[int index]         {             get             {                 return ((IList)_items)[index];             }              set             {                 ((IList)_items)[index] = value;             }         }          public int Count         {             get             {                 return ((IList<HighlightRule>)_items).Count;             }         }          public bool IsFixedSize         {             get             {                 return ((IList)_items).IsFixedSize;             }         }          public bool IsReadOnly         {             get             {                 return ((IList<HighlightRule>)_items).IsReadOnly;             }         }          public bool IsSynchronized         {             get             {                 return ((IList)_items).IsSynchronized;             }         }          public object SyncRoot         {             get             {                 return ((IList)_items).SyncRoot;             }         }          public event NotifyCollectionChangedEventHandler CollectionChanged;          public int Add(object value)         {             return ((IList)_items).Add(value);         }          public void Add(HighlightRule item)         {             ((IList<HighlightRule>)_items).Add(item);         }          public void Clear()         {             ((IList<HighlightRule>)_items).Clear();         }          public bool Contains(object value)         {             return ((IList)_items).Contains(value);         }          public bool Contains(HighlightRule item)         {             return ((IList<HighlightRule>)_items).Contains(item);         }          public void CopyTo(Array array, int index)         {             ((IList)_items).CopyTo(array, index);         }          public void CopyTo(HighlightRule[] array, int arrayIndex)         {             ((IList<HighlightRule>)_items).CopyTo(array, arrayIndex);         }          public ICollectionView CreateView()         {             return new CollectionView(_items);         }          public IEnumerator<HighlightRule> GetEnumerator()         {             return ((IList<HighlightRule>)_items).GetEnumerator();         }          public int IndexOf(object value)         {             return ((IList)_items).IndexOf(value);         }          public int IndexOf(HighlightRule item)         {             return ((IList<HighlightRule>)_items).IndexOf(item);         }          public void Insert(int index, object value)         {             ((IList)_items).Insert(index, value);         }          public void Insert(int index, HighlightRule item)         {             ((IList<HighlightRule>)_items).Insert(index, item);         }          public void Remove(object value)         {             ((IList)_items).Remove(value);         }          public bool Remove(HighlightRule item)         {             return ((IList<HighlightRule>)_items).Remove(item);         }          public void RemoveAt(int index)         {             ((IList<HighlightRule>)_items).RemoveAt(index);         }          IEnumerator IEnumerable.GetEnumerator()         {             return ((IList<HighlightRule>)_items).GetEnumerator();         }          void _items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)         {             CollectionChanged?.Invoke(this, e);         }      } 

Вот код правила подсветки:

Заголовок спойлера

    public class HighlightRule : DependencyObject     {         public delegate void HighlightTextChangedEventHandler(object sender, HighlightTextChangedEventArgs e);          public event HighlightTextChangedEventHandler HighlightTextChanged;          public HighlightRule()         {             Highlights = new ObservableCollection<Highlight>();         }          /// <summary>         /// Текст, который нужно подсветить         /// </summary>         public string HightlightedText         {             get { return (string)GetValue(HightlightedTextProperty); }             set { SetValue(HightlightedTextProperty, value); }         }          public static readonly DependencyProperty HightlightedTextProperty =             DependencyProperty.Register("HightlightedText", typeof(string), typeof(HighlightRule), new FrameworkPropertyMetadata(string.Empty, HighlightPropertyChanged));          public static void HighlightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)         {             var me = d as HighlightRule;             if (me != null)                 me.HighlightTextChanged?.Invoke(me, new HighlightTextChangedEventArgs((string)e.OldValue, (string)e.NewValue));         }          /// <summary>         /// Игнорировать регистр?          /// </summary>         public bool IgnoreCase         {             get { return (bool)GetValue(IgnoreCaseProperty); }             set { SetValue(IgnoreCaseProperty, value); }         }          public static readonly DependencyProperty IgnoreCaseProperty =             DependencyProperty.Register("IgnoreCase", typeof(bool), typeof(HighlightRule), new PropertyMetadata(true));           /// <summary>         /// Коллекция подсветок         /// </summary>         public ObservableCollection<Highlight> Highlights         {             get             {                 return (ObservableCollection<Highlight>)GetValue(HighlightsProperty);             }             set { SetValue(HighlightsProperty, value); }         }          public static readonly DependencyProperty HighlightsProperty =             DependencyProperty.Register("Highlights", typeof(ObservableCollection<Highlight>), typeof(HighlightRule), new PropertyMetadata(null));       }      public class HighlightTextChangedEventArgs : EventArgs     {         public string OldText { get; }          public string NewText { get; }          public HighlightTextChangedEventArgs(string oldText,string newText)         {             OldText = oldText;             NewText = newText;         }     } 

Никакой логики тут нет почти, поэтому без комментариев.

Вот абстрактный класс для подсветки:

    public abstract class Highlight : DependencyObject     {         public abstract void SetHighlight(Span span);          public abstract void SetHighlight(TextRange range);     } 

Мне на данный момент известно два способа подсветить фрагмент. Через Span и через TextRange. Пока что выбранный способ железно прописан в коде в процедуре подсветки, но в дальнейшем я планирую сделать это опционально.

Вот наследник для подсветки фона

    public class HighlightBackgroung : Highlight     {         public override void SetHighlight(Span span)         {             Brush brush = null;             Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() =>             {                 brush = Brush;             })).Wait();             span.Background = brush;         }          public override void SetHighlight(TextRange range)         {             Brush brush = null;             Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() =>             {                 brush = Brush;             })).Wait();             range.ApplyPropertyValue(TextElement.BackgroundProperty, brush);         }          /// <summary>         /// Кисть для подсветки фона         /// </summary>         public Brush Brush         {             get             {                 return (Brush)GetValue(BrushProperty);             }             set { SetValue(BrushProperty, value); }         }          public static readonly DependencyProperty BrushProperty =             DependencyProperty.Register("Brush", typeof(Brush), typeof(HighlightBackgroung), new PropertyMetadata(Brushes.Transparent));       } 

Ну тут нечего комментировать, кроме безопасности потоков. Дело в том, что экземпляр должен крутиться в основном потоке, а метод может быть вызван откуда угодно.

А это код подсветки цветом текста

    public class HighlightForeground : Highlight     {         public override void SetHighlight(Span span)         {             Brush brush = null;             Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() =>             {                 brush = Brush;             })).Wait();             span.Foreground = brush;         }          public override void SetHighlight(TextRange range)         {             Brush brush = null;             Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() =>             {                 brush = Brush;             })).Wait();             range.ApplyPropertyValue(TextElement.ForegroundProperty, brush);         }          /// <summary>         /// Кисть для цвета текста         /// </summary>         public Brush Brush         {             get { return (Brush)GetValue(BrushProperty); }             set { SetValue(BrushProperty, value); }         }          public static readonly DependencyProperty BrushProperty =             DependencyProperty.Register("Brush", typeof(Brush), typeof(HighlightForeground), new PropertyMetadata(Brushes.Black));     } 

Заключение

Ну вот пожалуй и все. Хотелось бы услышать ваше мнение.
ссылка на оригинал статьи https://habrahabr.ru/post/314060/

Криптовалюты на выручку е-коммерсу: когда платежи картой уже слишком громоздки, а банковские переводы медленнее самолёта

Глава Nextury Ventures Илья Лаурс, венчурный капиталист из Литвы, поднялся на рынке мобильных приложений, когда он ещё только зарождался, жил и работал в Кремниевой долине и вернулся в Литву инвестировать в финтек-стартапы на родине.


XXI век: самолёт в Америку летит 10 часов, банковский платёж идёт два дня

На прошлой неделе я выложил часть нашего с ним разговора, где речь шла про биткоины. Сегодня — время десерта, разговор про то, как криптовалюты могут изменить рынок платежей в частности и заставить измениться всю банковскую систему в целом — это уже непосредственно область профессиональных интересов Ильи и касается всех, кто когда-либо имел дело с оплатой из-за границы или монетизацией проектов микроплатежами.

Как криптовалюты изменят электронную коммерцию

Криптовалюты необходимы е-коммерсу, рынок в них отчаянно нуждается, и когда момент настанет — моментально их проглотит. Потому что банковские платежи и кредитки так же, как и физические деньги — несовместимы с виртуальной экономикой, ни один из этих инструментов не отвечает её требованиям. Это нонсенс, когда в двадцать первом веке, чтобы купить мне пуговицу, надо было заполнять форму сложнее, чем на получение прав: где живешь, какой адрес, какой телефон, номер кредитки, на кого она зарегистрирована и так далее.

Причём степень фрода и риска, и фейлов тоже неадекватна. В электронной коммерции количество мошенничеств — то есть использования чужих кредиток — зашкаливает. Неудобно, громоздко, ненадёжно, и главное — куча воровства. Это в таком сегменте, где, казалось бы, извините, ребята, банки могли постараться лучше.

Поэтому вся интернет-коммерция, виртуальные платежи, они просто умоляют: «Дайте нам удобный, надежный, простой инструмент для использования». Я уж не говорю о том, что последние достижения в области виртуальной коммерции требуют даже не микроплатежей – наноплатежей, когда ты покупаешь не просто пуговицу, а для цифрового фрака своего аватара в какой-то второй вселенной. Стоимость платежа в физических деньгах может быть треть цента, и для этого запускать весь механизм кредитки – это настолько громоздко!

Поговорив с ребятами из игровой индустрии, ты понимаешь, что из-за тяжеловесности платёжных инструментов, упускается до 90% прибыли: то есть они могли бы в десять раз больше делать денег, если все это было бы классно и удобно. Это целый класс, скажем так: микро, наноплатежи, нормальные платежи, надёжные для всей интернет-коммерции. Это гигантский рынок.

Сейчас много говорят об интернете вещей, когда вещи сами общаются между собой. Естественно, между ними будут возникать торгово-рыночные отношения: лампочка, условно говоря, сама себе декларирует, сколько она нажрала энергии, себе же прямо продаваясь, возможно, имеет какой-то цифровой баланс, и куда бы ее ни включили, она расплачивается за свою же энергию и по мере горения сама с себя списывает. Или ты дизайнер, твой комп требует трёхнедельного рендера, тут же получает доступ к виртуальной машине — ещё при этом сравнивает загруженность основных суперкомпьютеров и на аукционе выбирает, какой в данную секунду меньше загружен и может предложить лучшую цену, — и за использование ресурсов мгновенно рассчитывается биткоинами — и всё это без участия человека.

Эти хозрасчёты в интернете вещей уже сами по себе напрашиваются. Потому что людям в принципе удобнее махнуть мобилой или чем-то еще, и с тебя чтобы считали нормальное количество еврорублей, как говорят, а не безбожно курсом измененное — это тоже адекватно ожидать в двадцать первом веке. Потому что сейчас конверсия по той же кредитке — грабительская: в той же Америке рестораны и магазины платят банку до пяти процентов за обслуживание кредитки. Пользователь при конверсии теряет до трёх процентов. В наш цифровой век это не имеет вообще никакого смысла, это выгодно только банкам, а не рынку.

Биткоин и государство: задабривая левиафана

Пока развитие криптовалют очень зависит от того, как государство будет смотреть на биткоины. Сейчас тут очень много серой зоны, а традиционная реакция всех регуляторов на серую зону: мы можем наказать и закрыть, и не будем разбираться, что и как. А всё-таки деньги – это та сфера, где презумпция невиновности чаще всего не применяется: либо ты действуешь так, как разрешено, либо шаг в сторону принимается за побег. Именно поэтому одна из основных частей нашей работы сейчас – это своеобразный евангелизм, работа совместно с государством Литвы — Центробанком, Министерством финансов, на уровне как мэрии, так и министерства экономики: что это такое, как это работает, какие потенциальные риски или, наоборот, выгоды это приносит. Мы сейчас, наверное, больше половины времени проводим проясняя, регулируя и занимаясь такими проектами с государством, чтобы более или менее представлять, что это такое, какие законы применимы, какие действия нам нужно совершать, чтобы это все было легально и прозрачно.

А потом уже можно возвращаться к конкретным бизнесам. Вот иллюстрация для примера: Америка приняла закон, что биткоины относятся к классу физических товаров, то есть как, скажем, нефть, они подлежат регуляции как биржевые товары. Европа пока условно-формально держится точки зрения, что это просто иностранная валюта. То есть учёт, изменение баланса должны подчиняться таким же правилам, как при наличии на балансе иностранной валюты. Китай принял другой закон, что для них биткоин – это цифровой товар.

То есть ты можешь купить, хранить, инвестировать и так далее. Но дальше начинаются варианты: нужна или не нужна денежная лицензия, нужно или не нужно разрешение Центробанка, действует или нет закон о ликвидности и прочее.

Криптовалюты на смену банкам

Я надеюсь, что криптовалюты просто сменят в какой-то момент нынешнюю финансовую систему. Реформировать тут уже нечего, нужен квантовый скачок: как в своё время был квантовый скачок, например, золотообеспеченных валют в экономикообеспеченные, физической бумаги в цифровые деньги. То есть такие скачки в истории человечества происходили. Сейчас мы ходим со своими кусочками золота и все еще держимся за количество грамм в золоте в то время как надо просто взять, глубоко вдохнуть, повернуть холодную воду, ощутить первые турбуленции, больно получить по башке, потому что первые эксперименты всегда больно бьют, но потом свыкнуться и жить в нормальном мире.

Но единственный возможный путь к этому прийти — это снизу. Я бы дал, может, процентов пять вероятности, что появятся одно-два государства-выскочки вроде Эстонии, которые увидят в этом возможность, как Япония, разом шагнуть в технологическое будущее и мгновенно перейти из пешки в дамки. Но 95% за то, что просто в какой-то момент использование крипты приобретёт такую массовость, что это невозможно будет игнорировать, и всё-таки государства и банки подчинятся давлению снизу.

Международные транзакции на базе биткоина

Одна из компаний, в которую мы инвестируем и объявим это, занимается переводами платежей за рубеж. Сейчас, в двадцать первом веке, платёж в Америку путешествует два дня, стоит пятьдесят долларов, на конверсии валют съедается до пяти процентов – это полностью неадекватно, потому что технологически это пересылка смешного количества байтов — меньше, чем в электронной почте. Мы же не живём в каменном веке, мы не посылаем гонцов с мешком золота, чтобы оправдать два дня для перевода денег. Я могу на рейсовом самолёте кэш провезти в два раза быстрее, чем произвести банковский платеж.

И уже можно собрать на биткоине, что перевод евро из Литвы в доллары в Америке занимает тридцать минут, стоит один доллар – это для конечного пользователя, себестоимость его — пара центов, и конверсия валют практически нулевая.

Это будет смежный биткоину бизнес, который будет использовать биткоин, как промежуточный протокол, то есть ты посылаешь евро на евровый счет, который определяет суть платежа, понимает, куда, какой конечный отправитель, конвертирует мгновенно сам себя в биткоин, переводит биткоин в Америку, в Америке меняет биткоин на живой доллар на американском счету, и уже по американским рельсам пересылает его до конечной точки.

А внутри Европы (всё-таки молодцы европейцы), в этом году стала действовать sepa-схема — это интербанковские европейские платежи. Поэтому всю Европу можно обслуживать всего с одного счета.

То есть, с точки зрения юзеров это такой же местный платеж, как и любые другие, и такое же местное получение денег, но в промежутке это действует на биткоин-протоколе, который используется чисто для транспорта денег, то есть, он никак не используется, кроме как для передачи информации. И, кстати, в таких сервисах можно легко использовать параллельно биткоины, альткоины — что угодно, потому что в промежутках слой транспорта, он является слоем скрытым, неважно, что там внутри, он не подвержен, скажем так, риску флуктуаций, потому что за полсекунды курс биткоина жутко не изменится. Даже если изменится, риск, выраженный в вероятности и помноженный на потери, он все-таки оправдан и если он экономит до двадцати процентов от собственного платежа, то такой сервис, мы считаем, просто необходим в наш век. Мы ожидаем, что сразу начнёт набираться критическая масса бизнесов, которая этим пользуется, потому что это экономически выгодно, осмысленно, разумно.

Разумеется, мы не первые тут: есть TransferWise, литовский TransferGo и т.д. Они построены чуть на разных моделях. Например, самая частая модель – это взаимного кредитозачёта, то есть классического клиринга: копится сумма платежей в Америке, сумма платежей в Европе, разница между суммами обычно довольно мала, и клирится только она, да и то она ещё и агрегируется по дороге. То есть, сто должников в Америке и сто должников в Европе через один трансфер, который составляет десять процентов от всей массы, физически пересылается, клирится, и за счёт агрегации и клиринга достигается эффективность. Это классическая схема международных платежей. А вот конкретно на биткоиновских рельсах пока что публично компании не заявляли о себе. Скорее всего, я прогнозирую, будет пара десятков стартапов, и у каждого будет ненулевая вероятность стать доминирующим игроком. Включая, хочется надеяться, и наш.

Самая сложная здесь часть – это не технологическая, а регуляционная. Поэтому российский рынок мы не рассматриваем прямо сейчас. Я просто наугад скажу, что скорей всего мы наткнулись бы на жёсткие правила и ограничения, если бы мы захотели такой сервис сейчас запустить в России. То есть, мы тратим условно девяносто процентов усилий на юридические прояснения, и только когда мы точно знаем, что, например Европа-Америка, евро-доллар, такие страны-такие страны, мы точно влезаем в пространство правильно и не задеваем регуляторных ограничений, только тогда это открываем. Поэтому, скорее всего, Россия, хотя и есть в списке, не будет первой и не будет скоро.

ссылка на оригинал статьи https://geektimes.ru/post/282082/

Как превратить смартфон в микрофон (идеи и вопросы)

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

Зачем это нужно?

Бывает так, что нужно сделать озвучку для какого-то видео, но качественного микрофона под рукой нет. Озвучивать на внутренний микрофон — это значит угробить видео. А вот качество записи на многие современные смартфоны очень даже приличное. Поэтому приходится записывать на смартфон, а затем переносить записи на компьютер.
Но удобства здесь мало. Если вы делаете дубляж, то постоянно приходится перезаписывать фрагменты, где нужно чтобы ваша речь была быстрее или медленнее. А это значит, что каждый неудачный раз вам нужно снова копировать файл записи со смартфона на комп. Я хочу этого избежать, то есть сделать так, чтобы запись сразу оказывалась на компе, как будто вы подключили настоящий микрофон.
Ниже я перечислю свои идеи, приведу их плюсы и минусы. Хотел бы услышать ваши комментарии о возможности их реализации.

Идея 1. Смартфон в качестве BlueTooth гарнитуры

1) Написать драйвер для Android смартфона, который бы представлял его окружающим устройствам как беспроводная гарнитура (с микрофоном).
2) Написать приложение для Android смартфона, которое будет забирать звук со встроенного микрофона и направлять его этому драйверу.
3) Выполнить поиск bluetooth устройств на компьютере, подключить «беспроводную гарнитуру».
4) Выбрать её на компе в качестве приоритетного микрофона.
5) Profit

Плюсы

Никаких манипуляций на компе.
Не требует дополнительного АО для пользователя.

Минусы

Скорее всего нужен будет root на смартфоне

Мои комментарии и вопросы

1) Возможно ли создать такой драйвер? Мне кажется что да. Я видел что-то подобное для подключения DualShock 3 (bluetooth геймпад для PlayStation) к смартфону (Sixaxis Controller).
2) Будет ли задержка при передаче? Уверен, что да.
3) Будет ли передача происходить без потерь? Не знаю.

Идея 2. Аудиовыход смартфона на аудиовход компьютера

1) Создать переходник с TRS на TRRS (CTIA)
2) Создать аттенюатор line to mic (как его делать — обсудим в моём следующем видео)
3) Запустить приложение Mic To Speaker, выводящее звук со встроенного микрофона смартфона на динамик/аудиовыход смартфона.
4) Подключить смартфон к компьютеру через переходник с аттенюатором.
5) Выбрать на компе внешний микрофон как приоритетный.
5) Profit

Плюсы

Никаких манипуляций на компе.

Минусы

Требует дополнительное аппаратное обеспечение

Мои комментарии и вопросы

1. Возможно ли выводить определённые звуки (уведомления) на встроенный динамик, если вставлен штекер в аудио разъём?
2. Возможно ли записывать звук именно со внутреннего микрофона, если вдруг смартфон определит, что доступен внешний микрофон? Я думаю, что приложение само может выбрать с какого устройства брать звук (со встроенного либо со внешнего микрофона). Но чтобы не было лишних проблем, в смартфон лучше вставлять TRS штекер, а не TRRS.

Идея 3. Смартфон в качестве аудиокарты

1. Сделать программу (или что?), чтобы смартфон мог идентифицироваться USB хосту как аудиокарта (т. е. сообщить компу Pid:Vid, соответствующий какой-либо аудиокарте).
2. Написать приложение на Android, которое будет слать звук со встроенного микрофона на «аудиокарту».
3. Активировать подмену vid:pid и запустить приложение
4. Подключить смартфон к компу по usb
5. Выбрать на компе микрофон со внешней аудиокарты как приоритетный
6. Profit
Примечание: описанное не имеет отношения к USB Audio для android. Usb аудио позволяет подключать внешнюю звуковуху к смартфону. То есть звук со смартфона можно выводить на неё и вводить с неё на смартфон. Но нам нужно, чтобы сам смартфон выступал аудиокартой.

Плюсы

Никаких манипуляций на компе.

Минусы

Скорее всего нужен будет root на смартфоне

Мои комментарии и вопросы

1. Возможна ли подмена Vid:Pid или это можно сделать только аппаратно?
2. Возможно ли использовать usb_ModeSwitch для управления такой подменой с компа или же такие манипуляции можно делать только на смартфоне?
3. Хватит ли пропускной способности usb 2.0, чтобы нормально передавать звук?

Идея 4. Передавать аудиопоток по сети

1. Установить приложение, которое отправляет аудио поток со внутреннего микрофона по сети (я использовал Ip Webcam, но это несвободное по).
2. Пробросить сеть смартфона на комп через adb по usb (чтобы исключить wifi). Ip Webcam-gst может сделать это автоматически.
3. Получить доступ с компа к этому потоку.
4. Зарегистрировать в системе виртуальный микрофон. Завернуть в него получаемый http поток в качестве источника. [Нужно для универсальности. Хотя можно использовать записывалку, которая умеет сразу ловить такие потоки, например vlc или open broadcaster].
5. Выбрать на компе этот виртуальный микрофон как приоритетный
6. Profit

Плюсы

Не нужен root на смартфоне

Минусы

Требуется клиентское ПО для компьютера

Мои комментарии и вопросы

1. VLC имеет встроенную возможность захвата http потока, но имеет серьёзные неудобства при записи (по крайней мере в Gui). Как vlc может захватывать поток с помощью командной строки не разобрался. Может кто подскажет?
2. Ip Webcam-gst умеет регистрировать виртуальный микрофон, но не умеет использовать кодек, отличный от Wav. Кто разбирается в gstreamer конвейерах? Нужно собрать конвейер, который бы поддерживал бы Opus и aac.
3. Я видел приложение WoMic, которое реализует такой функционал. Оно требует Win или Mac. А на Linux я применял ipwebcam. Это несвободная программа. Я думаю, что лучше бы функционал ipwebcam (по аудио части) включить в KDE Connect. Я был бы рад, если кто-то мне с этим помог.

Идея 5. Компьютер как bluetooth наушники для смартфона

1. Написать драйвер (?) для компьютера, который бы представлял его окружающим устройствам как bluetooth аудио колонки.
2. Написать программу для компьютера, которая будет регистрировать виртуальный микрофон и направлять в него приходящий на «колонки» звук.
3. Запустить программу на компьютере и оставаться видимым bluetooth устройством.
4. Запустить приложение Mic To Speaker на смартфоне и подключить его к «беспроводным наушникам». (Я не проверял, можно ли изменять слив при работе этого приложения, но думаю что проблем быть не должно. Если будут проблемы, значит надо написать программу для android, которая будет направлять звук со встроенного микрофона на «bluetooth колонки»).
5. Выбрать на компьютере виртуальный микрофон как приоритетный.
6. Profit

Плюсы

Не нужен root на смартфоне

Минусы

Для одновременного нормального функционирования блютуса компа (например, для bluetooth клавиатуры) скорее всего понадобится дополнительный bt донгл. Я видел подобную ситуацию с dualshock драйвером для компа.

Мои комментарии и вопросы

Какой из всех предложенных вариантов обеспечит наименьшие задержки при передаче?
ссылка на оригинал статьи https://habrahabr.ru/post/314038/