Home | History | Annotate | Download | only in play_audio
      1 /*
      2  *
      3  * Copyright (C) 2018 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 #include "client_socket.h"
     18 #include "sdl_wrapper.h"
     19 
     20 #include "glog/logging.h"
     21 #include "gflags/gflags.h"
     22 #include "opuscpp/opus_wrapper.h"
     23 #include <SDL2/SDL.h>
     24 
     25 #include <cstdint>
     26 #include <tuple>
     27 #include <vector>
     28 
     29 DEFINE_int32(
     30     device_num, 1,
     31     "Cuttlefish device number, corresponding to username vsoc-## number");
     32 
     33 namespace {
     34 std::uint16_t AudioPort() {
     35   constexpr std::uint16_t kAudioStreamBasePort = 7444;
     36   std::uint16_t audio_port = kAudioStreamBasePort + (FLAGS_device_num - 1);
     37   return audio_port;
     38 }
     39 
     40 cfp::ClientSocket Connect() {
     41   const auto port = AudioPort();
     42   auto conn = cfp::ClientSocket{port};
     43   if (!conn.valid()) {
     44     LOG(FATAL) << "couldn't connect on port " << port;
     45   }
     46   return conn;
     47 }
     48 
     49 std::tuple<std::uint16_t, std::uint16_t> RecvHeader(cfp::ClientSocket* conn) {
     50   // creating variables because these must be received in order
     51   auto num_channels = conn->RecvUInt16();
     52   auto frame_rate = conn->RecvUInt16();
     53   LOG(INFO) << "\nnum_channels: " << num_channels
     54             << "\nframe_rate: " << frame_rate << '\n';
     55   return {num_channels, frame_rate};
     56 }
     57 
     58 // Returns frame_size and encoded audio
     59 std::tuple<std::uint32_t, std::vector<unsigned char>> RecvEncodedAudio(
     60     cfp::ClientSocket* conn) {
     61   auto length = conn->RecvUInt32();
     62   auto frame_size = conn->RecvUInt32();
     63   auto encoded = conn->RecvAll(length);
     64 
     65   if (encoded.size() < length) {
     66     encoded.clear();
     67   }
     68   return {frame_size, std::move(encoded)};
     69 }
     70 
     71 void PlayDecodedAudio(cfp::SDLAudioDevice* audio_device,
     72                       const std::vector<opus_int16>& audio) {
     73   auto sz = audio.size() * sizeof audio[0];
     74   auto ret = audio_device->QueueAudio(audio.data(), sz);
     75   if (ret < 0) {
     76     LOG(ERROR) << "failed to queue audio: " << SDL_GetError() << '\n';
     77   }
     78 }
     79 
     80 }  // namespace
     81 
     82 int main(int argc, char* argv[]) {
     83   ::google::InitGoogleLogging(argv[0]);
     84   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
     85   cfp::SDLLib sdl{};
     86 
     87   auto conn = Connect();
     88   const auto& [num_channels, frame_rate] = RecvHeader(&conn);
     89 
     90   auto audio_device = sdl.OpenAudioDevice(frame_rate, num_channels);
     91   auto dec =
     92       opus::Decoder{static_cast<std::uint32_t>(frame_rate), num_channels};
     93   CHECK(dec.valid()) << "Could not construct Decoder. Maybe bad frame_rate ("
     94                      << frame_rate <<") or num_channels (" << num_channels
     95                      << ")?";
     96 
     97   while (true) {
     98     CHECK(dec.valid()) << "decoder in invalid state";
     99     const auto& [frame_size, encoded] = RecvEncodedAudio(&conn);
    100     if (encoded.empty()) {
    101       break;
    102     }
    103     auto decoded = dec.Decode(encoded, frame_size, false);
    104     if (decoded.empty()) {
    105       break;
    106     }
    107     PlayDecodedAudio(&audio_device, decoded);
    108   }
    109 }
    110