Voicy Tech Blog

Voicy公式Techブログ

Go1.8とAngular4をプロダクションで使ってみた!Voicy WEB版の開発裏話

こんにちは。Voicy CTOの窪田です。

7月18日にVoicyのWeb版をリリースいたしました!さっそく使っていただけたでしょうか?
https://voicy.jp/

f:id:voice-tech:20170725220611p:plain これにより、いままでiPhone/iPadでしか聴けなかったパーソナリティの声を、PCやAndroidのブラウザでもお聴きいただけます!リリース直後には多くの方がSNS上に喜びの声を書き込んでいただいたのを読んで、本当に作ってよかったなぁと感じました。どうもありがとうございます!こういった生の声を直接聴けるのは、toCサービスをやる醍醐味だと思います。

そこで今回はこのWEB版の開発裏話をさせていただきます。

開発言語

言語はサーバーサイドがGo1.8で、クライアントサイドがAngular4を使用しています。それぞれのバージョンは2月と3月にリリースされたばかりの最新で、エンジニアとしては開発していてとても楽しかったです。Goについては以前のブログでも書いているので、よければそちらもご覧ください。

SPAの必要性

WEB版を使っていただくとわかりますが、画面遷移した場合でも、再生プレーヤーが上部に固定で表示されています。動画であれば画面中央にどーんと表示されてユーザの目線はそこに固定されるのですが、音声の良いところは他のページを見ながら聴くという、ながら聴きができるところです。

言い方を変えれば、他のページへ遷移しても音声を止めずに再生し続けないといけないということです。普通であれば他のページへ遷移すると音声も動画も止まってしまいますので、必然的に1つのページ内で表示を切り返るSPA(Single Page Application)で作る必要あり、Angularで開発することにしました。

OGP対応

ありがたいことに、Voicyではパーソナリティを始めとしたユーザーのみなさまが各チャンネルをFacebookTwitterといったSNSで多くのシェアをしていただいています。現在iOSアプリからシェアするとURLが表示されるだけなのですが、WEB版のURLで表示していただくと、このようにシェアした配信を表す写真とテキストが表示されます。(アプリも対応予定です。しばらくお待ちください)

f:id:voice-tech:20170723212347p:plain

この表示を行うために設定しているのがOGP(Open Graph Protocol)です。HTMLのMETAタグに設定するのですが、SPAでは大きな問題があります。それはSPAはシングルページというだけあって、大元のHTMLファイルは1つだけです。つまりMETAタグに設定できるOGPの内容が1つしかありません。そのため、どの配信をシェアしても同じ写真+テキストしか表示されないことになります。

Voicyでは日々多くのパーソナリティの方が配信しており、シェアした時にはその人の写真と配信内容のテキストをどうしても表示したいという強い思いがあり、いろいろと試行錯誤を行いました。

METAタグにflagmentを設定する

AJAXページのSEO対策としてMETAタグに
 <meta name=“fragment” content=“!”>
を設定するとクローラーが良い感じにhogehogeしてくれるというのがあります。(詳細は省略)

OGP対応もそこでできるかなと思いましたが、シェアした場合に各SNSがどこまでクローラーと同じように処理してくれるかが不明で調べている時間もなかったこと、対応するのに思っていたよりも工数がかかりそうだったことの2点を理由に見送りました。

SSRを使用する

Angularは2からSSR(Server Side Rendering)にも対応しています。SSRとはAngularによる描画をサーバーサイドで行い、結果のHTMLをクライアントへ返す方法です。これによりリクエストURLに応じてOGPを設定したMETAタグをクライアントへ返すことができますが、それだと結局画面遷移のたびにHTMLを書き換えることになるため、再生を止めないというSPA採用の目的が果たせなくなってしまいます。

index.htmlを動的に作成する

最終的にはこの方法を採用しました。Angularだけで解決することは諦め、PHPでアクセスURLを元にサーバーから必要な情報を取得し、OGPのMETAタグを動的に生成しています。プログラム自体はそこまで複雑でもないので、その時オフィスに来ていたエンジニアの方にさくっと作っていただきました(笑)

課題

トップ画面パフォーマンス

WEB版のトップ画面では多くの配信情報を取得しているのですが、そのパフォーマンスがあまり良くないという課題があります。ここはDBからの取得部分で改善できそうなポイントがあるので近々対応予定です。

モバイルで連続再生できない

iPhoneAndroidのブラウザでアクセスした場合、1つの記事の再生が終わっても次が自動で再生されません。これはモバイルブラウザの仕様で、プログラムから自動で音声や動画の再生を開始することができないためです。メディアデータはサイズが大きいため、ユーザーが想定していないデータを裏側でダウンロードし、パケット通信量を使いすぎないようにこういった制限が掛かっています。そのため、再生を開始するには画面をタップする等のユーザアクションをトリガーにする必要があるのです。(ブラウザによって多少実装が異なる場合もあります)

実は最初の音声を再生するタイミングで他の音声も全てダウンロードしておけば連続再生できるという裏技も一応あります。実際1パーソナリティの1配信分だけであればそこまでのデータ量ではないのかもしれません。しかし、ユーザーがサイト内を回遊し、いろんな人の配信を少しずつ聴くといった行動をした場合、たいして聴いてもいないのに大量のパケットを消費してしまうことになります。この点ついては、今後の使われ方を見ながらどうすべきか判断させていただきたいと思います。ご不便をおかけして申し訳ありませんが、ご了承ください。

Angular遅延ロード

今はフロントサイドの全てのコードを1つのModuleとして作っています。そのため、最初にアクセスしたタイミングで全てのページのデータをブラウザ側にダウンロードしているのですが、その中には設定画面のような使用頻度の低い画面も含まれています。AngularではModuleを分割して必要になった時にだけダウンロードする遅延ロード(Lazy Loading)というのもできるので、今後画面が増えていくことも考えて早めに対応していきたいと思います。

開発体制

開発は6月からの約1ヶ月半かけて2名で行いました。企画やデザインはもう少し前から取り掛かっていましたが。

サーバーサイドのGoとクライアントサイドのAngularでそれぞれ担当を分け、私は主にクライアントサイドを担当しました。2人ともGo、Angularは今回が初めてで、最近Hello Worldからスタートしたばかりなのですが、そのわりには1ヶ月半でここまで作りきれたのはなかなかではないかと手前味噌ながら思っております。

ちなみにたった2名で作ったのは単純にVoicy社内にそれしかエンジニアがいなかったからです(`・ω・´)キリッ
つまりはエンジニアを100%つぎ込んでWEB版を作っていたので、その間アプリ版の改修が止まってしまい、ユーザーの皆さまには申し訳なく思っております。しかしながら、VoicyではWEB版に限らず他にも新しいサービスをどんどん立ち上げていこうと考えています!改善を止めずに新規サービスを立ち上げていく。そんな無茶を実現するためにも、現在Voicyではエンジニアを大募集中です!本当に立ち上げフェーズのベンチャーで自分の力を試してみたい方、まずは話を聞いてみたいだけでも全然かまいませんので、一度オフィスへ遊びに来て下さい!
https://open.talentio.com/1/c/voicy/requisitions/detail/4803

GYAO!主催エンタメデジコンエンジニア勉強会で弊社伊東が登壇しました!

去る5/17、GYAO!さんが主催のイベントに弊社の伊東が登壇致しました!
デジタルコンテンツの中でも特にエンターテインメントに関するものを取り扱っているITエンジニアが集まり、働き方や技術情報、ノウハウを共有するイベント…ということで、弊社の伊東もVoicy代表としてVoicyを支えるインフラの技術についてお話させていただきました。

f:id:voice-tech:20170618182653j:plain

この記事では、当日のイベント全体の様子を伊東のセッション内容も含めてお伝え致します。

クラウドで実現する動画配信とAIのコラボレーション

f:id:voice-tech:20170618182841j:plain 日本マイクロソフトの畠山さんにAzureが提供する最新のAPIについてご紹介頂きました。
RESTさえ分かれば簡単に使える映像認識のAPIが画期的でした!

たとえば、水泳をしている男性の写真をAPIに投げると
・ポルノ度(裸だけど、スポーツだろうという分析でポルノ度は18%)
・カテゴリ(スイミング)
・性別
・年齢
以上のような情報が解析されて返ってきます。

画像だけではなく、Video indexer APIというAPIを使うと動画も解析できます。
どのシーン(コマ)にどの人が写っているのか、それは合計何分なのか、 音声、顔、文字、感情を検出して検索することもできるという優れもの。是非試してみたいですね。

Voicyシステムリプレースに至るまで

続いて、我らがVoicyのCIO兼ITOこと伊東のセッション!

f:id:voice-tech:20170618183031j:plain

Voicyがシステムをリプレースするに至るまでの経緯や判断基準についてをお話しました。 Voicyではこれまでネイティブアプリのみを提供していましたが、WEB版の開発に伴い既存のシステムをAPI化
する必要が出てきました。そこで既存環境を刷新することになり、現在は以下のような構成になるようにリプレースを進めています。

f:id:voice-tech:20170618190908p:plain

技術選定の最も重要なポイントは、事業の事を第一に考えて選定するということ。
あくまで事業を具現化するための1つの手法として技術があるのであって、先に技術がくるのではない。企画の思考を技術的に無理だから…といって狭めてしまうことがないようにしたい。というアツい想いを語っていました。

ちなみに、言語選定にまつわる詳しい話はコチラの記事にまとまっておりますので是非ごらんください。
VoicyがGoLangとEchoを採択した理由。 - Voicy Tech Blog

気持ちを伝える動画技術

Gyaoでフロントエンドエンジニアをされている浜田さんのセッションでは、浜田さんがハッカソンで作ったものをご紹介頂きました。

f:id:voice-tech:20170618191303j:plain

GoogleのCloud Vision APIとFirebaseを使った感情解析をするアプリの事例です。プレゼンを行う時に、オーディエンスの反応が分かっていれば、自分のプレゼンの仕方ももっと工夫ができるのでは…。そんな思いから、浜田さんはオーディエンスの表情から感情をリアルタイムで解析し、プレゼンターに伝えてあげることで自分のプレゼンの良し悪しを知ることができるアプリを作りました。冒頭のマイクロソフトさんのAPIでも画像解析の話題がありましたが、GoogleIBMなど、各社が色んなCognitive APIを提供しているので、アイディア次第で簡単に面白いアプリが作れますね。

風力と脳波を使ったものづくり

続いてもハッカソンでの制作事例です。Hack Dayという、見て・触って・作って楽しめる、Yahoo! JAPAN主催のクリエイティブイベントで高橋さんが制作したアプリは、なんと風力と脳波でVR上の女の子のスカートをめくるというもの。

f:id:voice-tech:20170618194808j:plain

「技術を使うって楽しい!」「技術を使うってエンターテイメントなんだ!」というのがよく伝わってくるプレゼンテーションでした。

Gyao エンタメテックカンパニーの働き方

Gyaoさんがエンタメテックカンパニーとして実践している人事制度についてご紹介がありました。

1. 大人の学びの法則 大人はどうやって学ぶのか?
→ 7割は仕事の直接の経験から学ぶ。研修より経験。

2. コルブの学習経験モデル
具体的な経験 > 内省的な観察 > 抽象的な概念化(教訓を引き出す) > 積極的な実験
このプロセスを回せる仕組みづくりを。

3. キムの成功循環モデル
関係の質 > 思考の質 > 行動の質 > 結果の質
→【結果から求めるのではなく、関係性に重きをおく】

上のような思想をベースにして、以下の2点を軸に制度設計を行なっているそうです。

人財開発

  • 人財開発カルテ:強み、課題、キャリアプラン、理想の経験を半年に一回更新
  • 人財開発会議:部門における人財開発プランの検討、全社視点でのキャリア形成支援の二回立てで実施

コンディション

健康と関係性 - ななめ会議:隣の部署の上司からヒアリングと議論、FB - 働き方、勤怠管理:36協定をきちんと守る、勤怠実績を経営会議にて報告 - どこでもオフィス・フレックス勤務 - 診療所の併設・メンタルヘルス対策

なかなか制度への落とし込みは大変なことだと思いますが、よく考え実施されているという印象を受けました。

パネルディスカッション

続いて、エンタメ業界のエンジニアとしてのスキルセットや働き方についてのパネルディスカッションが行われました。

f:id:voice-tech:20170618201229j:plain

Q. エンタメサービスでエンジニアは今後どんなスキルが必要でしょうか?

オンプレミスが過去のものとなりつつなる今、何がこれから求められる?

畠山さん:クラウドとAI。アプリケーションはもちろん作れるのは大前提として、クラウドは使えるようになったほうがいい。Paasのサービスは絶対に必要。AIについての最低限の理解、機械学習についても情報収集していくべき。

伊東:機械学習ビッグデータ解析。データが必要になってからデータを取ろうと思っても過去のデータは収集できないので、先を見通してデータを取得しておくべき。

高橋さん: ひとつは、 新しい技術を知っていること。AI、機械学習など今は簡単に扱えるようになってきている。そういった技術があること自体を知っているか知らないかの差は大きい。そして、 開発者自身が楽しんで作っていけるマインドセットも重要。

浜田さん: VODサービスは溢れ、どこも同じような機能や同じようなWEBサイトが多くなってきていると感じる。デザイン、UIがある意味均一化してきている。エンタメを謳うからにはそういった流れの中でフロントのUI/UXの差別化が必要。

AI、クラウド機械学習といったキーワードが目立ちました。
総じていえば「新しい技術にチャレンジしていくこと」へ抵抗感を持たず、前のめりに試していく好奇心と実行力が求めらるということでしょうか。

Q. リモートワークでのチーム開発について。うまくいっている方法や失敗談は?

畠山さん: コアタイムがなくなっている。自由があってグローバルチームの働き方としてはやりやすい。 反面、自由になりすぎると、どこでもいつでも働けてしまうため、過度に働きすぎてしまう人が出てくるのが課題。 自分自身でタイムマネージメントしていかなければならない。

伊東: リモートワークでも、全員が集まる時間は週の中で必ず確保するべき。
コミュニケーションの総量がどうしても少なくなってしまうため、関係性が構築できていない状態でのリモートワークは難しさを感じる。既に関係性が構築できている状態ならリモートも可能だと思う。

高橋さん: リモートワークはよく実施している。Googleハングアウトで常に多拠点間のオフィスとオフィスを繋いだ状態にして仮想的に同じ場所にいるような取り組みも行っている

浜田さん: みんな好きに働いているが、リモートワークはディスカッションには向いていない気がする。そういう場合は顔を合わせたほうがよい。

登壇者が所属するどの企業もリモートワークを取り入れているようでした。リモートワークを実施すると集中して作業ができる、通勤の時間削減などのメリットがありますが、コミュニケーションが必要なシーンでのバランスの取り方が重要ということです。

まとめ

今回は、エンターテインメントに関するものを取り扱っているITエンジニアが集まり、働き方や技術情報、ノウハウを共有するという趣旨のイベントだったからか、Coginitive系のAPIの話が多かったのが印象的でした。Voicyでも今後音声の解析や音声ビッグデータ等の領域で面白いことができるよう、更に事業を成長させて参ります!

声×テクノロジーで新しい文化を作りたい!Voicyでは一緒に働いてくれるエンジニアを募集中です。アットホームなオフィスですので、気になった方はぜひお茶でも飲みにきてください。 www.wantedly.com

スペシャルサンクス

写真を提供してくださった「ヤフー株式会社 公式カメラ隊」の皆様、ありがとうございます!!


Swift3でCore Audioを使用した音声ファイル変換

こんにちは!Voicy CTOの窪田です。

今回はSwift3でCore Audioを使って、WAVファイルをAACに変換する方法についてお話ししようと思います。

経緯

以前、Voicyの録音アプリでは音声を保存する際にはWAVファイルを使用していました。しかし無圧縮のWAVではサイズが大きいため、通信速度が遅い環境でアップロードに時間がかかってしまうという課題がありました。

そこで、録音が終わった後にWAVを圧縮形式のAACに変換すれば、WAVで録音している部分には手を加えなくて済むし良いのではないかと思い今回紹介するプログラムを作成しました。しかし、現実はそんなに甘くはなく、、、

Voicyでは最大10分間の録音ができるのですが、フルに録音したものをiPhone5AACに変換すると2分以上かかってしまったのです。iPhone6以降であれば問題なかったのですが、Voicyで活躍しているパーソナリティにはiPhone5を使用している方もいるので、録音するたびにそんな長時間待たせるわけにはいきません。

というわけで、最終的には録音しながらAACでリアルタイムに保存する対応を行うことになりました。そのため、Voicyのアプリでは今回紹介するフォーマットの変換処理は使っておりません。そして、せっかく作ったのにもったいないからブログのネタにしてやろうとか思ったわけでもありません(`・ω・´)キリッ

ちなみに、WAVファイルで録音していた時でもアップロード後にサーバー側で圧縮していたので、再生アプリでダウンロードする際の通信量は抑えられていました。サーバー側での圧縮処理にはAWSAmazon Elastic Transcoderを使用しています。

Core Audioを使用した変換

Core Audioと言っても処理によって複数のフレームワークやサービスに別れています。今回の変換処理ではAudio Toolboxフレームワークに含まれるExtended Audio File Serviceを使用します。昔のiOSではAACの変換は対応していなかったのですが、iOS 3.1あたりから対応したようです。10まで出ている現在では気にする必要はなさそうですね。ちなみにMP3への変換は未だ未対応です。

余談ですが、先日MP3のライセンスが終了というニュースがありました。未対応の理由がライセンスだったのであればこれを期に対応するのか、それともMP3はもう古いとしてずっと未対応なのかはちょっと気になるところではあります。個人的にAppleは後者ではないかと思っていますが。

WAVファイルを開く

それでは順番に変換処理を説明していきます。まずCore Audioを使用するにはAVFoundationをインポートする必要があります。

import AVFoundation

次に変換元となるWAVファイルを開きます。ファイルはプロジェクト内に元から存在するものとし、Bundle.mainでURLを取得してきています。

// 変換元のinput.wavを指すURL
let inFileUrl = URL(fileURLWithPath: Bundle.main.path(forResource: "input", ofType: "wav")!)

// WAVファイルを開く
var inFile: ExtAudioFileRef?
_ = ExtAudioFileOpenURL(inFileUrl as CFURL, &inFile)

// WAVファイルの情報を取得
var inASBDSize = UInt32(MemoryLayout<AudioStreamBasicDescription>.size)
var inFormat = AudioStreamBasicDescription()
ExtAudioFileGetProperty(inFile!, kExtAudioFileProperty_FileDataFormat, &inASBDSize, &inFormat)

そんなに難しいところは無いと思います。最後の部分では変換元であるWAVファイルの情報を取得しています。サンプリングレートやビットレート、ステレオかモノラルかといった音声ファイルの基本的な情報が含まれており、Core AudioではASBD(Audio Stream Basic Description)と呼ばれる構造体で表されます。

AACファイルを開く

次に変換先となるAACファイルを開きます。ここではテンポラリフォルダにファイルを作成しています。

// 変換先のoutput.aacを指すURL
let toUrl = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("output.aac"))

// AACファイル情報
var outASBDSize = UInt32(MemoryLayout<AudioStreamBasicDescription>.size)
var aacFormat = AudioStreamBasicDescription()
aacFormat.mFormatID         = kAudioFormatMPEG4AAC
aacFormat.mSampleRate       = 44100.0
aacFormat.mChannelsPerFrame = 1
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, nil, &outASBDSize, &aacFormat)

// AACファイルを開く
_ = ExtAudioFileCreateWithURL(
    outFileUrl as CFURL,
    kAudioFileM4AType,
    &aacFormat,
    nil,
    AudioFileFlags.eraseFile.rawValue,
    &outFile)

先ほどのWAVファイルでは、ファイルからASBDを取得していましたが、AACの場合はまだファイルが存在しないため、書き込むASBDの値を自分で指定する必要があります。ここではAACであることと、サンプリングレートに44.1kHz、チャンネル数に1(モノラル) を指定しています。

ASBDには他にも情報を指定する必要があるのですが、AudioFormatGetPropertyにkAudioFormatProperty_FormatInfoを指定することでその他の情報を自動的に埋めてくれる便利機能があるのでそれを使用しています。

ファイルを開く際にもkAudioFileM4ATypeでAACであることを指定しています。同じAACを指すものでもASBDに指定していたkAudioFormatMPEG4AACとは違うので間違えないように気をつけてください。AudioFileFlags.eraseFileは既存のファイルがあった場合に上書きすることを表しています。

変換ルールを指定

これでWAV、AACの両ファイルを開けましたが、じゃあどこでデータの変換処理するの?となります。

答えはファイルを読み込む時、もしくは書き込む時で、どちらで行うかは自分で指定する必要があります。ここでは書き込む時に指定してみました。

// 書き込みプロパティ設定
ExtAudioFileSetProperty(
    outFile!,
    kExtAudioFileProperty_ClientDataFormat,
    inASBDSize,
    &inFormat)

AACファイル(outFile)に対して、WAVファイルの情報(inASBDSize, inFormat)を指定しています。これにより、WAVファイルのデータを渡すからAACに変換して保存してねという命令をしていることになります。

WAV -> AAC 変換処理

いよいよメインの処理です。とはいえ先ほど指定した変換ルールのおかげで難しいことは全て自動的にやってくれるため、プログラマーがやることとしては

  1. バッファを作成
  2. WAVファイルを順次読み込み
  3. AACファイル書き込み

これだけです。

まずはバッファを作成します。

// バッファ作成
var readFrameSize: UInt32 = 1024 // 一度に読み込むフレーム数
var bufferSize = readFrameSize * inFormat.mBytesPerPacket
var buffer: UnsafeMutableRawPointer = malloc(Int(bufferSize))
defer { free(buffer) }

var audioBuffer = AudioBufferList()
audioBuffer.mNumberBuffers = 1
audioBuffer.mBuffers.mNumberChannels = inFormat.mChannelsPerFrame
audioBuffer.mBuffers.mDataByteSize = bufferSize
audioBuffer.mBuffers.mData = buffer

var readFrameSize: UInt32 = 1024

フレーム数は必要に応じて変更してください。
ちなみにこの数字を増減しても処理時間はあまり変わりませんでした。

var bufferSize = readFrameSize * inFormat.mBytesPerPacket

WAVファイルの場合、フレーム数とパケット数が同じなので、バッファサイズは フレーム数 × パケットサイズ になります。

var buffer: UnsafeMutableRawPointer = malloc(Int(bufferSize))
defer { free(buffer) }

バッファ領域はmallocで確保しています。mallocで確保した場合は自動的に解放されないため、処理を抜ける時に解放されるようにするため、deferでfreeを行なっています。

バッファを確保できたら、次はファイルの読み込みと書き込みを行ないます。

// ファイルを読み込んで出力
while (true) {
    // WAVファイル読み込み
    ExtAudioFileRead(inFile, &readFrameSize, &audioBuffer)
    // 読み込むデータがなくなれば終了
    if readFrameSize <= 0 { break }
    // AACファイル書き込み
    ExtAudioFileWrite(outFile, readFrameSize, &audioBuffer)
}

バッファにはWAVファイルのデータが読み込まれ、それをExtAudioFileWriteへ渡した際に、先ほど登録した変換ルールが適用されてAACに変換して保存されます。想像つくかもしれませんが、この変換処理が一番重いです。とはいえ最近の端末に限定して良いのであればそこまで気にしなくてもいいのかもしれませんが。

ファイルを閉じる

// ファイルを閉じる
ExtAudioFileDispose(inFile!)
ExtAudioFileDispose(outFile!)

最後にファイルを閉じてオブジェクトを破棄します。Extended Audio File ServiceではExtAudioFileDisposeを呼ぶとファイルのクローズとオブジェクトの破棄を同時に行ってくれます。

終わりに

Core AudioはiPhoneで音声アプリをつくるなら避けては通れないものです。ポインタもあっちこっちで出てくるので最初はとっつきにくいかも知れませんが、今回紹介したExtended Audio File Serviceのように便利な関数も多数用意されており、知れば知るほど楽しくなってきます。VoicyではこれからもCore Audioを使いこなし、音声技術のスペシャリスト集団になっていきたいと思います!

Voicyのメンバーがどういった思いでサービスを作っているのか、ぜひともこちらのインタビューも合わせてお読みください!

Twitterがしゃべる!?Playerカードの作成方法

こんにちは!Voicy CTOの窪田です。

先日Voicyのサイトにチャンネル紹介のページが追加されました! 公式チャンネルや人気のパーソナリティをピックアップして掲載しているのですが、それぞれのページをTwitterでシェアすると、なんとタイムライン上で音声を聴くことができます!

例えばこちらのVoicy公式チャンネルのURLをTwitterでつぶやくと
https://voicy.jp/channel/voicy.html

このように表示されます。

f:id:voice-tech:20170504190928p:plain

そしてツイートをクリックすると再生画面が展開されて、Twitterのタイムライン上で音声を聴くことができます!

f:id:voice-tech:20170504190933p:plain

そこで、今回はこの再生機能の作成方法ついてお話しさせていただきます。

Playerカードについて

タイムライン上での再生機能は、Twitterが提供しているPlayerカードというものを使用しています。正確にはTwitterカードで選べるカードタイプのうちの1つがPlayerカードです。表示される再生画面はHTMLで自作するので、デザインはかなり自由に作ることができ、もちろん音声に限らず動画も再生可能です。

Twitterカード自体は誰でもすぐに使用できるのですが、Playerカードだけはドメインの利用申請が必要になります。また、HTTPSでアクセスできるWebサーバーも必要です。

Playerカードは以下の手順で作成していきます。公式マニュアルも合わせてお読みください。

  1. 再生画面をHTMLで作成
  2. 再生画面をHTTPSでアクセスできるように配置
  3. シェアされるページに専用のMETAタグを設定
  4. シェアされるページのドメインTwitterに申請
  5. Card Validatorで動作確認

Playerカード作成手順

1. 再生画面をHTMLで作成

再生画面を作成する際の注意点が公式マニュアルの"申請時のポイント"に載っているので、それさえ守れば自由にデザインや機能を実装できます。

後から変更することもできるので、Voicyではまず最小限の機能だけを半日くらいで開発して申請を行い、その後正式版として作り直しました。申請時には特に以下の内容を意識して開発しました。

  • iPhoneAndroidTwitterアプリ、twitter.com、mobile.twitter.comなどのすべてのTwitterクライアントでエクスペリエンスをテストしてください。これらすべてのTwitterクライアントで動作しないカードは承認されません。
  • すべてのクライアントで動画コンテンツが表示エリアの横幅いっぱいに表示されるようにしてください。
  • 動画コンテンツとオーディオコンテンツに関する注意
    1. コンテンツが自動的に再生される動画では、初期設定を “消音” にする
    2. 長さが10秒を超えるコンテンツは自動的再生されないようにする
    3. 停止、一時停止、再生ボタンを設置する

2. 再生画面をHTTPSでアクセスできるように配置

再生画面はHTTPSでアクセスできる必要があります。実はVoicyのサイトはこれまでHTTPSに対応していなかったのですが、これを機にサイト全体をHTTPS化しました。

3. シェアされるページに専用のMETAタグを設定

Playerカードを使用するために、シェアされるページのMETAタグで再生画面に関する情報を指定します。この設定が必要なのはシェアされるページであって、再生画面のHTMLではないのでご注意ください。

さきほどのVoicy公式チャンネルページでは以下のように指定しています。

<meta name="twitter:card" content="player" />
<meta name="twitter:title" content="Voicy - Voicy公式チャンネル" />
<meta name="twitter:description" content="毎朝月曜から土曜まで、新鮮なニュースをお伝えするVoicy公式チャンネル。 これさえ聞けば日々の主要ニュースは網羅できるはず。通勤・通学のお供におすすめです。" />
<meta name="twitter:image" content="https://voicy.jp/tw/img/thumb/voicy.png" />
<meta name="twitter:site" content="@voicy_jp" />
<meta name="twitter:player" content="https://voicy.jp/tw/#voicy" />
<meta name="twitter:player:width" content="320" />
<meta name="twitter:player:height" content="450" />
プロパティ 必須 説明
twitter:card 必須 Playerカードを使用する場合は"player"固定です。
twitter:title 必須 タイムラインに表示されるサイトのタイトルです。
twitter:description 必須 タイムラインに表示されるサイトのタイトルです。
twitter:image 必須 タイムラインに表示されるサムネイル画像です。iframe未対応のブラウだでは再生画面の代わりに表示されます。
twitter:site 任意 TwitterのIDです。"twitter:site"もしくは"twitter:site:id"のどちらかが必須です。
twitter:player 必須 再生画面のURLです。HTTPSで指定する必要があります。
twitter:player:width 必須 再生画面の横幅です。
twitter:player:height 必須 再生画面の縦幅です。

プロパティに指定できる値はこの他にもあります。詳細は公式マニュアルをご覧いただきたいのですが、日本語ページと英語ページで説明が異なる部分もあるので、実際に作って動作確認することをオススメします。

4. シェアされるページのドメインTwitterに申請

公式マニュアルでは、「Playerカードを申請する」とあるので、新しいPlayerカードを作成したらその度に申請が必要なのかと思いましたが、実際はドメイン毎の承認になるので、一度承認されれば以降の申請は必要なさそうです。

マニュアルではCard Validatorで動作確認をしてから申請するように書いてあるのですが、Playerカードの場合はドメインの承認前はエラーとなってしまい動作確認ができません。

申請前の画面

f:id:voice-tech:20170504190942p:plain

そのため、多分大丈夫だろうという見込みで申請を行いました(笑) エラー画面に表示されているRequestApprovalのボタンを押して必要事項を入力します。

申請画面

f:id:voice-tech:20170504190938p:plain

Descriptionには簡単なサイトの説明を英語で入力します。"Mark my cards ~“のチェックボックスは基本的にチェック不要です。もしsensitive contentを扱うのであればチェックしてください。その他はデフォルトで入力されていました。

申請が完了するとエラーメッセージが変わります。

f:id:voice-tech:20170504190946p:plain

申請した翌日には承認され、以下のメールが送られてきました。

f:id:voice-tech:20170504191226p:plain

5. Card validatorで動作確認

無事承認されるとCard Validatorで確認することができます。

f:id:voice-tech:20170504190950p:plain

Audioカードについて

今回紹介したPlayerカードの他にも、TwitterにはAudioカードという似たような名前のものがあります。

Audioカードの方がPlayerカードよりもリッチな表現ができるようなのですが、残念ながらこれを使用するにはTwitterと企業提携を行う必要があるそうです。もしTwitterの方がいらしたらぜひ連絡ください(笑)

現在は@SoundCloudのアカウントがよくAudioカードを使用しています。スマホのアプリで見るとわかるのですが、PlayerカードだとWebViewが立ち上がって再生画面が表示されるのに対し、Audioカードではポップアップで表示されるので、ユーザー体験を考えるとAudioカードの方が良いと思います。

終わりに

現在は動画全盛期なので、動画のシェア方法は充実しているのですが、音声や音楽といった音だけのコンテンツに関しては十分とは言えません。Facebookでもタイムライン上で動画を流すことはできますが、音声だけとなると簡単にはできないのが現状です。(Music Storiesというサービスがあるのですが、新規の募集は受け付けていないそうです。。。)

それはさておき、今回のサイトリニューアルで、これまでアプリでしか聴けなかった音声を(一部ですが)ブラウザや、Twitter上でも聴けるようになりました!Voicyでは今後もあらゆる手段で声をお届けできるよう、新しいことへ積極的にチャレンジしていきます!

Voicyのメンバーがどういった思いでサービスを作っているのか、ぜひともこちらのインタビューも合わせてお読みください!

VoicyがGoLangとEchoを採択した理由。

Voicy社 ITO 伊東です。

現在iPhoneアプリを提供しているVoicyですが、WEB版を鋭意製作中であります。
これまではネイティブアプリ開発用の環境を構築しておりましたが、Webに最適化または双方で使うために環境を構築し直す必要が出てきました。

そこで、今回は環境を構築し直すにあたっての言語とフレームワークの選定についてお話します。

結構いろんな言語と比較したんですが、結果的には GoLang × Echoを採択しました。

言語選定の前提となるミッション

今回はAPIを作るのに適した環境を作るという事が一番重要なミッション。
いわゆるマイクロサービスというやつですね。小さい単位でサービスを作ってAPIを通して各機能を呼び出すということ。そうすることで

  • 開発チームがサービスごとに分かれて、得意な言語を利用して各サービスの開発を進めることができる
  • 変更をかけたいときは、システム全体ではなく、その小さなサービスごとに変更をかけられる
  • 小さなサービスで開発単位を進めるため、ビルドやテストの期間が短くなり開発効率が上がる
  • モノリシックなシステムだと何か障害が起きたときに、どこがおかしいのかルート構造をたどるのに時間がかかるが、原因の突き止めが比較的容易

つまり、用途・目的ごとに小さな(マイクロな)サービスを作っておくことで、「変化に強くて柔軟性の高い、アプリケーション開発を行おう」というのがマイクロサービスなのです。

引用元 https://www.salesforce.com/jp/blog/2016/03/microservices.html

はい、僕の言いたいことを全ていい切ってくれてますね(しろめ
コレガヤリタイカラゲンゴカエルンダ、コジンテキナスキルアップデハナインダ・・・

最適な言語はなんなのか?比べてみた

APIを作るのに適した環境を作るというのを念頭に比較してますが、個人の主観も大きく入っておりますのでその点ご了承くださいませ(しろめ

・Java8 & Lagom

Ruby & Rails

PHP & Lumen

・Python3 & Nameko

GoLang & Echo

を検討致しました。
個人的にはRoRが好きです。
今回はORマッパーを使わない想定です(ふるえ
※別に嫌いではないですがAPIという事で1ミリ秒でも早くレスポンスを返したいという事を優先しております。

Java8 & Lagom

速度    ◎
開発効率  △
API化 ◯
採用    ☓

Java8で以前マイクロサービスを開発をしたことがありまして、結構簡単に出来ましたね。(もともとJava使いだからですが)個人的な主観でいってしまいますが 、
選択したくない(キリ
なぜなら別の言語にチャレンジしたいから(しろめ

RubyOnRails

速度    △
開発効率  ◎
API化  △
採用    ◯

Railsはとても好きなフレームワークで ルーティングも簡単に制御できますし、開発効率も高いです。 Viewを使わずActiveRecordのORマッパーも使わないという事ですと、Railsを採用する意味が大きく損なわれてしまいましたね・・

PHP & Lumen

速度    △
開発効率  ◎
API化    ◯
採用    △

LumenはLaravelのマイクロフレームワーク版で同じIlluminateコンポーネントを使用しております。 ルーティング処理もとても評判が良く、とても悩みました。 PHP自体は使えるエンジニアもとても多く、CakeやLaravel等も開発効率が高くサービスリリースを行う上でとても強い武器になると思います。
が、実行速度が遅い(スクリプト言語に求めるなという話ですけどね)事から却下。

Python3 & Nameko

速度    △
開発効率  ◯
API化 ◯
採用    ◯

Python結構いい感じですね、APIを構築するのにとてもあっている気がしますし、永続処理や非同期処理も様々なツールを合わせることで上手く対応できますね。音声ビッグデータ解析等いろいろ行う予定であるVoicyにとってパイソンは通らなくてはならない道ではあります。適材適所の言語を使用すれば良いと私自身は考えますので、その時にパイソンを選択すれば良いかと思います。

GoLang & Echo

速度    ◯
開発効率  ◯
API化  ◯
採用    ◯

GoLang使いました。 APIを作るために存在しているようなくらい簡単に出来てしまいますね。 継承が出来ないので(無理無理できないことはないけど・・・) コーディングするときに少し戸惑いはありますが ルーティング簡単、APIつくるの簡単(というか、それ以外無理ですねこれ)という形でしょうか。

優勝 GoLang

個人的な権限を行使して、面白そうなGoLangに決めました。

GoLang用のフレームワークの選定(すでにEchoとか書いてしまっておりますが・・)

  • Gin
  • Iris
  • Echo の3つを検討致しました。

結論からいうと、Echoを採用致しました。

フレームワークの実行速度で比較

Gin  734
Echo 879
Kami 1237
Goji   1299
Bone 1463
http   1854
Gocraft 1915
Gorilla 3944
Martini 5823
ns/op

参考記事
http://qiita.com/najeira/items/bdc988c4e93b3b5ccf2f

個人的にはGinかEchoの2択に絞られました。

書きやすさで比較

今回はAPIを作るのに適した環境を作るという事を一番の念頭に入れてはおりましたので、その点でどのフレームワークが書きやすそうかという事を考えました。

参考記事
http://blog.iktakahiro.sh/entry/2016/12/10/090000

http://qiita.com/keika299/items/62e806ae42828bb3567a

実際に書いて動作させてみましたがルーティングがとても簡単。

    // ルーティング
    e.Get("/hello", handle.MainPage())
    e.Post("/hello", handle.MainPage())

これで事が足りてしまいます。

まとめ:GoLangAPI作るならEchoが良さそう!

Go自体並列処理が行うのが得意なので、色々とめんどうな処理もは早く処理できそうですし。

Pythonも最後まで捨てがたかったのですが

  1. 学習コスト
  2. 採用
  3. 実行速度(コンパイルする分早いのは当たり前ですけどね)
    (4.個人の趣味)

でしょうか。
RoRからGolangに移行するひとが結構知り合いにも居ましたが気落ちが大分わかりました。

クラウド放送局アプリVoicyの音声収録から配信までのシステム構成

はじめまして。VoicyでCTOをしている窪田です。

さて、今回は最初の技術記事ということで簡単なアプリの紹介を踏まえながらと全体のシステム構成についてお話ししたいと思います。

Voicyというアプリについて

Voicyとは人の声で聞くニュースメディアです。 最近はITで声と言えばAmazonのAlexaや初音ミクに代表される音声認識音声合成を思い浮かべる方も多いと思いますが、Voicyでは機械ではなく人の声でニュースを届けています。

ユーザーは自分の声でコンテンツを読み上げて配信する「パーソナリティ」と「リスナー」に分けられます。 そのためVoicyのアプリも「パーソナリティが使用する録音用」と「一般リスナーが使用する再生用」の二つがあり、並行して開発を進めています。(現在はiPhoneのみ)

f:id:voice-tech:20170401155929p:plain

Voicy [ボイシー] - ニュースは声で聴く時代へを App Store で

Voicy Recorderを App Store で

使い方としては、オーディションに合格したパーソナリティが録音用アプリでニュース記事を読んだり、好きなことについて語ったりしたものを収録し、一般のリスナーが再生用アプリで聞くという流れになります。

システム構成

Voicyのシステム構成を簡単な図にまとめたものがこちらになります。

f:id:voice-tech:20170401155943p:plain

1. 録音アプリ

録音用アプリは誰でもダウンロードして収録することができますが、再生用アプリへ配信して他の人に聞いてもらうためには、定期的に行っているパーソナリティオーディションに応募して合格する必要があります。そのため、アプリ内では配信権限の有無により項目の表示/非表示制御や、権限チェックが必要になります。もちろん不正アクセスを考慮して、サーバーサイドでも同様に権限チェックを行っています。

アプリで収録した音声ファイルはサーバーへ送られ、その後圧縮、フォーマット変換されます。音声ファイルは動画ほどではないとはいえ、通常のWebサービスに比べると大きなサイズのデータを扱うことになるため、サーバーのメモリ使用量は注意しておく必要があります。現在は十分なスペックを確保できていますが、ユーザー数の増加に合わせて当然見直しが必要になってくるため、モニタリングは欠かせません。

2. 再生アプリ

耳から便利にニュースが聞けるといった機能性だけであれば音声合成で十分です。Voicyでは、それに加えてパーソナリティの個性や人間味といった"その人らしさ"を伝えてたいと考えています。そのため、UIではパーソナリティの写真をメインにデザインし、初めてアプリを開いたリスナーが自分好みのチャンネルに出会えるような情報をトップ画面に載せています。

また、アプリを楽しく操作できるための工夫として、フリックや画面遷移したりするタイミングで効果音を鳴らしています。始めにアプリを開発する時は、音声、BGM、効果音といった音のデータをどう扱うかで苦労しました。例えば、マナーモード中にアプリを触ってる時は効果音鳴って欲しくないけど、再生ボタンを押したら音声は流れるようにしたい。そして音声が流れてる時であれば、音が出ている状態なのでマナーモード中であっても効果音鳴らしてもいいんじゃないか、といった具合です。

3. 記事クローラー

パーソナリティが読む記事を収集するためのクローラで、収集された記事はリアルタイムに録音用アプリに表示されます。クローラー毎日新聞スポニチといった提携メディアから記事を取得していますが、取得方法がメディアによって異なるため、提携先が増えるたびにクローラーを開発する必要があります。

とはいえ毎回ゼロから作るわけにもいかないので、クローラーのための共通フレームワークを自作し、面倒な処理のほとんどはフレームワークで行えるようになっています。フレームワークも一度作って終わりではなく、常に改善しているため、当初新しいクローラーを追加するのに丸一日かかっていた作業が、現在は早ければ1時間かからず、長くても3,4時間あれば作れるまでに効率化されました。

4. バッチ処理

上記以外にも、日次レポートの作成やキャッシュデータの更新といったバッチ処理が定期的に実行されています。こちらもクローラー同様に共通フレームワークを自作しているので、新しいバッチを追加する際でも、エンジニアは面倒なことは気にせずにビジネスロジックだけに集中して開発できるようになっています。

最後に

いかがでしたでしょうか。とても簡単ではありましたがVoicyが声を届けるための仕組みを紹介させていただきました。今後はそれぞれのシステムで使用されている技術ついて、もっと詳しく紹介していければと思います。

Voicyのサービスはまだ始まったばかりで、これからどんどん進化していきます!また、まだお話できないような新しいサービスもいろいろと考えております。その実現のためにもVoicyでは現在エンジニアを絶賛募集中です!ちょっと話を聞いてみたい、ベンチャーの雰囲気を感じてみたいといった理由でも構いませんので、ぜひ一度オフィスに遊びに来てください。

www.wantedly.com

パーソナリティをやっている声優やアナウンサーの方々もふらっと遊びに来てくれる、とてもフレンドリーでアットホームなオフィスです! こんなメンバーが働いている現場です。 よろしければインタビューもぜひご覧ください!

Voicy、テックブログはじめます。

ついにVoicyでもテックブログを開設いたしました!

以前からやろうやろうという話はしていたのですが、なんやかんやでサービスリリースから半年も経ってしまいました。これからは社内で使用している技術や開発手法はもちろん、声のベンチャーであるVoicyらしく 声 × IT の Voice Techというトピックをみなさんにお届けしていきますのでお楽しみに!

さて、今回は初回エントリーということで、Voicyという会社はどんな会社なのか、そして、Voicyでエンジニアとして働くことの面白さについて書いてみたいと思います。

Voicyってどんな会社?

株式会社Voicyは2016年に設立されたスタートアップです。
声で新しい文化を作るをビジョンに

  • 世の中に新しい価値を生む
  • 誰もやらないことをやる
  • 自分たちが最高に楽しむ

をミッションに掲げています。
2016年9月に声のメディアアプリVoicyをリリース、2017年3月にエンジェルラウンドでの資金調達に成功しました。

どんな人が働いているのか

メンバーの半数以上が熟練度の高いエンジニアとデザイナーで、残りのメンバーもビジネスマンとしての経験値の高い人が集まっています。人数規模はまだ小さいですが、全員が個性豊かなプロフェッショナル集団です。

開発の中心メンバーはエンジニアとして15年以上のキャリアを持つCTOの窪田、数々の企業やスタートアップで事業を作ってきたCIOの伊東の2名です。
代表の緒方がこれではCTOが二人になってしまう、伊東の役職はITOにするしかない…と悩むくらいに技術力の高いメンバーです。以下のインタビューでこれまでのキャリアや初期の開発裏話が語られています。

サービスではなく「業界」を作りたい。まだスタンダードがない分野へ挑戦し続けるCTOのVoicyアプリ開発秘話 | Voicyのメンバー紹介ブログ
自分たちの想像すら超える新しい文化を作りたい。超大規模インフラ開発から超ドベンチャーへ転職したCIOのVoicyジョインストーリー | Voicyのメンバー紹介ブログ

Voicyでエンジニアとして働く面白みとは

サービスにダイレクトに関わりながら進めるアジャイル開発

現在のVoicyは社員番号一桁台、アプリも正式ローンチしてまだ半年のフェーズ。そのため仕様書が降りてきてそれを淡々とこなしていくような開発ではなく、サービスにダイレクトに関わりながらアジャイル的な開発に携われます。たとえばアプリをこういう使い方をしている人は離脱率がこれくらいだね、どうしたら改善できるだろう?というような会話にエンジニアも参加していたりします。

エンドユーザーの声を直接聞ける

また、エンドユーザーと接する機会が多いのも特徴です。通常、自分が開発をしているプロダクトを実際に使ってくれているユーザーと会う機会はそこまで多くはないと思います。Voicyではアプリを使ってくれているユーザーがオフィスにフラっと遊びにきてくれたり、ユーザー感謝祭を開催したりと、エンジニアも直接ユーザーの声を聞く機会があります。 直接話してわかる気づきもありますし、純粋に、自分が作ったものを目の前で「これすごくいいですね!」と言ってもらえるのはやっぱり素直に嬉しいですよね。

音声という新たなインターフェース

Voicyは音声という新たなインターフェースの可能性を信じています。
現在運営しているアプリは、「声」でニュースを聴くアプリ。活字コンテンツに声の魅力を加えることにより、「体温のある情報を届けるプラットフォーム」を実現しました。

まだ公にできないこともありますが、今後も音声という未来のインターフェースを使ってまだ誰もやっていないサービスを開発していくつもりです。そこにエンジニアとして関われるというのは技術的にも、また文化を作っていくという意味でも非常にやりがいがあるといえます。

おわりに

ずっと開発の中心メンバーは窪田と伊東の2名です。とお伝えしてきましたが、中心というか実はフルコミットの開発メンバーが窪田と伊東しかいないんですよね。 というわけで一緒にサービス開発をしたいエンジニアも絶賛募集中です。

www.wantedly.com

アットホームなオフィスなのでちょっと話を聞いてみたいという方も気軽にコンタクトをくださればと思います。

今回は初回のエントリということで、技術的なことにはあまり触れませんでしたが、今後は窪田と伊東が社内で使用している技術や開発手法などを発信していく予定です。 ぜひチェックしてみてくださいね!