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