A library for controlling and monitoring a Chromecast. It currently only supports pause/play/volume, but also keeps track of the state of the device, such as media type, playback position, background images, etc. There is no support for queuing or playing new media files.
1. git clone https://github.com/NationalAssociationOfRealtors/chromecast.git
2. mix do deps.get, deps.compile
3. iex -S mix
iex(4)> {:ok, device} = Chromecast.start_link {192,168,1,138}
{:ok, #PID<0.225.0>}
iex(7)> Chromecast.state(device)
%Chromecast.State{destination_id: "web-5", ip: {192, 168, 1, 138},
media_session: nil,
media_status: %{"appDeviceId" => "BBC9E06BCA89EA246A21D650BE44BA52",
"backendData" => "[\"https://lh3.googleusercontent.com/mij2Eglc324jD_kxhu43aSnX8w9Xfr7XQdEwLpWpiVoFWZSh8Ljj=s1920-w1920-h1080-p-k-no-nd-mv\",\"Justin Brown\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/101005060236931055507/albums/5720519753508285169/6122212643311873906\",null,null,\"Photo by Justin Brown\",null,[[\"New York City, NY\",\"https://www.google.com/search?q=New+York+City%2C+New+York\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipPSuE14ATWH-FwoO3DGJyiyewcTORhjDEuFTF__\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],1293145096798261,[9700053]]",
"numLinkedUsers" => 0, "requestId" => "0",
"topicHistory" => ["[\"https://lh3.googleusercontent.com/proxy/GUfWvBxLY7h8Li2oVoqt5QMs8h6heAX-TTnlKUKND1JCbg2MKPD9yi1QzUXhp3oEWbpfkRp8MWRepmgYBMOm5vNn4O2F1XCCoWG37QCbweiYEJ8mTj_aknB0306wcWfqcSuo7gc6ZOdO2mOod9lnaX453YPntwNsNws4Ux_g=s1920-w1920-h1080-n-k-no-nd-mv\",null,null,null,120,11,null,null,null,\"https://500px.com/photo/105754217/gravity-chamber-by-alex-noriega?utm_source=google&utm_medium=chromecast&utm_campaign=september_launch\",null,null,\"Photo by Alex Noriega\",null,[],null,0,\"FEATURED_500PX_TITLE\",\"0312daec19f4b4cb0ccf374d83a605e3\",null,null,0,null,null,null,47,[[47,\"FEATURED_500PX_TITLE\",\"500px\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],-7860625334833097,[9700053]]",
"[\"https://lh3.googleusercontent.com/NcFlzZdTZazuc1FH1vuyExOFYMdz6rKtMrtdtghDJ_ScngVdnmWmgwxffJbyWRWfq-tvVFT5zZvtHWpeXvw=s1920-w1920-h1080-p-k-no-nd-mv\",\"Robin Griggs Wood\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/103698889037599783920/albums/5893830837236231873/6286435320971968402\",null,null,\"Photo by Robin Griggs Wood\",null,[[\"Palace of Fine Arts, San Francisco, California\",\"https://www.google.com/search?q=Palace+of+Fine+Arts%2C+San+Francisco\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipMKwdLuP0T3JWxRBCBiDGJxXNmSxTOIaAHM7Gxe\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],5097477668030082,[9700053]]",
"[\"https://lh5.googleusercontent.com/proxy/vkAEc_MrmRauQq8jR40hx_yh-ExzYSupzCaA3uKbLv6MKhRFd4tit_f1CTneIYHT7vYkgbPANzXQ0vuYzXm1WLpUyTFHv0Vcj13gH9Ibr_z9AJR0SrTQ2hmfXz7isqP_EhXtk9-ldjRQOhhc5n1waAu8IXtiid5Pt5ZYbNE2oooJysxGh8-2vprNq3yArVBNC-DWdvzEjaJoR_wfkdSGWG2houxsQzAG6ZgInJDJ1cz0U1_a8tdTStJ56CoTMAs=s1920-w1920-h1080-p-k-no-nd-mv\",null,null,null,120,11,null,null,null,\"http://www.gettyimages.com/detail/photo/suspension-bridge-royalty-free-image/107709060?esource=chromecast\",null,null,\"Photo by Daniel Muller\",null,[],null,0,\"FEATURED_GETTYIMAGES_TITLE\",\"89ae3a3b697da2318e0a9fbd8951b7d5\",null,null,0,null,null,null,48,[[48,\"FEATURED_GETTYIMAGES_TITLE\",\"Getty Images\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],3037105898765724,[9700053]]",
"[\"https://lh3.googleusercontent.com/SxgLlfCrzM66njIgpKlq2nkRrCdq2_sONwQDxl0AAImggIso_VkVzg=s1920-w1920-h1080-p-k-no-nd-mv\",\"Saurabh Paranjape\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/105737724482908033948/albums/6213733340481709841/6213733341343554690\",null,null,\"Photo by Saurabh Paranjape\",null,[[\"Westminster Bridge, London, England\",\"https://www.google.com/search?q=Westminster+Bridge\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipN2LkA4gtWKmP4xk7RWQFR9IKB9EnW2m4s3qVsp\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],-6380615397988733,[9700053]]",
"[\"https://lh3.googleusercontent.com/mij2Eglc324jD_kxhu43aSnX8w9Xfr7XQdEwLpWpiVoFWZSh8Ljj=s1920-w1920-h1080-p-k-no-nd-mv\",\"Justin Brown\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/101005060236931055507/albums/5720519753508285169/6122212643311873906\",null,null,\"Photo by Justin Brown\",null,[[\"New York City, NY\",\"https://www.google.com/search?q=New+York+City%2C+New+York\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipPSuE14ATWH-FwoO3DGJyiyewcTORhjDEuFTF__\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],1293145096798261,[9700053]]"]},
receiver_status: %{"requestId" => 1,
"status" => %{"applications" => [%{"appId" => "E8C28D3C",
"displayName" => "Backdrop", "isIdleScreen" => true,
"namespaces" => [%{"name" => "urn:x-cast:com.google.cast.sse"},
%{"name" => "urn:x-cast:com.google.cast.inject"}],
"sessionId" => "C6591D59-64B2-4357-98DE-A982A75FAA6F",
"statusText" => "", "transportId" => "web-5"}],
"volume" => %{"controlType" => "attenuation", "level" => 1.0,
"muted" => false, "stepInterval" => 0.05000000074505806}},
"type" => "RECEIVER_STATUS"}, request_id: 4,
session: "C6591D59-64B2-4357-98DE-A982A75FAA6F",
ssl: {:sslsocket, {:gen_tcp, #Port<0.7995>, :tls_connection, :undefined},
#PID<0.226.0>}}
iex(126)> Chromecast.state(device)
%Chromecast.State{destination_id: "web-13", ip: {192, 168, 1, 138},
media_session: 1936679159,
media_status: %{"appDeviceId" => "BBC9E06BCA89EA246A21D650BE44BA52",
"backendData" => "[\"https://lh4.googleusercontent.com/proxy/c5GLPnubdevNNbhBlOekeEAA64Us7uNSMJkhgjWZlCQIo1eqqwXve4RZlIcBQwahoEI32MXkXXOhZmFWayEpF-UJafokwVKemB2EWX42dJDUi6xCLmPYLRDEmZ5YPCDefGJikV2XgR8e9pE5b4XS215Bygf6t-oNSTK-Ae_uKtKq3gOMvFt7PmmFPj9uvqjCu9N1ehUQ6CXiH7Ke7z6nqpO5dW6kfDVvdAV1oEtl6bD572C1QHWaD5d9HKnRzx-l0j4CryxMq0xIODl2ziPasNGGe4zHCYpGXIzq7qrF=s1920-w1920-h1080-fcrop64=1,0000170affffef93-k-no-nd-mv\",null,null,null,120,11,null,null,null,\"http://www.gettyimages.com/detail/photo/grand-prismatic-spring-yellowstone-national-high-res-stock-photography/462556881?esource=chromecast\",null,null,\"Photo by Peter Adams\",null,[],null,0,\"FEATURED_GETTYIMAGES_TITLE\",\"363fad4f1769ed622205dc4e1b75281a\",null,null,0,null,null,null,48,[[48,\"FEATURED_GETTYIMAGES_TITLE\",\"Getty Images\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],4718130360558134,[9700053]]",
"currentTime" => 0.453, "customData" => %{"playerState" => 1},
"media" => %{"contentId" => "RuWRnIAwPIU",
"contentType" => "x-youtube/video",
"customData" => %{"currentIndex" => 2,
"listId" => "RQAGdO5p9nVvzfKwZGP9XUYZDXbqcljCV01fxpzRs0Qpu0d_ZPowkJ508lgJyOldy_hFam51_fF_NieXwcngOoZlXYeR89R8CXAMGvyLvP82nkOuUUAVbL1hQ"},
"duration" => 157.314693877551,
"metadata" => %{"images" => [%{"url" => "https://i.ytimg.com/vi/RuWRnIAwPIU/hqdefault.jpg"}],
"metadataType" => 0,
"title" => "Metropolis 80 Freeskate Vs Barcelona - Powerslide"},
"streamType" => "BUFFERED"}, "mediaSessionId" => 1936679159,
"numLinkedUsers" => 0, "playbackRate" => 1, "playerState" => "PLAYING",
"requestId" => "0", "supportedMediaCommands" => 3,
"topicHistory" => ["[\"https://lh5.googleusercontent.com/proxy/vkAEc_MrmRauQq8jR40hx_yh-ExzYSupzCaA3uKbLv6MKhRFd4tit_f1CTneIYHT7vYkgbPANzXQ0vuYzXm1WLpUyTFHv0Vcj13gH9Ibr_z9AJR0SrTQ2hmfXz7isqP_EhXtk9-ldjRQOhhc5n1waAu8IXtiid5Pt5ZYbNE2oooJysxGh8-2vprNq3yArVBNC-DWdvzEjaJoR_wfkdSGWG2houxsQzAG6ZgInJDJ1cz0U1_a8tdTStJ56CoTMAs=s1920-w1920-h1080-p-k-no-nd-mv\",null,null,null,120,11,null,null,null,\"http://www.gettyimages.com/detail/photo/suspension-bridge-royalty-free-image/107709060?esource=chromecast\",null,null,\"Photo by Daniel Muller\",null,[],null,0,\"FEATURED_GETTYIMAGES_TITLE\",\"89ae3a3b697da2318e0a9fbd8951b7d5\",null,null,0,null,null,null,48,[[48,\"FEATURED_GETTYIMAGES_TITLE\",\"Getty Images\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],3037105898765724,[9700053]]",
"[\"https://lh3.googleusercontent.com/SxgLlfCrzM66njIgpKlq2nkRrCdq2_sONwQDxl0AAImggIso_VkVzg=s1920-w1920-h1080-p-k-no-nd-mv\",\"Saurabh Paranjape\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/105737724482908033948/albums/6213733340481709841/6213733341343554690\",null,null,\"Photo by Saurabh Paranjape\",null,[[\"Westminster Bridge, London, England\",\"https://www.google.com/search?q=Westminster+Bridge\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipN2LkA4gtWKmP4xk7RWQFR9IKB9EnW2m4s3qVsp\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],-6380615397988733,[9700053]]",
"[\"https://lh3.googleusercontent.com/mij2Eglc324jD_kxhu43aSnX8w9Xfr7XQdEwLpWpiVoFWZSh8Ljj=s1920-w1920-h1080-p-k-no-nd-mv\",\"Justin Brown\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/101005060236931055507/albums/5720519753508285169/6122212643311873906\",null,null,\"Photo by Justin Brown\",null,[[\"New York City, NY\",\"https://www.google.com/search?q=New+York+City%2C+New+York\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipPSuE14ATWH-FwoO3DGJyiyewcTORhjDEuFTF__\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],1293145096798261,[9700053]]",
"[\"https://lh3.googleusercontent.com/LEwrbgnOQd-jBz6s5FuTqtKlUaa_UExFsBLBlzOi0rtsopryVScqkQ=s1920-w1920-h1080-p-k-no-nd-mv\",\"Aaron Choi\",null,null,120,7,null,null,null,\"https://plus.google.com/photos/111628818598106803270/albums/6117592132440816289/6140512115181587250\",null,null,\"Photo by Aaron Choi\",null,[[\"Manarola, Cinque Terre, Italy\",\"https://www.google.com/search?q=Manarola+in+Cinque+Terre%2C+Italy\"]],null,0,\"FEATURED_GPLUS_TITLE\",\"AF1QipNQEjzYMlvgXzfQkE6l9Yrsip6SGFnuQim2xlcY\",null,null,0,null,null,null,46,[[46,\"FEATURED_GPLUS_TITLE\",\"Google+\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],7159867778728899,[9700053]]",
"[\"https://lh4.googleusercontent.com/proxy/c5GLPnubdevNNbhBlOekeEAA64Us7uNSMJkhgjWZlCQIo1eqqwXve4RZlIcBQwahoEI32MXkXXOhZmFWayEpF-UJafokwVKemB2EWX42dJDUi6xCLmPYLRDEmZ5YPCDefGJikV2XgR8e9pE5b4XS215Bygf6t-oNSTK-Ae_uKtKq3gOMvFt7PmmFPj9uvqjCu9N1ehUQ6CXiH7Ke7z6nqpO5dW6kfDVvdAV1oEtl6bD572C1QHWaD5d9HKnRzx-l0j4CryxMq0xIODl2ziPasNGGe4zHCYpGXIzq7qrF=s1920-w1920-h1080-fcrop64=1,0000170affffef93-k-no-nd-mv\",null,null,null,120,11,null,null,null,\"http://www.gettyimages.com/detail/photo/grand-prismatic-spring-yellowstone-national-high-res-stock-photography/462556881?esource=chromecast\",null,null,\"Photo by Peter Adams\",null,[],null,0,\"FEATURED_GETTYIMAGES_TITLE\",\"363fad4f1769ed622205dc4e1b75281a\",null,null,0,null,null,null,48,[[48,\"FEATURED_GETTYIMAGES_TITLE\",\"Getty Images\"],[3,\"PHOTO_COMMUNITIES_TITLE\",\"Featured photos\"]],4718130360558134,[9700053]]"],
"volume" => %{"level" => 1, "muted" => false}},
receiver_status: %{"requestId" => 12,
"status" => %{"applications" => [%{"appId" => "233637DE",
"displayName" => "YouTube", "isIdleScreen" => false,
"namespaces" => [%{"name" => "urn:x-cast:com.google.youtube.mdx"},
%{"name" => "urn:x-cast:com.google.cast.media"},
%{"name" => "urn:x-cast:com.google.cast.cac"},
%{"name" => "urn:x-cast:com.google.cast.inject"}],
"sessionId" => "9F2318D0-8581-446E-9BFB-AA8FDABD74F4",
"statusText" => "YouTube", "transportId" => "web-13"}],
"volume" => %{"controlType" => "attenuation", "level" => 1.0,
"muted" => false, "stepInterval" => 0.05000000074505806}},
"type" => "RECEIVER_STATUS"}, request_id: 39,
session: "9F2318D0-8581-446E-9BFB-AA8FDABD74F4",
ssl: {:sslsocket, {:gen_tcp, #Port<0.7995>, :tls_connection, :undefined},
#PID<0.226.0>}}
Chromecast.start_link(ip \\ {192, 168, 1, 15})
starts a GenServer
that opens a binary SSL connection to the Chromecast. The protocol is based on Protobufs, and uses the exprotobuf
library. Every few seconds the Chromecast will send out a ping
request and expects a pong
within a few seconds, otherwise it closes the session. Periodically Chromecast sends a request with it's current state, this is captured by the Chromecast process and it's state is updated. To pause media call Chromecast.pause(:device)
where device is the PID
returned when calling Chromecast.start_link
. Play is similar Chromecast.play(:device)
. You can easily connect to multiple Chromecasts by calling Chromecast.start_link(ip)
with unique IP addresses. You can discover your Chromecast(s) using mDNS and/or SSDP.