15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/openbsd/audio_manager_openbsd.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <fcntl.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_path.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_output_dispatcher.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_parameters.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/pulse/pulse_output.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/pulse/pulse_stubs.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/channel_layout.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/limits.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media_switches.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using media_audio_pulse::kModulePulse;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using media_audio_pulse::InitializeStubs;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using media_audio_pulse::StubPathMap;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of output streams that can be open simultaneously.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxOutputStreams = 50;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Default sample rate for input and output streams.
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kDefaultSampleRate = 48000;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const base::FilePath::CharType kPulseLib[] =
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FILE_PATH_LITERAL("libpulse.so.0");
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of AudioManager.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool HasAudioHardware() {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int fd;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *file;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((file = getenv("AUDIOCTLDEVICE")) == 0 || *file == '\0')
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file = "/dev/audioctl";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((fd = open(file, O_RDONLY)) < 0)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close(fd);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerOpenBSD::HasAudioOutputDevices() {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HasAudioHardware();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerOpenBSD::HasAudioInputDevices() {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HasAudioHardware();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioParameters AudioManagerOpenBSD::GetInputStreamParameters(
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& device_id) {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kDefaultInputBufferSize = 1024;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int user_buffer_size = GetUserBufferSize();
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int buffer_size = user_buffer_size ?
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      user_buffer_size : kDefaultInputBufferSize;
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AudioParameters(
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      kDefaultSampleRate, 16, buffer_size);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AudioManagerOpenBSD::AudioManagerOpenBSD(AudioLogFactory* audio_log_factory)
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : AudioManagerBase(audio_log_factory),
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      pulse_library_is_initialized_(false) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetMaxOutputStreamsAllowed(kMaxOutputStreams);
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StubPathMap paths;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if the pulse library is avialbale.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  paths[kModulePulse].push_back(kPulseLib);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!InitializeStubs(paths)) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(WARNING) << "Failed on loading the Pulse library and symbols";
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pulse_library_is_initialized_ = true;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioManagerOpenBSD::~AudioManagerOpenBSD() {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shutdown();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerOpenBSD::MakeLinearOutputStream(
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MakeOutputStream(params);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerOpenBSD::MakeLowLatencyOutputStream(
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const AudioParameters& params,
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& device_id) {
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MakeOutputStream(params);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerOpenBSD::MakeLinearInputStream(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params, const std::string& device_id) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerOpenBSD::MakeLowLatencyInputStream(
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params, const std::string& device_id) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioParameters AudioManagerOpenBSD::GetPreferredOutputStreamParameters(
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& output_device_id,
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const AudioParameters& input_params) {
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // TODO(tommi): Support |output_device_id|.
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kDefaultOutputBufferSize = 512;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int sample_rate = kDefaultSampleRate;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int buffer_size = kDefaultOutputBufferSize;
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bits_per_sample = 16;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (input_params.IsValid()) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sample_rate = input_params.sample_rate();
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bits_per_sample = input_params.bits_per_sample();
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    channel_layout = input_params.channel_layout();
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_size = std::min(buffer_size, input_params.frames_per_buffer());
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int user_buffer_size = GetUserBufferSize();
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (user_buffer_size)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_size = user_buffer_size;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AudioParameters(
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS);
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerOpenBSD::MakeOutputStream(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (pulse_library_is_initialized_)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return new PulseAudioOutputStream(params, this);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(xians): Merge AudioManagerOpenBSD with AudioManagerPulse;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return new AudioManagerOpenBSD(audio_log_factory);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
161