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); 156*23bfcc55SJulian 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 " 186b543dbc2SStephan Aßmus "%4ld, expected frame was %4d, new frame is %4d\n", 187b543dbc2SStephan Aßmus 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 " 194b543dbc2SStephan Aßmus "%Ld\n", start - fLastDataAvailableTime); 195e92593f4Sbeveloper offset = expected_frame; 196e92593f4Sbeveloper out_frames++; 197e92593f4Sbeveloper } else { 198e92593f4Sbeveloper // buffer more than 10% of buffer duration too late 199b543dbc2SStephan Aßmus // TODO: zerofill buffer 200b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too late, time delta " 201b543dbc2SStephan Aßmus "%Ld\n", start - fLastDataAvailableTime); 202e92593f4Sbeveloper } 203e92593f4Sbeveloper } else { // start <= fLastDataAvailableTime 204e92593f4Sbeveloper // the new buffer is too early 205b543dbc2SStephan Aßmus if ((fLastDataAvailableTime - start) 206b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 207e92593f4Sbeveloper // buffer is less than 10% of buffer duration too early 208b543dbc2SStephan Aßmus printf("short glitch, buffer too early, time delta " 209b543dbc2SStephan Aßmus "%Ld\n", fLastDataAvailableTime - start); 210e92593f4Sbeveloper offset = expected_frame; 211e92593f4Sbeveloper out_frames--; 212e92593f4Sbeveloper if (out_frames < 1) 213e92593f4Sbeveloper out_frames = 1; 214e92593f4Sbeveloper } else { 215e92593f4Sbeveloper // buffer more than 10% of buffer duration too early 216b543dbc2SStephan Aßmus // TODO: zerofill buffer 217b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too early, time delta " 218b543dbc2SStephan Aßmus "%Ld\n", fLastDataAvailableTime - start); 219e92593f4Sbeveloper } 220e92593f4Sbeveloper } 221e92593f4Sbeveloper } 222e92593f4Sbeveloper } 223e92593f4Sbeveloper } 2247b0daf5cSbeveloper 225b543dbc2SStephan Aßmus // printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", 226b543dbc2SStephan Aßmus // start, 227b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 228b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 229b543dbc2SStephan Aßmus // offset + out_frames); 2307b0daf5cSbeveloper if (offset + out_frames > fMixBufferFrameCount) { 2317b0daf5cSbeveloper int out_frames1 = fMixBufferFrameCount - offset; 2327b0daf5cSbeveloper int out_frames2 = out_frames - out_frames1; 2337b0daf5cSbeveloper int in_frames1 = (out_frames1 * in_frames) / out_frames; 2347b0daf5cSbeveloper int in_frames2 = in_frames - in_frames1; 2357b0daf5cSbeveloper 236b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 237b543dbc2SStephan Aßmus // "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 238b543dbc2SStephan Aßmus // start, 239b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 240b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 241b543dbc2SStephan Aßmus // offset + out_frames1 - 1, 0, out_frames2 - 1); 242b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 243b543dbc2SStephan Aßmus "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 244b543dbc2SStephan Aßmus start, 245b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 246b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 247b543dbc2SStephan Aßmus offset + out_frames1 - 1, 0, out_frames2 - 1); 248b543dbc2SStephan Aßmus PRINT(5, " in_frames %5d, out_frames %5d, in_frames1 %5d, " 249b543dbc2SStephan Aßmus "out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n", 250b543dbc2SStephan Aßmus in_frames, out_frames, in_frames1, out_frames1, in_frames2, 251b543dbc2SStephan Aßmus out_frames2); 2527b0daf5cSbeveloper 253e92593f4Sbeveloper fLastDataFrameWritten = out_frames2 - 1; 254e92593f4Sbeveloper 255b543dbc2SStephan Aßmus // convert offset from frames into bytes 256b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2578d28117fSbeveloper 2587b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 259b543dbc2SStephan Aßmus fResampler[i]->Resample( 260b543dbc2SStephan Aßmus reinterpret_cast<char*>(data) 261b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 262b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames1, 263b543dbc2SStephan Aßmus reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base) 264b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), out_frames1, 2657b0daf5cSbeveloper fInputChannelInfo[i].gain); 2667b0daf5cSbeveloper 267b543dbc2SStephan Aßmus fResampler[i]->Resample( 268b543dbc2SStephan Aßmus reinterpret_cast<char*>(data) 269b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio) 270b543dbc2SStephan Aßmus + in_frames1 * bytes_per_frame(fInput.format.u.raw_audio), 271b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames2, 2727b0daf5cSbeveloper reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base), 273b543dbc2SStephan Aßmus fInputChannelCount * sizeof(float), out_frames2, 2747b0daf5cSbeveloper fInputChannelInfo[i].gain); 275e92593f4Sbeveloper 2767b0daf5cSbeveloper } 2777b0daf5cSbeveloper } else { 278b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 279b543dbc2SStephan Aßmus // "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 280b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 281b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 282b543dbc2SStephan Aßmus // offset + out_frames - 1); 283b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 284b543dbc2SStephan Aßmus "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 285b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 286b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 287b543dbc2SStephan Aßmus offset + out_frames - 1); 288191033efSbeveloper PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames); 2898d28117fSbeveloper 290e92593f4Sbeveloper fLastDataFrameWritten = offset + out_frames - 1; 291b543dbc2SStephan Aßmus // convert offset from frames into bytes 292b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2937b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 294b543dbc2SStephan Aßmus fResampler[i]->Resample( 295b543dbc2SStephan Aßmus reinterpret_cast<char*>(data) 296b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 297b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames, 298b543dbc2SStephan Aßmus reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base) 299b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), 300b543dbc2SStephan Aßmus out_frames, fInputChannelInfo[i].gain); 3017b0daf5cSbeveloper } 3027b0daf5cSbeveloper } 303e92593f4Sbeveloper fLastDataAvailableTime = start + buffer_duration; 304678c2017Sbeveloper } 3057ee2c804Sbeveloper 306bf7ab50dSStephan Aßmus 307b006bbe1SStephan Aßmus void 308b006bbe1SStephan Aßmus MixerInput::UpdateResamplingAlgorithm() 3097ee2c804Sbeveloper { 310b006bbe1SStephan Aßmus if (fResampler != NULL) { 311b006bbe1SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) 312b006bbe1SStephan Aßmus delete fResampler[i]; 313b006bbe1SStephan Aßmus delete[] fResampler; 3147ee2c804Sbeveloper } 315b006bbe1SStephan Aßmus // create resamplers 316b006bbe1SStephan Aßmus fResampler = new Resampler*[fInputChannelCount]; 317b006bbe1SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 318b006bbe1SStephan Aßmus switch (fCore->Settings()->ResamplingAlgorithm()) { 319b006bbe1SStephan Aßmus case 2: 320b006bbe1SStephan Aßmus fResampler[i] = new Interpolate( 321b006bbe1SStephan Aßmus fInput.format.u.raw_audio.format, 322b006bbe1SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 323b006bbe1SStephan Aßmus break; 324b006bbe1SStephan Aßmus default: 325b006bbe1SStephan Aßmus fResampler[i] = new Resampler( 326b006bbe1SStephan Aßmus fInput.format.u.raw_audio.format, 327b006bbe1SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 328b006bbe1SStephan Aßmus } 329b006bbe1SStephan Aßmus } 330e6c7c99fSbeveloper } 331e6c7c99fSbeveloper 332bf7ab50dSStephan Aßmus 333d91580cdSbeveloper int 334fae6ce82Sbeveloper MixerInput::GetInputChannelCount() 335fae6ce82Sbeveloper { 336fae6ce82Sbeveloper return fInputChannelCount; 337fae6ce82Sbeveloper } 338fae6ce82Sbeveloper 339bf7ab50dSStephan Aßmus 3402e9d6607Sbeveloper void 3419c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type) 3422e9d6607Sbeveloper { 3439c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 344e6c7c99fSbeveloper 3452e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3462e9d6607Sbeveloper return; 3472e9d6607Sbeveloper 3482e9d6607Sbeveloper // test if it is already set 3499c3be6a5Sbeveloper if (fInputChannelInfo[channel].destination_mask & mask) 3502e9d6607Sbeveloper return; 3512e9d6607Sbeveloper 3529c3be6a5Sbeveloper // verify that no other channel has id 3539c3be6a5Sbeveloper if (-1 != GetInputChannelForDestination(destination_type)) { 354b543dbc2SStephan Aßmus ERROR("MixerInput::AddInputChannelDestination: destination_type %d " 355b543dbc2SStephan Aßmus "already assigned to channel %d\n", destination_type, 356b543dbc2SStephan Aßmus GetInputChannelForDestination(destination_type)); 3579c3be6a5Sbeveloper return; 3589c3be6a5Sbeveloper } 3592e9d6607Sbeveloper 3602e9d6607Sbeveloper // add it to specified channel 3619c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask |= mask; 3622e9d6607Sbeveloper 3639c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 364b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 3652e9d6607Sbeveloper } 3662e9d6607Sbeveloper 367a9cf57cfSAxel Dörfler 3682e9d6607Sbeveloper void 3699c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type) 3702e9d6607Sbeveloper { 3719c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3722e9d6607Sbeveloper 3732e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3742e9d6607Sbeveloper return; 3752e9d6607Sbeveloper 3762e9d6607Sbeveloper // test if it is really set 3779c3be6a5Sbeveloper if ((fInputChannelInfo[channel].destination_mask & mask) == 0) 3782e9d6607Sbeveloper return; 3792e9d6607Sbeveloper 3802e9d6607Sbeveloper // remove it from specified channel 3819c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask &= ~mask; 3822e9d6607Sbeveloper 3839c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 384b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 3852e9d6607Sbeveloper } 3862e9d6607Sbeveloper 387a9cf57cfSAxel Dörfler 3889c3be6a5Sbeveloper bool 3899c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type) 3902e9d6607Sbeveloper { 3912e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3929c3be6a5Sbeveloper return false; 3939c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3949c3be6a5Sbeveloper return false; 395b543dbc2SStephan Aßmus return fInputChannelInfo[channel].destination_mask 396b543dbc2SStephan Aßmus & ChannelTypeToChannelMask(destination_type); 3972e9d6607Sbeveloper } 3982e9d6607Sbeveloper 399a9cf57cfSAxel Dörfler 4009c3be6a5Sbeveloper int 4019c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type) 4029c3be6a5Sbeveloper { 4039c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 4049c3be6a5Sbeveloper return -1; 4059c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 4069c3be6a5Sbeveloper for (int chan = 0; chan < fInputChannelCount; chan++) { 4079c3be6a5Sbeveloper if (fInputChannelInfo[chan].destination_mask & mask) 4089c3be6a5Sbeveloper return chan; 4099c3be6a5Sbeveloper } 4109c3be6a5Sbeveloper return -1; 4119c3be6a5Sbeveloper } 4129c3be6a5Sbeveloper 413a9cf57cfSAxel Dörfler 4149c3be6a5Sbeveloper int 4152e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel) 4162e9d6607Sbeveloper { 4172e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4182e9d6607Sbeveloper return 0; 4199c3be6a5Sbeveloper return GetChannelType(channel, fInputChannelMask); 4202e9d6607Sbeveloper } 4212e9d6607Sbeveloper 422a9cf57cfSAxel Dörfler 4232e9d6607Sbeveloper void 4242e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain) 4252e9d6607Sbeveloper { 4262e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4272e9d6607Sbeveloper return; 4282e9d6607Sbeveloper if (gain < 0.0f) 4292e9d6607Sbeveloper gain = 0.0f; 4302e9d6607Sbeveloper 4312e9d6607Sbeveloper fInputChannelInfo[channel].gain = gain; 4322e9d6607Sbeveloper } 4332e9d6607Sbeveloper 434a9cf57cfSAxel Dörfler 4352e9d6607Sbeveloper float 4362e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel) 4372e9d6607Sbeveloper { 4382e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4392e9d6607Sbeveloper return 0.0f; 4402e9d6607Sbeveloper return fInputChannelInfo[channel].gain; 4412e9d6607Sbeveloper } 4422e9d6607Sbeveloper 443a9cf57cfSAxel Dörfler 4442e9d6607Sbeveloper void 445b006bbe1SStephan Aßmus MixerInput::_UpdateInputChannelDestinationMask() 4462e9d6607Sbeveloper { 4472e9d6607Sbeveloper // is the user already messed with the assignmens, don't do anything. 4489c3be6a5Sbeveloper if (fUserOverridesChannelDestinations) 4492e9d6607Sbeveloper return; 4502e9d6607Sbeveloper 451b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinationMask: enter\n"); 4522e9d6607Sbeveloper 453806cf560Sbeveloper // first apply a 1:1 mapping 454b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 455b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = GetChannelMask(i, 456b543dbc2SStephan Aßmus fInputChannelMask); 457b543dbc2SStephan Aßmus } 458806cf560Sbeveloper 459806cf560Sbeveloper // specialize this, depending on the available physical output channels 460643e1b2eSbeveloper if (fCore->OutputChannelCount() <= 2) { 461643e1b2eSbeveloper // less or equal two channels 462b543dbc2SStephan Aßmus if (fInputChannelCount == 1 463b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 464b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 465ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 466806cf560Sbeveloper } 467643e1b2eSbeveloper } else { 468643e1b2eSbeveloper // more than two channel output card 469b543dbc2SStephan Aßmus if (fInputChannelCount == 1 470b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 471b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 472ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 473806cf560Sbeveloper } 474b543dbc2SStephan Aßmus if (fInputChannelCount == 2 475b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) { 476b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 477b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 478806cf560Sbeveloper } 479b543dbc2SStephan Aßmus if (fInputChannelCount == 2 480b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) { 481b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 482b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 483806cf560Sbeveloper } 484b543dbc2SStephan Aßmus if (fInputChannelCount == 2 485b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) { 486b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 487b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 488806cf560Sbeveloper } 489b543dbc2SStephan Aßmus if (fInputChannelCount == 2 490b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) { 491b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 492b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 493806cf560Sbeveloper } 4942e9d6607Sbeveloper } 4952e9d6607Sbeveloper 496b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 497b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinationMask: input channel %d, " 498b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 499b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 500b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 501b543dbc2SStephan Aßmus } 502b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinationMask: leave\n"); 5032e9d6607Sbeveloper } 5042e9d6607Sbeveloper 505a9cf57cfSAxel Dörfler 5062e9d6607Sbeveloper void 507b006bbe1SStephan Aßmus MixerInput::_UpdateInputChannelDestinations() 5082e9d6607Sbeveloper { 509d91580cdSbeveloper int channel_count; 5102e9d6607Sbeveloper uint32 all_bits; 5112e9d6607Sbeveloper uint32 mask; 5122e9d6607Sbeveloper 513b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: enter\n"); 514b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 515b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: input channel %d, " 516b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 517b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 518b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 519b543dbc2SStephan Aßmus } 5202e9d6607Sbeveloper 5212e9d6607Sbeveloper all_bits = 0; 5222e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 5239c3be6a5Sbeveloper all_bits |= fInputChannelInfo[i].destination_mask; 5242e9d6607Sbeveloper 525b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits); 5262e9d6607Sbeveloper 5272e9d6607Sbeveloper channel_count = count_nonzero_bits(all_bits); 528b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: %d input channels, %d mixer " 529b543dbc2SStephan Aßmus "channels (%d old)\n", fInputChannelCount, channel_count, 530b543dbc2SStephan Aßmus fMixerChannelCount); 5312e9d6607Sbeveloper if (channel_count != fMixerChannelCount) { 5329c3be6a5Sbeveloper delete [] fMixerChannelInfo; 5332e9d6607Sbeveloper fMixerChannelInfo = new mixer_chan_info[channel_count]; 5342e9d6607Sbeveloper fMixerChannelCount = channel_count; 5352e9d6607Sbeveloper } 5362e9d6607Sbeveloper 5372e9d6607Sbeveloper // assign each mixer channel one type 5389c3be6a5Sbeveloper // and the gain from the fChannelTypeGain[] 539d91580cdSbeveloper mask = 1; 540d91580cdSbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5412e9d6607Sbeveloper while (mask != 0 && (all_bits & mask) == 0) 5422e9d6607Sbeveloper mask <<= 1; 5439c3be6a5Sbeveloper fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask); 544b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain 545b543dbc2SStephan Aßmus = fChannelTypeGain[fMixerChannelInfo[i].destination_type]; 5462e9d6607Sbeveloper mask <<= 1; 5472e9d6607Sbeveloper } 5482e9d6607Sbeveloper 5492e9d6607Sbeveloper // assign buffer_base pointer for each mixer channel 5502e9d6607Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5512e9d6607Sbeveloper int j; 5522e9d6607Sbeveloper for (j = 0; j < fInputChannelCount; j++) { 553b543dbc2SStephan Aßmus if (fInputChannelInfo[j].destination_mask 554b543dbc2SStephan Aßmus & ChannelTypeToChannelMask( 555b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_type)) { 556b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] 557b543dbc2SStephan Aßmus : 0; 5582e9d6607Sbeveloper break; 5592e9d6607Sbeveloper } 5602e9d6607Sbeveloper } 5612e9d6607Sbeveloper if (j == fInputChannelCount) { 562a2ca4723Sbeveloper ERROR("buffer assignment failed for mixer chan %d\n", i); 5632e9d6607Sbeveloper fMixerChannelInfo[i].buffer_base = fMixBuffer; 5642e9d6607Sbeveloper } 5652e9d6607Sbeveloper } 5662e9d6607Sbeveloper 567b543dbc2SStephan Aßmus for (int i = 0; i < fMixerChannelCount; i++) { 568b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: mixer channel %d, type %2d, " 569b543dbc2SStephan Aßmus "base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type, 570b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base, 571b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain); 572b543dbc2SStephan Aßmus } 5732e9d6607Sbeveloper 574b006bbe1SStephan Aßmus TRACE("_UpdateInputChannelDestinations: leave\n"); 5752e9d6607Sbeveloper } 576bf7ab50dSStephan Aßmus 577a9cf57cfSAxel Dörfler 578bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose 579bf7ab50dSStephan Aßmus // and is about to be modified at a later point 58069517c15Sbeveloper /* 5812e9d6607Sbeveloper void 582b543dbc2SStephan Aßmus MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, 583b543dbc2SStephan Aßmus float gain) 5842e9d6607Sbeveloper { 585b543dbc2SStephan Aßmus TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, 586b543dbc2SStephan Aßmus gain %.4f\n", channel, destination_type, gain); 5879c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 5889c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 5899c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 5902e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 5912e9d6607Sbeveloper return; 5929c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 5939c3be6a5Sbeveloper return; 5942e9d6607Sbeveloper if (gain < 0.0f) 5952e9d6607Sbeveloper gain = 0.0f; 5969c3be6a5Sbeveloper fChannelTypeGain[destination_type] = gain; 5979c3be6a5Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5989c3be6a5Sbeveloper if (fMixerChannelInfo[i].destination_type == destination_type) { 5999c3be6a5Sbeveloper fMixerChannelInfo[i].destination_gain = gain; 6009c3be6a5Sbeveloper return; 6019c3be6a5Sbeveloper } 6029c3be6a5Sbeveloper } 6032e9d6607Sbeveloper } 6042e9d6607Sbeveloper 605a9cf57cfSAxel Dörfler 6062e9d6607Sbeveloper float 6079c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type) 6082e9d6607Sbeveloper { 6099c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 6109c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 6119c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 6122e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 6139c3be6a5Sbeveloper return 0.0f; 6149c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 6159c3be6a5Sbeveloper return 0.0f; 6169c3be6a5Sbeveloper return fChannelTypeGain[destination_type]; 6172e9d6607Sbeveloper } 61869517c15Sbeveloper */ 61969517c15Sbeveloper 620a9cf57cfSAxel Dörfler 62169517c15Sbeveloper void 62269517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain) 62369517c15Sbeveloper { 62469517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 62569517c15Sbeveloper return; 62669517c15Sbeveloper if (gain < 0.0f) 62769517c15Sbeveloper gain = 0.0f; 62869517c15Sbeveloper 62969517c15Sbeveloper fMixerChannelInfo[mixer_channel].destination_gain = gain; 63069517c15Sbeveloper fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain; 63169517c15Sbeveloper } 63269517c15Sbeveloper 633a9cf57cfSAxel Dörfler 63469517c15Sbeveloper float 63569517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel) 63669517c15Sbeveloper { 63769517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 63869517c15Sbeveloper return 0.0; 63969517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_gain; 64069517c15Sbeveloper } 64169517c15Sbeveloper 642a9cf57cfSAxel Dörfler 64369517c15Sbeveloper int 64469517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel) 64569517c15Sbeveloper { 64669517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 64769517c15Sbeveloper return -1; 64869517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_type; 64969517c15Sbeveloper } 6502e9d6607Sbeveloper 651a9cf57cfSAxel Dörfler 6522e9d6607Sbeveloper void 6531c237c18Sbeveloper MixerInput::SetEnabled(bool yesno) 6541c237c18Sbeveloper { 6551c237c18Sbeveloper fEnabled = yesno; 6561c237c18Sbeveloper } 6571c237c18Sbeveloper 658a9cf57cfSAxel Dörfler 6591c237c18Sbeveloper bool 6601c237c18Sbeveloper MixerInput::IsEnabled() 6611c237c18Sbeveloper { 6621c237c18Sbeveloper return fEnabled; 6631c237c18Sbeveloper } 6641c237c18Sbeveloper 665a9cf57cfSAxel Dörfler 6661c237c18Sbeveloper void 6678d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames) 6682e9d6607Sbeveloper { 669a9cf57cfSAxel Dörfler TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", 670a9cf57cfSAxel Dörfler framerate, frames); 671d5848e21Sbeveloper 6727b0daf5cSbeveloper fMixBufferFrameRate = framerate; 673a9cf57cfSAxel Dörfler fDebugMixBufferFrames = frames; 6742e9d6607Sbeveloper 675d5848e21Sbeveloper // frames and/or framerate can be 0 (if no output is connected) 676d5848e21Sbeveloper if (framerate == 0 || frames == 0) { 677a9cf57cfSAxel Dörfler if (fMixBuffer != NULL) { 678d5848e21Sbeveloper rtm_free(fMixBuffer); 679a9cf57cfSAxel Dörfler fMixBuffer = NULL; 680d5848e21Sbeveloper } 681d5848e21Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 682d5848e21Sbeveloper fInputChannelInfo[i].buffer_base = 0; 683d5848e21Sbeveloper fMixBufferFrameCount = 0; 684d5848e21Sbeveloper 685b006bbe1SStephan Aßmus _UpdateInputChannelDestinationMask(); 686b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 687d5848e21Sbeveloper return; 688d5848e21Sbeveloper } 6897b0daf5cSbeveloper 6907b0daf5cSbeveloper // make fMixBufferFrameCount an integral multiple of frames, 6917b0daf5cSbeveloper // but at least 3 times duration of our input buffer 6927b0daf5cSbeveloper // and at least 2 times duration of the output buffer 693b543dbc2SStephan Aßmus bigtime_t inputBufferLength = duration_for_frames( 694b543dbc2SStephan Aßmus fInput.format.u.raw_audio.frame_rate, 695b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)); 6967b0daf5cSbeveloper bigtime_t outputBufferLength = duration_for_frames(framerate, frames); 697b543dbc2SStephan Aßmus bigtime_t mixerBufferLength 698b543dbc2SStephan Aßmus = max_c(3 * inputBufferLength, 2 * outputBufferLength); 6997b0daf5cSbeveloper int temp = frames_for_duration(framerate, mixerBufferLength); 7007b0daf5cSbeveloper fMixBufferFrameCount = ((temp / frames) + 1) * frames; 7017b0daf5cSbeveloper 702a2ca4723Sbeveloper TRACE(" inputBufferLength %10Ld\n", inputBufferLength); 703a2ca4723Sbeveloper TRACE(" outputBufferLength %10Ld\n", outputBufferLength); 704a2ca4723Sbeveloper TRACE(" mixerBufferLength %10Ld\n", mixerBufferLength); 705d91580cdSbeveloper TRACE(" fMixBufferFrameCount %10d\n", fMixBufferFrameCount); 7067b0daf5cSbeveloper 7078d28117fSbeveloper ASSERT((fMixBufferFrameCount % frames) == 0); 7088d28117fSbeveloper 709e92593f4Sbeveloper fLastDataFrameWritten = -1; 710e92593f4Sbeveloper fFractionalFrames = 0.0; 711e92593f4Sbeveloper 7122e9d6607Sbeveloper rtm_free(fMixBuffer); 713356855c3Sbeveloper rtm_delete_pool(fRtmPool); 714a9cf57cfSAxel Dörfler 7157b0daf5cSbeveloper int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount; 716a9cf57cfSAxel Dörfler if (rtm_create_pool(&fRtmPool, size) != B_OK) 717a9cf57cfSAxel Dörfler fRtmPool = NULL; 718a9cf57cfSAxel Dörfler 719356855c3Sbeveloper fMixBuffer = (float*)rtm_alloc(fRtmPool, size); 720a9cf57cfSAxel Dörfler if (fMixBuffer == NULL) 721a9cf57cfSAxel Dörfler return; 7227b0daf5cSbeveloper 7237b0daf5cSbeveloper memset(fMixBuffer, 0, size); 7242e9d6607Sbeveloper 7252e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 7267b0daf5cSbeveloper fInputChannelInfo[i].buffer_base = &fMixBuffer[i]; 727d5848e21Sbeveloper 728b006bbe1SStephan Aßmus _UpdateInputChannelDestinationMask(); 729b006bbe1SStephan Aßmus _UpdateInputChannelDestinations(); 7302e9d6607Sbeveloper } 731