1bf7ab50dSStephan Aßmus /* 2b543dbc2SStephan Aßmus * Copyright 2003-2010 Haiku Inc. All rights reserved. 3bf7ab50dSStephan Aßmus * Distributed under the terms of the MIT License. 4bf7ab50dSStephan Aßmus * 5bf7ab50dSStephan Aßmus * Authors: 6bf7ab50dSStephan Aßmus * Marcus Overhagen 7bf7ab50dSStephan Aßmus */ 8a9cf57cfSAxel Dörfler 9a9cf57cfSAxel Dörfler 10bf7ab50dSStephan Aßmus #include "MixerCore.h" 11a9cf57cfSAxel Dörfler 12a9cf57cfSAxel Dörfler #include <Buffer.h> 13a9cf57cfSAxel Dörfler #include <string.h> 14a9cf57cfSAxel Dörfler #include <TimeSource.h> // TODO: debug only 15a9cf57cfSAxel Dörfler 16a9cf57cfSAxel Dörfler #include "ByteSwap.h" 17a79b30c3SStephan Aßmus #include "Interpolate.h" 18bf7ab50dSStephan Aßmus #include "MixerInput.h" 19bf7ab50dSStephan Aßmus #include "MixerUtils.h" 20bf7ab50dSStephan Aßmus #include "Resampler.h" 21bf7ab50dSStephan Aßmus 22678c2017Sbeveloper 23a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore* core, const media_input& input, 24b006bbe1SStephan Aßmus float mixFrameRate, int32 mixFrameCount) 25a9cf57cfSAxel Dörfler : 26a9cf57cfSAxel Dörfler fCore(core), 272e9d6607Sbeveloper fInput(input), 28b006bbe1SStephan Aßmus fInputByteSwap(NULL), 291c237c18Sbeveloper fEnabled(true), 30b006bbe1SStephan Aßmus fInputChannelInfo(NULL), 312e9d6607Sbeveloper fInputChannelCount(0), 322e9d6607Sbeveloper fInputChannelMask(0), 332e9d6607Sbeveloper fMixerChannelInfo(0), 342e9d6607Sbeveloper fMixerChannelCount(0), 35b006bbe1SStephan Aßmus fMixBuffer(NULL), 367b0daf5cSbeveloper fMixBufferFrameRate(0), 377b0daf5cSbeveloper fMixBufferFrameCount(0), 38e92593f4Sbeveloper fLastDataFrameWritten(-1), 39af8d0a4dSbeveloper fLastDataAvailableTime(-1), 40e92593f4Sbeveloper fFractionalFrames(0.0), 41b006bbe1SStephan Aßmus fResampler(NULL), 42b006bbe1SStephan Aßmus fRtmPool(NULL), 439c3be6a5Sbeveloper fUserOverridesChannelDestinations(false) 44678c2017Sbeveloper { 45e6c7c99fSbeveloper fix_multiaudio_format(&fInput.format.u.raw_audio); 46e6c7c99fSbeveloper PRINT_INPUT("MixerInput::MixerInput", fInput); 47e6c7c99fSbeveloper PRINT_CHANNEL_MASK(fInput.format); 482e9d6607Sbeveloper 492e9d6607Sbeveloper ASSERT(fInput.format.u.raw_audio.channel_count > 0); 502e9d6607Sbeveloper 519c3be6a5Sbeveloper for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 529c3be6a5Sbeveloper fChannelTypeGain[i] = 1.0f; 539c3be6a5Sbeveloper 542e9d6607Sbeveloper fInputChannelCount = fInput.format.u.raw_audio.channel_count; 552e9d6607Sbeveloper fInputChannelMask = fInput.format.u.raw_audio.channel_mask; 562e9d6607Sbeveloper fInputChannelInfo = new input_chan_info[fInputChannelCount]; 572e9d6607Sbeveloper 5888777023Sbeveloper // perhaps we need byte swapping 5988777023Sbeveloper if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) { 60a9cf57cfSAxel Dörfler if (fInput.format.u.raw_audio.format 61a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_FLOAT 62a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 63a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_INT 64a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 65a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_SHORT) { 6688777023Sbeveloper fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format); 6788777023Sbeveloper } 6888777023Sbeveloper } 6988777023Sbeveloper 702e9d6607Sbeveloper // initialize fInputChannelInfo 712e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) { 72b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base = 0; 73b543dbc2SStephan Aßmus // will be set by SetMixBufferFormat() 74b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = 0; 75b006bbe1SStephan Aßmus // will be set by _UpdateInputChannelDestinationMask() 762e9d6607Sbeveloper fInputChannelInfo[i].gain = 1.0; 772e9d6607Sbeveloper } 782e9d6607Sbeveloper 79b006bbe1SStephan Aßmus UpdateResamplingAlgorithm(); 807b0daf5cSbeveloper 81b543dbc2SStephan Aßmus // fMixerChannelInfo and fMixerChannelCount will be initialized by 82b006bbe1SStephan Aßmus // _UpdateInputChannelDestinations() 83bf7ab50dSStephan Aßmus SetMixBufferFormat((int32)mixFrameRate, mixFrameCount); 84678c2017Sbeveloper } 85678c2017Sbeveloper 86a9cf57cfSAxel Dörfler 87678c2017Sbeveloper MixerInput::~MixerInput() 88678c2017Sbeveloper { 892e9d6607Sbeveloper if (fMixBuffer) 902e9d6607Sbeveloper rtm_free(fMixBuffer); 91356855c3Sbeveloper if (fRtmPool) 92356855c3Sbeveloper rtm_delete_pool(fRtmPool); 932e9d6607Sbeveloper delete[] fInputChannelInfo; 942e9d6607Sbeveloper delete[] fMixerChannelInfo; 957b0daf5cSbeveloper 967b0daf5cSbeveloper // delete resamplers 97b006bbe1SStephan Aßmus if (fResampler != NULL) { 987b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) 997b0daf5cSbeveloper delete fResampler[i]; 1007b0daf5cSbeveloper delete[] fResampler; 101b006bbe1SStephan Aßmus } 102db6f1135SJérôme Duval delete fInputByteSwap; 103678c2017Sbeveloper } 104678c2017Sbeveloper 105a9cf57cfSAxel Dörfler 106b006bbe1SStephan Aßmus int32 107b006bbe1SStephan Aßmus MixerInput::ID() 108b006bbe1SStephan Aßmus { 109b006bbe1SStephan Aßmus return fInput.destination.id; 110b006bbe1SStephan Aßmus } 111b006bbe1SStephan Aßmus 112b006bbe1SStephan Aßmus 113b006bbe1SStephan Aßmus media_input& 114b006bbe1SStephan Aßmus MixerInput::MediaInput() 115b006bbe1SStephan Aßmus { 116b006bbe1SStephan Aßmus return fInput; 117b006bbe1SStephan Aßmus } 118b006bbe1SStephan Aßmus 119b006bbe1SStephan Aßmus 120678c2017Sbeveloper void 121678c2017Sbeveloper MixerInput::BufferReceived(BBuffer* buffer) 122678c2017Sbeveloper { 12388777023Sbeveloper void* data; 12488777023Sbeveloper size_t size; 12588777023Sbeveloper bigtime_t start; 126e92593f4Sbeveloper bigtime_t buffer_duration; 12788777023Sbeveloper 128d5848e21Sbeveloper if (!fMixBuffer) { 129b543dbc2SStephan Aßmus ERROR("MixerInput::BufferReceived: dropped incoming buffer as we " 130b543dbc2SStephan Aßmus "don't have a mix buffer\n"); 131d5848e21Sbeveloper return; 132d5848e21Sbeveloper } 1332e9d6607Sbeveloper 13488777023Sbeveloper data = buffer->Data(); 13588777023Sbeveloper size = buffer->SizeUsed(); 13688777023Sbeveloper start = buffer->Header()->start_time; 137b543dbc2SStephan Aßmus buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, 138b543dbc2SStephan Aßmus size / bytes_per_frame(fInput.format.u.raw_audio)); 1398d28117fSbeveloper if (start < 0) { 140b543dbc2SStephan Aßmus ERROR("MixerInput::BufferReceived: buffer with negative start time of " 141b543dbc2SStephan Aßmus "%Ld dropped\n", start); 1428d28117fSbeveloper return; 1438d28117fSbeveloper } 14488777023Sbeveloper 14588777023Sbeveloper // swap the byte order of this buffer, if necessary 14688777023Sbeveloper if (fInputByteSwap) 14788777023Sbeveloper fInputByteSwap->Swap(data, size); 14888777023Sbeveloper 149b543dbc2SStephan Aßmus int offset = frames_for_duration(fMixBufferFrameRate, start) 150b543dbc2SStephan Aßmus % fMixBufferFrameCount; 1518d28117fSbeveloper 152b543dbc2SStephan Aßmus PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", 153b543dbc2SStephan Aßmus start, offset); 1547b0daf5cSbeveloper 155191033efSbeveloper int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio); 15623bfcc55SJulian Harnath double frames = ((double)in_frames * fMixBufferFrameRate) 157b543dbc2SStephan Aßmus / fInput.format.u.raw_audio.frame_rate; 158e92593f4Sbeveloper int out_frames = int(frames); 159e92593f4Sbeveloper fFractionalFrames += frames - double(out_frames); 160e92593f4Sbeveloper if (fFractionalFrames >= 1.0) { 161e92593f4Sbeveloper fFractionalFrames -= 1.0; 1627619f562Sbeveloper out_frames++; 163e92593f4Sbeveloper } 164e92593f4Sbeveloper 165e92593f4Sbeveloper // if fLastDataFrameWritten != -1, then we have a valid last position 166e92593f4Sbeveloper // and can do glitch compensation 167e92593f4Sbeveloper if (fLastDataFrameWritten >= 0) { 168b543dbc2SStephan Aßmus int expected_frame = (fLastDataFrameWritten + 1) 169b543dbc2SStephan Aßmus % fMixBufferFrameCount; 170e92593f4Sbeveloper if (offset != expected_frame) { 171e92593f4Sbeveloper // due to rounding and other errors, offset might be off by +/- 1 172e92593f4Sbeveloper // this is not really a bad glitch, we just adjust the position 173e92593f4Sbeveloper if (offset == fLastDataFrameWritten) { 174b543dbc2SStephan Aßmus // printf("MixerInput::BufferReceived: -1 frame GLITCH! last " 175b543dbc2SStephan Aßmus // "frame was %ld, expected frame was %d, new frame is %d\n", 176b543dbc2SStephan Aßmus // fLastDataFrameWritten, expected_frame, offset); 177e92593f4Sbeveloper offset = expected_frame; 178b543dbc2SStephan Aßmus } else if (offset == ((fLastDataFrameWritten + 2) 179b543dbc2SStephan Aßmus % fMixBufferFrameCount)) { 180b543dbc2SStephan Aßmus // printf("MixerInput::BufferReceived: +1 frame GLITCH! last " 181b543dbc2SStephan Aßmus // "frame was %ld, expected frame was %d, new frame is %d\n", 182b543dbc2SStephan Aßmus // fLastDataFrameWritten, expected_frame, offset); 183e92593f4Sbeveloper offset = expected_frame; 184e92593f4Sbeveloper } else { 185b543dbc2SStephan Aßmus printf("MixerInput::BufferReceived: GLITCH! last frame was " 186*973f1214SJérôme Duval "%4" B_PRId32 ", expected frame was %4d, new frame is %4d" 187*973f1214SJérôme Duval "\n", fLastDataFrameWritten, expected_frame, offset); 188e92593f4Sbeveloper 189e92593f4Sbeveloper if (start > fLastDataAvailableTime) { 190b543dbc2SStephan Aßmus if ((start - fLastDataAvailableTime) 191b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 192e92593f4Sbeveloper // buffer is less than 10% of buffer duration too late 193b543dbc2SStephan Aßmus printf("short glitch, buffer too late, time delta " 194*973f1214SJérôme Duval "%" B_PRIdBIGTIME "\n", start 195*973f1214SJérôme Duval - fLastDataAvailableTime); 196e92593f4Sbeveloper offset = expected_frame; 197e92593f4Sbeveloper out_frames++; 198e92593f4Sbeveloper } else { 199e92593f4Sbeveloper // buffer more than 10% of buffer duration too late 200b543dbc2SStephan Aßmus // TODO: zerofill buffer 201b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too late, time delta " 202*973f1214SJérôme Duval "%" B_PRIdBIGTIME "\n", start 203*973f1214SJérôme Duval - fLastDataAvailableTime); 204e92593f4Sbeveloper } 205e92593f4Sbeveloper } else { // start <= fLastDataAvailableTime 206e92593f4Sbeveloper // the new buffer is too early 207b543dbc2SStephan Aßmus if ((fLastDataAvailableTime - start) 208b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 209e92593f4Sbeveloper // buffer is less than 10% of buffer duration too early 210b543dbc2SStephan Aßmus printf("short glitch, buffer too early, time delta " 211*973f1214SJérôme Duval "%" B_PRIdBIGTIME "\n", fLastDataAvailableTime 212*973f1214SJérôme Duval - start); 213e92593f4Sbeveloper offset = expected_frame; 214e92593f4Sbeveloper out_frames--; 215e92593f4Sbeveloper if (out_frames < 1) 216e92593f4Sbeveloper out_frames = 1; 217e92593f4Sbeveloper } else { 218e92593f4Sbeveloper // buffer more than 10% of buffer duration too early 219b543dbc2SStephan Aßmus // TODO: zerofill buffer 220b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too early, time delta " 221*973f1214SJérôme Duval "%" B_PRIdBIGTIME "\n", fLastDataAvailableTime 222*973f1214SJérôme Duval - start); 223e92593f4Sbeveloper } 224e92593f4Sbeveloper } 225e92593f4Sbeveloper } 226e92593f4Sbeveloper } 227e92593f4Sbeveloper } 2287b0daf5cSbeveloper 229b543dbc2SStephan Aßmus // printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", 230b543dbc2SStephan Aßmus // start, 231b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 232b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 233b543dbc2SStephan Aßmus // offset + out_frames); 2347b0daf5cSbeveloper if (offset + out_frames > fMixBufferFrameCount) { 2357b0daf5cSbeveloper int out_frames1 = fMixBufferFrameCount - offset; 2367b0daf5cSbeveloper int out_frames2 = out_frames - out_frames1; 2377b0daf5cSbeveloper int in_frames1 = (out_frames1 * in_frames) / out_frames; 2387b0daf5cSbeveloper int in_frames2 = in_frames - in_frames1; 2397b0daf5cSbeveloper 240b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 241b543dbc2SStephan Aßmus // "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 242b543dbc2SStephan Aßmus // start, 243b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 244b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 245b543dbc2SStephan Aßmus // offset + out_frames1 - 1, 0, out_frames2 - 1); 246b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 247b543dbc2SStephan Aßmus "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 248b543dbc2SStephan Aßmus start, 249b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 250b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 251b543dbc2SStephan Aßmus offset + out_frames1 - 1, 0, out_frames2 - 1); 252b543dbc2SStephan Aßmus PRINT(5, " in_frames %5d, out_frames %5d, in_frames1 %5d, " 253b543dbc2SStephan Aßmus "out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n", 254b543dbc2SStephan Aßmus in_frames, out_frames, in_frames1, out_frames1, in_frames2, 255b543dbc2SStephan Aßmus out_frames2); 2567b0daf5cSbeveloper 257e92593f4Sbeveloper fLastDataFrameWritten = out_frames2 - 1; 258e92593f4Sbeveloper 259b543dbc2SStephan Aßmus // convert offset from frames into bytes 260b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2618d28117fSbeveloper 2627b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 263b543dbc2SStephan Aßmus fResampler[i]->Resample( 264b543dbc2SStephan Aßmus reinterpret_cast<char*>(data) 265b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 266b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames1, 267b543dbc2SStephan Aßmus reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base) 268b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), out_frames1, 2697b0daf5cSbeveloper fInputChannelInfo[i].gain); 2707b0daf5cSbeveloper 271b543dbc2SStephan Aßmus fResampler[i]->Resample( 272b543dbc2SStephan Aßmus reinterpret_cast<char*>(data) 273b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio) 274b543dbc2SStephan Aßmus + in_frames1 * bytes_per_frame(fInput.format.u.raw_audio), 275b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames2, 2767b0daf5cSbeveloper reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base), 277b543dbc2SStephan Aßmus fInputChannelCount * sizeof(float), out_frames2, 2787b0daf5cSbeveloper fInputChannelInfo[i].gain); 279e92593f4Sbeveloper 2807b0daf5cSbeveloper } 2817b0daf5cSbeveloper } else { 282b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 283b543dbc2SStephan Aßmus // "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 284b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 285b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 286b543dbc2SStephan Aßmus // offset + out_frames - 1); 287b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 288b543dbc2SStephan Aßmus "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 289b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 290b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 291b543dbc2SStephan Aßmus offset + out_frames - 1); 292191033efSbeveloper PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames); 2938d28117fSbeveloper 294e92593f4Sbeveloper fLastDataFrameWritten = offset + out_frames - 1; 295b543dbc2SStephan Aßmus // convert offset from frames into bytes 296b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2977b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 298b543dbc2SStephan Aßmus fResampler[i]->Resample( 299b543dbc2SStephan Aßmus reinterpret_cast<char*>(data) 300b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 301b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames, 302b543dbc2SStephan Aßmus reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base) 303b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), 304b543dbc2SStephan Aßmus out_frames, fInputChannelInfo[i].gain); 3057b0daf5cSbeveloper } 3067b0daf5cSbeveloper } 307e92593f4Sbeveloper fLastDataAvailableTime = start + buffer_duration; 308678c2017Sbeveloper } 3097ee2c804Sbeveloper 310bf7ab50dSStephan Aßmus 311b006bbe1SStephan Aßmus void 312b006bbe1SStephan Aßmus MixerInput::UpdateResamplingAlgorithm() 3137ee2c804Sbeveloper { 314b006bbe1SStephan Aßmus if (fResampler != NULL) { 315b006bbe1SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) 316b006bbe1SStephan Aßmus delete fResampler[i]; 317b006bbe1SStephan Aßmus delete[] fResampler; 3187ee2c804Sbeveloper } 319b006bbe1SStephan Aßmus // create resamplers 320b006bbe1SStephan Aßmus fResampler = new Resampler*[fInputChannelCount]; 321b006bbe1SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 322b006bbe1SStephan Aßmus switch (fCore->Settings()->ResamplingAlgorithm()) { 323b006bbe1SStephan Aßmus case 2: 324b006bbe1SStephan Aßmus fResampler[i] = new Interpolate( 325b006bbe1SStephan Aßmus fInput.format.u.raw_audio.format, 326b006bbe1SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 327b006bbe1SStephan Aßmus break; 328b006bbe1SStephan Aßmus default: 329b006bbe1SStephan Aßmus fResampler[i] = new Resampler( 330b006bbe1SStephan Aßmus fInput.format.u.raw_audio.format, 331b006bbe1SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 332b006bbe1SStephan Aßmus } 333b006bbe1SStephan Aßmus } 334e6c7c99fSbeveloper } 335e6c7c99fSbeveloper 336bf7ab50dSStephan Aßmus 337d91580cdSbeveloper int 338fae6ce82Sbeveloper MixerInput::GetInputChannelCount() 339fae6ce82Sbeveloper { 340fae6ce82Sbeveloper return fInputChannelCount; 341fae6ce82Sbeveloper } 342fae6ce82Sbeveloper 343bf7ab50dSStephan Aßmus 3442e9d6607Sbeveloper void 3459c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type) 3462e9d6607Sbeveloper { 3479c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 348e6c7c99fSbeveloper 3492e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3502e9d6607Sbeveloper return; 3512e9d6607Sbeveloper 3522e9d6607Sbeveloper // test if it is already set 3539c3be6a5Sbeveloper if (fInputChannelInfo[channel].destination_mask & mask) 3542e9d6607Sbeveloper return; 3552e9d6607Sbeveloper 3569c3be6a5Sbeveloper // verify that no other channel has id 3579c3be6a5Sbeveloper if (-1 != GetInputChannelForDestination(destination_type)) { 358b543dbc2SStephan Aßmus ERROR("MixerInput::AddInputChannelDestination: destination_type %d " 359b543dbc2SStephan Aßmus "already assigned to channel %d\n", destination_type, 360b543dbc2SStephan Aßmus GetInputChannelForDestination(destination_type)); 3619c3be6a5Sbeveloper return; 3629c3be6a5Sbeveloper } 3632e9d6607Sbeveloper 3642e9d6607Sbeveloper // add it to specified channel 3659c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask |= mask; 3662e9d6607Sbeveloper 3679c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 368b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 3692e9d6607Sbeveloper } 3702e9d6607Sbeveloper 371a9cf57cfSAxel Dörfler 3722e9d6607Sbeveloper void 3739c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type) 3742e9d6607Sbeveloper { 3759c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3762e9d6607Sbeveloper 3772e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3782e9d6607Sbeveloper return; 3792e9d6607Sbeveloper 3802e9d6607Sbeveloper // test if it is really set 3819c3be6a5Sbeveloper if ((fInputChannelInfo[channel].destination_mask & mask) == 0) 3822e9d6607Sbeveloper return; 3832e9d6607Sbeveloper 3842e9d6607Sbeveloper // remove it from specified channel 3859c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask &= ~mask; 3862e9d6607Sbeveloper 3879c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 388b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 3892e9d6607Sbeveloper } 3902e9d6607Sbeveloper 391a9cf57cfSAxel Dörfler 3929c3be6a5Sbeveloper bool 3939c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type) 3942e9d6607Sbeveloper { 3952e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3969c3be6a5Sbeveloper return false; 3979c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3989c3be6a5Sbeveloper return false; 399b543dbc2SStephan Aßmus return fInputChannelInfo[channel].destination_mask 400b543dbc2SStephan Aßmus & ChannelTypeToChannelMask(destination_type); 4012e9d6607Sbeveloper } 4022e9d6607Sbeveloper 403a9cf57cfSAxel Dörfler 4049c3be6a5Sbeveloper int 4059c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type) 4069c3be6a5Sbeveloper { 4079c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 4089c3be6a5Sbeveloper return -1; 4099c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 4109c3be6a5Sbeveloper for (int chan = 0; chan < fInputChannelCount; chan++) { 4119c3be6a5Sbeveloper if (fInputChannelInfo[chan].destination_mask & mask) 4129c3be6a5Sbeveloper return chan; 4139c3be6a5Sbeveloper } 4149c3be6a5Sbeveloper return -1; 4159c3be6a5Sbeveloper } 4169c3be6a5Sbeveloper 417a9cf57cfSAxel Dörfler 4189c3be6a5Sbeveloper int 4192e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel) 4202e9d6607Sbeveloper { 4212e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4222e9d6607Sbeveloper return 0; 4239c3be6a5Sbeveloper return GetChannelType(channel, fInputChannelMask); 4242e9d6607Sbeveloper } 4252e9d6607Sbeveloper 426a9cf57cfSAxel Dörfler 4272e9d6607Sbeveloper void 4282e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain) 4292e9d6607Sbeveloper { 4302e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4312e9d6607Sbeveloper return; 4322e9d6607Sbeveloper if (gain < 0.0f) 4332e9d6607Sbeveloper gain = 0.0f; 4342e9d6607Sbeveloper 4352e9d6607Sbeveloper fInputChannelInfo[channel].gain = gain; 4362e9d6607Sbeveloper } 4372e9d6607Sbeveloper 438a9cf57cfSAxel Dörfler 4392e9d6607Sbeveloper float 4402e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel) 4412e9d6607Sbeveloper { 4422e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4432e9d6607Sbeveloper return 0.0f; 4442e9d6607Sbeveloper return fInputChannelInfo[channel].gain; 4452e9d6607Sbeveloper } 4462e9d6607Sbeveloper 447a9cf57cfSAxel Dörfler 4482e9d6607Sbeveloper void 449b006bbe1SStephan Aßmus MixerInput::_UpdateInputChannelDestinationMask() 4502e9d6607Sbeveloper { 4512e9d6607Sbeveloper // is the user already messed with the assignmens, don't do anything. 4529c3be6a5Sbeveloper if (fUserOverridesChannelDestinations) 4532e9d6607Sbeveloper return; 4542e9d6607Sbeveloper 455b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinationMask: enter\n"); 4562e9d6607Sbeveloper 457806cf560Sbeveloper // first apply a 1:1 mapping 458b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 459b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = GetChannelMask(i, 460b543dbc2SStephan Aßmus fInputChannelMask); 461b543dbc2SStephan Aßmus } 462806cf560Sbeveloper 463806cf560Sbeveloper // specialize this, depending on the available physical output channels 464643e1b2eSbeveloper if (fCore->OutputChannelCount() <= 2) { 465643e1b2eSbeveloper // less or equal two channels 466b543dbc2SStephan Aßmus if (fInputChannelCount == 1 467b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 468b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 469ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 470806cf560Sbeveloper } 471643e1b2eSbeveloper } else { 472643e1b2eSbeveloper // more than two channel output card 473b543dbc2SStephan Aßmus if (fInputChannelCount == 1 474b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 475b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 476ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 477806cf560Sbeveloper } 478b543dbc2SStephan Aßmus if (fInputChannelCount == 2 479b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) { 480b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 481b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 482806cf560Sbeveloper } 483b543dbc2SStephan Aßmus if (fInputChannelCount == 2 484b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) { 485b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 486b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 487806cf560Sbeveloper } 488b543dbc2SStephan Aßmus if (fInputChannelCount == 2 489b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) { 490b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 491b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 492806cf560Sbeveloper } 493b543dbc2SStephan Aßmus if (fInputChannelCount == 2 494b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) { 495b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 496b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 497806cf560Sbeveloper } 4982e9d6607Sbeveloper } 4992e9d6607Sbeveloper 500b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 501b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinationMask: input channel %d, " 502b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 503b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 504b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 505b543dbc2SStephan Aßmus } 506b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinationMask: leave\n"); 5072e9d6607Sbeveloper } 5082e9d6607Sbeveloper 509a9cf57cfSAxel Dörfler 5102e9d6607Sbeveloper void 511b006bbe1SStephan Aßmus MixerInput::_UpdateInputChannelDestinations() 5122e9d6607Sbeveloper { 513d91580cdSbeveloper int channel_count; 5142e9d6607Sbeveloper uint32 all_bits; 5152e9d6607Sbeveloper uint32 mask; 5162e9d6607Sbeveloper 517b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: enter\n"); 518b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 519b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: input channel %d, " 520b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 521b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 522b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 523b543dbc2SStephan Aßmus } 5242e9d6607Sbeveloper 5252e9d6607Sbeveloper all_bits = 0; 5262e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 5279c3be6a5Sbeveloper all_bits |= fInputChannelInfo[i].destination_mask; 5282e9d6607Sbeveloper 529b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits); 5302e9d6607Sbeveloper 5312e9d6607Sbeveloper channel_count = count_nonzero_bits(all_bits); 532b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: %d input channels, %d mixer " 533b543dbc2SStephan Aßmus "channels (%d old)\n", fInputChannelCount, channel_count, 534b543dbc2SStephan Aßmus fMixerChannelCount); 5352e9d6607Sbeveloper if (channel_count != fMixerChannelCount) { 5369c3be6a5Sbeveloper delete [] fMixerChannelInfo; 5372e9d6607Sbeveloper fMixerChannelInfo = new mixer_chan_info[channel_count]; 5382e9d6607Sbeveloper fMixerChannelCount = channel_count; 5392e9d6607Sbeveloper } 5402e9d6607Sbeveloper 5412e9d6607Sbeveloper // assign each mixer channel one type 5429c3be6a5Sbeveloper // and the gain from the fChannelTypeGain[] 543d91580cdSbeveloper mask = 1; 544d91580cdSbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5452e9d6607Sbeveloper while (mask != 0 && (all_bits & mask) == 0) 5462e9d6607Sbeveloper mask <<= 1; 5479c3be6a5Sbeveloper fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask); 548b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain 549b543dbc2SStephan Aßmus = fChannelTypeGain[fMixerChannelInfo[i].destination_type]; 5502e9d6607Sbeveloper mask <<= 1; 5512e9d6607Sbeveloper } 5522e9d6607Sbeveloper 5532e9d6607Sbeveloper // assign buffer_base pointer for each mixer channel 5542e9d6607Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5552e9d6607Sbeveloper int j; 5562e9d6607Sbeveloper for (j = 0; j < fInputChannelCount; j++) { 557b543dbc2SStephan Aßmus if (fInputChannelInfo[j].destination_mask 558b543dbc2SStephan Aßmus & ChannelTypeToChannelMask( 559b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_type)) { 560b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] 561b543dbc2SStephan Aßmus : 0; 5622e9d6607Sbeveloper break; 5632e9d6607Sbeveloper } 5642e9d6607Sbeveloper } 5652e9d6607Sbeveloper if (j == fInputChannelCount) { 566a2ca4723Sbeveloper ERROR("buffer assignment failed for mixer chan %d\n", i); 5672e9d6607Sbeveloper fMixerChannelInfo[i].buffer_base = fMixBuffer; 5682e9d6607Sbeveloper } 5692e9d6607Sbeveloper } 5702e9d6607Sbeveloper 571b543dbc2SStephan Aßmus for (int i = 0; i < fMixerChannelCount; i++) { 572b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: mixer channel %d, type %2d, " 573b543dbc2SStephan Aßmus "base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type, 574b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base, 575b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain); 576b543dbc2SStephan Aßmus } 5772e9d6607Sbeveloper 578b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: leave\n"); 5792e9d6607Sbeveloper } 580bf7ab50dSStephan Aßmus 581a9cf57cfSAxel Dörfler 582bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose 583bf7ab50dSStephan Aßmus // and is about to be modified at a later point 58469517c15Sbeveloper /* 5852e9d6607Sbeveloper void 586b543dbc2SStephan Aßmus MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, 587b543dbc2SStephan Aßmus float gain) 5882e9d6607Sbeveloper { 589b543dbc2SStephan Aßmus TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, 590b543dbc2SStephan Aßmus gain %.4f\n", channel, destination_type, gain); 5919c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 5929c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 5939c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 5942e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 5952e9d6607Sbeveloper return; 5969c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 5979c3be6a5Sbeveloper return; 5982e9d6607Sbeveloper if (gain < 0.0f) 5992e9d6607Sbeveloper gain = 0.0f; 6009c3be6a5Sbeveloper fChannelTypeGain[destination_type] = gain; 6019c3be6a5Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 6029c3be6a5Sbeveloper if (fMixerChannelInfo[i].destination_type == destination_type) { 6039c3be6a5Sbeveloper fMixerChannelInfo[i].destination_gain = gain; 6049c3be6a5Sbeveloper return; 6059c3be6a5Sbeveloper } 6069c3be6a5Sbeveloper } 6072e9d6607Sbeveloper } 6082e9d6607Sbeveloper 609a9cf57cfSAxel Dörfler 6102e9d6607Sbeveloper float 6119c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type) 6122e9d6607Sbeveloper { 6139c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 6149c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 6159c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 6162e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 6179c3be6a5Sbeveloper return 0.0f; 6189c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 6199c3be6a5Sbeveloper return 0.0f; 6209c3be6a5Sbeveloper return fChannelTypeGain[destination_type]; 6212e9d6607Sbeveloper } 62269517c15Sbeveloper */ 62369517c15Sbeveloper 624a9cf57cfSAxel Dörfler 62569517c15Sbeveloper void 62669517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain) 62769517c15Sbeveloper { 62869517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 62969517c15Sbeveloper return; 63069517c15Sbeveloper if (gain < 0.0f) 63169517c15Sbeveloper gain = 0.0f; 63269517c15Sbeveloper 63369517c15Sbeveloper fMixerChannelInfo[mixer_channel].destination_gain = gain; 63469517c15Sbeveloper fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain; 63569517c15Sbeveloper } 63669517c15Sbeveloper 637a9cf57cfSAxel Dörfler 63869517c15Sbeveloper float 63969517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel) 64069517c15Sbeveloper { 64169517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 64269517c15Sbeveloper return 0.0; 64369517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_gain; 64469517c15Sbeveloper } 64569517c15Sbeveloper 646a9cf57cfSAxel Dörfler 64769517c15Sbeveloper int 64869517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel) 64969517c15Sbeveloper { 65069517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 65169517c15Sbeveloper return -1; 65269517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_type; 65369517c15Sbeveloper } 6542e9d6607Sbeveloper 655a9cf57cfSAxel Dörfler 6562e9d6607Sbeveloper void 6571c237c18Sbeveloper MixerInput::SetEnabled(bool yesno) 6581c237c18Sbeveloper { 6591c237c18Sbeveloper fEnabled = yesno; 6601c237c18Sbeveloper } 6611c237c18Sbeveloper 662a9cf57cfSAxel Dörfler 6631c237c18Sbeveloper bool 6641c237c18Sbeveloper MixerInput::IsEnabled() 6651c237c18Sbeveloper { 6661c237c18Sbeveloper return fEnabled; 6671c237c18Sbeveloper } 6681c237c18Sbeveloper 669a9cf57cfSAxel Dörfler 6701c237c18Sbeveloper void 6718d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames) 6722e9d6607Sbeveloper { 673a9cf57cfSAxel Dörfler TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", 674a9cf57cfSAxel Dörfler framerate, frames); 675d5848e21Sbeveloper 6767b0daf5cSbeveloper fMixBufferFrameRate = framerate; 677a9cf57cfSAxel Dörfler fDebugMixBufferFrames = frames; 6782e9d6607Sbeveloper 679d5848e21Sbeveloper // frames and/or framerate can be 0 (if no output is connected) 680d5848e21Sbeveloper if (framerate == 0 || frames == 0) { 681a9cf57cfSAxel Dörfler if (fMixBuffer != NULL) { 682d5848e21Sbeveloper rtm_free(fMixBuffer); 683a9cf57cfSAxel Dörfler fMixBuffer = NULL; 684d5848e21Sbeveloper } 685d5848e21Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 686d5848e21Sbeveloper fInputChannelInfo[i].buffer_base = 0; 687d5848e21Sbeveloper fMixBufferFrameCount = 0; 688d5848e21Sbeveloper 689b006bbe1SStephan Aßmus _UpdateInputChannelDestinationMask(); 690b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 691d5848e21Sbeveloper return; 692d5848e21Sbeveloper } 6937b0daf5cSbeveloper 6947b0daf5cSbeveloper // make fMixBufferFrameCount an integral multiple of frames, 6957b0daf5cSbeveloper // but at least 3 times duration of our input buffer 6967b0daf5cSbeveloper // and at least 2 times duration of the output buffer 697b543dbc2SStephan Aßmus bigtime_t inputBufferLength = duration_for_frames( 698b543dbc2SStephan Aßmus fInput.format.u.raw_audio.frame_rate, 699b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)); 7007b0daf5cSbeveloper bigtime_t outputBufferLength = duration_for_frames(framerate, frames); 701b543dbc2SStephan Aßmus bigtime_t mixerBufferLength 702b543dbc2SStephan Aßmus = max_c(3 * inputBufferLength, 2 * outputBufferLength); 7037b0daf5cSbeveloper int temp = frames_for_duration(framerate, mixerBufferLength); 7047b0daf5cSbeveloper fMixBufferFrameCount = ((temp / frames) + 1) * frames; 7057b0daf5cSbeveloper 706a2ca4723Sbeveloper TRACE(" inputBufferLength %10Ld\n", inputBufferLength); 707a2ca4723Sbeveloper TRACE(" outputBufferLength %10Ld\n", outputBufferLength); 708a2ca4723Sbeveloper TRACE(" mixerBufferLength %10Ld\n", mixerBufferLength); 709d91580cdSbeveloper TRACE(" fMixBufferFrameCount %10d\n", fMixBufferFrameCount); 7107b0daf5cSbeveloper 7118d28117fSbeveloper ASSERT((fMixBufferFrameCount % frames) == 0); 7128d28117fSbeveloper 713e92593f4Sbeveloper fLastDataFrameWritten = -1; 714e92593f4Sbeveloper fFractionalFrames = 0.0; 715e92593f4Sbeveloper 7162e9d6607Sbeveloper rtm_free(fMixBuffer); 717356855c3Sbeveloper rtm_delete_pool(fRtmPool); 718a9cf57cfSAxel Dörfler 7197b0daf5cSbeveloper int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount; 720a9cf57cfSAxel Dörfler if (rtm_create_pool(&fRtmPool, size) != B_OK) 721a9cf57cfSAxel Dörfler fRtmPool = NULL; 722a9cf57cfSAxel Dörfler 723356855c3Sbeveloper fMixBuffer = (float*)rtm_alloc(fRtmPool, size); 724a9cf57cfSAxel Dörfler if (fMixBuffer == NULL) 725a9cf57cfSAxel Dörfler return; 7267b0daf5cSbeveloper 7277b0daf5cSbeveloper memset(fMixBuffer, 0, size); 7282e9d6607Sbeveloper 7292e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 7307b0daf5cSbeveloper fInputChannelInfo[i].buffer_base = &fMixBuffer[i]; 731d5848e21Sbeveloper 732b006bbe1SStephan Aßmus _UpdateInputChannelDestinationMask(); 733b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 7342e9d6607Sbeveloper } 735