1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/cras/cras_unified.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/cras/audio_manager_cras.h" 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace media { 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Overview of operation: 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 1) An object of CrasUnifiedStream is created by the AudioManager 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// factory: audio_man->MakeAudioStream(). 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 2) Next some thread will call Open(), at that point a client is created and 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// configured for the correct format and sample rate. 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 3) Then Start(source) is called and a stream is added to the CRAS client 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// which will create its own thread that periodically calls the source for more 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// data as buffers are being consumed. 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 4) When finished Stop() is called, which is handled by stopping the stream. 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 5) Finally Close() is called. It cleans up and notifies the audio manager, 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// which likely will destroy this object. 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// For output-only streams, a unified stream is created with 0 input channels. 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Simplified data flow for unified streams: 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// +-------------+ +------------------+ 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | CRAS Server | | Chrome Client | 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// +------+------+ Add Stream +---------+--------+ 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |<----------------------------------| 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | buffer_frames captured to shm | 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |---------------------------------->| 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | UnifiedCallback() 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | ReadWriteAudio() 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | buffer_frames written to shm | 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |<----------------------------------| 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ... Repeats for each block. ... 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | Remove stream | 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |<----------------------------------| 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Simplified data flow for output only streams: 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// +-------------+ +------------------+ 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | CRAS Server | | Chrome Client | 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// +------+------+ Add Stream +---------+--------+ 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |<----------------------------------| 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | Near out of samples, request more | 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |---------------------------------->| 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | UnifiedCallback() 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | WriteAudio() 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | buffer_frames written to shm | 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |<----------------------------------| 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ... Repeats for each block. ... 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | Remove stream | 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// |<----------------------------------| 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// | | 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// For Unified streams the Chrome client is notified whenever buffer_frames have 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// been captured. For Output streams the client is notified a few milliseconds 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// before the hardware buffer underruns and fills the buffer with another block 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// of audio. 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CrasUnifiedStream::CrasUnifiedStream(const AudioParameters& params, 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AudioManagerCras* manager) 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : client_(NULL), 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_id_(0), 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) params_(params), 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bytes_per_frame_(0), 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) is_playing_(false), 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) volume_(1.0), 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) manager_(manager), 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_callback_(NULL), 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_direction_(CRAS_STREAM_OUTPUT) { 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(manager_); 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(params_.channels() > 0); 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Must have at least one input or output. If there are both they must be the 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // same. 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int input_channels = params_.input_channels(); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (input_channels) { 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // A unified stream for input and output. 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(params_.channels() == input_channels); 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_direction_ = CRAS_STREAM_UNIFIED; 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_bus_ = AudioBus::Create(input_channels, 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) params_.frames_per_buffer()); 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_bus_ = AudioBus::Create(params); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CrasUnifiedStream::~CrasUnifiedStream() { 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!is_playing_); 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CrasUnifiedStream::Open() { 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Sanity check input values. 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (params_.sample_rate() <= 0) { 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Unsupported audio frequency."; 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (AudioManagerCras::BitsToFormat(params_.bits_per_sample()) == 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SND_PCM_FORMAT_UNKNOWN) { 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Unsupported pcm format"; 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create the client and connect to the CRAS server. 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (cras_client_create(&client_)) { 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Couldn't create CRAS client.\n"; 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_ = NULL; 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (cras_client_connect(client_)) { 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Couldn't connect CRAS client.\n"; 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_destroy(client_); 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_ = NULL; 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Then start running the client. 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (cras_client_run_thread(client_)) { 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Couldn't run CRAS client.\n"; 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_destroy(client_); 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_ = NULL; 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CrasUnifiedStream::Close() { 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (client_) { 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_stop(client_); 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_destroy(client_); 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_ = NULL; 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Signal to the manager that we're closed and can be removed. 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Should be last call in the method as it deletes "this". 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) manager_->ReleaseOutputStream(this); 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CrasUnifiedStream::Start(AudioSourceCallback* callback) { 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CHECK(callback); 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Channel map to CRAS_CHANNEL, values in the same order of 1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // corresponding source in Chromium defined Channels. 1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) static const int kChannelMap[] = { 1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_FL, 1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_FR, 1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_FC, 1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_LFE, 1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_RL, 1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_RR, 1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_FLC, 1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_FRC, 1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_RC, 1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_SL, 1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CRAS_CH_SR 1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) }; 1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_callback_ = callback; 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Only start if we can enter the playing state. 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (is_playing_) 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Prepare |audio_format| and |stream_params| for the stream we 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // will create. 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_audio_format* audio_format = cras_audio_format_create( 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AudioManagerCras::BitsToFormat(params_.bits_per_sample()), 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) params_.sample_rate(), 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) params_.channels()); 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!audio_format) { 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Error setting up audio parameters."; 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) callback->OnError(this); 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Initialize channel layout to all -1 to indicate that none of 1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // the channels is set in the layout. 1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int8 layout[CRAS_CH_MAX] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; 1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Converts to CRAS defined channels. ChannelOrder will return -1 2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // for channels that does not present in params_.channel_layout(). 2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (size_t i = 0; i < arraysize(kChannelMap); ++i) 2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(), 2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) static_cast<Channels>(i)); 2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (cras_audio_format_set_channel_layout(audio_format, layout)) { 2061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) LOG(WARNING) << "Error setting channel layout."; 2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) callback->OnError(this); 2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 2091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_stream_params* stream_params = cras_client_unified_params_create( 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_direction_, 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) params_.frames_per_buffer(), 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CRAS_STREAM_TYPE_DEFAULT, 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0, 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) this, 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CrasUnifiedStream::UnifiedCallback, 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CrasUnifiedStream::StreamError, 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) audio_format); 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!stream_params) { 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Error setting up stream parameters."; 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) callback->OnError(this); 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_audio_format_destroy(audio_format); 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Before starting the stream, save the number of bytes in a frame for use in 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // the callback. 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format); 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Adding the stream will start the audio callbacks requesting data. 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (cras_client_add_stream(client_, &stream_id_, stream_params) < 0) { 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(WARNING) << "Failed to add the stream"; 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) callback->OnError(this); 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_audio_format_destroy(audio_format); 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_stream_params_destroy(stream_params); 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Set initial volume. 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_set_stream_volume(client_, stream_id_, volume_); 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Done with config params. 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_audio_format_destroy(audio_format); 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_stream_params_destroy(stream_params); 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) is_playing_ = true; 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CrasUnifiedStream::Stop() { 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!client_) 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Removing the stream from the client stops audio. 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_rm_stream(client_, stream_id_); 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) is_playing_ = false; 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CrasUnifiedStream::SetVolume(double volume) { 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!client_) 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) volume_ = static_cast<float>(volume); 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_set_stream_volume(client_, stream_id_, volume_); 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CrasUnifiedStream::GetVolume(double* volume) { 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *volume = volume_; 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uint32 CrasUnifiedStream::GetBytesLatency( 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const struct timespec& latency_ts) { 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint32 latency_usec; 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Treat negative latency (if we are too slow to render) as 0. 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (latency_ts.tv_sec < 0 || latency_ts.tv_nsec < 0) { 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latency_usec = 0; 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latency_usec = (latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond) + 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond; 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) double frames_latency = 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond; 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return static_cast<unsigned int>(frames_latency * bytes_per_frame_); 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Static callback asking for samples. 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int CrasUnifiedStream::UnifiedCallback(cras_client* client, 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_stream_id_t stream_id, 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* input_samples, 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* output_samples, 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) unsigned int frames, 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* input_ts, 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* output_ts, 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void* arg) { 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg); 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return me->DispatchCallback(frames, 300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_samples, 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_samples, 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_ts, 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_ts); 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Static callback for stream errors. 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int CrasUnifiedStream::StreamError(cras_client* client, 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_stream_id_t stream_id, 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int err, 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void* arg) { 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg); 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) me->NotifyStreamError(err); 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return 0; 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Calls the appropriate rendering function for this type of stream. 317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uint32 CrasUnifiedStream::DispatchCallback(size_t frames, 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* input_samples, 319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* output_samples, 320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* input_ts, 321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* output_ts) { 322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) switch (stream_direction_) { 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case CRAS_STREAM_OUTPUT: 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return WriteAudio(frames, output_samples, output_ts); 325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case CRAS_STREAM_INPUT: 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NOTREACHED() << "CrasUnifiedStream doesn't support input streams."; 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return 0; 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case CRAS_STREAM_UNIFIED: 329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ReadWriteAudio(frames, input_samples, output_samples, 330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_ts, output_ts); 331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch default: 332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return 0; 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Note these are run from a real time thread, so don't waste cycles here. 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uint32 CrasUnifiedStream::ReadWriteAudio(size_t frames, 340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* input_samples, 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* output_samples, 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* input_ts, 343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* output_ts) { 344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames())); 345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(source_callback_); 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint32 bytes_per_sample = bytes_per_frame_ / params_.channels(); 348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_bus_->FromInterleaved(input_samples, frames, bytes_per_sample); 349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Determine latency and pass that on to the source. We have the capture time 351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // of the first input sample and the playback time of the next audio sample 352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // passed from the audio server, add them together for total latency. 353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint32 total_delay_bytes; 354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) timespec latency_ts = {0, 0}; 355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_calc_capture_latency(input_ts, &latency_ts); 356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) total_delay_bytes = GetBytesLatency(latency_ts); 357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_calc_playback_latency(output_ts, &latency_ts); 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) total_delay_bytes += GetBytesLatency(latency_ts); 359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int frames_filled = source_callback_->OnMoreData( 361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_bus_.get(), 362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AudioBuffersState(0, total_delay_bytes)); 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_bus_->ToInterleaved(frames_filled, bytes_per_sample, output_samples); 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return frames_filled; 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uint32 CrasUnifiedStream::WriteAudio(size_t frames, 370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint8* buffer, 371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const timespec* sample_ts) { 372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames())); 373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Determine latency and pass that on to the source. 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) timespec latency_ts = {0, 0}; 376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cras_client_calc_playback_latency(sample_ts, &latency_ts); 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int frames_filled = source_callback_->OnMoreData( 379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts))); 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Note: If this ever changes to output raw float the data must be clipped and 382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // sanitized since it may come from an untrusted source such as NaCl. 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_bus_->ToInterleaved( 384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) frames_filled, bytes_per_frame_ / params_.channels(), buffer); 385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return frames_filled; 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CrasUnifiedStream::NotifyStreamError(int err) { 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This will remove the stream from the client. 391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (source_callback_) 392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_callback_->OnError(this); 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace media 396